diff --git a/colors/README.md b/colors/README.md index 3148b7cab3..3c371197f9 100644 --- a/colors/README.md +++ b/colors/README.md @@ -1,18 +1,19 @@ # colors Is a basic console color module intended for [Deno](https://deno.land/). It is -inspired by [chalk](https://www.npmjs.com/package/chalk) and +inspired by [chalk](https://www.npmjs.com/package/chalk), +[kleur](https://www.npmjs.com/package/kleur), and [colors](https://www.npmjs.com/package/colors) on npm. ## Usage -The main modules exports a single function name `color` which is a function that -provides chaining to stack colors. Basic usage looks like this: +The main modules exports several functions which can color the output to the +console: ```ts -import { color } from "https://deno.land/x/std/colors/mod.ts"; +import { bgBlue, red, bold } from "https://deno.land/x/std/colors/mod.ts"; -console.log(color.bgBlue.red.bold("Hello world!")); +console.log(bgBlue(red(bold("Hello world!")))); ``` ## TODO diff --git a/colors/example.ts b/colors/example.ts index e98a32ec98..02bc93432e 100644 --- a/colors/example.ts +++ b/colors/example.ts @@ -1,3 +1,3 @@ -import { color } from "./mod.ts"; +import { bgBlue, red, bold, italic } from "./mod.ts"; -console.log(color.bgBlue.red.bold("Hello world!")); +console.log(bgBlue(italic(red(bold("Hello world!"))))); diff --git a/colors/mod.ts b/colors/mod.ts index 8316060dbb..e271c54cf7 100644 --- a/colors/mod.ts +++ b/colors/mod.ts @@ -1,33 +1,131 @@ // Copyright 2018-2019 the Deno authors. All rights reserved. MIT license. -import { styles } from "./styles.ts"; -type Styles = { readonly [S in keyof typeof styles]: Color }; - -type Color = Styles & { - (str: string): string; -}; - -const styleStack: string[] = []; - -export const color = function color(str: string): string { - styleStack.reverse(); - while (styleStack.length) { - const style = styleStack.pop(); - const code = styles[style]; - str = `${code.open}${str.replace(code.closeRe, code.open)}${ - code.close - }`.replace(/\r?\n/g, `${code.close}$&${code.open}`); - } - return str; -} as Color; - -for (const style of Object.keys(styles)) { - Object.defineProperty(color, style, { - get() { - styleStack.push(style); - return color; - }, - enumerable: true, - configurable: false - }); +interface Code { + open: string; + close: string; + regexp: RegExp; +} + +let enabled = true; + +export function setEnabled(value: boolean) { + enabled = value; +} + +export function getEnabled(): boolean { + return enabled; +} + +function code(open: number, close: number): Code { + return { + open: `\x1b[${open}m`, + close: `\x1b[${close}m`, + regexp: new RegExp(`\\x1b\\[${close}m`, "g") + }; +} + +function run(str: string, code: Code) { + return enabled + ? `${code.open}${str.replace(code.regexp, code.open)}${code.close}` + : str; +} + +export function reset(str: string): string { + return run(str, code(0, 0)); +} + +export function bold(str: string): string { + return run(str, code(1, 22)); +} + +export function dim(str: string): string { + return run(str, code(2, 22)); +} + +export function italic(str: string): string { + return run(str, code(3, 23)); +} + +export function underline(str: string): string { + return run(str, code(4, 24)); +} + +export function inverse(str: string): string { + return run(str, code(7, 27)); +} + +export function hidden(str: string): string { + return run(str, code(8, 28)); +} + +export function strikethrough(str: string): string { + return run(str, code(9, 29)); +} + +export function black(str: string): string { + return run(str, code(30, 39)); +} + +export function red(str: string): string { + return run(str, code(31, 39)); +} + +export function green(str: string): string { + return run(str, code(32, 39)); +} + +export function yellow(str: string): string { + return run(str, code(33, 39)); +} + +export function blue(str: string): string { + return run(str, code(34, 39)); +} + +export function magenta(str: string): string { + return run(str, code(35, 39)); +} + +export function cyan(str: string): string { + return run(str, code(36, 39)); +} + +export function white(str: string): string { + return run(str, code(37, 39)); +} + +export function gray(str: string): string { + return run(str, code(90, 39)); +} + +export function bgBlack(str: string): string { + return run(str, code(40, 49)); +} + +export function bgRed(str: string): string { + return run(str, code(41, 49)); +} + +export function bgGreen(str: string): string { + return run(str, code(42, 49)); +} + +export function bgYellow(str: string): string { + return run(str, code(43, 49)); +} + +export function bgBlue(str: string): string { + return run(str, code(44, 49)); +} + +export function bgMagenta(str: string): string { + return run(str, code(45, 49)); +} + +export function bgCyan(str: string): string { + return run(str, code(46, 49)); +} + +export function bgWhite(str: string): string { + return run(str, code(47, 49)); } diff --git a/colors/styles.ts b/colors/styles.ts deleted file mode 100644 index c9fd0eb3d4..0000000000 --- a/colors/styles.ts +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license. -const matchOperatorsRe = /[|\\{}()[\]^$+*?.]/g; -function escapeStringRegexp(str: string): string { - return str.replace(matchOperatorsRe, "\\$&"); -} - -const codes = { - reset: [0, 0], - bold: [1, 22], - dim: [2, 22], - italic: [3, 23], - underline: [4, 24], - inverse: [7, 27], - hidden: [8, 28], - strikethrough: [9, 29], - - black: [30, 39], - red: [31, 39], - green: [32, 39], - yellow: [33, 39], - blue: [34, 39], - magenta: [35, 39], - cyan: [36, 39], - white: [37, 39], - - blackBright: [90, 39], - redBright: [91, 39], - greenBright: [92, 39], - yellowBright: [93, 39], - blueBright: [94, 39], - magentaBright: [95, 39], - cyanBright: [96, 39], - whiteBright: [97, 39], - - bgBlack: [40, 49], - bgRed: [41, 49], - bgGreen: [42, 49], - bgYellow: [43, 49], - bgBlue: [44, 49], - bgMagenta: [45, 49], - bgCyan: [46, 49], - bgWhite: [47, 49], - - bgBlackBright: [100, 49], - bgRedBright: [101, 49], - bgGreenBright: [102, 49], - bgYellowBright: [103, 49], - bgBlueBright: [104, 49], - bgMagentaBright: [105, 49], - bgCyanBright: [106, 49], - bgWhiteBright: [107, 49] -}; - -type Styles = { - [S in keyof T]: { open: string; close: string; closeRe: RegExp } -}; - -export const styles: Styles = {} as any; - -for (const [style, [open, close]] of Object.entries(codes)) { - styles[style] = { - open: `\u001b[${open}m`, - close: `\u001b[${close}m`, - closeRe: new RegExp(escapeStringRegexp(`\u001b[${close}m`), "g") - }; -} diff --git a/colors/test.ts b/colors/test.ts index 266868090f..f12f0cbb1f 100644 --- a/colors/test.ts +++ b/colors/test.ts @@ -1,25 +1,21 @@ -import { assertEqual, test } from "../testing/mod.ts"; -import { color } from "./mod.ts"; +import { assert, test } from "../testing/mod.ts"; +import { red, bgBlue, setEnabled, getEnabled } from "./mod.ts"; import "./example.ts"; test(function singleColor() { - assertEqual(color.red("Hello world"), "Hello world"); + assert.equal(red("Hello world"), "Hello world"); }); test(function doubleColor() { - assertEqual(color.red.bgBlue("Hello world"), - "Hello world"); -}); - -test(function newLinesContinueColors() { - assertEqual(color.red("Hello\nworld"), - "Hello\nworld"); - assertEqual(color.red("Hello\r\nworld"), - "Hello\r\nworld"); - assertEqual(color.red("Hello\n\nworld"), - "Hello\n\nworld"); + assert.equal(bgBlue(red("Hello world")), "Hello world"); }); test(function replacesCloseCharacters() { - assertEqual(color.red("Hello"), "Hello"); + assert.equal(red("Hello"), "Hello"); +}); + +test(function enablingColors() { + assert.equal(getEnabled(), true); + setEnabled(false); + assert.equal(bgBlue(red("Hello world")), "Hello world"); });