@peteanderson/ansi 3.0.0 → 3.2.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.
Files changed (105) hide show
  1. package/README.md +4 -0
  2. package/dist/cjs/ansi.d.ts +11 -9
  3. package/dist/cjs/ansi.d.ts.map +1 -1
  4. package/dist/cjs/ansi.js +4 -1
  5. package/dist/cjs/ansi.js.map +1 -1
  6. package/dist/cjs/cursor.d.ts +6 -6
  7. package/dist/cjs/cursor.d.ts.map +1 -1
  8. package/dist/cjs/cursor.js +32 -30
  9. package/dist/cjs/cursor.js.map +1 -1
  10. package/dist/cjs/erase.d.ts.map +1 -1
  11. package/dist/cjs/erase.js +8 -7
  12. package/dist/cjs/erase.js.map +1 -1
  13. package/dist/cjs/index.d.ts +10 -8
  14. package/dist/cjs/index.d.ts.map +1 -1
  15. package/dist/cjs/scroll.d.ts +2 -2
  16. package/dist/cjs/scroll.d.ts.map +1 -1
  17. package/dist/cjs/scroll.js +5 -4
  18. package/dist/cjs/scroll.js.map +1 -1
  19. package/dist/cjs/sgr/color/channel.d.ts.map +1 -1
  20. package/dist/cjs/sgr/color/channel.js +2 -1
  21. package/dist/cjs/sgr/color/channel.js.map +1 -1
  22. package/dist/cjs/sgr/format-builder.d.ts.map +1 -1
  23. package/dist/cjs/sgr/format-builder.js +3 -2
  24. package/dist/cjs/sgr/format-builder.js.map +1 -1
  25. package/dist/cjs/sgr/reset.d.ts.map +1 -1
  26. package/dist/cjs/sgr/reset.js +2 -1
  27. package/dist/cjs/sgr/reset.js.map +1 -1
  28. package/dist/cjs/simplify/simplify.d.ts.map +1 -1
  29. package/dist/cjs/simplify/simplify.js +2 -1
  30. package/dist/cjs/simplify/simplify.js.map +1 -1
  31. package/dist/cjs/slice.d.ts +6 -1
  32. package/dist/cjs/slice.d.ts.map +1 -1
  33. package/dist/cjs/slice.js +8 -7
  34. package/dist/cjs/slice.js.map +1 -1
  35. package/dist/cjs/split-at.d.ts +12 -0
  36. package/dist/cjs/split-at.d.ts.map +1 -0
  37. package/dist/cjs/split-at.js +32 -0
  38. package/dist/cjs/split-at.js.map +1 -0
  39. package/dist/cjs/terminal.d.ts.map +1 -1
  40. package/dist/cjs/terminal.js +13 -12
  41. package/dist/cjs/terminal.js.map +1 -1
  42. package/dist/cjs/types.d.ts +2 -0
  43. package/dist/cjs/types.d.ts.map +1 -1
  44. package/dist/cjs/utils.d.ts +5 -0
  45. package/dist/cjs/utils.d.ts.map +1 -0
  46. package/dist/cjs/utils.js +14 -0
  47. package/dist/cjs/utils.js.map +1 -0
  48. package/dist/esm/ansi.d.ts +11 -9
  49. package/dist/esm/ansi.d.ts.map +1 -1
  50. package/dist/esm/ansi.js +3 -1
  51. package/dist/esm/ansi.js.map +1 -1
  52. package/dist/esm/cursor.d.ts +6 -6
  53. package/dist/esm/cursor.d.ts.map +1 -1
  54. package/dist/esm/cursor.js +18 -16
  55. package/dist/esm/cursor.js.map +1 -1
  56. package/dist/esm/erase.d.ts.map +1 -1
  57. package/dist/esm/erase.js +8 -7
  58. package/dist/esm/erase.js.map +1 -1
  59. package/dist/esm/scroll.d.ts +2 -2
  60. package/dist/esm/scroll.d.ts.map +1 -1
  61. package/dist/esm/scroll.js +5 -4
  62. package/dist/esm/scroll.js.map +1 -1
  63. package/dist/esm/sgr/color/channel.d.ts.map +1 -1
  64. package/dist/esm/sgr/color/channel.js +2 -1
  65. package/dist/esm/sgr/color/channel.js.map +1 -1
  66. package/dist/esm/sgr/format-builder.d.ts.map +1 -1
  67. package/dist/esm/sgr/format-builder.js +3 -2
  68. package/dist/esm/sgr/format-builder.js.map +1 -1
  69. package/dist/esm/sgr/reset.d.ts.map +1 -1
  70. package/dist/esm/sgr/reset.js +2 -1
  71. package/dist/esm/sgr/reset.js.map +1 -1
  72. package/dist/esm/simplify/simplify.d.ts.map +1 -1
  73. package/dist/esm/simplify/simplify.js +2 -1
  74. package/dist/esm/simplify/simplify.js.map +1 -1
  75. package/dist/esm/slice.d.ts +6 -1
  76. package/dist/esm/slice.d.ts.map +1 -1
  77. package/dist/esm/slice.js +8 -9
  78. package/dist/esm/slice.js.map +1 -1
  79. package/dist/esm/split-at.d.ts +12 -0
  80. package/dist/esm/split-at.d.ts.map +1 -0
  81. package/dist/esm/split-at.js +29 -0
  82. package/dist/esm/split-at.js.map +1 -0
  83. package/dist/esm/terminal.d.ts.map +1 -1
  84. package/dist/esm/terminal.js +13 -12
  85. package/dist/esm/terminal.js.map +1 -1
  86. package/dist/esm/types.d.ts +2 -0
  87. package/dist/esm/types.d.ts.map +1 -1
  88. package/dist/esm/utils.d.ts +5 -0
  89. package/dist/esm/utils.d.ts.map +1 -0
  90. package/dist/esm/utils.js +8 -0
  91. package/dist/esm/utils.js.map +1 -0
  92. package/package.json +1 -1
  93. package/src/ansi.ts +3 -1
  94. package/src/cursor.ts +18 -18
  95. package/src/erase.ts +9 -7
  96. package/src/scroll.ts +6 -4
  97. package/src/sgr/color/channel.ts +2 -1
  98. package/src/sgr/format-builder.ts +3 -2
  99. package/src/sgr/reset.ts +3 -1
  100. package/src/simplify/simplify.ts +2 -1
  101. package/src/slice.ts +11 -10
  102. package/src/split-at.ts +44 -0
  103. package/src/terminal.ts +14 -12
  104. package/src/types.ts +2 -0
  105. package/src/utils.ts +15 -0
