summaryrefslogtreecommitdiff
path: root/colors
diff options
context:
space:
mode:
Diffstat (limited to 'colors')
-rw-r--r--colors/README.md28
-rw-r--r--colors/main.ts33
-rw-r--r--colors/main_test.ts10
-rw-r--r--colors/styles.ts66
4 files changed, 137 insertions, 0 deletions
diff --git a/colors/README.md b/colors/README.md
new file mode 100644
index 000000000..f20d1939a
--- /dev/null
+++ b/colors/README.md
@@ -0,0 +1,28 @@
+# colors
+
+Is a basic console color library intended for [Deno](https://deno.land/). It is
+inspired by packages like [chalk](https://www.npmjs.com/package/chalk) 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:
+
+```ts
+import { color } from "https://deno.land/x/colors/main.ts";
+
+console.log(color.bgBlue.red.bold("Hello world!"));
+```
+
+## TODO
+
+- Currently, it just assumes it is running in an environment that supports ANSI
+ escape code terminal coloring. It should actually detect, specifically
+ windows and adjust properly.
+
+- Test coverage is very basic at the moment.
+
+---
+
+Copyright 2018 the Deno authors. All rights reserved. MIT license.
diff --git a/colors/main.ts b/colors/main.ts
new file mode 100644
index 000000000..af4e1aace
--- /dev/null
+++ b/colors/main.ts
@@ -0,0 +1,33 @@
+// Copyright 2018 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
+ });
+}
diff --git a/colors/main_test.ts b/colors/main_test.ts
new file mode 100644
index 000000000..596a592a6
--- /dev/null
+++ b/colors/main_test.ts
@@ -0,0 +1,10 @@
+import { assertEqual, test } from "https://deno.land/x/testing/testing.ts";
+import { color } from "./main";
+
+test(function singleColor() {
+ assertEqual(color.red("Hello world"), "Hello world");
+});
+
+test(function doubleColor() {
+ assertEqual(color.red.bgBlue("Hello world"), "Hello world");
+});
diff --git a/colors/styles.ts b/colors/styles.ts
new file mode 100644
index 000000000..74f609b83
--- /dev/null
+++ b/colors/styles.ts
@@ -0,0 +1,66 @@
+// Copyright 2018 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<T> = {
+ [S in keyof T]: { open: string; close: string; closeRe: RegExp }
+};
+
+export const styles: Styles<typeof codes> = {} 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")
+ };
+}