@peteanderson/ansi 0.3.1 → 0.3.3

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/README.md CHANGED
@@ -101,6 +101,18 @@ Available if feature is enabled:
101
101
  - `caret.x(col)` - move cursor to column (1-based)
102
102
  - `caret.save` / `caret.restore` - save/restore cursor position (VT100)
103
103
 
104
+ ### `terminal`
105
+
106
+ Terminal control features (available if feature is enabled):
107
+
108
+ - `terminal.focusReporting.enable` / `terminal.focusReporting.disable` - enable/disable focus
109
+ reporting
110
+ - `terminal.alternateBuffer.on` / `terminal.alternateBuffer.off` - switch to/from alternate buffer
111
+ - `terminal.alternateBuffer.legacy.on` / `terminal.alternateBuffer.legacy.off` - use legacy
112
+ alternate buffer sequences
113
+ - `terminal.bracketedPasteMode.enable` / `terminal.bracketedPasteMode.disable` - enable/disable
114
+ bracketed paste mode
115
+
104
116
  ### `erase`
105
117
 
106
118
  Available if feature is enabled:
@@ -153,6 +165,7 @@ Object containing the detected feature configuration:
153
165
  caret : boolean;
154
166
  erase : boolean;
155
167
  scroll : boolean;
168
+ terminal : boolean;
156
169
  }
