From 503159805f044d6874543d659951b3ccdf9092f5 Mon Sep 17 00:00:00 2001 From: Felipe Date: Sun, 4 Feb 2018 15:10:22 -0200 Subject: [PATCH] Added wrapper support The wrapper marks the unprintable characters from each style tag. This is very useful when debugging or outputing it in different terminals. You can use it to identify the unprintable characters or even to escape them. Also added tests for it. Added a description about it to the readme dile. wq --- index.js | 14 ++++++++++++-- readme.md | 20 ++++++++++++++++++++ test/chalk.js | 2 +- test/wrapper.js | 25 +++++++++++++++++++++++++ types/index.d.ts | 7 +++++++ 5 files changed, 65 insertions(+), 3 deletions(-) create mode 100644 test/wrapper.js diff --git a/index.js b/index.js index 05e62b3..ad9d4b3 100644 --- a/index.js +++ b/index.js @@ -22,6 +22,10 @@ function applyOptions(obj, options) { const scLevel = supportsColor ? supportsColor.level : 0; obj.level = options.level === undefined ? scLevel : options.level; obj.enabled = 'enabled' in options ? options.enabled : obj.level > 0; + + // By default, wrappers are empty strings + const defaultWrapper = {pre: '', post: ''}; + obj.wrapper = typeof options.wrapper === 'object' ? Object.assign({}, defaultWrapper, options.wrapper) : defaultWrapper; } function Chalk(options) { @@ -149,6 +153,9 @@ function build(_styles, _empty, key) { // See below for fix regarding invisible grey/dim combination on Windows builder.hasGrey = this.hasGrey || key === 'gray' || key === 'grey'; + // Setting the wrapper in case it is being used + builder.wrapper = this.wrapper; + // `__proto__` is used because we must return a function, but there is // no way to create a function with a different prototype builder.__proto__ = proto; // eslint-disable-line no-proto @@ -189,12 +196,15 @@ function applyStyle() { // Replace any instances already present with a re-opening code // otherwise only the part of the string until said closing code // will be colored, and the rest will simply be 'plain'. - str = code.open + str.replace(code.closeRe, code.open) + code.close; + const open = this.wrapper.pre + code.open + this.wrapper.post; + const close = this.wrapper.pre + code.close + this.wrapper.post; + + str = open + str.replace(code.closeRe, code.open) + close; // Close the styling before a linebreak and reopen // after next line to fix a bleed issue on macOS // https://github.com/chalk/chalk/pull/92 - str = str.replace(/\r?\n/g, `${code.close}$&${code.open}`); + str = str.replace(/\r?\n/g, `${close}$&${open}`); } // Reset the original `dim` if we changed it to work around the Windows dimmed gray issue diff --git a/readme.md b/readme.md index eb74603..2754499 100644 --- a/readme.md +++ b/readme.md @@ -149,6 +149,26 @@ Levels are as follows: 2. 256 color support 3. Truecolor support (16 million colors) +### chalk.wrapper + +The wrapper marks the unprintable characters. +A wrapper can be added to the styles, so you can escape characters or add marks to then. +By default, these wrappers are empty strings `""`. + +The wrappers object has two properties, `pre` and `post`. +For example: + +```js +const ctx = new chalk.constructor({wrapper: { + pre: '>', + post: '<', +}}); + +ctx.red('foo') // outputs "><" +``` + +This can be specially useful when escaping characters, using it into a _PS1_ string or debugging and outputing it into different terminals/TTYs. + ### chalk.supportsColor Detect whether the terminal [supports color](https://github.com/chalk/supports-color). Used internally and handled for you, but exposed for convenience. diff --git a/test/chalk.js b/test/chalk.js index 8480dad..d2add8d 100644 --- a/test/chalk.js +++ b/test/chalk.js @@ -6,7 +6,7 @@ require('./_supports-color')(__dirname); const m = require('..'); console.log('TERM:', process.env.TERM || '[none]'); -console.log('platform:', process.platform || '[unknown]'); +console.log('Platform:', process.platform || '[unknown]'); test('don\'t add any styling when called as the base function', t => { t.is(m('foo'), 'foo'); diff --git a/test/wrapper.js b/test/wrapper.js new file mode 100644 index 0000000..156e4eb --- /dev/null +++ b/test/wrapper.js @@ -0,0 +1,25 @@ +// Import path from 'path'; +import test from 'ava'; +// Import execa from 'execa'; + +// Spoof supports-color +require('./_supports-color')(__dirname); + +const m = require('..'); + +m.wrapper = { + pre: '@', + post: '#' +}; + +test('add wrapper to underline', t => { + t.is(m.underline('foo'), '@\u001B[4m#foo@\u001B[24m#'); +}); + +test('add wrapper to color', t => { + t.is(m.red('foo'), '@\u001B[31m#foo@\u001B[39m#'); +}); + +test('add wrapper to bgColor', t => { + t.is(m.bgRed('foo'), '@\u001B[41m#foo@\u001B[49m#'); +}); diff --git a/types/index.d.ts b/types/index.d.ts index b4e4dc5..c5a4708 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -11,6 +11,12 @@ export const enum Level { export interface ChalkOptions { enabled?: boolean; level?: Level; + wrapper?: Wrapper; +} + +export interface Wrapper { + pre: String, + post: String } export interface ChalkConstructor { @@ -31,6 +37,7 @@ export interface Chalk { constructor: ChalkConstructor; enabled: boolean; level: Level; + wrapper: Wrapper; rgb(r: number, g: number, b: number): this; hsl(h: number, s: number, l: number): this; hsv(h: number, s: number, v: number): this;