@@ -0,0 +1,29 @@
1
+ import { scanCSI, skippedSequences } from "./slice.js";
2
+ /**
3
+ * Split a string into two parts at the given visible index (i.e., the given visible character,
4
+ * ignoring ANSI escape codes). The returned strings will include any ANSI escape codes from within
5
+ * each slice.
6
+ *
7
+ * Note that unlike {@linkcode slice}, this function doesn't, by default include any SGR codes (m)
8
+ * from before or after the split point. If you need to preserve the terminal state before and after
9
+ * the split, pass `true` for the `includeSkipped` parameter.
10
+ */
11
+ export function splitAt(text, visibleIndex, includeSkipped = false) {
12
+ if (!visibleIndex)
13
+ return ["", text];
14
+ if (visibleIndex < 0)
15
+ throw new Error("visibleIndex must be non-negative");
16
+ if (visibleIndex > text.length)
17
+ return [text, ""];
18
+ const { index } = scanCSI(text, 0, visibleIndex);
19
+ if (index === text.length)
20
+ return [text, ""];
21
+ let start = text.slice(0, index);
22
+ let end = text.slice(index);
23
+ if (includeSkipped) {
24
+ start += skippedSequences(text, index);
25
+ end = skippedSequences(text, 0, index) + end;
26
+ }
27
+ return [start, end];
28
+ }
29
+ //# sourceMappingURL=split-at.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"split-at.js","sourceRoot":"","sources":["../../src/split-at.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,OAAO,EAAE,gBAAgB,EAAC,MAAM,SAAS,CAAC;AAIlD;;;;;;;;GAQG;AACH,MAAM,UAAU,OAAO,CACtB,IAAuB,EACvB,YAAuB,EACvB,iBAA2B,KAAK;IAEhC,IAAI,CAAC,YAAY;QAChB,OAAO,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;IAEnB,IAAI,YAAY,GAAG,CAAC;QACnB,MAAM,IAAI,KAAK,CAAC,mCAAmC,CAAC,CAAC;IAEtD,IAAI,YAAY,GAAG,IAAI,CAAC,MAAM;QAC7B,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;IAEnB,MAAM,EAAC,KAAK,EAAC,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC,EAAE,YAAY,CAAC,CAAC;IAE/C,IAAI,KAAK,KAAK,IAAI,CAAC,MAAM;QACxB,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;IAEnB,IAAI,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;IACjC,IAAI,GAAG,GAAK,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IAE9B,IAAI,cAAc,EAAE,CAAC;QACpB,KAAK,IAAI,gBAAgB,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;QACvC,GAAG,GAAM,gBAAgB,CAAC,IAAI,EAAE,CAAC,EAAE,KAAK,CAAC,GAAG,GAAG,CAAC;IACjD,CAAC;IAED,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;AACrB,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"terminal.d.ts","sourceRoot":"","sources":["../../src/terminal.ts"],"names":[],"mappings":"AAAA,QAAA,MAAM,QAAQ;;;;;;;;;;;;;;;;;;;;;CAwBb,CAAC;AAEF,MAAM,MAAM,QAAQ,GAAG,OAAO,QAAQ,CAAC;AA4BvC,eAAO,MAAM,YAAY,GAAI,iBAAc,KAAG,QAAyC,CAAC"}
1
+ {"version":3,"file":"terminal.d.ts","sourceRoot":"","sources":["../../src/terminal.ts"],"names":[],"mappings":"AAEA,QAAA,MAAM,QAAQ;;;;;;;;;;;;;;;;;;;;;CAwBb,CAAC;AAEF,MAAM,MAAM,QAAQ,GAAG,OAAO,QAAQ,CAAC;AA4BvC,eAAO,MAAM,YAAY,GAAI,iBAAc,KAAG,QAAyC,CAAC"}
@@ -1,23 +1,24 @@
1
+ import { csi } from "./utils.js";
1
2
  const terminal = {
2
3
  focusReporting: {
3
- enable: "\x1b[?1004h",
4
- disable: "\x1b[?1004l",
5
- focus: "\x1b[I",
6
- blur: "\x1b[O",
4
+ enable: csi("?1004h"),
5
+ disable: csi("?1004l"),
6
+ focus: csi("I"),
7
+ blur: csi("O"),
7
8
  },
8
9
  alternateScreen: {
9
- enable: "\x1b[?1049h",
10
- disable: "\x1b[?1049l",
10
+ enable: csi("?1049h"),
11
+ disable: csi("?1049l"),
11
12
  legacy: {
12
- enable: "\x1b[?47h",
13
- disable: "\x1b[?47l",
13
+ enable: csi("?47h"),
14
+ disable: csi("?47l"),
14
15
  },
15
16
  },
16
17
  bracketedPaste: {
17
- enable: "\x1b[?2004h",
18
- disable: "\x1b[?2004l",
19
- start: "\x1b[200~",
20
- end: "\x1b[201~",
18
+ enable: csi("?2004h"),
19
+ disable: csi("?2004l"),
20
+ start: csi("200~"),
21
+ end: csi("201~"),
21
22
  },
22
23
  };