157
170
  ```
158
171
 
package/dist/ansi.d.ts CHANGED
@@ -8,6 +8,7 @@ declare const ansi: typeof makeAnsi & {
8
8
  scroll: ReturnType<typeof makeScroll>;
9
9
  reset: string;
10
10
  style: ReturnType<typeof makeStyle>;
11
+ terminal: ReturnType<typeof makeTerminal>;
11
12
  padEnd: typeof padEnd;
12
13
  padStart: typeof padStart;
13
14
  strip: typeof strip;
@@ -25,6 +26,7 @@ import { makeCaret } from "./caret";
25
26
  import { makeErase } from "./erase";
26
27
  import { makeScroll } from "./scroll";
27
28
  import { makeStyle } from "./sgr/style";
29
+ import { makeTerminal } from "./terminal";
28
30
  import { padEnd } from "./pad";
29
31
  import { padStart } from "./pad";
30
32
  import { strip } from "./strip";
@@ -40,6 +42,7 @@ type Ansi = ReturnType<typeof makeColor> & {
40
42
  scroll: ReturnType<typeof makeScroll>;
41
43
  reset: string;
42
44
  style: ReturnType<typeof makeStyle>;
45
+ terminal: ReturnType<typeof makeTerminal>;
43
46
  padEnd: typeof padEnd;
44
47
  padStart: typeof padStart;
45
48
  strip: typeof strip;
package/dist/ansi.js CHANGED
@@ -8,6 +8,7 @@ const { makeColor, makeReset, makeStyle } = require("./sgr");
8
8
  const { simplify } = require("./simplify");
9
9
  const { slice } = require("./slice");
10
10
  const { sanitize, strip, visibleLength } = require("./strip");
11
+ const { makeTerminal } = require("./terminal");
11
12
  /**
12
13
  @typedef {import("./features/features").Args} Args
13
14
 
@@ -19,6 +20,8 @@ const { sanitize, strip, visibleLength } = require("./strip");
19
20
  reset : string;
20
21
  style : ReturnType<typeof makeStyle>;
21
22
 
23
+ terminal : ReturnType<typeof makeTerminal>;
24
+
22
25
  padEnd : typeof padEnd;
23
26
  padStart : typeof padStart;
24
27
 
@@ -41,6 +44,7 @@ function makeAnsi(...args) {
41
44
  reset: makeReset(features.colorDepth > 1),
42
45
  style: makeStyle(features.style),
43
46
  ...makeColor(features.colorDepth),
47
+ terminal: makeTerminal(features.terminal),
44
48
  padEnd,
45
49
  padStart,
46
50
  strip,
@@ -1,6 +1,6 @@
1
1
  export type ColorDepth = import("./types").ColorDepth;
2
2
  export type Features = import("./types").Features;
3
- export function build(isTTY: boolean, colorDepth: ColorDepth, style?: boolean, caret?: boolean, erase?: boolean, scroll?: boolean): Features;
3
+ export function build(isTTY: boolean, colorDepth: ColorDepth, style?: boolean, caret?: boolean, erase?: boolean, scroll?: boolean, terminal?: boolean): Features;
4
4
  /** @type {(isTTY: boolean, enabled: boolean) => Features} */
5
5
  export const boolean: (isTTY: boolean, enabled: boolean) => Features;
6
6
  /** @type {(isTTY: boolean, colorDepth: ColorDepth) => Features} */
@@ -24,12 +24,17 @@ function normalizeColorDepth(colorDepth) {
24
24
  caret? : boolean,
25
25
  erase? : boolean,
26
26
  scroll? : boolean,
27
+ terminal? : boolean,
27
28
  ) => Features
28
29
  }
29
30
  */
30
- function build(isTTY, colorDepth, style, caret, erase, scroll) {
31
- if (style !== undefined && caret !== undefined && erase !== undefined && scroll !== undefined)
32
- return { colorDepth: normalizeColorDepth(colorDepth), style, caret, erase, scroll };
31
+ function build(isTTY, colorDepth, style, caret, erase, scroll, terminal) {
32
+ if (style !== undefined &&
33
+ caret !== undefined &&
34
+ erase !== undefined &&
35
+ scroll !== undefined &&
36
+ terminal !== undefined)
37
+ return { colorDepth: normalizeColorDepth(colorDepth), style, caret, erase, scroll, terminal };
33
38
  const support = detectFeatureSupport(isTTY, colorDepth);
34
39
  return {
35
40
  colorDepth: normalizeColorDepth(colorDepth),
@@ -37,6 +42,7 @@ function build(isTTY, colorDepth, style, caret, erase, scroll) {
37
42
  caret: caret ?? support.caret,
38
43
  erase: erase ?? support.erase,
39
44
  scroll: scroll ?? support.scroll,
45
+ terminal: terminal ?? support.terminal,
40
46
  };
41
47
  }
42
48
  /** @type {(isTTY: boolean, enabled: boolean) => Features} */
@@ -28,6 +28,7 @@ function detectFeatureSupport(isTTY, colorDepth) {
28
28
  caret: enabled,
29
29
  erase: enabled,
30
30
  scroll: enabled,
31
+ terminal: enabled,
31
32
  };
32
33
  }
33
34
  module.exports = { detectFeatureSupport, getColorDepth };
@@ -28,12 +28,12 @@ function getFeatures(...args) {
28
28
  return tty(features);
29
29
  if (features instanceof Socket)
30
30
  return pipe();
31
- const { colorDepth, style, caret, erase, scroll } = features;
31
+ const { colorDepth, style, caret, erase, scroll, terminal } = features;
32
32
  stream ??= process.stdout;
33
33
  if (colorDepth)
34
- build(stream.isTTY, colorDepth, style, caret, erase, scroll);
34
+ build(stream.isTTY, colorDepth, style, caret, erase, scroll, terminal);
35
35
  if (stream.isTTY)
36
- return build(true, getColorDepth(stream), style, caret, erase, scroll);
37
- return build(false, getColorDepth(), style, caret, erase, scroll);
36
+ return build(true, getColorDepth(stream), style, caret, erase, scroll, terminal);
37
+ return build(false, getColorDepth(), style, caret, erase, scroll, terminal);
38
38
  }
39
39
  module.exports = { getFeatures };
package/dist/index.d.ts CHANGED
@@ -47,6 +47,28 @@ declare const _exports: ((...args: Args) => Ansi) & {
47
47
  }>;
48
48
  reset: string;
49
49
  style: ReturnType<typeof import("./sgr/style").makeStyle>;
50
+ terminal: ReturnType<(enabled?: boolean) => {
51
+ focusReporting: {
52
+ enable: string;
53
+ disable: string;
54
+ focus: string;
55
+ blur: string;
56
+ };
57
+ alternateScreen: {
58
+ enable: string;
59
+ disable: string;
60
+ legacy: {
61
+ enable: string;
62
+ disable: string;
63
+ };
64
+ };
65
+ bracketedPaste: {
66
+ enable: string;
67
+ disable: string;
68
+ start: string;
69
+ end: string;
70
+ };
71
+ }>;
50
72
  padEnd: (text: string, targetLength: number, fillString?: string) => string;
51
73
  padStart: (text: string, targetLength: number, fillString?: string) => string;
52
74
  strip: (text: string) => string;
package/dist/sgr/sgr.js CHANGED
@@ -34,7 +34,7 @@ function sgr(open, close, reset = false) {
34
34
  const rxClose = new RegExp(`(?<start>\\x1b\\[(?:\\d+;)*)${closeCode}(?<end>(?:;\\d+)*m)`, "g");
35
35
  const replace = `$<start>${reopenCode}$<end>`;
36
36
  /** @type {(text: string) => string} */
37
- const func = s => openSequence + s.replace(rxClose, replace) + closeSequence;
37
+ const func = s => s ? openSequence + s.replace(rxClose, replace) + closeSequence : s;
38
38
  return Object.assign(func, {
39
39
  codes: { open, close },
40
40
  open: openSequence,
@@ -21,8 +21,17 @@ function buildIntensityAtom(attribute, codes, index, state) {
21
21
  if (code === 22)
22
22
  return { attribute, code: [code] };
23
23
  const current = state.get("intensity");
24
- if (!current || current.length == 1 && current[0] === code || current[0] === 22)
24
+ if (
25
+ // If there is no intensity currently in the state, then we can just set the new state.
26
+ !current ||
27
+ // If the current intensity is normal (22), then we can just set the new state.
28
+ // Note that while the ultimate transition may return a code sequence of `[22, 1]` or
29
+ // `[22, 2]`, in our state representation, the only two-code intensity is `[1, 2]`.
30
+ current[0] === 22 ||
31
+ // If the current intensity is equal to the new intensity, then return the same state.
32
+ current.length === 1 && current[0] === code)
25
33
  return { attribute, code: [code] };
34
+ // Otherwise, we need to set both intensity codes.
26
35
  return { attribute, code: [1, 2] };
27
36
  }
28
37
  module.exports = { buildExtendedColorAtom, buildIntensityAtom };
@@ -0,0 +1,22 @@
1
+ export function makeTerminal(enabled?: boolean): {
2
+ focusReporting: {
3
+ enable: string;
4
+ disable: string;
5
+ focus: string;
6
+ blur: string;
7
+ };
8
+ alternateScreen: {
9
+ enable: string;
10
+ disable: string;
11
+ legacy: {
12
+ enable: string;
13
+ disable: string;
14
+ };
15
+ };
16
+ bracketedPaste: {
17
+ enable: string;
18
+ disable: string;
19
+ start: string;
20
+ end: string;
21
+ };
22
+ };
@@ -0,0 +1,48 @@
1
+ "use strict";
2
+ const terminal = {
3
+ focusReporting: {
4
+ enable: "\x1b[?1004h",
5
+ disable: "\x1b[?1004l",
6
+ focus: "\x1b[I",
7
+ blur: "\x1b[O",
8
+ },
9
+ alternateScreen: {
10
+ enable: "\x1b[?1049h",
11
+ disable: "\x1b[?1049l",
12
+ legacy: {
13
+ enable: "\x1b[?47h",
14
+ disable: "\x1b[?47l",
15
+ },
16
+ },
17
+ bracketedPaste: {
18
+ enable: "\x1b[?2004h",
19
+ disable: "\x1b[?2004l",
20
+ start: "\x1b[200~",
21
+ end: "\x1b[201~",
22
+ },
23
+ };
24
+ /** @type {typeof terminal} */
25
+ const disabled = {
26
+ focusReporting: {
27
+ enable: "",
28
+ disable: "",
29
+ focus: "",
30
+ blur: "",
31
+ },
32
+ alternateScreen: {
33
+ enable: "",
34
+ disable: "",
35
+ legacy: {
36
+ enable: "",
37
+ disable: "",
38
+ },
39
+ },
40
+ bracketedPaste: {
41
+ enable: "",
42
+ disable: "",
43
+ start: "",
44
+ end: "",
45
+ },
46
+ };
47
+ const makeTerminal = (enabled = true) => enabled ? terminal : disabled;
48
+ module.exports = { makeTerminal };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name" : "@peteanderson/ansi",
3
- "version" : "0.3.1",
3
+ "version" : "0.3.3",
4
4
  "description" : "ANSI escape sequence generation with automatic feature detection",
5
5
  "author" : {
6
6
  "name" : "Pete Anderson",
package/src/ansi.js CHANGED
@@ -9,6 +9,7 @@ const {makeColor, makeReset, makeStyle} = require("./sgr");
9
9
  const {simplify} = require("./simplify");
10
10
  const {slice} = require("./slice");
11
11
  const {sanitize, strip, visibleLength} = require("./strip");
12
+ const {makeTerminal} = require("./terminal");
12
13
 
13
14
  /**
14
15
  @typedef {import("./features/features").Args} Args
@@ -21,6 +22,8 @@ const {sanitize, strip, visibleLength} = require("./strip");
21
22
  reset : string;
22
23
  style : ReturnType<typeof makeStyle>;
23
24
 
25
+ terminal : ReturnType<typeof makeTerminal>;
26
+
24
27
  padEnd : typeof padEnd;
25
28
  padStart : typeof padStart;
26
29
 
@@ -47,6 +50,8 @@ function makeAnsi(...args) {
47
50
  style : makeStyle(features.style),
48
51
  ...makeColor(features.colorDepth),
49
52
 
53
+ terminal: makeTerminal(features.terminal),
54
+
50
55
  padEnd,
51
56
  padStart,
52
57
 
@@ -28,20 +28,28 @@ function normalizeColorDepth(colorDepth) {
28
28
  caret? : boolean,
29
29
  erase? : boolean,
30
30
  scroll? : boolean,
31
+ terminal? : boolean,
31
32
  ) => Features
32
33
  }
33
34
  */
34
- function build(isTTY, colorDepth, style, caret, erase, scroll) {
35
- if (style !== undefined && caret !== undefined && erase !== undefined && scroll !== undefined)
36
- return {colorDepth: normalizeColorDepth(colorDepth), style, caret, erase, scroll};
35
+ function build(isTTY, colorDepth, style, caret, erase, scroll, terminal) {
36
+ if (
37
+ style !== undefined &&
38
+ caret !== undefined &&
39
+ erase !== undefined &&
40
+ scroll !== undefined &&
41
+ terminal !== undefined
42
+ )
43
+ return {colorDepth: normalizeColorDepth(colorDepth), style, caret, erase, scroll, terminal};
37
44
 
38
45
  const support = detectFeatureSupport(isTTY, colorDepth);
39
46
  return {
40
47
  colorDepth : normalizeColorDepth(colorDepth),
41
- style : style ?? support.style,
42
- caret : caret ?? support.caret,
43
- erase : erase ?? support.erase,
44
- scroll : scroll ?? support.scroll,
48
+ style : style ?? support.style,
49
+ caret : caret ?? support.caret,
50
+ erase : erase ?? support.erase,
51
+ scroll : scroll ?? support.scroll,
52
+ terminal : terminal ?? support.terminal,
45
53
  };
46
54
  }
47
55
 
@@ -29,10 +29,11 @@ function getColorDepth(stream) {
29
29
  function detectFeatureSupport(isTTY, colorDepth) {
30
30
  const enabled = process.env.TERM !== "dumb" && isTTY;
31
31
  return {
32
- style : colorDepth > 1,
33
- caret : enabled,
34
- erase : enabled,
35
- scroll : enabled,
32
+ style : colorDepth > 1,
33
+ caret : enabled,
34
+ erase : enabled,
35
+ scroll : enabled,
36
+ terminal : enabled,
36
37
  };
37
38
  }
38
39
 
@@ -37,17 +37,17 @@ function getFeatures(...args) {
37
37
  if (features instanceof Socket)
38
38
  return pipe();
39
39
 
40
- const {colorDepth, style, caret, erase, scroll} = features;
40
+ const {colorDepth, style, caret, erase, scroll, terminal} = features;
41
41
 
42
42
  stream ??= process.stdout;
43
43
 
44
44
  if (colorDepth)
45
- build(stream.isTTY, colorDepth, style, caret, erase, scroll);
45
+ build(stream.isTTY, colorDepth, style, caret, erase, scroll, terminal);
46
46
 
47
47
  if (stream.isTTY)
48
- return build(true, getColorDepth(stream), style, caret, erase, scroll);
48
+ return build(true, getColorDepth(stream), style, caret, erase, scroll, terminal);
49
49
 
50
- return build(false, getColorDepth(), style, caret, erase, scroll);
50
+ return build(false, getColorDepth(), style, caret, erase, scroll, terminal);
51
51
  }
52
52
 
53
53
  module.exports = {getFeatures};
@@ -6,4 +6,5 @@ export interface Features {
6
6
  caret : boolean;
7
7
  erase : boolean;
8
8
  scroll : boolean;
9
+ terminal : boolean;
9
10
  }
package/src/sgr/sgr.js CHANGED
@@ -46,7 +46,7 @@ function sgr(open, close, reset = false) {
46
46
  const replace = `$<start>${reopenCode}$<end>`;
47
47
 
48
48
  /** @type {(text: string) => string} */
49
- const func = s => openSequence + s.replace(rxClose, replace) + closeSequence;
49
+ const func = s => s ? openSequence + s.replace(rxClose, replace) + closeSequence : s;
50
50
 
51
51
  return Object.assign(func, {
52
52
  codes : {open, close},
@@ -25,9 +25,19 @@ function buildIntensityAtom(attribute, codes, index, state) {
25
25
  return {attribute, code: [code]};
26
26
 
27
27
  const current = state.get("intensity");
28
- if (!current || current.length == 1 && current[0] === code || current[0] === 22)
28
+ if (
29
+ // If there is no intensity currently in the state, then we can just set the new state.
30
+ !current ||
31
+ // If the current intensity is normal (22), then we can just set the new state.
32
+ // Note that while the ultimate transition may return a code sequence of `[22, 1]` or
33
+ // `[22, 2]`, in our state representation, the only two-code intensity is `[1, 2]`.
34
+ current[0] === 22 ||
35
+ // If the current intensity is equal to the new intensity, then return the same state.
36
+ current.length === 1 && current[0] === code
37
+ )
29
38
  return {attribute, code: [code]};
30
39
 
40
+ // Otherwise, we need to set both intensity codes.
31
41
  return {attribute, code: [1, 2]};
32
42
  }
33
43
 
@@ -0,0 +1,58 @@
1
+ "use strict";
2
+
3
+ const terminal = {
4
+ focusReporting: {
5
+ enable : "\x1b[?1004h",
6
+ disable : "\x1b[?1004l",
7
+ focus : "\x1b[I",
8
+ blur : "\x1b[O",
9
+ },
10
+
11
+ alternateScreen: {
12
+ enable : "\x1b[?1049h",
13
+ disable : "\x1b[?1049l",
14
+
15
+ legacy: {
16
+ enable : "\x1b[?47h",
17
+ disable : "\x1b[?47l",
18
+ },
19
+ },
20
+
21
+ bracketedPaste: {
22
+ enable : "\x1b[?2004h",
23
+ disable : "\x1b[?2004l",
24
+ start : "\x1b[200~",
25
+ end : "\x1b[201~",
26
+ },
27
+ };
28
+
29
+ /** @type {typeof terminal} */
30
+ const disabled = {
31
+ focusReporting: {
32
+ enable : "",
33
+ disable : "",
34
+ focus : "",
35
+ blur : "",
36
+ },
37
+
38
+ alternateScreen: {
39
+ enable : "",
40
+ disable : "",
41
+
42
+ legacy: {
43
+ enable : "",
44
+ disable : "",
45
+ },
46
+ },
47
+
48
+ bracketedPaste: {
49
+ enable : "",
50
+ disable : "",
51
+ start : "",
52
+ end : "",
53
+ },
54
+ };
55
+
56
+ const makeTerminal = (enabled = true) => enabled ? terminal : disabled;
57
+
58
+ module.exports = {makeTerminal};