@peteanderson/ansi 3.1.0 → 3.3.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.
@@ -2,6 +2,7 @@ export declare function scanCSI(text: string, fromStringIndex: number, visibleCo
2
2
  index: number;
3
3
  length: number;
4
4
  };
5
+ export declare function skippedSequences(text: string, start: number, end?: number): string;
5
6
  /**
6
7
  * Return a slice of the given text, counting only visible characters (i.e. ignoring ANSI escape
7
8
  * codes). The returned slice will include any ANSI escape codes from within the slice. In addition,
@@ -10,6 +11,14 @@ export declare function scanCSI(text: string, fromStringIndex: number, visibleCo
10
11
  * printed. If you compose two or more slices together, there may be redundant SGR sequences at the
11
12
  * boundaries, but the result will be correct. You can use `simplify` to remove the redundancies.
12
13
  *
14
+ * Negative indices for `start` or `end` are interpreted as offsets from the end of the string,
15
+ * counting only visible characters. For example, `slice(text, -1)` returns a string containing only
16
+ * the last visible character of `text`, as well as any SGR codes from before and after that
17
+ * character.
18
+ *
19
+ * This function is analogous to `String.prototype.slice`. If the given string contains no ANSI
20
+ * sequences, the result will be the same as `text.slice(start, end)`.
21
+ *
13
22
  * Note the following caveats:
14
23
  *
15
24
  * * Any non-SGR ANSI codes prior to or after the slice will be ignored.
@@ -21,6 +30,6 @@ export declare function scanCSI(text: string, fromStringIndex: number, visibleCo
21
30
  * of the slice as it would be if the whole string were printed. This function is intended mostly
22
31
  * for text that contains SGR codes, but no other ANSI codes or control characters.
23
32
  */
24
- export declare function slice(text: string, start: number, end: number): string;
33
+ export declare function slice(text: string, start: number, end?: number): string;
25
34
  export type Slice = typeof slice;
26
35
  //# sourceMappingURL=slice.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"slice.d.ts","sourceRoot":"","sources":["../../src/slice.ts"],"names":[],"mappings":"AAIA,wBAAgB,OAAO,CACtB,IAAI,EAAc,MAAM,EACxB,eAAe,EAAG,MAAM,EACxB,YAAY,EAAM,MAAM,GACtB;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAC,CAsBjC;AAOD;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CA6BtE;AAED,MAAM,MAAM,KAAK,GAAG,OAAO,KAAK,CAAC"}
1
+ {"version":3,"file":"slice.d.ts","sourceRoot":"","sources":["../../src/slice.ts"],"names":[],"mappings":"AAIA,wBAAgB,OAAO,CACtB,IAAI,EAAc,MAAM,EACxB,eAAe,EAAG,MAAM,EACxB,YAAY,EAAM,MAAM,GACtB;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAC,CAsBjC;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,CAGlF;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAgB,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,CA8BvE;AAED,MAAM,MAAM,KAAK,GAAG,OAAO,KAAK,CAAC"}
package/dist/cjs/slice.js CHANGED
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.scanCSI = scanCSI;
4
+ exports.skippedSequences = skippedSequences;
4
5
  exports.slice = slice;
5
6
  const patterns_1 = require("./patterns");
6
7
  const simplify_1 = require("./simplify");