23
24
  const disabled = {
@@ -1 +1 @@
1
- {"version":3,"file":"terminal.js","sourceRoot":"","sources":["../../src/terminal.ts"],"names":[],"mappings":"AAAA,MAAM,QAAQ,GAAG;IAChB,cAAc,EAAE;QACf,MAAM,EAAI,aAAa;QACvB,OAAO,EAAG,aAAa;QACvB,KAAK,EAAK,QAAQ;QAClB,IAAI,EAAM,QAAQ;KAClB;IAED,eAAe,EAAE;QAChB,MAAM,EAAI,aAAa;QACvB,OAAO,EAAG,aAAa;QAEvB,MAAM,EAAE;YACP,MAAM,EAAI,WAAW;YACrB,OAAO,EAAG,WAAW;SACrB;KACD;IAED,cAAc,EAAE;QACf,MAAM,EAAI,aAAa;QACvB,OAAO,EAAG,aAAa;QACvB,KAAK,EAAK,WAAW;QACrB,GAAG,EAAO,WAAW;KACrB;CACD,CAAC;AAIF,MAAM,QAAQ,GAAa;IAC1B,cAAc,EAAE;QACf,MAAM,EAAI,EAAE;QACZ,OAAO,EAAG,EAAE;QACZ,KAAK,EAAK,EAAE;QACZ,IAAI,EAAM,EAAE;KACZ;IAED,eAAe,EAAE;QAChB,MAAM,EAAI,EAAE;QACZ,OAAO,EAAG,EAAE;QAEZ,MAAM,EAAE;YACP,MAAM,EAAI,EAAE;YACZ,OAAO,EAAG,EAAE;SACZ;KACD;IAED,cAAc,EAAE;QACf,MAAM,EAAI,EAAE;QACZ,OAAO,EAAG,EAAE;QACZ,KAAK,EAAK,EAAE;QACZ,GAAG,EAAO,EAAE;KACZ;CACD,CAAC;AAEF,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,OAAO,GAAG,IAAI,EAAY,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC"}
1
+ {"version":3,"file":"terminal.js","sourceRoot":"","sources":["../../src/terminal.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,GAAG,EAAC,MAAM,SAAS,CAAC;AAE5B,MAAM,QAAQ,GAAG;IAChB,cAAc,EAAE;QACf,MAAM,EAAI,GAAG,CAAC,QAAQ,CAAC;QACvB,OAAO,EAAG,GAAG,CAAC,QAAQ,CAAC;QACvB,KAAK,EAAK,GAAG,CAAC,GAAG,CAAC;QAClB,IAAI,EAAM,GAAG,CAAC,GAAG,CAAC;KAClB;IAED,eAAe,EAAE;QAChB,MAAM,EAAI,GAAG,CAAC,QAAQ,CAAC;QACvB,OAAO,EAAG,GAAG,CAAC,QAAQ,CAAC;QAEvB,MAAM,EAAE;YACP,MAAM,EAAI,GAAG,CAAC,MAAM,CAAC;YACrB,OAAO,EAAG,GAAG,CAAC,MAAM,CAAC;SACrB;KACD;IAED,cAAc,EAAE;QACf,MAAM,EAAI,GAAG,CAAC,QAAQ,CAAC;QACvB,OAAO,EAAG,GAAG,CAAC,QAAQ,CAAC;QACvB,KAAK,EAAK,GAAG,CAAC,MAAM,CAAC;QACrB,GAAG,EAAO,GAAG,CAAC,MAAM,CAAC;KACrB;CACD,CAAC;AAIF,MAAM,QAAQ,GAAa;IAC1B,cAAc,EAAE;QACf,MAAM,EAAI,EAAE;QACZ,OAAO,EAAG,EAAE;QACZ,KAAK,EAAK,EAAE;QACZ,IAAI,EAAM,EAAE;KACZ;IAED,eAAe,EAAE;QAChB,MAAM,EAAI,EAAE;QACZ,OAAO,EAAG,EAAE;QAEZ,MAAM,EAAE;YACP,MAAM,EAAI,EAAE;YACZ,OAAO,EAAG,EAAE;SACZ;KACD;IAED,cAAc,EAAE;QACf,MAAM,EAAI,EAAE;QACZ,OAAO,EAAG,EAAE;QACZ,KAAK,EAAK,EAAE;QACZ,GAAG,EAAO,EAAE;KACZ;CACD,CAAC;AAEF,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,OAAO,GAAG,IAAI,EAAY,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC"}
@@ -6,6 +6,7 @@ import type { Scroll } from "./scroll.js";
6
6
  import type { SGR } from "./sgr/index.js";
7
7
  import type { Simplify } from "./simplify/index.js";
8
8
  import type { Slice } from "./slice.js";
9
+ import type { SplitAt } from "./split-at.js";
9
10
  import type { Sanitize, Strip, VisibleLength } from "./strip.js";
10
11
  import type { Terminal } from "./terminal.js";
11
12
  export type Ansi = SGR & {
@@ -19,6 +20,7 @@ export type Ansi = SGR & {
19
20
  visibleLength: VisibleLength;
20
21
  sanitize: Sanitize;
21
22
  slice: Slice;
23
+ splitAt: SplitAt;
22
24
  simplify: Simplify;
23
25
  features: Features;
24
26
  };
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,MAAM,EAAC,MAA8B,UAAU,CAAC;AAC7D,OAAO,KAAK,EAAC,KAAK,EAAC,MAA+B,SAAS,CAAC;AAC5D,OAAO,KAAK,EAAC,QAAQ,EAAC,MAA4B,YAAY,CAAC;AAC/D,OAAO,KAAK,EAAC,MAAM,EAAE,QAAQ,EAAC,MAAoB,OAAO,CAAC;AAC1D,OAAO,KAAK,EAAC,MAAM,EAAC,MAA8B,UAAU,CAAC;AAC7D,OAAO,KAAK,EAAC,GAAG,EAAC,MAAiC,OAAO,CAAC;AAC1D,OAAO,KAAK,EAAC,QAAQ,EAAC,MAA4B,YAAY,CAAC;AAC/D,OAAO,KAAK,EAAC,KAAK,EAAC,MAA+B,SAAS,CAAC;AAC5D,OAAO,KAAK,EAAC,QAAQ,EAAE,KAAK,EAAE,aAAa,EAAC,MAAM,SAAS,CAAC;AAC5D,OAAO,KAAK,EAAC,QAAQ,EAAC,MAA4B,YAAY,CAAC;AAE/D,MAAM,MAAM,IAAI,GAAG,GAAG,GAAG;IACxB,MAAM,EAAK,MAAM,CAAC;IAClB,KAAK,EAAM,KAAK,CAAC;IACjB,MAAM,EAAK,MAAM,CAAC;IAClB,QAAQ,EAAG,QAAQ,CAAC;IAEpB,MAAM,EAAK,MAAM,CAAC;IAClB,QAAQ,EAAG,QAAQ,CAAC;IAEpB,KAAK,EAAW,KAAK,CAAC;IACtB,aAAa,EAAG,aAAa,CAAC;IAC9B,QAAQ,EAAQ,QAAQ,CAAC;IACzB,KAAK,EAAW,KAAK,CAAC;IACtB,QAAQ,EAAQ,QAAQ,CAAC;IAEzB,QAAQ,EAAG,QAAQ,CAAC;CACpB,CAAC"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,MAAM,EAAC,MAA8B,UAAU,CAAC;AAC7D,OAAO,KAAK,EAAC,KAAK,EAAC,MAA+B,SAAS,CAAC;AAC5D,OAAO,KAAK,EAAC,QAAQ,EAAC,MAA4B,YAAY,CAAC;AAC/D,OAAO,KAAK,EAAC,MAAM,EAAE,QAAQ,EAAC,MAAoB,OAAO,CAAC;AAC1D,OAAO,KAAK,EAAC,MAAM,EAAC,MAA8B,UAAU,CAAC;AAC7D,OAAO,KAAK,EAAC,GAAG,EAAC,MAAiC,OAAO,CAAC;AAC1D,OAAO,KAAK,EAAC,QAAQ,EAAC,MAA4B,YAAY,CAAC;AAC/D,OAAO,KAAK,EAAC,KAAK,EAAC,MAA+B,SAAS,CAAC;AAC5D,OAAO,KAAK,EAAC,OAAO,EAAC,MAA6B,YAAY,CAAC;AAC/D,OAAO,KAAK,EAAC,QAAQ,EAAE,KAAK,EAAE,aAAa,EAAC,MAAM,SAAS,CAAC;AAC5D,OAAO,KAAK,EAAC,QAAQ,EAAC,MAA4B,YAAY,CAAC;AAE/D,MAAM,MAAM,IAAI,GAAG,GAAG,GAAG;IACxB,MAAM,EAAK,MAAM,CAAC;IAClB,KAAK,EAAM,KAAK,CAAC;IACjB,MAAM,EAAK,MAAM,CAAC;IAClB,QAAQ,EAAG,QAAQ,CAAC;IAEpB,MAAM,EAAK,MAAM,CAAC;IAClB,QAAQ,EAAG,QAAQ,CAAC;IAEpB,KAAK,EAAW,KAAK,CAAC;IACtB,aAAa,EAAG,aAAa,CAAC;IAC9B,QAAQ,EAAQ,QAAQ,CAAC;IACzB,KAAK,EAAW,KAAK,CAAC;IACtB,OAAO,EAAS,OAAO,CAAC;IACxB,QAAQ,EAAQ,QAAQ,CAAC;IAEzB,QAAQ,EAAG,QAAQ,CAAC;CACpB,CAAC"}
@@ -0,0 +1,5 @@
1
+ export declare function csi(command: string): string;
2
+ export declare function csi(params: string | number | undefined, command: string): string;
3
+ export declare const count: <Param extends [number?] = [count?: number]>(code: string) => (...args: Param) => string;
4
+ export declare const noop: () => string;
5
+ //# sourceMappingURL=utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/utils.ts"],"names":[],"mappings":"AAAA,wBAAgB,GAAG,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAAC;AAC7C,wBAAgB,GAAG,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAAC;AAQlF,eAAO,MAAM,KAAK,GAAI,KAAK,SAAS,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC,EAC/D,MAAM,MAAM,KACV,CAAC,GAAG,IAAI,EAAE,KAAK,KAAK,MACmE,CAAC;AAE3F,eAAO,MAAM,IAAI,cAAW,CAAC"}
@@ -0,0 +1,8 @@
1
+ export function csi(...args) {
2
+ const command = args.pop();
3
+ const params = args.pop();
4
+ return `\x1b[${params === undefined ? "" : params}${command}`;
5
+ }
6
+ export const count = (code) => (count) => count === 0 ? "" : csi(count === 1 ? undefined : count, code);
7
+ export const noop = () => "";
8
+ //# sourceMappingURL=utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.js","sourceRoot":"","sources":["../../src/utils.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,GAAG,CAAC,GAAG,IAAsD;IAC5E,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,EAAY,CAAC;IACrC,MAAM,MAAM,GAAI,IAAI,CAAC,GAAG,EAAE,CAAC;IAE3B,OAAO,QAAQ,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,OAAO,EAAE,CAAC;AAC/D,CAAC;AAED,MAAM,CAAC,MAAM,KAAK,GAAG,CACpB,IAAY,EACiB,EAAE,CAC/B,CAAC,KAAc,EAAU,EAAE,CAAC,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;AAE3F,MAAM,CAAC,MAAM,IAAI,GAAG,GAAG,EAAE,CAAC,EAAE,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name" : "@peteanderson/ansi",
3
- "version" : "3.0.0",
3
+ "version" : "3.2.0",
4
4
  "description" : "ANSI escape sequence generation with automatic feature detection",
5
5
  "author" : {
6
6
  "name" : "Pete Anderson",
package/src/ansi.ts CHANGED
@@ -6,6 +6,7 @@ import {makeScroll} from "./scroll";
6
6
  import {makeSGR} from "./sgr";
7
7
  import {simplify} from "./simplify";
8
8
  import {slice} from "./slice";
9
+ import {splitAt} from "./split-at";
9
10
  import {sanitize, strip, visibleLength} from "./strip";
10
11
  import {makeTerminal} from "./terminal";
11
12
 
@@ -32,6 +33,7 @@ export function makeAnsi(...args: Args): Ansi {
32
33
  sanitize,
33
34
  slice,
34
35
  simplify,
36
+ splitAt,
35
37
 
36
38
  features,
37
39
  };
@@ -41,7 +43,7 @@ export const ansi = makeAnsi();
41
43
 
42
44
  export const {fg, bg, style, reset, cursor, erase, scroll, terminal} = ansi;
43
45
 
44
- export {padEnd, padStart, strip, visibleLength}
46
+ export {padEnd, padStart, splitAt, strip, visibleLength}
45
47
 
46
48
  export default Object.assign(
47
49
  Object.defineProperty(makeAnsi.bind(undefined), "name", {value: "ansi"}),
package/src/cursor.ts CHANGED
@@ -1,7 +1,4 @@
1
- const move = (code: string) => (count?: number): string =>
2
- `\x1b[${count === undefined ? "" : count ? count : "?"}${code}`;
3
-
4
- const noop = (): string => "";
1
+ import {csi, count as move, noop} from "./utils";
5
2
 
6
3
  const cursor = {
7
4
  up : move("A"),
@@ -11,35 +8,38 @@ const cursor = {
11
8
  nextLine : move("E"),
12
9
  prevLine : move("F"),
13
10
 
14
- x: (x: number): string => `\x1b[${x}G`,
11
+ // Don't use `move`/`count` here, because it will output an empty string if `x` is `0`, but the
12
+ // terminal accepts `\x1b[0G` and will process it the same as `\x1b[1G`/`x1b[G`. Also, the
13
+ // parameter for `move`/`count` is optional, but the parameter for `x` is required.
14
+ x: (x: number) => csi(x, "G"),
15
15
 
16
16
  // These are the old VT100 codes, but they're widely supported by old and new terminals. The
17
17
  // newer VT220 codes are standardized by ECMA and ISO, and are also widely supported, but might
18
18
  // not work in some older terminals. The VT220 codes are:
19
19
  //
20
20
  // ```
21
- // save : "\x1b[s",
22
- // restore : "\x1b[u",
21
+ // save : csi("s"),
22
+ // restore : csi("u"),
23
23
  // ```
24
24
  save : "\x1b7",
25
25
  restore : "\x1b8",
26
26
 
27
- hide : "\x1b[?25l",
28
- show : "\x1b[?25h",
27
+ hide : csi("?25l"),
28
+ show : csi("?25h"),
29
29
 
30
30
  position: {
31
- get: "\x1b[6n",
32
- set: (x: number, y: number): string => `\x1b[${y};${x}H`,
31
+ get: csi("6n"),
32
+ set: (x: number, y: number): string => csi(`${y};${x}H`),
33
33
  },
34
34
 
35
35
  shape: {
36
- steadyBlock : "\x1b[2 q",
37
- steadyBar : "\x1b[6 q",
38
- steadyUnderline : "\x1b[4 q",
39
- blinkingBlock : "\x1b[1 q",
40
- blinkingBar : "\x1b[5 q",
41
- blinkingUnderline : "\x1b[3 q",
42
- default : "\x1b[0 q",
36
+ steadyBlock : csi("2 q"),
37
+ steadyBar : csi("6 q"),
38
+ steadyUnderline : csi("4 q"),
39
+ blinkingBlock : csi("1 q"),
40
+ blinkingBar : csi("5 q"),
41
+ blinkingUnderline : csi("3 q"),
42
+ default : csi("0 q"),
43
43
  },
44
44
  };
45
45
 
package/src/erase.ts CHANGED
@@ -1,14 +1,16 @@
1
+ import {csi} from "./utils";
2
+
1
3
  const erase = {
2
4
  line: {
3
- toStart : "\x1b[1K",
4
- toEnd : "\x1b[0K",
5
- full : "\x1b[2K",
5
+ toStart : csi("1K"),
6
+ toEnd : csi("0K"),
7
+ full : csi("2K"),
6
8
  },
7
9
  screen: {
8
- toStart : "\x1b[1J",
9
- toEnd : "\x1b[0J",
10
- full : "\x1b[2J",
11
- scrollback : "\x1b[3J",
10
+ toStart : csi("1J"),
11
+ toEnd : csi("0J"),
12
+ full : csi("2J"),
13
+ scrollback : csi("3J"),
12
14
  },
13
15
  };
14
16
 
package/src/scroll.ts CHANGED
@@ -1,13 +1,15 @@
1
+ import {count, noop} from "./utils";
2
+
1
3
  const scroll = {
2
- up : (lines?: number): string => `\x1b[${lines ?? 1}S`,
3
- down : (lines?: number): string => `\x1b[${lines ?? 1}T`,
4
+ up : count<[lines?: number]>("S"),
5
+ down : count<[lines?: number]>("T"),
4
6
  };
5
7
 
6
8
  export type Scroll = typeof scroll;
7
9
 
8
10
  const disabled: Scroll = {
9
- up : () => "",
10
- down : () => "",
11
+ up : noop,
12
+ down : noop,
11
13
  };
12
14
 
13
15
  export const makeScroll = (enabled = true): Scroll => enabled ? scroll : disabled;
@@ -1,3 +1,4 @@
1
+ import {csi} from "../../utils";
1
2
  import {lazy} from "../lazy";
2
3
  import {buildContext} from "./context";
3
4
  import {makeRGB, makeX256} from "./rgb";
@@ -29,7 +30,7 @@ export function makeChannel(
29
30
  const rtn = {
30
31
  rgb : makeRGB(ctx),
31
32
  x256 : makeX256(ctx),
32
- default : colorDepth > 1 ? `\x1b[${close}m` : "",
33
+ default : colorDepth > 1 ? csi(close, "m") : "",
33
34
  } as Channel;
34
35
 
35
36
  for (let i = 0; i < colors.length; i++) {
@@ -1,4 +1,5 @@
1
1
  import {define} from "@peteanderson/props";
2
+ import {csi} from "../utils";
2
3
  import {combineCodes} from "./combine";
3
4
  import {lazy} from "./lazy";
4
5
 
@@ -19,8 +20,8 @@ export const makeFormatBuilder = (makeChain: ChainBuilder): FormatBuilder =>
19
20
  const empty = Array.isArray(open) && !open.length;
20
21
  const openCode = empty ? "" : codeSequence(open);
21
22
  const closeCode = empty ? "" : codeSequence(close);
22
- const openSequence = empty ? "" :`\x1b[${openCode}m`;
23
- const closeSequence = empty ? "" :`\x1b[${closeCode}m`;
23
+ const openSequence = empty ? "" : csi(openCode, "m");
24
+ const closeSequence = empty ? "" : csi(closeCode, "m");
24
25
  const reopenCode = reset && !empty ? `${closeCode};${openCode}` : openCode;
25
26
 
26
27
  const rxClose = new RegExp(
package/src/sgr/reset.ts CHANGED
@@ -1 +1,3 @@
1
- export const makeReset = (enabled = true): string => enabled ? "\x1b[m" : "";
1
+ import {csi} from "../utils";
2
+
3
+ export const makeReset = (enabled = true): string => enabled ? csi("m") : "";
@@ -1,4 +1,5 @@
1
1
  import {rxSGR} from "../patterns";
2
+ import {csi} from "../utils";
2
3
  import {State} from "./state";
3
4
 
4
5
  export function simplify(text: string): string {
@@ -20,7 +21,7 @@ export function simplify(text: string): string {
20
21
 
21
22
  const newCodes = state.update(codes);
22
23
  if (newCodes.length)
23
- result += `\x1b[${newCodes.join(";")}m`;
24
+ result += csi(newCodes.join(";"), "m");
24
25
  result += chunk;
25
26
  }
26
27
 
package/src/slice.ts CHANGED
@@ -2,7 +2,7 @@ import {rxCSI, rxSGR} from "./patterns";
2
2
  import {simplify} from "./simplify";
3
3
  import {visibleLength} from "./strip";
4
4
 
5
- function scanCSI(
5
+ export function scanCSI(
6
6
  text : string,
7
7
  fromStringIndex : number,
8
8
  visibleCount : number,
@@ -30,7 +30,7 @@ function scanCSI(
30
30
  return {index, length};
31
31
  }
32
32
 
33
- function skippedSequences(text: string, start: number, end?: number): string {
33
+ export function skippedSequences(text: string, start: number, end?: number): string {
34
34
  const sequences = text.slice(start, end).match(new RegExp(rxSGR));
35
35
  return sequences ? simplify(sequences.join("")) : "";
36
36
  }
@@ -54,17 +54,18 @@ function skippedSequences(text: string, start: number, end?: number): string {
54
54
  * of the slice as it would be if the whole string were printed. This function is intended mostly
55
55
  * for text that contains SGR codes, but no other ANSI codes or control characters.
56
56
  */
57
- export function slice(text: string, start: number, end: number): string {
57
+ export function slice(text: string, start: number, end?: number): string {
58
58
  let textVisibleLength: number | undefined;
59
59
  const getVisibleLength = () => textVisibleLength ??= visibleLength(text);
60
60
 
61
- if (start < 0 || end < 0) {
62
- textVisibleLength = getVisibleLength();
63
- if (start < 0)
64
- start = Math.max(0, textVisibleLength + start);
65
- if (end < 0)
66
- end = Math.max(0, textVisibleLength + end);
67
- }
61
+ if (end === undefined)
62
+ end = getVisibleLength();
63
+
64
+ if (start < 0)
65
+ start = Math.max(0, getVisibleLength() + start);
66
+ if (end < 0)
67
+ end = Math.max(0, getVisibleLength() + end);
68
+
68
69
  if (start > end)
69
70
  return "";
70
71
 
@@ -0,0 +1,44 @@
1
+ import {scanCSI, skippedSequences} from "./slice";
2
+
3
+ import type {slice} from "./slice";
4
+
5
+ /**
6
+ * Split a string into two parts at the given visible index (i.e., the given visible character,
7
+ * ignoring ANSI escape codes). The returned strings will include any ANSI escape codes from within
8
+ * each slice.
9
+ *
10
+ * Note that unlike {@linkcode slice}, this function doesn't, by default include any SGR codes (m)
11
+ * from before or after the split point. If you need to preserve the terminal state before and after
12
+ * the split, pass `true` for the `includeSkipped` parameter.
13
+ */
14
+ export function splitAt(
15
+ text : string,
16
+ visibleIndex : number,
17
+ includeSkipped : boolean = false,
18
+ ): [start: string, end: string] {
19
+ if (!visibleIndex)
20
+ return ["", text];
21
+
22
+ if (visibleIndex < 0)
23
+ throw new Error("visibleIndex must be non-negative");
24
+
25
+ if (visibleIndex > text.length)
26
+ return [text, ""];
27
+
28
+ const {index} = scanCSI(text, 0, visibleIndex);
29
+
30
+ if (index === text.length)
31
+ return [text, ""];
32
+
33
+ let start = text.slice(0, index);
34
+ let end = text.slice(index);
35
+
36
+ if (includeSkipped) {
37
+ start += skippedSequences(text, index);
38
+ end = skippedSequences(text, 0, index) + end;
39
+ }
40
+
41
+ return [start, end];
42
+ }
43
+
44
+ export type SplitAt = typeof splitAt;
package/src/terminal.ts CHANGED
@@ -1,26 +1,28 @@
1
+ import {csi} from "./utils";
2
+
1
3
  const terminal = {
2
4
  focusReporting: {
3
- enable : "\x1b[?1004h",
4
- disable : "\x1b[?1004l",
5
- focus : "\x1b[I",
6
- blur : "\x1b[O",
5
+ enable : csi("?1004h"),
6
+ disable : csi("?1004l"),
7
+ focus : csi("I"),
8
+ blur : csi("O"),
7
9
  },
8
10
 
9
11
  alternateScreen: {
10
- enable : "\x1b[?1049h",
11
- disable : "\x1b[?1049l",
12
+ enable : csi("?1049h"),
13
+ disable : csi("?1049l"),
12
14
 
13
15
  legacy: {
14
- enable : "\x1b[?47h",
15
- disable : "\x1b[?47l",
16
+ enable : csi("?47h"),
17
+ disable : csi("?47l"),
16
18
  },
17
19
  },
18
20
 
19
21
  bracketedPaste: {
20
- enable : "\x1b[?2004h",
21
- disable : "\x1b[?2004l",
22
- start : "\x1b[200~",
23
- end : "\x1b[201~",
22
+ enable : csi("?2004h"),
23
+ disable : csi("?2004l"),
24
+ start : csi("200~"),
25
+ end : csi("201~"),
24
26
  },
25
27
  };
26
28
 
package/src/types.ts CHANGED
@@ -6,6 +6,7 @@ import type {Scroll} from "./scroll";
6
6
  import type {SGR} from "./sgr";
7
7
  import type {Simplify} from "./simplify";
8
8
  import type {Slice} from "./slice";
9
+ import type {SplitAt} from "./split-at";
9
10
  import type {Sanitize, Strip, VisibleLength} from "./strip";
10
11
  import type {Terminal} from "./terminal";
11
12
 
@@ -22,6 +23,7 @@ export type Ansi = SGR & {
22
23
  visibleLength : VisibleLength;
23
24
  sanitize : Sanitize;
24
25
  slice : Slice;
26
+ splitAt : SplitAt;
25
27
  simplify : Simplify;
26
28
 
27
29
  features : Features;
package/src/utils.ts ADDED
@@ -0,0 +1,15 @@
1
+ export function csi(command: string): string;
2
+ export function csi(params: string | number | undefined, command: string): string;
3
+ export function csi(...args: [string] | [string | number | undefined, string]): string {
4
+ const command = args.pop() as string;
5
+ const params = args.pop();
6
+
7
+ return `\x1b[${params === undefined ? "" : params}${command}`;
8
+ }
9
+
10
+ export const count = <Param extends [number?] = [count?: number]>(
11
+ code: string
12
+ ): (...args: Param) => string =>
13
+ (count?: number): string => count === 0 ? "" : csi(count === 1 ? undefined : count, code);
14
+
15
+ export const noop = () => "";