@peteanderson/ansi 0.3.2 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/ansi.d.ts +28 -37
- package/dist/ansi.d.ts.map +1 -0
- package/dist/ansi.js +29 -52
- package/dist/ansi.js.map +1 -0
- package/dist/caret.d.ts +5 -3
- package/dist/caret.d.ts.map +1 -0
- package/dist/caret.js +6 -8
- package/dist/caret.js.map +1 -0
- package/dist/erase.d.ts +5 -1
- package/dist/erase.d.ts.map +1 -0
- package/dist/erase.js +4 -2
- package/dist/erase.js.map +1 -0
- package/dist/features/build.d.ts +7 -11
- package/dist/features/build.d.ts.map +1 -0
- package/dist/features/build.js +12 -25
- package/dist/features/build.js.map +1 -0
- package/dist/features/detect.d.ts +4 -4
- package/dist/features/detect.d.ts.map +1 -0
- package/dist/features/detect.js +5 -6
- package/dist/features/detect.js.map +1 -0
- package/dist/features/features.d.ts +4 -4
- package/dist/features/features.d.ts.map +1 -0
- package/dist/features/features.js +24 -34
- package/dist/features/features.js.map +1 -0
- package/dist/features/index.d.ts +2 -2
- package/dist/features/index.d.ts.map +1 -0
- package/dist/features/index.js +17 -1
- package/dist/features/index.js.map +1 -0
- package/dist/features/types.d.ts +10 -0
- package/dist/features/types.d.ts.map +1 -0
- package/dist/features/types.js +3 -0
- package/dist/features/types.js.map +1 -0
- package/dist/index.d.ts +3 -81
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +23 -1
- package/dist/index.js.map +1 -0
- package/dist/pad.d.ts +3 -12
- package/dist/pad.d.ts.map +1 -0
- package/dist/pad.js +8 -14
- package/dist/pad.js.map +1 -0
- package/dist/patterns.d.ts +4 -3
- package/dist/patterns.d.ts.map +1 -0
- package/dist/patterns.js +6 -4
- package/dist/patterns.js.map +1 -0
- package/dist/scroll.d.ts +5 -3
- package/dist/scroll.d.ts.map +1 -0
- package/dist/scroll.js +6 -6
- package/dist/scroll.js.map +1 -0
- package/dist/sgr/color/color.d.ts +5 -9
- package/dist/sgr/color/color.d.ts.map +1 -0
- package/dist/sgr/color/color.js +22 -29
- package/dist/sgr/color/color.js.map +1 -0
- package/dist/sgr/color/index.d.ts +2 -2
- package/dist/sgr/color/index.d.ts.map +1 -0
- package/dist/sgr/color/index.js +17 -1
- package/dist/sgr/color/index.js.map +1 -0
- package/dist/sgr/color/test-rgb.d.ts +3 -0
- package/dist/sgr/color/test-rgb.d.ts.map +1 -0
- package/dist/sgr/color/test-rgb.js +149 -0
- package/dist/sgr/color/test-rgb.js.map +1 -0
- package/dist/sgr/color/types.d.ts +30 -0
- package/dist/sgr/color/types.d.ts.map +1 -0
- package/dist/sgr/color/types.js +3 -0
- package/dist/sgr/color/types.js.map +1 -0
- package/dist/sgr/color/utils.d.ts +7 -27
- package/dist/sgr/color/utils.d.ts.map +1 -0
- package/dist/sgr/color/utils.js +17 -32
- package/dist/sgr/color/utils.js.map +1 -0
- package/dist/sgr/index.d.ts +4 -9
- package/dist/sgr/index.d.ts.map +1 -0
- package/dist/sgr/index.js +18 -4
- package/dist/sgr/index.js.map +1 -0
- package/dist/sgr/reset.d.ts +2 -1
- package/dist/sgr/reset.d.ts.map +1 -0
- package/dist/sgr/reset.js +4 -1
- package/dist/sgr/reset.js.map +1 -0
- package/dist/sgr/sgr.d.ts +4 -3
- package/dist/sgr/sgr.d.ts.map +1 -0
- package/dist/sgr/sgr.js +8 -22
- package/dist/sgr/sgr.js.map +1 -0
- package/dist/sgr/style.d.ts +3 -1
- package/dist/sgr/style.d.ts.map +1 -0
- package/dist/sgr/style.js +5 -3
- package/dist/sgr/style.js.map +1 -0
- package/dist/sgr/utils.d.ts +3 -2
- package/dist/sgr/utils.d.ts.map +1 -0
- package/dist/sgr/utils.js +3 -3
- package/dist/sgr/utils.js.map +1 -0
- package/dist/simplify/atom.d.ts +4 -3
- package/dist/simplify/atom.d.ts.map +1 -0
- package/dist/simplify/atom.js +12 -9
- package/dist/simplify/atom.js.map +1 -0
- package/dist/simplify/index.d.ts +2 -2
- package/dist/simplify/index.d.ts.map +1 -0
- package/dist/simplify/index.js +17 -1
- package/dist/simplify/index.js.map +1 -0
- package/dist/simplify/lookup.d.ts +3 -5
- package/dist/simplify/lookup.d.ts.map +1 -0
- package/dist/simplify/lookup.js +9 -13
- package/dist/simplify/lookup.js.map +1 -0
- package/dist/simplify/simplify.d.ts +2 -1
- package/dist/simplify/simplify.d.ts.map +1 -0
- package/dist/simplify/simplify.js +7 -7
- package/dist/simplify/simplify.js.map +1 -0
- package/dist/simplify/state.d.ts +3 -8
- package/dist/simplify/state.d.ts.map +1 -0
- package/dist/simplify/state.js +9 -13
- package/dist/simplify/state.js.map +1 -0
- package/dist/simplify/test.d.ts +2 -0
- package/dist/simplify/test.d.ts.map +1 -0
- package/dist/simplify/test.js +64 -0
- package/dist/simplify/test.js.map +1 -0
- package/dist/simplify/types.d.ts +9 -0
- package/dist/simplify/types.d.ts.map +1 -0
- package/dist/simplify/types.js +3 -0
- package/dist/simplify/types.js.map +1 -0
- package/dist/simplify/utils.d.ts +3 -2
- package/dist/simplify/utils.d.ts.map +1 -0
- package/dist/simplify/utils.js +4 -3
- package/dist/simplify/utils.js.map +1 -0
- package/dist/slice.d.ts +21 -1
- package/dist/slice.d.ts.map +1 -0
- package/dist/slice.js +10 -22
- package/dist/slice.js.map +1 -0
- package/dist/strip.d.ts +4 -15
- package/dist/strip.d.ts.map +1 -0
- package/dist/strip.js +10 -17
- package/dist/strip.js.map +1 -0
- package/dist/terminal.d.ts +5 -1
- package/dist/terminal.d.ts.map +1 -0
- package/dist/terminal.js +4 -2
- package/dist/terminal.js.map +1 -0
- package/package.json +9 -22
- package/src/ansi.ts +71 -0
- package/src/{caret.js → caret.ts} +9 -15
- package/src/{erase.js → erase.ts} +7 -10
- package/src/features/build.ts +52 -0
- package/src/features/detect.ts +33 -0
- package/src/features/features.ts +48 -0
- package/src/features/index.ts +1 -0
- package/src/features/{types.d.ts → types.ts} +1 -1
- package/src/index.ts +2 -0
- package/src/pad.ts +7 -0
- package/src/{patterns.js → patterns.ts} +3 -5
- package/src/scroll.ts +13 -0
- package/src/sgr/color/{color.js → color.ts} +26 -35
- package/src/sgr/color/index.ts +1 -0
- package/src/sgr/color/{types.d.ts → types.ts} +6 -2
- package/src/sgr/color/utils.ts +58 -0
- package/src/sgr/index.ts +3 -0
- package/src/sgr/reset.ts +1 -0
- package/src/sgr/sgr.ts +68 -0
- package/src/sgr/{style.js → style.ts} +3 -5
- package/src/sgr/{utils.js → utils.ts} +3 -6
- package/src/simplify/{atom.js → atom.ts} +11 -13
- package/src/simplify/index.ts +1 -0
- package/src/simplify/{lookup.js → lookup.ts} +5 -14
- package/src/simplify/{simplify.js → simplify.ts} +4 -10
- package/src/simplify/state.ts +63 -0
- package/src/simplify/{types.d.ts → types.ts} +5 -5
- package/src/simplify/{utils.js → utils.ts} +4 -10
- package/src/{slice.js → slice.ts} +12 -26
- package/src/strip.ts +5 -0
- package/src/{terminal.js → terminal.ts} +4 -7
- package/LICENSE +0 -7
- package/README.md +0 -174
- package/src/ansi.js +0 -70
- package/src/features/build.js +0 -68
- package/src/features/detect.js +0 -40
- package/src/features/features.js +0 -53
- package/src/features/index.js +0 -1
- package/src/index.js +0 -1
- package/src/pad.js +0 -21
- package/src/scroll.js +0 -18
- package/src/sgr/color/index.js +0 -1
- package/src/sgr/color/utils.js +0 -81
- package/src/sgr/index.js +0 -5
- package/src/sgr/reset.js +0 -3
- package/src/sgr/sgr.js +0 -77
- package/src/simplify/index.js +0 -1
- package/src/simplify/state.js +0 -73
- package/src/strip.js +0 -23
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { getColorDepth, detectFeatureSupport } from "./detect";
|
|
2
|
+
import type { ColorDepth, Features } from "./types";
|
|
3
|
+
|
|
4
|
+
function normalizeColorDepth(colorDepth: number): ColorDepth {
|
|
5
|
+
colorDepth = Math.floor(colorDepth);
|
|
6
|
+
if (colorDepth >= 24) return 24;
|
|
7
|
+
if (colorDepth >= 8) return 8;
|
|
8
|
+
if (colorDepth >= 4) return 4;
|
|
9
|
+
if (colorDepth === 3) return 3;
|
|
10
|
+
return 1;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function build(
|
|
14
|
+
isTTY : boolean,
|
|
15
|
+
colorDepth : ColorDepth,
|
|
16
|
+
style? : boolean,
|
|
17
|
+
caret? : boolean,
|
|
18
|
+
erase? : boolean,
|
|
19
|
+
scroll? : boolean,
|
|
20
|
+
terminal? : boolean,
|
|
21
|
+
): Features {
|
|
22
|
+
if (
|
|
23
|
+
style !== undefined &&
|
|
24
|
+
caret !== undefined &&
|
|
25
|
+
erase !== undefined &&
|
|
26
|
+
scroll !== undefined &&
|
|
27
|
+
terminal !== undefined
|
|
28
|
+
)
|
|
29
|
+
return {colorDepth: normalizeColorDepth(colorDepth), style, caret, erase, scroll, terminal};
|
|
30
|
+
|
|
31
|
+
const support = detectFeatureSupport(isTTY, colorDepth);
|
|
32
|
+
return {
|
|
33
|
+
colorDepth : normalizeColorDepth(colorDepth),
|
|
34
|
+
style : style ?? support.style,
|
|
35
|
+
caret : caret ?? support.caret,
|
|
36
|
+
erase : erase ?? support.erase,
|
|
37
|
+
scroll : scroll ?? support.scroll,
|
|
38
|
+
terminal : terminal ?? support.terminal,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export const boolean = (isTTY: boolean, enabled: boolean): Features =>
|
|
43
|
+
build(isTTY, enabled ? 4 : 1);
|
|
44
|
+
|
|
45
|
+
export const number = (isTTY: boolean, colorDepth: ColorDepth): Features =>
|
|
46
|
+
build(isTTY, colorDepth);
|
|
47
|
+
|
|
48
|
+
export const tty = (stream: NodeJS.WriteStream): Features =>
|
|
49
|
+
build(true, getColorDepth(stream));
|
|
50
|
+
|
|
51
|
+
export const pipe = (): Features =>
|
|
52
|
+
build(false, getColorDepth());
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { ColorDepth, Features } from "./types";
|
|
2
|
+
|
|
3
|
+
export function getColorDepth(stream?: NodeJS.WriteStream): ColorDepth {
|
|
4
|
+
if (stream?.isTTY)
|
|
5
|
+
return stream.getColorDepth() as ColorDepth;
|
|
6
|
+
|
|
7
|
+
if (process.env.NO_COLOR || process.env.NODE_DISABLE_COLORS)
|
|
8
|
+
return 1;
|
|
9
|
+
|
|
10
|
+
switch (process.env.FORCE_COLOR) {
|
|
11
|
+
case "":
|
|
12
|
+
case "true":
|
|
13
|
+
case "1":
|
|
14
|
+
return 4;
|
|
15
|
+
case "2":
|
|
16
|
+
return 8;
|
|
17
|
+
case "3":
|
|
18
|
+
return 24;
|
|
19
|
+
default:
|
|
20
|
+
return 1;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function detectFeatureSupport(isTTY: boolean, colorDepth: ColorDepth): Omit<Features, "colorDepth"> {
|
|
25
|
+
const enabled = process.env.TERM !== "dumb" && isTTY;
|
|
26
|
+
return {
|
|
27
|
+
style : colorDepth > 1,
|
|
28
|
+
caret : enabled,
|
|
29
|
+
erase : enabled,
|
|
30
|
+
scroll : enabled,
|
|
31
|
+
terminal : enabled,
|
|
32
|
+
};
|
|
33
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { Socket } from "node:net";
|
|
2
|
+
import { WriteStream } from "node:tty";
|
|
3
|
+
import { build, boolean, number, tty, pipe } from "./build";
|
|
4
|
+
import { getColorDepth } from "./detect";
|
|
5
|
+
import type { ColorDepth, Features } from "./types";
|
|
6
|
+
|
|
7
|
+
export type Args =
|
|
8
|
+
| [enabled : boolean, stream?: NodeJS.WriteStream]
|
|
9
|
+
| [colorDepth : ColorDepth, stream?: NodeJS.WriteStream]
|
|
10
|
+
| [features : Partial<Features>, stream?: NodeJS.WriteStream]
|
|
11
|
+
| [socket : Socket]
|
|
12
|
+
| [stream? : NodeJS.WriteStream];
|
|
13
|
+
|
|
14
|
+
export function getFeatures(...args: Args): Features {
|
|
15
|
+
const [first, second] = args as [
|
|
16
|
+
boolean | ColorDepth | Partial<Features> | Socket | NodeJS.WriteStream | undefined,
|
|
17
|
+
NodeJS.WriteStream | undefined,
|
|
18
|
+
];
|
|
19
|
+
|
|
20
|
+
if (typeof first === "boolean")
|
|
21
|
+
return boolean((second ?? process.stdout).isTTY, first);
|
|
22
|
+
|
|
23
|
+
if (typeof first === "number")
|
|
24
|
+
return number((second ?? process.stdout).isTTY, first);
|
|
25
|
+
|
|
26
|
+
let input: Partial<Features> | Socket | NodeJS.WriteStream =
|
|
27
|
+
!first || typeof first !== "object"
|
|
28
|
+
? second ?? process.stdout
|
|
29
|
+
: first;
|
|
30
|
+
|
|
31
|
+
if (input instanceof WriteStream)
|
|
32
|
+
return tty(input);
|
|
33
|
+
|
|
34
|
+
if (input instanceof Socket)
|
|
35
|
+
return pipe();
|
|
36
|
+
|
|
37
|
+
const {colorDepth, style, caret, erase, scroll, terminal} = input as Partial<Features>;
|
|
38
|
+
|
|
39
|
+
const stream = second ?? process.stdout;
|
|
40
|
+
|
|
41
|
+
if (colorDepth)
|
|
42
|
+
build(stream.isTTY, colorDepth, style, caret, erase, scroll, terminal);
|
|
43
|
+
|
|
44
|
+
if (stream.isTTY)
|
|
45
|
+
return build(true, getColorDepth(stream), style, caret, erase, scroll, terminal);
|
|
46
|
+
|
|
47
|
+
return build(false, getColorDepth(), style, caret, erase, scroll, terminal);
|
|
48
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./features";
|
package/src/index.ts
ADDED
package/src/pad.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import {visibleLength} from "./strip";
|
|
2
|
+
|
|
3
|
+
export const padEnd = (text: string, targetLength: number, fillString = " "): string =>
|
|
4
|
+
text + fillString.repeat(Math.max(0, targetLength - visibleLength(text)) / fillString.length);
|
|
5
|
+
|
|
6
|
+
export const padStart = (text: string, targetLength: number, fillString = " "): string =>
|
|
7
|
+
fillString.repeat(Math.max(0, targetLength - visibleLength(text)) / fillString.length) + text;
|
|
@@ -37,8 +37,6 @@ timeit(() => long .replace(new RegExp(rxSGR.source, "g"), ""), {description: "lo
|
|
|
37
37
|
```
|
|
38
38
|
*/
|
|
39
39
|
|
|
40
|
-
const rxSGR = Object.freeze(/\x1b\[[\d;]*m/g);
|
|
41
|
-
const rxCSI = Object.freeze(/\x1b\[[0-?]*[ -/]*[@-~]/g);
|
|
42
|
-
const rxUnsafe = Object.freeze(/\x1b\[[0-?]*[ -/]*[@-ln-~]/g); // Everything except SGR codes (m).
|
|
43
|
-
|
|
44
|
-
module.exports = {rxSGR, rxCSI, rxUnsafe};
|
|
40
|
+
export const rxSGR = Object.freeze(/\x1b\[[\d;]*m/g);
|
|
41
|
+
export const rxCSI = Object.freeze(/\x1b\[[0-?]*[ -/]*[@-~]/g);
|
|
42
|
+
export const rxUnsafe = Object.freeze(/\x1b\[[0-?]*[ -/]*[@-ln-~]/g); // Everything except SGR codes (m).
|
package/src/scroll.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
const scroll = {
|
|
2
|
+
up : (lines?: number): string => `\x1b[${lines ?? 1}S`,
|
|
3
|
+
down : (lines?: number): string => `\x1b[${lines ?? 1}T`,
|
|
4
|
+
};
|
|
5
|
+
|
|
6
|
+
export type Scroll = typeof scroll;
|
|
7
|
+
|
|
8
|
+
const disabled: Scroll = {
|
|
9
|
+
up : () => "",
|
|
10
|
+
down : () => "",
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export const makeScroll = (enabled = true): Scroll => enabled ? scroll : disabled;
|
|
@@ -1,25 +1,23 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import {makeSGR} from "../sgr";
|
|
2
|
+
import {makeStyle} from "../style";
|
|
3
|
+
import {clip, rgbToX16, rgbToX256, rgbToX8, x256ToRgb} from "./utils";
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
5
|
+
import type {ColorDepth} from "../../features/types";
|
|
6
|
+
import type {SGR} from "../sgr";
|
|
7
|
+
import type {Channel, Color} from "./types";
|
|
8
|
+
|
|
9
|
+
export type {Color} from "./types";
|
|
9
10
|
|
|
10
11
|
const fgOpen = 30, fgClose = 39;
|
|
11
12
|
const bgOpen = 40, bgClose = 49;
|
|
12
13
|
|
|
13
|
-
|
|
14
|
-
function makeChannel(colorDepth, open, close) {
|
|
14
|
+
function makeChannel(colorDepth: ColorDepth, open: number, close: number): Channel {
|
|
15
15
|
const sgrBase = makeSGR(colorDepth > 1);
|
|
16
16
|
const style = makeStyle(colorDepth > 1);
|
|
17
17
|
|
|
18
|
-
|
|
19
|
-
const sgr = code => sgrBase(code, close);
|
|
18
|
+
const sgr = (code: number | number[]): SGR => sgrBase(code, close);
|
|
20
19
|
|
|
21
|
-
|
|
22
|
-
const bright =
|
|
20
|
+
const bright: (index: number) => SGR =
|
|
23
21
|
colorDepth >= 4 ? index => sgr(open + 60 + index) :
|
|
24
22
|
colorDepth === 3 ?
|
|
25
23
|
open === fgOpen ?
|
|
@@ -27,11 +25,10 @@ function makeChannel(colorDepth, open, close) {
|
|
|
27
25
|
index => sgr(open + index) :
|
|
28
26
|
() => sgr(0);
|
|
29
27
|
|
|
30
|
-
|
|
31
|
-
const x16ToX8 =
|
|
28
|
+
const x16ToX8: (code: number) => SGR =
|
|
32
29
|
open === fgOpen ?
|
|
33
30
|
code => code >= 60 ? style.bold.combine(sgr(open + code - 60)) : sgr(open + code) :
|
|
34
|
-
code => code >= 60 ? sgr(open + code - 60)
|
|
31
|
+
code => code >= 60 ? sgr(open + code - 60) : sgr(open + code);
|
|
35
32
|
|
|
36
33
|
return {
|
|
37
34
|
black : sgr(open + 0),
|
|
@@ -62,43 +59,37 @@ function makeChannel(colorDepth, open, close) {
|
|
|
62
59
|
(r, g, b) => sgr(open + rgbToX8(...clip(r, g, b))) :
|
|
63
60
|
() => sgr(0),
|
|
64
61
|
|
|
65
|
-
/** @type {(...args: [number] | [number, number, number]) => SGR} */
|
|
66
62
|
x256:
|
|
67
63
|
colorDepth >= 8 ?
|
|
68
|
-
(...args) => sgr(
|
|
64
|
+
(...args: [number] | [number, number, number]): SGR => sgr(
|
|
69
65
|
[open + 8, 5, args.length === 3 ? rgbToX256(...clip(...args)) : clip(args[0])],
|
|
70
66
|
) :
|
|
71
67
|
colorDepth >= 4 ?
|
|
72
|
-
(...args) => sgr(
|
|
68
|
+
(...args: [number] | [number, number, number]): SGR => sgr(
|
|
73
69
|
open +
|
|
74
70
|
rgbToX16(...(args.length === 3 ? clip(...args) : x256ToRgb(clip(args[0])))),
|
|
75
71
|
) :
|
|
76
72
|
colorDepth === 3 ?
|
|
77
73
|
open === fgOpen ?
|
|
78
|
-
(...args) => x16ToX8(
|
|
79
|
-
args.length === 3
|
|
80
|
-
rgbToX16(...clip(...args))
|
|
81
|
-
rgbToX16(...x256ToRgb(clip(args[0]))),
|
|
74
|
+
(...args: [number] | [number, number, number]): SGR => x16ToX8(
|
|
75
|
+
args.length === 3
|
|
76
|
+
? rgbToX16(...clip(...args))
|
|
77
|
+
: rgbToX16(...x256ToRgb(clip(args[0]))),
|
|
82
78
|
) :
|
|
83
|
-
(...args) => sgr(
|
|
84
|
-
open +
|
|
85
|
-
...args.length === 3 ? clip(...args) : x256ToRgb(clip(args[0])),
|
|
86
|
-
),
|
|
79
|
+
(...args: [number] | [number, number, number]): SGR => sgr(
|
|
80
|
+
open +
|
|
81
|
+
rgbToX8(...args.length === 3 ? clip(...args) : x256ToRgb(clip(args[0]))),
|
|
87
82
|
) :
|
|
88
|
-
() => sgr(0),
|
|
83
|
+
(): SGR => sgr(0),
|
|
89
84
|
|
|
90
85
|
default: colorDepth > 1 ? `\x1b[${close}m` : "",
|
|
91
86
|
};
|
|
92
87
|
}
|
|
93
88
|
|
|
94
|
-
|
|
95
|
-
const cache = {};
|
|
89
|
+
const cache: Partial<Record<ColorDepth, Color>> = {};
|
|
96
90
|
|
|
97
|
-
|
|
98
|
-
const makeColor = (colorDepth = 4) =>
|
|
91
|
+
export const makeColor = (colorDepth: ColorDepth = 4): Color =>
|
|
99
92
|
cache[colorDepth] ?? (cache[colorDepth] = {
|
|
100
93
|
fg : makeChannel(colorDepth, fgOpen, fgClose),
|
|
101
94
|
bg : makeChannel(colorDepth, bgOpen, bgClose),
|
|
102
|
-
});
|
|
103
|
-
|
|
104
|
-
module.exports = {makeColor};
|
|
95
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./color";
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import type {SGR} from "../sgr";
|
|
2
|
+
|
|
1
3
|
export interface Channel {
|
|
2
4
|
black : SGR;
|
|
3
5
|
red : SGR;
|
|
@@ -24,5 +26,7 @@ export interface Channel {
|
|
|
24
26
|
(r: number, g: number, b: number): SGR;
|
|
25
27
|
};
|
|
26
28
|
|
|
27
|
-
default: string
|
|
28
|
-
}
|
|
29
|
+
default: string;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export type Color = {fg: Channel; bg: Channel};
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
export function rgbToX256(r: number, g: number, b: number): number {
|
|
2
|
+
if (r === g && g === b)
|
|
3
|
+
return 232 + Math.floor(r * 24 / 256);
|
|
4
|
+
|
|
5
|
+
return (
|
|
6
|
+
16 +
|
|
7
|
+
Math.floor(r * 6 / 256) * 36 +
|
|
8
|
+
Math.floor(g * 6 / 256) * 6 +
|
|
9
|
+
Math.floor(b * 6 / 256)
|
|
10
|
+
);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function x256ToRgb(code: number): [number, number, number] {
|
|
14
|
+
if (code >= 232) {
|
|
15
|
+
const gray = Math.round((code - 232) * 255 / 24);
|
|
16
|
+
return [gray, gray, gray];
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
code -= 16;
|
|
20
|
+
const r = Math.floor(code / 36) * 51;
|
|
21
|
+
const g = Math.floor((code % 36) / 6) * 51;
|
|
22
|
+
const b = (code % 6) * 51;
|
|
23
|
+
return [r, g, b];
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function rgbToX16(r: number, g: number, b: number): number {
|
|
27
|
+
r = Math.min(2, Math.floor(r / 85));
|
|
28
|
+
g = Math.min(2, Math.floor(g / 85));
|
|
29
|
+
b = Math.min(2, Math.floor(b / 85));
|
|
30
|
+
|
|
31
|
+
const index = (r ? 1 : 0) | (g ? 2 : 0) | (b ? 4 : 0);
|
|
32
|
+
|
|
33
|
+
const twos = (r === 2 ? 1 : 0) + (g === 2 ? 1 : 0) + (b === 2 ? 1 : 0);
|
|
34
|
+
const ones = (r === 1 ? 1 : 0) + (g === 1 ? 1 : 0) + (b === 1 ? 1 : 0);
|
|
35
|
+
const bright = twos > 0 && twos >= ones;
|
|
36
|
+
|
|
37
|
+
return index + (bright ? 60 : 0);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export function rgbToX8(r: number, g: number, b: number): number {
|
|
41
|
+
r = r >= 128 ? 1 : 0;
|
|
42
|
+
g = g >= 128 ? 1 : 0;
|
|
43
|
+
b = b >= 128 ? 1 : 0;
|
|
44
|
+
|
|
45
|
+
return (r ? 1 : 0) | (g ? 2 : 0) | (b ? 4 : 0);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export function clip(x: number): number;
|
|
49
|
+
export function clip(r: number, g: number, b: number): [number, number, number];
|
|
50
|
+
export function clip(...args: [number] | [number, number, number]): number | [number, number, number] {
|
|
51
|
+
return args.length === 1
|
|
52
|
+
? Math.max(0, Math.min(255, Math.floor(args[0])))
|
|
53
|
+
: [
|
|
54
|
+
Math.max(0, Math.min(255, Math.floor(args[0]))),
|
|
55
|
+
Math.max(0, Math.min(255, Math.floor(args[1]))),
|
|
56
|
+
Math.max(0, Math.min(255, Math.floor(args[2]))),
|
|
57
|
+
];
|
|
58
|
+
}
|
package/src/sgr/index.ts
ADDED
package/src/sgr/reset.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const makeReset = (enabled = true): string => enabled ? "\x1b[0m" : "";
|
package/src/sgr/sgr.ts
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
export type Code = number | number[];
|
|
2
|
+
|
|
3
|
+
export interface SGR {
|
|
4
|
+
(text: string): string;
|
|
5
|
+
open : string;
|
|
6
|
+
close : string;
|
|
7
|
+
codes : {open: Code; close: Code};
|
|
8
|
+
combine : (...styles: SGR[]) => SGR;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function combine(code: Code, codes: Code[]): Code {
|
|
12
|
+
if (!codes.length)
|
|
13
|
+
return code;
|
|
14
|
+
|
|
15
|
+
const rtn = Array.isArray(code) ? [...code] : [code];
|
|
16
|
+
|
|
17
|
+
for (const c of codes) {
|
|
18
|
+
if (Array.isArray(c))
|
|
19
|
+
rtn.push(...c);
|
|
20
|
+
else
|
|
21
|
+
rtn.push(c);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
return rtn;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const codeSequence = (code: Code): string | number => Array.isArray(code) ? code.join(";") : code;
|
|
28
|
+
|
|
29
|
+
function sgr(open: Code, close: Code, reset = false): SGR {
|
|
30
|
+
const openCode = codeSequence(open);
|
|
31
|
+
const closeCode = codeSequence(close);
|
|
32
|
+
const openSequence = `\x1b[${openCode}m`;
|
|
33
|
+
const closeSequence = `\x1b[${closeCode}m`;
|
|
34
|
+
const reopenCode = reset ? `${closeCode};${openCode}` : openCode;
|
|
35
|
+
|
|
36
|
+
const rxClose = new RegExp(
|
|
37
|
+
`(?<start>\\x1b\\[(?:\\d+;)*)${closeCode}(?<end>(?:;\\d+)*m)`,
|
|
38
|
+
"g"
|
|
39
|
+
);
|
|
40
|
+
const replace = `$<start>${reopenCode}$<end>`;
|
|
41
|
+
|
|
42
|
+
const func = (s: string) => s ? openSequence + s.replace(rxClose, replace) + closeSequence : s;
|
|
43
|
+
|
|
44
|
+
return Object.assign(func, {
|
|
45
|
+
codes : {open, close},
|
|
46
|
+
open : openSequence,
|
|
47
|
+
close : closeSequence,
|
|
48
|
+
combine : (...styles: SGR[]) => sgr(
|
|
49
|
+
combine(open, styles.map(s => s.codes.open)),
|
|
50
|
+
combine(close, styles.map(s => s.codes.close)),
|
|
51
|
+
),
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
let disabledSGR = null as unknown as SGR;
|
|
56
|
+
disabledSGR = Object.assign(
|
|
57
|
+
(s: string) => s,
|
|
58
|
+
{
|
|
59
|
+
codes : {open: 0, close: 0},
|
|
60
|
+
open : "",
|
|
61
|
+
close : "",
|
|
62
|
+
combine : (): SGR => disabledSGR,
|
|
63
|
+
},
|
|
64
|
+
);
|
|
65
|
+
|
|
66
|
+
const disabled = (): SGR => disabledSGR;
|
|
67
|
+
|
|
68
|
+
export const makeSGR = (enabled = true): typeof sgr => enabled ? sgr : disabled;
|
|
@@ -1,8 +1,6 @@
|
|
|
1
|
-
|
|
1
|
+
import {makeSGR} from "./sgr";
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
function makeStyle(enabled = true) {
|
|
3
|
+
export function makeStyle(enabled = true) {
|
|
6
4
|
const sgr = makeSGR(enabled);
|
|
7
5
|
|
|
8
6
|
return {
|
|
@@ -20,4 +18,4 @@ function makeStyle(enabled = true) {
|
|
|
20
18
|
};
|
|
21
19
|
}
|
|
22
20
|
|
|
23
|
-
|
|
21
|
+
export type Style = ReturnType<typeof makeStyle>;
|
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
|
|
1
|
+
import type {Code} from "./sgr";
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
function combine(code, codes, ) {
|
|
3
|
+
export function combine(code: Code, codes: Code[]): Code {
|
|
5
4
|
if (!codes.length)
|
|
6
5
|
return code;
|
|
7
6
|
|
|
@@ -15,6 +14,4 @@ function combine(code, codes, ) {
|
|
|
15
14
|
}
|
|
16
15
|
|
|
17
16
|
return rtn;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
module.exports = {combine};
|
|
17
|
+
}
|
|
@@ -1,9 +1,6 @@
|
|
|
1
|
-
|
|
1
|
+
import type {Attribute, BuildAtom} from "./types";
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
/** @type {BuildAtom} */
|
|
6
|
-
function buildExtendedColorAtom(attribute, codes, index) {
|
|
3
|
+
export const buildExtendedColorAtom: BuildAtom = (attribute, codes, index) => {
|
|
7
4
|
switch (codes[index + 1]) {
|
|
8
5
|
case 2:
|
|
9
6
|
if (index + 5 >= codes.length)
|
|
@@ -16,19 +13,20 @@ function buildExtendedColorAtom(attribute, codes, index) {
|
|
|
16
13
|
default:
|
|
17
14
|
return {attribute, code: codes.slice(index, index + 2), skip: 1};
|
|
18
15
|
}
|
|
19
|
-
}
|
|
16
|
+
};
|
|
20
17
|
|
|
21
|
-
|
|
22
|
-
function buildIntensityAtom(attribute, codes, index, state) {
|
|
18
|
+
export const buildIntensityAtom: BuildAtom = (attribute, codes, index, state) => {
|
|
23
19
|
const code = codes[index];
|
|
24
20
|
if (code === 22)
|
|
25
21
|
return {attribute, code: [code]};
|
|
26
22
|
|
|
27
|
-
const current = state.get("intensity");
|
|
28
|
-
if (
|
|
23
|
+
const current = state.get("intensity" as Attribute);
|
|
24
|
+
if (
|
|
25
|
+
!current ||
|
|
26
|
+
current[0] === 22 ||
|
|
27
|
+
current.length === 1 && current[0] === code
|
|
28
|
+
)
|
|
29
29
|
return {attribute, code: [code]};
|
|
30
30
|
|
|
31
31
|
return {attribute, code: [1, 2]};
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
module.exports = {buildExtendedColorAtom, buildIntensityAtom};
|
|
32
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./simplify";
|
|
@@ -1,14 +1,8 @@
|
|
|
1
|
-
|
|
1
|
+
import {buildExtendedColorAtom, buildIntensityAtom} from "./atom";
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
import type {Atom, Attribute, AttributeMap, BuildAtom} from "./types";
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
/** @typedef {import("./types").Attribute} Attribute */
|
|
7
|
-
/** @typedef {import("./types").AttributeMap} AttributeMap */
|
|
8
|
-
/** @typedef {import("./types").BuildAtom} BuildAtom */
|
|
9
|
-
|
|
10
|
-
/** @type {Record<number, [attribute: Attribute, buildAtom?: BuildAtom]>} */
|
|
11
|
-
const codeMap = {
|
|
5
|
+
const codeMap: Record<number, [attribute: Attribute, buildAtom?: BuildAtom]> = {
|
|
12
6
|
0 : ["reset"],
|
|
13
7
|
1 : ["intensity", buildIntensityAtom],
|
|
14
8
|
2 : ["intensity", buildIntensityAtom],
|
|
@@ -67,8 +61,7 @@ const codeMap = {
|
|
|
67
61
|
107 : ["bg"],
|
|
68
62
|
};
|
|
69
63
|
|
|
70
|
-
|
|
71
|
-
function lookUpAtom(codes, index, state) {
|
|
64
|
+
export function lookUpAtom(codes: number[], index: number, state: AttributeMap): Atom {
|
|
72
65
|
const code = codes[index];
|
|
73
66
|
const entry = codeMap[code];
|
|
74
67
|
|
|
@@ -81,6 +74,4 @@ function lookUpAtom(codes, index, state) {
|
|
|
81
74
|
return buildAtom(attribute, codes, index, state);
|
|
82
75
|
|
|
83
76
|
return {attribute, code: [code]};
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
module.exports = {lookUpAtom};
|
|
77
|
+
}
|
|
@@ -1,10 +1,7 @@
|
|
|
1
|
-
|
|
1
|
+
import {rxSGR} from "../patterns";
|
|
2
|
+
import {State} from "./state";
|
|
2
3
|
|
|
3
|
-
|
|
4
|
-
const {State} = require("./state");
|
|
5
|
-
|
|
6
|
-
/** @type {(text: string) => string} */
|
|
7
|
-
function simplify(text) {
|
|
4
|
+
export function simplify(text: string): string {
|
|
8
5
|
// `.split` doesn't modify `lastIndex`, so no clone is necessary here.
|
|
9
6
|
const parts = text.split(rxSGR);
|
|
10
7
|
|
|
@@ -16,7 +13,6 @@ function simplify(text) {
|
|
|
16
13
|
let chunk = parts[i++];
|
|
17
14
|
|
|
18
15
|
while (!chunk && i < parts.length) {
|
|
19
|
-
// Merge consecutive SGR sequences.
|
|
20
16
|
codes.push(...parts[i++].split(";").map(Number));
|
|
21
17
|
chunk = parts[i++];
|
|
22
18
|
}
|
|
@@ -28,6 +24,4 @@ function simplify(text) {
|
|
|
28
24
|
}
|
|
29
25
|
|
|
30
26
|
return result;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
module.exports = {simplify};
|
|
27
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import {lookUpAtom} from "./lookup";
|
|
2
|
+
import {arraysEqual, transitionIntensity} from "./utils";
|
|
3
|
+
|
|
4
|
+
import type {Attribute, AttributeMap} from "./types";
|
|
5
|
+
|
|
6
|
+
const defaultCodes: Map<Attribute, number[]> = new Map([
|
|
7
|
+
["intensity", [22]],
|
|
8
|
+
["italic", [23]],
|
|
9
|
+
["underline", [24]],
|
|
10
|
+
["inverse", [27]],
|
|
11
|
+
["hidden", [28]],
|
|
12
|
+
["strikethrough", [29]],
|
|
13
|
+
["fg", [39]],
|
|
14
|
+
["bg", [49]],
|
|
15
|
+
["frame", [54]],
|
|
16
|
+
["overline", [55]],
|
|
17
|
+
]);
|
|
18
|
+
|
|
19
|
+
export class State extends Map<Attribute, number[]> implements AttributeMap {
|
|
20
|
+
update(codes: number[]): number[] {
|
|
21
|
+
let snapshot: AttributeMap = new Map(this);
|
|
22
|
+
|
|
23
|
+
const attributes = new Set<Attribute>();
|
|
24
|
+
|
|
25
|
+
for (let i = 0; i < codes.length; i++) {
|
|
26
|
+
const {attribute, code, skip} = lookUpAtom(codes, i, this);
|
|
27
|
+
|
|
28
|
+
if (attribute === "reset") {
|
|
29
|
+
attributes.clear();
|
|
30
|
+
this.clear();
|
|
31
|
+
attributes.add("reset");
|
|
32
|
+
for (const [attr, defaultCode] of defaultCodes)
|
|
33
|
+
this.set(attr, defaultCode);
|
|
34
|
+
|
|
35
|
+
snapshot = new Map(this);
|
|
36
|
+
continue;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
attributes.add(attribute);
|
|
40
|
+
this.set(attribute, code);
|
|
41
|
+
|
|
42
|
+
if (skip)
|
|
43
|
+
i += skip;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return Array.from(attributes).flatMap(attribute => {
|
|
47
|
+
if (attribute === "reset")
|
|
48
|
+
return [0];
|
|
49
|
+
|
|
50
|
+
const code = this.get(attribute)!;
|
|
51
|
+
|
|
52
|
+
if (arraysEqual(code, snapshot.get(attribute)))
|
|
53
|
+
return [];
|
|
54
|
+
|
|
55
|
+
if (attribute === "intensity") {
|
|
56
|
+
const previous = snapshot.get(attribute);
|
|
57
|
+
return transitionIntensity(previous, code);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return code;
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
}
|