@@ -36,6 +37,14 @@ function skippedSequences(text, start, end) {
36
37
  * printed. If you compose two or more slices together, there may be redundant SGR sequences at the
37
38
  * boundaries, but the result will be correct. You can use `simplify` to remove the redundancies.
38
39
  *
40
+ * Negative indices for `start` or `end` are interpreted as offsets from the end of the string,
41
+ * counting only visible characters. For example, `slice(text, -1)` returns a string containing only
42
+ * the last visible character of `text`, as well as any SGR codes from before and after that
43
+ * character.
44
+ *
45
+ * This function is analogous to `String.prototype.slice`. If the given string contains no ANSI
46
+ * sequences, the result will be the same as `text.slice(start, end)`.
47
+ *
39
48
  * Note the following caveats:
40
49
  *
41
50
  * * Any non-SGR ANSI codes prior to or after the slice will be ignored.
@@ -50,13 +59,12 @@ function skippedSequences(text, start, end) {
50
59
  function slice(text, start, end) {
51
60
  let textVisibleLength;
52
61
  const getVisibleLength = () => textVisibleLength ??= (0, strip_1.visibleLength)(text);
53
- if (start < 0 || end < 0) {
54
- textVisibleLength = getVisibleLength();
55
- if (start < 0)
56
- start = Math.max(0, textVisibleLength + start);
57
- if (end < 0)
58
- end = Math.max(0, textVisibleLength + end);
59
- }
62
+ if (end === undefined)
63
+ end = getVisibleLength();
64
+ if (start < 0)
65
+ start = Math.max(0, getVisibleLength() + start);
66
+ if (end < 0)
67
+ end = Math.max(0, getVisibleLength() + end);
60
68
  if (start > end)
61
69
  return "";
62
70
  if (start === 0 && (end >= text.length || end >= getVisibleLength()))
@@ -1 +1 @@
1
- {"version":3,"file":"slice.js","sourceRoot":"","sources":["../../src/slice.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"slice.js","sourceRoot":"","sources":["../../src/slice.ts"],"names":[],"mappings":";;AAIA,0BA0BC;AAED,4CAGC;AA6BD,sBA8BC;AA9FD,yCAAyC;AACzC,yCAAyC;AACzC,mCAAsC;AAEtC,SAAgB,OAAO,CACtB,IAAwB,EACxB,eAAwB,EACxB,YAAwB;IAExB,gEAAgE;IAChE,MAAM,EAAE,GAAG,IAAI,MAAM,CAAC,gBAAK,CAAC,CAAC;IAE7B,IAAI,MAAM,GAAG,CAAC,CAAC;IACf,IAAI,KAAK,GAAI,eAAe,CAAC;IAE7B,OAAO,KAAK,GAAG,IAAI,CAAC,MAAM,IAAI,MAAM,GAAG,YAAY,EAAE,CAAC;QACrD,IAAI,IAAI,CAAC,KAAK,CAAC,KAAK,MAAM,EAAE,CAAC;YAC5B,EAAE,CAAC,SAAS,GAAG,KAAK,CAAC;YACrB,MAAM,KAAK,GAAG,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAC5B,IAAI,KAAK,EAAE,KAAK,KAAK,KAAK,EAAE,CAAC;gBAC5B,KAAK,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;gBACzB,SAAS;YACV,CAAC;QACF,CAAC;QAED,KAAK,EAAE,CAAC;QACR,MAAM,EAAE,CAAC;IACV,CAAC;IAED,OAAO,EAAC,KAAK,EAAE,MAAM,EAAC,CAAC;AACxB,CAAC;AAED,SAAgB,gBAAgB,CAAC,IAAY,EAAE,KAAa,EAAE,GAAY;IACzE,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,IAAI,MAAM,CAAC,gBAAK,CAAC,CAAC,CAAC;IAClE,OAAO,SAAS,CAAC,CAAC,CAAC,IAAA,mBAAQ,EAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;AACtD,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,SAAgB,KAAK,CAAC,IAAY,EAAE,KAAa,EAAE,GAAY;IAC9D,IAAI,iBAAqC,CAAC;IAC1C,MAAM,gBAAgB,GAAG,GAAG,EAAE,CAAC,iBAAiB,KAAK,IAAA,qBAAa,EAAC,IAAI,CAAC,CAAC;IAEzE,IAAI,GAAG,KAAK,SAAS;QACpB,GAAG,GAAG,gBAAgB,EAAE,CAAC;IAE1B,IAAI,KAAK,GAAG,CAAC;QACZ,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,gBAAgB,EAAE,GAAG,KAAK,CAAC,CAAC;IACjD,IAAI,GAAG,GAAG,CAAC;QACV,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,gBAAgB,EAAE,GAAG,GAAG,CAAC,CAAC;IAE7C,IAAI,KAAK,GAAG,GAAG;QACd,OAAO,EAAE,CAAC;IAEX,IAAI,KAAK,KAAK,CAAC,IAAI,CAAC,GAAG,IAAI,IAAI,CAAC,MAAM,IAAI,GAAG,IAAI,gBAAgB,EAAE,CAAC;QACnE,OAAO,IAAI,CAAC;IAEb,MAAM,EAAC,KAAK,EAAE,UAAU,EAAE,MAAM,EAAE,cAAc,EAAC,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC,EAAE,KAAK,CAAC,CAAC;IAE5E,MAAM,QAAQ,GACb,UAAU,GAAG,IAAI,CAAC,MAAM,IAAI,cAAc,GAAG,GAAG;QAC/C,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,UAAU,EAAE,GAAG,GAAG,cAAc,CAAC,CAAC,KAAK;QACvD,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC;IAEhB,mGAAmG;IACnG,MAAM,gBAAgB,GAAI,gBAAgB,CAAC,IAAI,EAAE,CAAC,EAAE,UAAU,CAAC,CAAC;IAChE,MAAM,iBAAiB,GAAG,gBAAgB,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;IAE3D,OAAO,gBAAgB,GAAG,IAAI,CAAC,KAAK,CAAC,UAAU,EAAE,QAAQ,CAAC,GAAG,iBAAiB,CAAC;AAChF,CAAC"}
@@ -3,10 +3,10 @@
3
3
  * ignoring ANSI escape codes). The returned strings will include any ANSI escape codes from within
4
4
  * each slice.
5
5
  *
6
- * Note that unlike {@linkcode slice}, this function does not include any SGR codes (m) from before
7
- * or after the split point. If you need to preserve the terminal state before and after the split,
8
- * use {@linkcode slice} instead.
6
+ * Note that unlike {@linkcode slice}, this function doesn't, by default include any SGR codes (m)
7
+ * from before or after the split point. If you need to preserve the terminal state before and after
8
+ * the split, pass `true` for the `includeSkipped` parameter.
9
9
  */
10
- export declare function splitAt(text: string, visibleIndex: number): [start: string, end: string];
10
+ export declare function splitAt(text: string, visibleIndex: number, includeSkipped?: boolean): [start: string, end: string];
11
11
  export type SplitAt = typeof splitAt;
12
12
  //# sourceMappingURL=split-at.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"split-at.d.ts","sourceRoot":"","sources":["../../src/split-at.ts"],"names":[],"mappings":"AAIA;;;;;;;;GAQG;AACH,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,CAAC,CAgBxF;AAED,MAAM,MAAM,OAAO,GAAG,OAAO,OAAO,CAAC"}
1
+ {"version":3,"file":"split-at.d.ts","sourceRoot":"","sources":["../../src/split-at.ts"],"names":[],"mappings":"AAKA;;;;;;;;GAQG;AACH,wBAAgB,OAAO,CACtB,IAAI,EAAa,MAAM,EACvB,YAAY,EAAK,MAAM,EACvB,cAAc,GAAG,OAAe,GAC9B,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,CAAC,CAwB9B;AAED,MAAM,MAAM,OAAO,GAAG,OAAO,OAAO,CAAC"}
@@ -2,25 +2,32 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.splitAt = splitAt;
4
4
  const slice_1 = require("./slice");
5
+ const strip_1 = require("./strip");
5
6
  /**
6
7
  * Split a string into two parts at the given visible index (i.e., the given visible character,
7
8
  * ignoring ANSI escape codes). The returned strings will include any ANSI escape codes from within
8
9
  * each slice.
9
10
  *
10
- * Note that unlike {@linkcode slice}, this function does not include any SGR codes (m) from before
11
- * or after the split point. If you need to preserve the terminal state before and after the split,
12
- * use {@linkcode slice} instead.
11
+ * Note that unlike {@linkcode slice}, this function doesn't, by default include any SGR codes (m)
12
+ * from before or after the split point. If you need to preserve the terminal state before and after
13
+ * the split, pass `true` for the `includeSkipped` parameter.
13
14
  */
14
- function splitAt(text, visibleIndex) {
15
+ function splitAt(text, visibleIndex, includeSkipped = false) {
15
16
  if (!visibleIndex)
16
17
  return ["", text];
17
18
  if (visibleIndex < 0)
18
- throw new Error("visibleIndex must be non-negative");
19
+ visibleIndex = Math.max(0, (0, strip_1.visibleLength)(text) + visibleIndex);
19
20
  if (visibleIndex > text.length)
20
21
  return [text, ""];
21
22
  const { index } = (0, slice_1.scanCSI)(text, 0, visibleIndex);
22
23
  if (index === text.length)
23
24
  return [text, ""];
24
- return [text.slice(0, index), text.slice(index)];
25
+ let start = text.slice(0, index);
26
+ let end = text.slice(index);
27
+ if (includeSkipped) {
28
+ start += (0, slice_1.skippedSequences)(text, index);
29
+ end = (0, slice_1.skippedSequences)(text, 0, index) + end;
30
+ }
31
+ return [start, end];
25
32
  }
26
33
  //# sourceMappingURL=split-at.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"split-at.js","sourceRoot":"","sources":["../../src/split-at.ts"],"names":[],"mappings":";;AAaA,0BAgBC;AA7BD,mCAAgC;AAIhC;;;;;;;;GAQG;AACH,SAAgB,OAAO,CAAC,IAAY,EAAE,YAAoB;IACzD,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,IAAA,eAAO,EAAC,IAAI,EAAE,CAAC,EAAE,YAAY,CAAC,CAAC;IAE/C,IAAI,KAAK,KAAK,IAAI,CAAC,MAAM;QACxB,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;IAEnB,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC;AAClD,CAAC"}
1
+ {"version":3,"file":"split-at.js","sourceRoot":"","sources":["../../src/split-at.ts"],"names":[],"mappings":";;AAcA,0BA4BC;AA1CD,mCAAkD;AAClD,mCAAkD;AAIlD;;;;;;;;GAQG;AACH,SAAgB,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,YAAY,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAA,qBAAa,EAAC,IAAI,CAAC,GAAG,YAAY,CAAC,CAAC;IAEhE,IAAI,YAAY,GAAG,IAAI,CAAC,MAAM;QAC7B,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;IAEnB,MAAM,EAAC,KAAK,EAAC,GAAG,IAAA,eAAO,EAAC,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,IAAA,wBAAgB,EAAC,IAAI,EAAE,KAAK,CAAC,CAAC;QACvC,GAAG,GAAM,IAAA,wBAAgB,EAAC,IAAI,EAAE,CAAC,EAAE,KAAK,CAAC,GAAG,GAAG,CAAC;IACjD,CAAC;IAED,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;AACrB,CAAC"}
@@ -2,6 +2,7 @@ export declare function scanCSI(text: string, fromStringIndex: number, visibleCo
2
2
  index: number;
3
3
  length: number;
4
4
  };
5
+ export declare function skippedSequences(text: string, start: number, end?: number): string;
5
6
  /**
6
7
  * Return a slice of the given text, counting only visible characters (i.e. ignoring ANSI escape
7
8
  * codes). The returned slice will include any ANSI escape codes from within the slice. In addition,
@@ -10,6 +11,14 @@ export declare function scanCSI(text: string, fromStringIndex: number, visibleCo
10
11
  * printed. If you compose two or more slices together, there may be redundant SGR sequences at the
11
12
  * boundaries, but the result will be correct. You can use `simplify` to remove the redundancies.
12
13
  *
14
+ * Negative indices for `start` or `end` are interpreted as offsets from the end of the string,
15
+ * counting only visible characters. For example, `slice(text, -1)` returns a string containing only
16
+ * the last visible character of `text`, as well as any SGR codes from before and after that
17
+ * character.
18
+ *
19
+ * This function is analogous to `String.prototype.slice`. If the given string contains no ANSI
20
+ * sequences, the result will be the same as `text.slice(start, end)`.
21
+ *
13
22
  * Note the following caveats:
14
23
  *
15
24
  * * Any non-SGR ANSI codes prior to or after the slice will be ignored.
@@ -21,6 +30,6 @@ export declare function scanCSI(text: string, fromStringIndex: number, visibleCo
21
30
  * of the slice as it would be if the whole string were printed. This function is intended mostly
22
31
  * for text that contains SGR codes, but no other ANSI codes or control characters.
23
32
  */
24
- export declare function slice(text: string, start: number, end: number): string;
33
+ export declare function slice(text: string, start: number, end?: number): string;
25
34
  export type Slice = typeof slice;
26
35
  //# sourceMappingURL=slice.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"slice.d.ts","sourceRoot":"","sources":["../../src/slice.ts"],"names":[],"mappings":"AAIA,wBAAgB,OAAO,CACtB,IAAI,EAAc,MAAM,EACxB,eAAe,EAAG,MAAM,EACxB,YAAY,EAAM,MAAM,GACtB;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAC,CAsBjC;AAOD;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CA6BtE;AAED,MAAM,MAAM,KAAK,GAAG,OAAO,KAAK,CAAC"}
1
+ {"version":3,"file":"slice.d.ts","sourceRoot":"","sources":["../../src/slice.ts"],"names":[],"mappings":"AAIA,wBAAgB,OAAO,CACtB,IAAI,EAAc,MAAM,EACxB,eAAe,EAAG,MAAM,EACxB,YAAY,EAAM,MAAM,GACtB;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAC,CAsBjC;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,CAGlF;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAgB,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,CA8BvE;AAED,MAAM,MAAM,KAAK,GAAG,OAAO,KAAK,CAAC"}
package/dist/esm/slice.js CHANGED
@@ -20,7 +20,7 @@ export function scanCSI(text, fromStringIndex, visibleCount) {
20
20
  }
21
21
  return { index, length };
22
22
  }
23
- function skippedSequences(text, start, end) {
23
+ export function skippedSequences(text, start, end) {
24
24
  const sequences = text.slice(start, end).match(new RegExp(rxSGR));
25
25
  return sequences ? simplify(sequences.join("")) : "";
26
26
  }
@@ -32,6 +32,14 @@ function skippedSequences(text, start, end) {
32
32
  * printed. If you compose two or more slices together, there may be redundant SGR sequences at the
33
33
  * boundaries, but the result will be correct. You can use `simplify` to remove the redundancies.
34
34
  *
35
+ * Negative indices for `start` or `end` are interpreted as offsets from the end of the string,
36
+ * counting only visible characters. For example, `slice(text, -1)` returns a string containing only
37
+ * the last visible character of `text`, as well as any SGR codes from before and after that
38
+ * character.
39
+ *
40
+ * This function is analogous to `String.prototype.slice`. If the given string contains no ANSI
41
+ * sequences, the result will be the same as `text.slice(start, end)`.
42
+ *
35
43
  * Note the following caveats:
36
44
  *
37
45
  * * Any non-SGR ANSI codes prior to or after the slice will be ignored.
@@ -46,13 +54,12 @@ function skippedSequences(text, start, end) {
46
54
  export function slice(text, start, end) {
47
55
  let textVisibleLength;
48
56
  const getVisibleLength = () => textVisibleLength ??= visibleLength(text);
49
- if (start < 0 || end < 0) {
50
- textVisibleLength = getVisibleLength();
51
- if (start < 0)
52
- start = Math.max(0, textVisibleLength + start);
53
- if (end < 0)
54
- end = Math.max(0, textVisibleLength + end);
55
- }
57
+ if (end === undefined)
58
+ end = getVisibleLength();
59
+ if (start < 0)
60
+ start = Math.max(0, getVisibleLength() + start);
61
+ if (end < 0)
62
+ end = Math.max(0, getVisibleLength() + end);
56
63
  if (start > end)
57
64
  return "";
58
65
  if (start === 0 && (end >= text.length || end >= getVisibleLength()))
@@ -1 +1 @@
1
- {"version":3,"file":"slice.js","sourceRoot":"","sources":["../../src/slice.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"slice.js","sourceRoot":"","sources":["../../src/slice.ts"],"names":[],"mappings":"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"}
@@ -3,10 +3,10 @@
3
3
  * ignoring ANSI escape codes). The returned strings will include any ANSI escape codes from within
4
4
  * each slice.
5
5
  *
6
- * Note that unlike {@linkcode slice}, this function does not include any SGR codes (m) from before
7
- * or after the split point. If you need to preserve the terminal state before and after the split,
8
- * use {@linkcode slice} instead.
6
+ * Note that unlike {@linkcode slice}, this function doesn't, by default include any SGR codes (m)
7
+ * from before or after the split point. If you need to preserve the terminal state before and after
8
+ * the split, pass `true` for the `includeSkipped` parameter.
9
9
  */
10
- export declare function splitAt(text: string, visibleIndex: number): [start: string, end: string];
10
+ export declare function splitAt(text: string, visibleIndex: number, includeSkipped?: boolean): [start: string, end: string];
11
11
  export type SplitAt = typeof splitAt;
12
12
  //# sourceMappingURL=split-at.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"split-at.d.ts","sourceRoot":"","sources":["../../src/split-at.ts"],"names":[],"mappings":"AAIA;;;;;;;;GAQG;AACH,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,CAAC,CAgBxF;AAED,MAAM,MAAM,OAAO,GAAG,OAAO,OAAO,CAAC"}
1
+ {"version":3,"file":"split-at.d.ts","sourceRoot":"","sources":["../../src/split-at.ts"],"names":[],"mappings":"AAKA;;;;;;;;GAQG;AACH,wBAAgB,OAAO,CACtB,IAAI,EAAa,MAAM,EACvB,YAAY,EAAK,MAAM,EACvB,cAAc,GAAG,OAAe,GAC9B,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,CAAC,CAwB9B;AAED,MAAM,MAAM,OAAO,GAAG,OAAO,OAAO,CAAC"}
@@ -1,23 +1,30 @@
1
- import { scanCSI } from "./slice.js";
1
+ import { scanCSI, skippedSequences } from "./slice.js";
2
+ import { visibleLength } from "./strip.js";
2
3
  /**
3
4
  * Split a string into two parts at the given visible index (i.e., the given visible character,
4
5
  * ignoring ANSI escape codes). The returned strings will include any ANSI escape codes from within
5
6
  * each slice.
6
7
  *
7
- * Note that unlike {@linkcode slice}, this function does not include any SGR codes (m) from before
8
- * or after the split point. If you need to preserve the terminal state before and after the split,
9
- * use {@linkcode slice} instead.
8
+ * Note that unlike {@linkcode slice}, this function doesn't, by default include any SGR codes (m)
9
+ * from before or after the split point. If you need to preserve the terminal state before and after
10
+ * the split, pass `true` for the `includeSkipped` parameter.
10
11
  */
11
- export function splitAt(text, visibleIndex) {
12
+ export function splitAt(text, visibleIndex, includeSkipped = false) {
12
13
  if (!visibleIndex)
13
14
  return ["", text];
14
15
  if (visibleIndex < 0)
15
- throw new Error("visibleIndex must be non-negative");
16
+ visibleIndex = Math.max(0, visibleLength(text) + visibleIndex);
16
17
  if (visibleIndex > text.length)
17
18
  return [text, ""];
18
19
  const { index } = scanCSI(text, 0, visibleIndex);
19
20
  if (index === text.length)
20
21
  return [text, ""];
21
- return [text.slice(0, index), text.slice(index)];
22
+ let start = text.slice(0, index);
23
+ let end = text.slice(index);
24
+ if (includeSkipped) {
25
+ start += skippedSequences(text, index);
26
+ end = skippedSequences(text, 0, index) + end;
27
+ }
28
+ return [start, end];
22
29
  }
23
30
  //# sourceMappingURL=split-at.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"split-at.js","sourceRoot":"","sources":["../../src/split-at.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,OAAO,EAAC,MAAM,SAAS,CAAC;AAIhC;;;;;;;;GAQG;AACH,MAAM,UAAU,OAAO,CAAC,IAAY,EAAE,YAAoB;IACzD,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,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC;AAClD,CAAC"}
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;AAClD,OAAO,EAAC,aAAa,EAAC,MAAkB,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,YAAY,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,aAAa,CAAC,IAAI,CAAC,GAAG,YAAY,CAAC,CAAC;IAEhE,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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name" : "@peteanderson/ansi",
3
- "version" : "3.1.0",
3
+ "version" : "3.3.0",
4
4
  "description" : "ANSI escape sequence generation with automatic feature detection",
5
5
  "author" : {
6
6
  "name" : "Pete Anderson",
package/src/slice.ts CHANGED
@@ -30,7 +30,7 @@ export 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
  }
@@ -43,6 +43,14 @@ function skippedSequences(text: string, start: number, end?: number): string {
43
43
  * printed. If you compose two or more slices together, there may be redundant SGR sequences at the
44
44
  * boundaries, but the result will be correct. You can use `simplify` to remove the redundancies.
45
45
  *
46
+ * Negative indices for `start` or `end` are interpreted as offsets from the end of the string,
47
+ * counting only visible characters. For example, `slice(text, -1)` returns a string containing only
48
+ * the last visible character of `text`, as well as any SGR codes from before and after that
49
+ * character.
50
+ *
51
+ * This function is analogous to `String.prototype.slice`. If the given string contains no ANSI
52
+ * sequences, the result will be the same as `text.slice(start, end)`.
53
+ *
46
54
  * Note the following caveats:
47
55
  *
48
56
  * * Any non-SGR ANSI codes prior to or after the slice will be ignored.
@@ -54,17 +62,18 @@ function skippedSequences(text: string, start: number, end?: number): string {
54
62
  * of the slice as it would be if the whole string were printed. This function is intended mostly
55
63
  * for text that contains SGR codes, but no other ANSI codes or control characters.
56
64
  */
57
- export function slice(text: string, start: number, end: number): string {
65
+ export function slice(text: string, start: number, end?: number): string {
58
66
  let textVisibleLength: number | undefined;
59
67
  const getVisibleLength = () => textVisibleLength ??= visibleLength(text);
60
68
 
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
- }
69
+ if (end === undefined)
70
+ end = getVisibleLength();
71
+
72
+ if (start < 0)
73
+ start = Math.max(0, getVisibleLength() + start);
74
+ if (end < 0)
75
+ end = Math.max(0, getVisibleLength() + end);
76
+
68
77
  if (start > end)
69
78
  return "";
70
79
 
package/src/split-at.ts CHANGED
@@ -1,4 +1,5 @@
1
- import {scanCSI} from "./slice";
1
+ import {scanCSI, skippedSequences} from "./slice";
2
+ import {visibleLength} from "./strip";
2
3
 
3
4
  import type {slice} from "./slice";
4
5
 
@@ -7,16 +8,20 @@ import type {slice} from "./slice";
7
8
  * ignoring ANSI escape codes). The returned strings will include any ANSI escape codes from within
8
9
  * each slice.
9
10
  *
10
- * Note that unlike {@linkcode slice}, this function does not include any SGR codes (m) from before
11
- * or after the split point. If you need to preserve the terminal state before and after the split,
12
- * use {@linkcode slice} instead.
11
+ * Note that unlike {@linkcode slice}, this function doesn't, by default include any SGR codes (m)
12
+ * from before or after the split point. If you need to preserve the terminal state before and after
13
+ * the split, pass `true` for the `includeSkipped` parameter.
13
14
  */
14
- export function splitAt(text: string, visibleIndex: number): [start: string, end: string] {
15
+ export function splitAt(
16
+ text : string,
17
+ visibleIndex : number,
18
+ includeSkipped : boolean = false,
19
+ ): [start: string, end: string] {
15
20
  if (!visibleIndex)
16
21
  return ["", text];
17
22
 
18
23
  if (visibleIndex < 0)
19
- throw new Error("visibleIndex must be non-negative");
24
+ visibleIndex = Math.max(0, visibleLength(text) + visibleIndex);
20
25
 
21
26
  if (visibleIndex > text.length)
22
27
  return [text, ""];
@@ -26,7 +31,15 @@ export function splitAt(text: string, visibleIndex: number): [start: string, end
26
31
  if (index === text.length)
27
32
  return [text, ""];
28
33
 
29
- return [text.slice(0, index), text.slice(index)];
34
+ let start = text.slice(0, index);
35
+ let end = text.slice(index);
36
+
37
+ if (includeSkipped) {
38
+ start += skippedSequences(text, index);
39
+ end = skippedSequences(text, 0, index) + end;
40
+ }
41
+
42
+ return [start, end];
30
43
  }
31
44
 
32
45
  export type SplitAt = typeof splitAt;