@code-yeongyu/senpi-tui 2026.8.18 → 2026.8.20

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.
@@ -1 +1 @@
1
- {"version":3,"file":"text.d.ts","sourceRoot":"","sources":["../../src/components/text.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAG3C;;GAEG;AACH,qBAAa,IAAK,YAAW,SAAS;IACrC,OAAO,CAAC,IAAI,CAAS;IACrB,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,UAAU,CAAC,CAA2B;IAG9C,OAAO,CAAC,UAAU,CAAC,CAAS;IAC5B,OAAO,CAAC,WAAW,CAAC,CAAS;IAC7B,OAAO,CAAC,WAAW,CAAC,CAAW;gBAEnB,IAAI,GAAE,MAAW,EAAE,QAAQ,GAAE,MAAU,EAAE,QAAQ,GAAE,MAAU,EAAE,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM;IAOhH,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAO3B,aAAa,CAAC,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI;IAO1D,UAAU,IAAI,IAAI;IAMlB,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE;CA6D/B"}
1
+ {"version":3,"file":"text.d.ts","sourceRoot":"","sources":["../../src/components/text.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAG3C;;GAEG;AACH,qBAAa,IAAK,YAAW,SAAS;IACrC,OAAO,CAAC,IAAI,CAAS;IACrB,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,UAAU,CAAC,CAA2B;IAG9C,OAAO,CAAC,UAAU,CAAC,CAAS;IAC5B,OAAO,CAAC,WAAW,CAAC,CAAS;IAC7B,OAAO,CAAC,WAAW,CAAC,CAAW;gBAEnB,IAAI,GAAE,MAAW,EAAE,QAAQ,GAAE,MAAU,EAAE,QAAQ,GAAE,MAAU,EAAE,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM;IAOhH,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAO3B,aAAa,CAAC,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI;IAO1D,UAAU,IAAI,IAAI;IAMlB,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE;CA8D/B"}
@@ -41,13 +41,14 @@ export class Text {
41
41
  }
42
42
  // Replace tabs with 3 spaces
43
43
  const normalizedText = this.text.replace(/\t/g, " ");
44
- // Calculate content width (subtract left/right margins)
45
- const contentWidth = Math.max(1, width - this.paddingX * 2);
44
+ // Reduce margins when necessary so content and padding fit within the available width.
45
+ const paddingX = Math.min(this.paddingX, Math.max(0, Math.floor((width - 1) / 2)));
46
+ const contentWidth = Math.max(1, width - paddingX * 2);
46
47
  // Wrap text (this preserves ANSI codes but does NOT pad)
47
48
  const wrappedLines = wrapTextWithAnsi(normalizedText, contentWidth);
48
49
  // Add margins and background to each line
49
- const leftMargin = " ".repeat(this.paddingX);
50
- const rightMargin = " ".repeat(this.paddingX);
50
+ const leftMargin = " ".repeat(paddingX);
51
+ const rightMargin = " ".repeat(paddingX);
51
52
  const contentLines = [];
52
53
  for (const line of wrappedLines) {
53
54
  // Add margins
@@ -1 +1 @@
1
- {"version":3,"file":"text.js","sourceRoot":"","sources":["../../src/components/text.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Component } from \"../tui.ts\";\nimport { applyBackgroundToLine, visibleWidth, wrapTextWithAnsi } from \"../utils.ts\";\n\n/**\n * Text component - displays multi-line text with word wrapping\n */\nexport class Text implements Component {\n\tprivate text: string;\n\tprivate paddingX: number; // Left/right padding\n\tprivate paddingY: number; // Top/bottom padding\n\tprivate customBgFn?: (text: string) => string;\n\n\t// Cache for rendered output\n\tprivate cachedText?: string;\n\tprivate cachedWidth?: number;\n\tprivate cachedLines?: string[];\n\n\tconstructor(text: string = \"\", paddingX: number = 1, paddingY: number = 1, customBgFn?: (text: string) => string) {\n\t\tthis.text = text;\n\t\tthis.paddingX = paddingX;\n\t\tthis.paddingY = paddingY;\n\t\tthis.customBgFn = customBgFn;\n\t}\n\n\tsetText(text: string): void {\n\t\tthis.text = text;\n\t\tthis.cachedText = undefined;\n\t\tthis.cachedWidth = undefined;\n\t\tthis.cachedLines = undefined;\n\t}\n\n\tsetCustomBgFn(customBgFn?: (text: string) => string): void {\n\t\tthis.customBgFn = customBgFn;\n\t\tthis.cachedText = undefined;\n\t\tthis.cachedWidth = undefined;\n\t\tthis.cachedLines = undefined;\n\t}\n\n\tinvalidate(): void {\n\t\tthis.cachedText = undefined;\n\t\tthis.cachedWidth = undefined;\n\t\tthis.cachedLines = undefined;\n\t}\n\n\trender(width: number): string[] {\n\t\t// Check cache\n\t\tif (this.cachedLines && this.cachedText === this.text && this.cachedWidth === width) {\n\t\t\treturn this.cachedLines;\n\t\t}\n\n\t\t// Don't render anything if there's no actual text\n\t\tif (!this.text || this.text.trim() === \"\") {\n\t\t\tconst result: string[] = [];\n\t\t\tthis.cachedText = this.text;\n\t\t\tthis.cachedWidth = width;\n\t\t\tthis.cachedLines = result;\n\t\t\treturn result;\n\t\t}\n\n\t\t// Replace tabs with 3 spaces\n\t\tconst normalizedText = this.text.replace(/\\t/g, \" \");\n\n\t\t// Calculate content width (subtract left/right margins)\n\t\tconst contentWidth = Math.max(1, width - this.paddingX * 2);\n\n\t\t// Wrap text (this preserves ANSI codes but does NOT pad)\n\t\tconst wrappedLines = wrapTextWithAnsi(normalizedText, contentWidth);\n\n\t\t// Add margins and background to each line\n\t\tconst leftMargin = \" \".repeat(this.paddingX);\n\t\tconst rightMargin = \" \".repeat(this.paddingX);\n\t\tconst contentLines: string[] = [];\n\n\t\tfor (const line of wrappedLines) {\n\t\t\t// Add margins\n\t\t\tconst lineWithMargins = leftMargin + line + rightMargin;\n\n\t\t\t// Apply background if specified (this also pads to full width)\n\t\t\tif (this.customBgFn) {\n\t\t\t\tcontentLines.push(applyBackgroundToLine(lineWithMargins, width, this.customBgFn));\n\t\t\t} else {\n\t\t\t\t// No background - just pad to width with spaces\n\t\t\t\tconst visibleLen = visibleWidth(lineWithMargins);\n\t\t\t\tconst paddingNeeded = Math.max(0, width - visibleLen);\n\t\t\t\tcontentLines.push(lineWithMargins + \" \".repeat(paddingNeeded));\n\t\t\t}\n\t\t}\n\n\t\t// Add top/bottom padding (empty lines)\n\t\tconst emptyLine = \" \".repeat(width);\n\t\tconst emptyLines: string[] = [];\n\t\tfor (let i = 0; i < this.paddingY; i++) {\n\t\t\tconst line = this.customBgFn ? applyBackgroundToLine(emptyLine, width, this.customBgFn) : emptyLine;\n\t\t\temptyLines.push(line);\n\t\t}\n\n\t\tconst result = [...emptyLines, ...contentLines, ...emptyLines];\n\n\t\t// Update cache\n\t\tthis.cachedText = this.text;\n\t\tthis.cachedWidth = width;\n\t\tthis.cachedLines = result;\n\n\t\treturn result.length > 0 ? result : [\"\"];\n\t}\n}\n"]}
1
+ {"version":3,"file":"text.js","sourceRoot":"","sources":["../../src/components/text.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Component } from \"../tui.ts\";\nimport { applyBackgroundToLine, visibleWidth, wrapTextWithAnsi } from \"../utils.ts\";\n\n/**\n * Text component - displays multi-line text with word wrapping\n */\nexport class Text implements Component {\n\tprivate text: string;\n\tprivate paddingX: number; // Left/right padding\n\tprivate paddingY: number; // Top/bottom padding\n\tprivate customBgFn?: (text: string) => string;\n\n\t// Cache for rendered output\n\tprivate cachedText?: string;\n\tprivate cachedWidth?: number;\n\tprivate cachedLines?: string[];\n\n\tconstructor(text: string = \"\", paddingX: number = 1, paddingY: number = 1, customBgFn?: (text: string) => string) {\n\t\tthis.text = text;\n\t\tthis.paddingX = paddingX;\n\t\tthis.paddingY = paddingY;\n\t\tthis.customBgFn = customBgFn;\n\t}\n\n\tsetText(text: string): void {\n\t\tthis.text = text;\n\t\tthis.cachedText = undefined;\n\t\tthis.cachedWidth = undefined;\n\t\tthis.cachedLines = undefined;\n\t}\n\n\tsetCustomBgFn(customBgFn?: (text: string) => string): void {\n\t\tthis.customBgFn = customBgFn;\n\t\tthis.cachedText = undefined;\n\t\tthis.cachedWidth = undefined;\n\t\tthis.cachedLines = undefined;\n\t}\n\n\tinvalidate(): void {\n\t\tthis.cachedText = undefined;\n\t\tthis.cachedWidth = undefined;\n\t\tthis.cachedLines = undefined;\n\t}\n\n\trender(width: number): string[] {\n\t\t// Check cache\n\t\tif (this.cachedLines && this.cachedText === this.text && this.cachedWidth === width) {\n\t\t\treturn this.cachedLines;\n\t\t}\n\n\t\t// Don't render anything if there's no actual text\n\t\tif (!this.text || this.text.trim() === \"\") {\n\t\t\tconst result: string[] = [];\n\t\t\tthis.cachedText = this.text;\n\t\t\tthis.cachedWidth = width;\n\t\t\tthis.cachedLines = result;\n\t\t\treturn result;\n\t\t}\n\n\t\t// Replace tabs with 3 spaces\n\t\tconst normalizedText = this.text.replace(/\\t/g, \" \");\n\n\t\t// Reduce margins when necessary so content and padding fit within the available width.\n\t\tconst paddingX = Math.min(this.paddingX, Math.max(0, Math.floor((width - 1) / 2)));\n\t\tconst contentWidth = Math.max(1, width - paddingX * 2);\n\n\t\t// Wrap text (this preserves ANSI codes but does NOT pad)\n\t\tconst wrappedLines = wrapTextWithAnsi(normalizedText, contentWidth);\n\n\t\t// Add margins and background to each line\n\t\tconst leftMargin = \" \".repeat(paddingX);\n\t\tconst rightMargin = \" \".repeat(paddingX);\n\t\tconst contentLines: string[] = [];\n\n\t\tfor (const line of wrappedLines) {\n\t\t\t// Add margins\n\t\t\tconst lineWithMargins = leftMargin + line + rightMargin;\n\n\t\t\t// Apply background if specified (this also pads to full width)\n\t\t\tif (this.customBgFn) {\n\t\t\t\tcontentLines.push(applyBackgroundToLine(lineWithMargins, width, this.customBgFn));\n\t\t\t} else {\n\t\t\t\t// No background - just pad to width with spaces\n\t\t\t\tconst visibleLen = visibleWidth(lineWithMargins);\n\t\t\t\tconst paddingNeeded = Math.max(0, width - visibleLen);\n\t\t\t\tcontentLines.push(lineWithMargins + \" \".repeat(paddingNeeded));\n\t\t\t}\n\t\t}\n\n\t\t// Add top/bottom padding (empty lines)\n\t\tconst emptyLine = \" \".repeat(width);\n\t\tconst emptyLines: string[] = [];\n\t\tfor (let i = 0; i < this.paddingY; i++) {\n\t\t\tconst line = this.customBgFn ? applyBackgroundToLine(emptyLine, width, this.customBgFn) : emptyLine;\n\t\t\temptyLines.push(line);\n\t\t}\n\n\t\tconst result = [...emptyLines, ...contentLines, ...emptyLines];\n\n\t\t// Update cache\n\t\tthis.cachedText = this.text;\n\t\tthis.cachedWidth = width;\n\t\tthis.cachedLines = result;\n\n\t\treturn result.length > 0 ? result : [\"\"];\n\t}\n}\n"]}
@@ -1,4 +1,5 @@
1
1
  import type { AutocompleteProvider } from "./autocomplete.ts";
2
+ import type { EditorImageState } from "./image-markers.ts";
2
3
  import type { EditorPasteState } from "./paste-markers.ts";
3
4
  import type { Component } from "./tui.ts";
4
5
  /**
@@ -45,6 +46,74 @@ export interface EditorComponent extends Component {
45
46
  * When not implemented, callers must transfer the expanded text instead.
46
47
  */
47
48
  setPasteState?(state: EditorPasteState): void;
49
+ /**
50
+ * Insert the next atomic `[Image #N]` marker at the cursor and return its id.
51
+ * The editor stores ids only; the caller keeps the image payload keyed by id.
52
+ *
53
+ * The returned id is the marker's FINAL canonical number - its 1-based
54
+ * reading position after the editor renumbers the visible markers to stay
55
+ * 1..k in reading order - and `onImageMarkersChanged` fires (with the
56
+ * PRE-renumber ids) before the id is returned, so the caller registering its
57
+ * payload under the returned id immediately after the call always lands on
58
+ * a vacant slot.
59
+ *
60
+ * Paired contract: implement insertImageMarker together with
61
+ * onImageMarkersChanged. Callers must be told when markers are removed or
62
+ * renumbered, otherwise their payload map desynchronizes from the visible
63
+ * numbers; an editor exposing insertImageMarker without the callback is
64
+ * treated as image-unaware and receives the plain text path instead.
65
+ */
66
+ insertImageMarker?(): number;
67
+ /**
68
+ * Snapshot the image-marker registry (ids only, never image bytes) so markers
69
+ * can be transferred to another editor instance alongside getText().
70
+ *
71
+ * Paired contract: implement getImageMarkerState and setImageMarkerState
72
+ * together. Callers only hand markers to an editor that can export them
73
+ * again; an editor implementing setImageMarkerState without
74
+ * getImageMarkerState is treated as marker-unaware and its markers are
75
+ * dropped on transfer.
76
+ */
77
+ getImageMarkerState?(): EditorImageState;
78
+ /**
79
+ * Install an image-marker registry snapshot taken from another editor
80
+ * instance. Called after setText() with that editor's raw (marker) text.
81
+ * Paired contract: implement together with getImageMarkerState (see above).
82
+ */
83
+ setImageMarkerState?(state: EditorImageState): void;
84
+ /**
85
+ * Called with the image-marker ids in text reading order whenever markers are
86
+ * added, removed, pruned or renumbered.
87
+ *
88
+ * The reported ids are the keys the caller currently keys its payloads by
89
+ * (the PRE-renumber ids), and after every change the visible numbers are
90
+ * canonical 1..k in reading order, so the caller re-keys payload
91
+ * `order[i]` onto slot `i + 1`.
92
+ *
93
+ * Paired contract: required whenever insertImageMarker is implemented (see
94
+ * above) - the reported order is the only signal that keeps the caller's
95
+ * payload map aligned with the displayed `[Image #N]` numbers.
96
+ */
97
+ onImageMarkersChanged?: (order: number[]) => void;
98
+ /**
99
+ * Snapshot the attachment payloads keyed by marker id so the editor's undo
100
+ * stack can restore them together with the marker text and registry ids.
101
+ * The editor stores the returned value opaquely; return `undefined` to store
102
+ * nothing.
103
+ *
104
+ * Paired contract: implement together with restoreAttachmentState. Without
105
+ * these hooks an undo that revives a deleted marker displays it with no (or
106
+ * the wrong) payload behind it, because the delete re-keyed the survivors.
107
+ */
108
+ snapshotAttachmentState?: () => unknown;
109
+ /**
110
+ * Restore the attachment payloads captured by {@link snapshotAttachmentState}
111
+ * when the editor's undo pops the matching snapshot. Called before
112
+ * `onImageMarkersChanged` fires for that undo.
113
+ *
114
+ * Paired contract: implement together with snapshotAttachmentState.
115
+ */
116
+ restoreAttachmentState?: (state: unknown) => void;
48
117
  /** Set the autocomplete provider */
49
118
  setAutocompleteProvider?(provider: AutocompleteProvider): void;
50
119
  /** Border color function */
@@ -1 +1 @@
1
- {"version":3,"file":"editor-component.d.ts","sourceRoot":"","sources":["../src/editor-component.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAC9D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAC3D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAE1C;;;;;;GAMG;AACH,MAAM,WAAW,eAAgB,SAAQ,SAAS;IAKjD,mCAAmC;IACnC,OAAO,IAAI,MAAM,CAAC;IAElB,2BAA2B;IAC3B,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAE5B,qEAAqE;IACrE,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAMhC,iDAAiD;IACjD,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAElC,+BAA+B;IAC/B,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAMlC,iDAAiD;IACjD,YAAY,CAAC,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAMlC,6CAA6C;IAC7C,kBAAkB,CAAC,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAExC;;;OAGG;IACH,eAAe,CAAC,IAAI,MAAM,CAAC;IAE3B;;;;;;;;OAQG;IACH,aAAa,CAAC,IAAI,gBAAgB,CAAC;IAEnC;;;;;OAKG;IACH,aAAa,CAAC,CAAC,KAAK,EAAE,gBAAgB,GAAG,IAAI,CAAC;IAM9C,oCAAoC;IACpC,uBAAuB,CAAC,CAAC,QAAQ,EAAE,oBAAoB,GAAG,IAAI,CAAC;IAM/D,4BAA4B;IAC5B,WAAW,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,CAAC;IAEtC,6BAA6B;IAC7B,WAAW,CAAC,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAEpC,qDAAqD;IACrD,yBAAyB,CAAC,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CACrD"}
1
+ {"version":3,"file":"editor-component.d.ts","sourceRoot":"","sources":["../src/editor-component.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAC9D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAC3D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAC3D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAE1C;;;;;;GAMG;AACH,MAAM,WAAW,eAAgB,SAAQ,SAAS;IAKjD,mCAAmC;IACnC,OAAO,IAAI,MAAM,CAAC;IAElB,2BAA2B;IAC3B,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAE5B,qEAAqE;IACrE,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAMhC,iDAAiD;IACjD,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAElC,+BAA+B;IAC/B,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAMlC,iDAAiD;IACjD,YAAY,CAAC,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAMlC,6CAA6C;IAC7C,kBAAkB,CAAC,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAExC;;;OAGG;IACH,eAAe,CAAC,IAAI,MAAM,CAAC;IAE3B;;;;;;;;OAQG;IACH,aAAa,CAAC,IAAI,gBAAgB,CAAC;IAEnC;;;;;OAKG;IACH,aAAa,CAAC,CAAC,KAAK,EAAE,gBAAgB,GAAG,IAAI,CAAC;IAM9C;;;;;;;;;;;;;;;;OAgBG;IACH,iBAAiB,CAAC,IAAI,MAAM,CAAC;IAE7B;;;;;;;;;OASG;IACH,mBAAmB,CAAC,IAAI,gBAAgB,CAAC;IAEzC;;;;OAIG;IACH,mBAAmB,CAAC,CAAC,KAAK,EAAE,gBAAgB,GAAG,IAAI,CAAC;IAEpD;;;;;;;;;;;;OAYG;IACH,qBAAqB,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IAElD;;;;;;;;;OASG;IACH,uBAAuB,CAAC,EAAE,MAAM,OAAO,CAAC;IAExC;;;;;;OAMG;IACH,sBAAsB,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;IAMlD,oCAAoC;IACpC,uBAAuB,CAAC,CAAC,QAAQ,EAAE,oBAAoB,GAAG,IAAI,CAAC;IAM/D,4BAA4B;IAC5B,WAAW,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,CAAC;IAEtC,6BAA6B;IAC7B,WAAW,CAAC,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAEpC,qDAAqD;IACrD,yBAAyB,CAAC,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CACrD"}
@@ -1 +1 @@
1
- {"version":3,"file":"editor-component.js","sourceRoot":"","sources":["../src/editor-component.ts"],"names":[],"mappings":"","sourcesContent":["import type { AutocompleteProvider } from \"./autocomplete.ts\";\nimport type { EditorPasteState } from \"./paste-markers.ts\";\nimport type { Component } from \"./tui.ts\";\n\n/**\n * Interface for custom editor components.\n *\n * This allows extensions to provide their own editor implementation\n * (e.g., vim mode, emacs mode, custom keybindings) while maintaining\n * compatibility with the core application.\n */\nexport interface EditorComponent extends Component {\n\t// =========================================================================\n\t// Core text access (required)\n\t// =========================================================================\n\n\t/** Get the current text content */\n\tgetText(): string;\n\n\t/** Set the text content */\n\tsetText(text: string): void;\n\n\t/** Handle raw terminal input (key presses, paste sequences, etc.) */\n\thandleInput(data: string): void;\n\n\t// =========================================================================\n\t// Callbacks (required)\n\t// =========================================================================\n\n\t/** Called when user submits (e.g., Enter key) */\n\tonSubmit?: (text: string) => void;\n\n\t/** Called when text changes */\n\tonChange?: (text: string) => void;\n\n\t// =========================================================================\n\t// History support (optional)\n\t// =========================================================================\n\n\t/** Add text to history for up/down navigation */\n\taddToHistory?(text: string): void;\n\n\t// =========================================================================\n\t// Advanced text manipulation (optional)\n\t// =========================================================================\n\n\t/** Insert text at current cursor position */\n\tinsertTextAtCursor?(text: string): void;\n\n\t/**\n\t * Get text with any markers expanded (e.g., paste markers).\n\t * Falls back to getText() if not implemented.\n\t */\n\tgetExpandedText?(): string;\n\n\t/**\n\t * Snapshot the paste-marker registry so collapsed markers can be\n\t * transferred to another editor instance alongside getText().\n\t *\n\t * Paired contract: implement getPasteState and setPasteState together.\n\t * Callers only hand collapsed markers to an editor that can export them\n\t * again; an editor implementing setPasteState without getPasteState is\n\t * treated as paste-unaware and receives expanded text instead.\n\t */\n\tgetPasteState?(): EditorPasteState;\n\n\t/**\n\t * Install a paste-marker registry snapshot taken from another editor\n\t * instance. Called after setText() with that editor's raw (marker) text.\n\t * Paired contract: implement together with getPasteState (see above).\n\t * When not implemented, callers must transfer the expanded text instead.\n\t */\n\tsetPasteState?(state: EditorPasteState): void;\n\n\t// =========================================================================\n\t// Autocomplete support (optional)\n\t// =========================================================================\n\n\t/** Set the autocomplete provider */\n\tsetAutocompleteProvider?(provider: AutocompleteProvider): void;\n\n\t// =========================================================================\n\t// Appearance (optional)\n\t// =========================================================================\n\n\t/** Border color function */\n\tborderColor?: (str: string) => string;\n\n\t/** Set horizontal padding */\n\tsetPaddingX?(padding: number): void;\n\n\t/** Set max visible items in autocomplete dropdown */\n\tsetAutocompleteMaxVisible?(maxVisible: number): void;\n}\n"]}
1
+ {"version":3,"file":"editor-component.js","sourceRoot":"","sources":["../src/editor-component.ts"],"names":[],"mappings":"","sourcesContent":["import type { AutocompleteProvider } from \"./autocomplete.ts\";\nimport type { EditorImageState } from \"./image-markers.ts\";\nimport type { EditorPasteState } from \"./paste-markers.ts\";\nimport type { Component } from \"./tui.ts\";\n\n/**\n * Interface for custom editor components.\n *\n * This allows extensions to provide their own editor implementation\n * (e.g., vim mode, emacs mode, custom keybindings) while maintaining\n * compatibility with the core application.\n */\nexport interface EditorComponent extends Component {\n\t// =========================================================================\n\t// Core text access (required)\n\t// =========================================================================\n\n\t/** Get the current text content */\n\tgetText(): string;\n\n\t/** Set the text content */\n\tsetText(text: string): void;\n\n\t/** Handle raw terminal input (key presses, paste sequences, etc.) */\n\thandleInput(data: string): void;\n\n\t// =========================================================================\n\t// Callbacks (required)\n\t// =========================================================================\n\n\t/** Called when user submits (e.g., Enter key) */\n\tonSubmit?: (text: string) => void;\n\n\t/** Called when text changes */\n\tonChange?: (text: string) => void;\n\n\t// =========================================================================\n\t// History support (optional)\n\t// =========================================================================\n\n\t/** Add text to history for up/down navigation */\n\taddToHistory?(text: string): void;\n\n\t// =========================================================================\n\t// Advanced text manipulation (optional)\n\t// =========================================================================\n\n\t/** Insert text at current cursor position */\n\tinsertTextAtCursor?(text: string): void;\n\n\t/**\n\t * Get text with any markers expanded (e.g., paste markers).\n\t * Falls back to getText() if not implemented.\n\t */\n\tgetExpandedText?(): string;\n\n\t/**\n\t * Snapshot the paste-marker registry so collapsed markers can be\n\t * transferred to another editor instance alongside getText().\n\t *\n\t * Paired contract: implement getPasteState and setPasteState together.\n\t * Callers only hand collapsed markers to an editor that can export them\n\t * again; an editor implementing setPasteState without getPasteState is\n\t * treated as paste-unaware and receives expanded text instead.\n\t */\n\tgetPasteState?(): EditorPasteState;\n\n\t/**\n\t * Install a paste-marker registry snapshot taken from another editor\n\t * instance. Called after setText() with that editor's raw (marker) text.\n\t * Paired contract: implement together with getPasteState (see above).\n\t * When not implemented, callers must transfer the expanded text instead.\n\t */\n\tsetPasteState?(state: EditorPasteState): void;\n\n\t// =========================================================================\n\t// Image markers (optional)\n\t// =========================================================================\n\n\t/**\n\t * Insert the next atomic `[Image #N]` marker at the cursor and return its id.\n\t * The editor stores ids only; the caller keeps the image payload keyed by id.\n\t *\n\t * The returned id is the marker's FINAL canonical number - its 1-based\n\t * reading position after the editor renumbers the visible markers to stay\n\t * 1..k in reading order - and `onImageMarkersChanged` fires (with the\n\t * PRE-renumber ids) before the id is returned, so the caller registering its\n\t * payload under the returned id immediately after the call always lands on\n\t * a vacant slot.\n\t *\n\t * Paired contract: implement insertImageMarker together with\n\t * onImageMarkersChanged. Callers must be told when markers are removed or\n\t * renumbered, otherwise their payload map desynchronizes from the visible\n\t * numbers; an editor exposing insertImageMarker without the callback is\n\t * treated as image-unaware and receives the plain text path instead.\n\t */\n\tinsertImageMarker?(): number;\n\n\t/**\n\t * Snapshot the image-marker registry (ids only, never image bytes) so markers\n\t * can be transferred to another editor instance alongside getText().\n\t *\n\t * Paired contract: implement getImageMarkerState and setImageMarkerState\n\t * together. Callers only hand markers to an editor that can export them\n\t * again; an editor implementing setImageMarkerState without\n\t * getImageMarkerState is treated as marker-unaware and its markers are\n\t * dropped on transfer.\n\t */\n\tgetImageMarkerState?(): EditorImageState;\n\n\t/**\n\t * Install an image-marker registry snapshot taken from another editor\n\t * instance. Called after setText() with that editor's raw (marker) text.\n\t * Paired contract: implement together with getImageMarkerState (see above).\n\t */\n\tsetImageMarkerState?(state: EditorImageState): void;\n\n\t/**\n\t * Called with the image-marker ids in text reading order whenever markers are\n\t * added, removed, pruned or renumbered.\n\t *\n\t * The reported ids are the keys the caller currently keys its payloads by\n\t * (the PRE-renumber ids), and after every change the visible numbers are\n\t * canonical 1..k in reading order, so the caller re-keys payload\n\t * `order[i]` onto slot `i + 1`.\n\t *\n\t * Paired contract: required whenever insertImageMarker is implemented (see\n\t * above) - the reported order is the only signal that keeps the caller's\n\t * payload map aligned with the displayed `[Image #N]` numbers.\n\t */\n\tonImageMarkersChanged?: (order: number[]) => void;\n\n\t/**\n\t * Snapshot the attachment payloads keyed by marker id so the editor's undo\n\t * stack can restore them together with the marker text and registry ids.\n\t * The editor stores the returned value opaquely; return `undefined` to store\n\t * nothing.\n\t *\n\t * Paired contract: implement together with restoreAttachmentState. Without\n\t * these hooks an undo that revives a deleted marker displays it with no (or\n\t * the wrong) payload behind it, because the delete re-keyed the survivors.\n\t */\n\tsnapshotAttachmentState?: () => unknown;\n\n\t/**\n\t * Restore the attachment payloads captured by {@link snapshotAttachmentState}\n\t * when the editor's undo pops the matching snapshot. Called before\n\t * `onImageMarkersChanged` fires for that undo.\n\t *\n\t * Paired contract: implement together with snapshotAttachmentState.\n\t */\n\trestoreAttachmentState?: (state: unknown) => void;\n\n\t// =========================================================================\n\t// Autocomplete support (optional)\n\t// =========================================================================\n\n\t/** Set the autocomplete provider */\n\tsetAutocompleteProvider?(provider: AutocompleteProvider): void;\n\n\t// =========================================================================\n\t// Appearance (optional)\n\t// =========================================================================\n\n\t/** Border color function */\n\tborderColor?: (str: string) => string;\n\n\t/** Set horizontal padding */\n\tsetPaddingX?(padding: number): void;\n\n\t/** Set max visible items in autocomplete dropdown */\n\tsetAutocompleteMaxVisible?(maxVisible: number): void;\n}\n"]}
@@ -0,0 +1,46 @@
1
+ export declare const IMAGE_MARKER_REGEX: RegExp;
2
+ export declare const IMAGE_MARKER_SINGLE: RegExp;
3
+ /** Registry state for transfer between editor instances; ids only, never image bytes. */
4
+ export interface EditorImageState {
5
+ ids: readonly number[];
6
+ imageCounter: number;
7
+ }
8
+ export interface ImageMarkerRemoval {
9
+ text: string;
10
+ removed: boolean;
11
+ }
12
+ export interface ImageMarkerCanonicalization {
13
+ text: string;
14
+ /** Original ids in reading order; index i became marker `[Image #${i + 1}]`. */
15
+ order: number[];
16
+ }
17
+ export declare function formatImageMarker(id: number): string;
18
+ export declare function isImageMarker(segment: string): boolean;
19
+ export declare function imageMarkerId(segment: string): number | undefined;
20
+ /**
21
+ * Tracks the ids of atomic `[Image #N]` markers living in editor text.
22
+ *
23
+ * The registry deliberately stores NO image payload: the owner (interactive mode) keeps the bytes
24
+ * keyed by id, and this class only guarantees that the visible numbers stay a contiguous
25
+ * `1..k` sequence so the Nth marker in reading order maps to the Nth submitted image.
26
+ */
27
+ export declare class ImageMarkerRegistry {
28
+ private entries;
29
+ private imageCounter;
30
+ /** Registers the next id and returns its canonical marker. */
31
+ add(): string;
32
+ /** Registered markers occurring EXACTLY once in `text` - the only ones safe to treat as atomic. */
33
+ authorizedMarkers(text: string): ReadonlySet<string>;
34
+ /** Rewrites authorized markers to `1..k` in reading order, returning the original id order. */
35
+ canonicalize(text: string): ImageMarkerCanonicalization;
36
+ clear(): void;
37
+ /** Registered, authorized ids in TEXT READING ORDER (not insertion order). */
38
+ ids(text: string): number[];
39
+ install(state: EditorImageState, text: string): void;
40
+ prune(text: string, previousText?: string): void;
41
+ /** Deletes `id`'s marker from `text` and renumbers every higher id downward by one. */
42
+ remove(id: number, text: string): ImageMarkerRemoval;
43
+ restore(state: EditorImageState): void;
44
+ snapshot(): EditorImageState;
45
+ }
46
+ //# sourceMappingURL=image-markers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"image-markers.d.ts","sourceRoot":"","sources":["../src/image-markers.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,kBAAkB,QAA2B,CAAC;AAC3D,eAAO,MAAM,mBAAmB,QAA4B,CAAC;AAE7D,yFAAyF;AACzF,MAAM,WAAW,gBAAgB;IAChC,GAAG,EAAE,SAAS,MAAM,EAAE,CAAC;IACvB,YAAY,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,kBAAkB;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,OAAO,CAAC;CACjB;AAED,MAAM,WAAW,2BAA2B;IAC3C,IAAI,EAAE,MAAM,CAAC;IACb,gFAAgF;IAChF,KAAK,EAAE,MAAM,EAAE,CAAC;CAChB;AAED,wBAAgB,iBAAiB,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAEpD;AAED,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAEtD;AAED,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAGjE;AAoBD;;;;;;GAMG;AACH,qBAAa,mBAAmB;IAC/B,OAAO,CAAC,OAAO,CAAqB;IACpC,OAAO,CAAC,YAAY,CAAK;IAEzB,8DAA8D;IAC9D,GAAG,IAAI,MAAM;IAMb,mGAAmG;IACnG,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,CAAC,MAAM,CAAC;IASpD,+FAA+F;IAC/F,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,2BAA2B;IAgBvD,KAAK,IAAI,IAAI;IAKb,8EAA8E;IAC9E,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE;IAU3B,OAAO,CAAC,KAAK,EAAE,gBAAgB,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI;IAKpD,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI;IAShD,uFAAuF;IACvF,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,kBAAkB;IAiBpD,OAAO,CAAC,KAAK,EAAE,gBAAgB,GAAG,IAAI;IAKtC,QAAQ,IAAI,gBAAgB;CAG5B"}
@@ -0,0 +1,130 @@
1
+ export const IMAGE_MARKER_REGEX = /\[Image #([1-9]\d*)\]/g;
2
+ export const IMAGE_MARKER_SINGLE = /^\[Image #([1-9]\d*)\]$/;
3
+ export function formatImageMarker(id) {
4
+ return `[Image #${id}]`;
5
+ }
6
+ export function isImageMarker(segment) {
7
+ return segment.length >= 10 && IMAGE_MARKER_SINGLE.test(segment);
8
+ }
9
+ export function imageMarkerId(segment) {
10
+ const match = segment.length >= 10 ? IMAGE_MARKER_SINGLE.exec(segment) : null;
11
+ return match ? Number.parseInt(match[1], 10) : undefined;
12
+ }
13
+ function countOccurrences(text, marker) {
14
+ let count = 0;
15
+ let offset = 0;
16
+ while (offset <= text.length - marker.length) {
17
+ const index = text.indexOf(marker, offset);
18
+ if (index === -1)
19
+ break;
20
+ count++;
21
+ offset = index + marker.length;
22
+ }
23
+ return count;
24
+ }
25
+ function replaceSingleOccurrence(text, marker, replacement) {
26
+ const index = text.indexOf(marker);
27
+ if (index === -1 || text.indexOf(marker, index + marker.length) !== -1)
28
+ return text;
29
+ return text.slice(0, index) + replacement + text.slice(index + marker.length);
30
+ }
31
+ /**
32
+ * Tracks the ids of atomic `[Image #N]` markers living in editor text.
33
+ *
34
+ * The registry deliberately stores NO image payload: the owner (interactive mode) keeps the bytes
35
+ * keyed by id, and this class only guarantees that the visible numbers stay a contiguous
36
+ * `1..k` sequence so the Nth marker in reading order maps to the Nth submitted image.
37
+ */
38
+ export class ImageMarkerRegistry {
39
+ constructor() {
40
+ this.entries = new Set();
41
+ this.imageCounter = 0;
42
+ }
43
+ /** Registers the next id and returns its canonical marker. */
44
+ add() {
45
+ const id = ++this.imageCounter;
46
+ this.entries.add(id);
47
+ return formatImageMarker(id);
48
+ }
49
+ /** Registered markers occurring EXACTLY once in `text` - the only ones safe to treat as atomic. */
50
+ authorizedMarkers(text) {
51
+ const markers = new Set();
52
+ for (const id of this.entries) {
53
+ const marker = formatImageMarker(id);
54
+ if (countOccurrences(text, marker) === 1)
55
+ markers.add(marker);
56
+ }
57
+ return markers;
58
+ }
59
+ /** Rewrites authorized markers to `1..k` in reading order, returning the original id order. */
60
+ canonicalize(text) {
61
+ const order = this.ids(text);
62
+ if (order.length === 0)
63
+ return { text, order };
64
+ const renumbered = new Map();
65
+ for (const [index, id] of order.entries())
66
+ renumbered.set(id, index + 1);
67
+ const updatedText = text.replace(IMAGE_MARKER_REGEX, (marker) => {
68
+ const id = imageMarkerId(marker);
69
+ const newId = id === undefined ? undefined : renumbered.get(id);
70
+ return newId === undefined ? marker : formatImageMarker(newId);
71
+ });
72
+ this.entries = new Set(order.map((_, index) => index + 1));
73
+ this.imageCounter = this.entries.size;
74
+ return { text: updatedText, order };
75
+ }
76
+ clear() {
77
+ this.entries.clear();
78
+ this.imageCounter = 0;
79
+ }
80
+ /** Registered, authorized ids in TEXT READING ORDER (not insertion order). */
81
+ ids(text) {
82
+ const authorized = this.authorizedMarkers(text);
83
+ const ordered = [];
84
+ for (const match of text.matchAll(IMAGE_MARKER_REGEX)) {
85
+ if (!authorized.has(match[0]))
86
+ continue;
87
+ ordered.push(Number.parseInt(match[1], 10));
88
+ }
89
+ return ordered;
90
+ }
91
+ install(state, text) {
92
+ this.restore(state);
93
+ this.prune(text);
94
+ }
95
+ prune(text, previousText) {
96
+ for (const id of [...this.entries]) {
97
+ const marker = formatImageMarker(id);
98
+ const wasAuthorized = previousText === undefined || countOccurrences(previousText, marker) === 1;
99
+ if (!wasAuthorized || countOccurrences(text, marker) !== 1)
100
+ this.entries.delete(id);
101
+ }
102
+ this.imageCounter = Math.max(...this.entries, 0);
103
+ }
104
+ /** Deletes `id`'s marker from `text` and renumbers every higher id downward by one. */
105
+ remove(id, text) {
106
+ if (!this.entries.delete(id))
107
+ return { text, removed: false };
108
+ let updatedText = replaceSingleOccurrence(text, formatImageMarker(id), "");
109
+ const higherIds = [...this.entries].filter((entryId) => entryId > id).sort((a, b) => a - b);
110
+ for (const oldId of higherIds) {
111
+ this.entries.delete(oldId);
112
+ const marker = formatImageMarker(oldId);
113
+ if (countOccurrences(updatedText, marker) !== 1)
114
+ continue;
115
+ const newId = oldId - 1;
116
+ updatedText = replaceSingleOccurrence(updatedText, marker, formatImageMarker(newId));
117
+ this.entries.add(newId);
118
+ }
119
+ this.imageCounter = Math.max(...this.entries, 0);
120
+ return { text: updatedText, removed: true };
121
+ }
122
+ restore(state) {
123
+ this.entries = new Set(state.ids);
124
+ this.imageCounter = Math.max(state.imageCounter, ...this.entries, 0);
125
+ }
126
+ snapshot() {
127
+ return { ids: [...this.entries].sort((a, b) => a - b), imageCounter: this.imageCounter };
128
+ }
129
+ }
130
+ //# sourceMappingURL=image-markers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"image-markers.js","sourceRoot":"","sources":["../src/image-markers.ts"],"names":[],"mappings":"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","sourcesContent":["export const IMAGE_MARKER_REGEX = /\\[Image #([1-9]\\d*)\\]/g;\nexport const IMAGE_MARKER_SINGLE = /^\\[Image #([1-9]\\d*)\\]$/;\n\n/** Registry state for transfer between editor instances; ids only, never image bytes. */\nexport interface EditorImageState {\n\tids: readonly number[];\n\timageCounter: number;\n}\n\nexport interface ImageMarkerRemoval {\n\ttext: string;\n\tremoved: boolean;\n}\n\nexport interface ImageMarkerCanonicalization {\n\ttext: string;\n\t/** Original ids in reading order; index i became marker `[Image #${i + 1}]`. */\n\torder: number[];\n}\n\nexport function formatImageMarker(id: number): string {\n\treturn `[Image #${id}]`;\n}\n\nexport function isImageMarker(segment: string): boolean {\n\treturn segment.length >= 10 && IMAGE_MARKER_SINGLE.test(segment);\n}\n\nexport function imageMarkerId(segment: string): number | undefined {\n\tconst match = segment.length >= 10 ? IMAGE_MARKER_SINGLE.exec(segment) : null;\n\treturn match ? Number.parseInt(match[1]!, 10) : undefined;\n}\n\nfunction countOccurrences(text: string, marker: string): number {\n\tlet count = 0;\n\tlet offset = 0;\n\twhile (offset <= text.length - marker.length) {\n\t\tconst index = text.indexOf(marker, offset);\n\t\tif (index === -1) break;\n\t\tcount++;\n\t\toffset = index + marker.length;\n\t}\n\treturn count;\n}\n\nfunction replaceSingleOccurrence(text: string, marker: string, replacement: string): string {\n\tconst index = text.indexOf(marker);\n\tif (index === -1 || text.indexOf(marker, index + marker.length) !== -1) return text;\n\treturn text.slice(0, index) + replacement + text.slice(index + marker.length);\n}\n\n/**\n * Tracks the ids of atomic `[Image #N]` markers living in editor text.\n *\n * The registry deliberately stores NO image payload: the owner (interactive mode) keeps the bytes\n * keyed by id, and this class only guarantees that the visible numbers stay a contiguous\n * `1..k` sequence so the Nth marker in reading order maps to the Nth submitted image.\n */\nexport class ImageMarkerRegistry {\n\tprivate entries = new Set<number>();\n\tprivate imageCounter = 0;\n\n\t/** Registers the next id and returns its canonical marker. */\n\tadd(): string {\n\t\tconst id = ++this.imageCounter;\n\t\tthis.entries.add(id);\n\t\treturn formatImageMarker(id);\n\t}\n\n\t/** Registered markers occurring EXACTLY once in `text` - the only ones safe to treat as atomic. */\n\tauthorizedMarkers(text: string): ReadonlySet<string> {\n\t\tconst markers = new Set<string>();\n\t\tfor (const id of this.entries) {\n\t\t\tconst marker = formatImageMarker(id);\n\t\t\tif (countOccurrences(text, marker) === 1) markers.add(marker);\n\t\t}\n\t\treturn markers;\n\t}\n\n\t/** Rewrites authorized markers to `1..k` in reading order, returning the original id order. */\n\tcanonicalize(text: string): ImageMarkerCanonicalization {\n\t\tconst order = this.ids(text);\n\t\tif (order.length === 0) return { text, order };\n\n\t\tconst renumbered = new Map<number, number>();\n\t\tfor (const [index, id] of order.entries()) renumbered.set(id, index + 1);\n\t\tconst updatedText = text.replace(IMAGE_MARKER_REGEX, (marker) => {\n\t\t\tconst id = imageMarkerId(marker);\n\t\t\tconst newId = id === undefined ? undefined : renumbered.get(id);\n\t\t\treturn newId === undefined ? marker : formatImageMarker(newId);\n\t\t});\n\t\tthis.entries = new Set(order.map((_, index) => index + 1));\n\t\tthis.imageCounter = this.entries.size;\n\t\treturn { text: updatedText, order };\n\t}\n\n\tclear(): void {\n\t\tthis.entries.clear();\n\t\tthis.imageCounter = 0;\n\t}\n\n\t/** Registered, authorized ids in TEXT READING ORDER (not insertion order). */\n\tids(text: string): number[] {\n\t\tconst authorized = this.authorizedMarkers(text);\n\t\tconst ordered: number[] = [];\n\t\tfor (const match of text.matchAll(IMAGE_MARKER_REGEX)) {\n\t\t\tif (!authorized.has(match[0])) continue;\n\t\t\tordered.push(Number.parseInt(match[1]!, 10));\n\t\t}\n\t\treturn ordered;\n\t}\n\n\tinstall(state: EditorImageState, text: string): void {\n\t\tthis.restore(state);\n\t\tthis.prune(text);\n\t}\n\n\tprune(text: string, previousText?: string): void {\n\t\tfor (const id of [...this.entries]) {\n\t\t\tconst marker = formatImageMarker(id);\n\t\t\tconst wasAuthorized = previousText === undefined || countOccurrences(previousText, marker) === 1;\n\t\t\tif (!wasAuthorized || countOccurrences(text, marker) !== 1) this.entries.delete(id);\n\t\t}\n\t\tthis.imageCounter = Math.max(...this.entries, 0);\n\t}\n\n\t/** Deletes `id`'s marker from `text` and renumbers every higher id downward by one. */\n\tremove(id: number, text: string): ImageMarkerRemoval {\n\t\tif (!this.entries.delete(id)) return { text, removed: false };\n\n\t\tlet updatedText = replaceSingleOccurrence(text, formatImageMarker(id), \"\");\n\t\tconst higherIds = [...this.entries].filter((entryId) => entryId > id).sort((a, b) => a - b);\n\t\tfor (const oldId of higherIds) {\n\t\t\tthis.entries.delete(oldId);\n\t\t\tconst marker = formatImageMarker(oldId);\n\t\t\tif (countOccurrences(updatedText, marker) !== 1) continue;\n\t\t\tconst newId = oldId - 1;\n\t\t\tupdatedText = replaceSingleOccurrence(updatedText, marker, formatImageMarker(newId));\n\t\t\tthis.entries.add(newId);\n\t\t}\n\t\tthis.imageCounter = Math.max(...this.entries, 0);\n\t\treturn { text: updatedText, removed: true };\n\t}\n\n\trestore(state: EditorImageState): void {\n\t\tthis.entries = new Set(state.ids);\n\t\tthis.imageCounter = Math.max(state.imageCounter, ...this.entries, 0);\n\t}\n\n\tsnapshot(): EditorImageState {\n\t\treturn { ids: [...this.entries].sort((a, b) => a - b), imageCounter: this.imageCounter };\n\t}\n}\n"]}
package/dist/index.d.ts CHANGED
@@ -19,6 +19,7 @@ export { TruncatedText } from "./components/truncated-text.ts";
19
19
  export { type StackChild, type StackEntry, type StackEntryOptions, type StackOptions, VStack, } from "./components/v-stack.ts";
20
20
  export type { EditorComponent } from "./editor-component.ts";
21
21
  export { type FuzzyMatch, fuzzyFilter, fuzzyMatch } from "./fuzzy.ts";
22
+ export { type EditorImageState, formatImageMarker, IMAGE_MARKER_REGEX, IMAGE_MARKER_SINGLE, type ImageMarkerCanonicalization, ImageMarkerRegistry, type ImageMarkerRemoval, imageMarkerId, isImageMarker, } from "./image-markers.ts";
22
23
  export { getKeybindings, type Keybinding, type KeybindingConflict, type KeybindingDefinition, type KeybindingDefinitions, type Keybindings, type KeybindingsConfig, KeybindingsManager, setKeybindings, TUI_KEYBINDINGS, } from "./keybindings.ts";
23
24
  export { decodeKittyPrintable, isKeyRelease, isKeyRepeat, isKittyProtocolActive, Key, type KeyEventType, type KeyId, matchesKey, parseKey, setKittyProtocolActive, } from "./keys.ts";
24
25
  export { type EditorPasteState, expandPasteMarkers } from "./paste-markers.ts";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -23,6 +23,8 @@ export { TruncatedText } from "./components/truncated-text.js";
23
23
  export { VStack, } from "./components/v-stack.js";
24
24
  // Fuzzy matching
25
25
  export { fuzzyFilter, fuzzyMatch } from "./fuzzy.js";
26
+ // Atomic image markers (ids only - never image bytes)
27
+ export { formatImageMarker, IMAGE_MARKER_REGEX, IMAGE_MARKER_SINGLE, ImageMarkerRegistry, imageMarkerId, isImageMarker, } from "./image-markers.js";
26
28
  // Keybindings
27
29
  export { getKeybindings, KeybindingsManager, setKeybindings, TUI_KEYBINDINGS, } from "./keybindings.js";
28
30
  // Keyboard input handling
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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","sourcesContent":["// Core TUI interfaces and classes\n\nimport type { CellDimensions, ImageDimensions } from \"./terminal-image.ts\";\nimport { calculateImageCellSize } from \"./terminal-image.ts\";\n\nexport { Marked, type Token, type Tokens } from \"marked\";\n// Fullscreen transcript search\nexport {\n\tAltScreenSearchComponent,\n\ttype AltScreenSearchMatch,\n\ttype AltScreenSearchSegment,\n\tfindAltScreenSearchMatches,\n\tgetAltScreenSearchMatchKey,\n} from \"./alt-screen-search.ts\";\n// Autocomplete support\nexport {\n\ttype AutocompleteItem,\n\ttype AutocompleteProvider,\n\ttype AutocompleteSuggestions,\n\tCombinedAutocompleteProvider,\n\ttype SlashCommand,\n} from \"./autocomplete.ts\";\n// Components\nexport { Box } from \"./components/box.ts\";\nexport { CancellableLoader } from \"./components/cancellable-loader.ts\";\nexport {\n\tEditor,\n\ttype EditorOptions,\n\ttype EditorTheme,\n} from \"./components/editor.ts\";\nexport { HStack } from \"./components/h-stack.ts\";\nexport { Image, type ImageOptions, type ImageTheme } from \"./components/image.ts\";\nexport { Input } from \"./components/input.ts\";\nexport { Loader, type LoaderIndicatorOptions } from \"./components/loader.ts\";\nexport {\n\tclearRenderCache,\n\ttype DefaultTextStyle,\n\tgetMarkdownHighlightCallCount,\n\tMarkdown,\n\ttype MarkdownOptions,\n\ttype MarkdownTheme,\n\tresetMarkdownHighlightCallCount,\n} from \"./components/markdown.ts\";\nexport {\n\tScrollView,\n\ttype ScrollViewOptions,\n\ttype ScrollViewScrollbar,\n\ttype ScrollViewScrollToOptions,\n} from \"./components/scroll-view.ts\";\nexport {\n\ttype SelectItem,\n\tSelectList,\n\ttype SelectListLayoutOptions,\n\ttype SelectListRenderRow,\n\ttype SelectListRowParts,\n\ttype SelectListTheme,\n\ttype SelectListTruncatePrimaryContext,\n} from \"./components/select-list.ts\";\nexport { type SettingItem, SettingsList, type SettingsListTheme } from \"./components/settings-list.ts\";\nexport { Spacer } from \"./components/spacer.ts\";\nexport { Text } from \"./components/text.ts\";\nexport { TruncatedText } from \"./components/truncated-text.ts\";\nexport {\n\ttype StackChild,\n\ttype StackEntry,\n\ttype StackEntryOptions,\n\ttype StackOptions,\n\tVStack,\n} from \"./components/v-stack.ts\";\n// Editor component interface (for custom editors)\nexport type { EditorComponent } from \"./editor-component.ts\";\n// Fuzzy matching\nexport { type FuzzyMatch, fuzzyFilter, fuzzyMatch } from \"./fuzzy.ts\";\n// Keybindings\nexport {\n\tgetKeybindings,\n\ttype Keybinding,\n\ttype KeybindingConflict,\n\ttype KeybindingDefinition,\n\ttype KeybindingDefinitions,\n\ttype Keybindings,\n\ttype KeybindingsConfig,\n\tKeybindingsManager,\n\tsetKeybindings,\n\tTUI_KEYBINDINGS,\n} from \"./keybindings.ts\";\n// Keyboard input handling\nexport {\n\tdecodeKittyPrintable,\n\tisKeyRelease,\n\tisKeyRepeat,\n\tisKittyProtocolActive,\n\tKey,\n\ttype KeyEventType,\n\ttype KeyId,\n\tmatchesKey,\n\tparseKey,\n\tsetKittyProtocolActive,\n} from \"./keys.ts\";\nexport { type EditorPasteState, expandPasteMarkers } from \"./paste-markers.ts\";\n// Input buffering for batch splitting\nexport { StdinBuffer, type StdinBufferEventMap, type StdinBufferOptions } from \"./stdin-buffer.ts\";\n// Terminal interface and implementations\nexport { ProcessTerminal, type ProcessTerminalOptions, type Terminal } from \"./terminal.ts\";\n// Terminal colors\nexport {\n\tparseOsc11BackgroundColor,\n\tparseTerminalColorSchemeReport,\n\ttype RgbColor,\n\ttype TerminalColorScheme,\n} from \"./terminal-colors.ts\";\n// Terminal image support\nexport function calculateImageRows(\n\timageDimensions: ImageDimensions,\n\ttargetWidthCells: number,\n\tcellDimensions: CellDimensions = { widthPx: 9, heightPx: 18 },\n): number {\n\treturn calculateImageCellSize(imageDimensions, targetWidthCells, undefined, cellDimensions).rows;\n}\nexport {\n\tallocateImageId,\n\tbuildKittyPlaceholderRow,\n\ttype CellDimensions,\n\tdeleteAllKittyImages,\n\tdeleteKittyImage,\n\tdetectCapabilities,\n\tencodeITerm2,\n\tencodeKitty,\n\tgetCapabilities,\n\tgetCellDimensions,\n\tgetGifDimensions,\n\tgetImageDimensions,\n\tgetJpegDimensions,\n\tgetPngDimensions,\n\tgetWebpDimensions,\n\thyperlink,\n\ttype ImageDimensions,\n\ttype ImageProtocol,\n\ttype ImageRenderOptions,\n\timageFallback,\n\tKITTY_PLACEHOLDER_MAX,\n\touterKittyGraphicsMode,\n\trenderImage,\n\tresetCapabilitiesCache,\n\tsetCapabilities,\n\tsetCellDimensions,\n\ttype TerminalCapabilities,\n\ttype TmuxPassthroughState,\n\twrapTmuxPassthrough,\n} from \"./terminal-image.ts\";\nexport { sanitizeTerminalLabel, shortenImagePath } from \"./terminal-text.ts\";\nexport {\n\ttype Component,\n\tContainer,\n\tCURSOR_MARKER,\n\tcompositeTuiLine,\n\ttype Focusable,\n\tisFocusable,\n\tisViewportTUI,\n\ttype OverlayAnchor,\n\ttype OverlayHandle,\n\ttype OverlayMargin,\n\ttype OverlayOptions,\n\ttype OverlayUnfocusOptions,\n\ttype SizeValue,\n\tTUI,\n\ttype TuiInputListener,\n\ttype TuiInputListenerResult,\n\ttype TuiMode,\n\ttype TuiStopOptions,\n\ttype ViewportTUI,\n} from \"./tui.ts\";\nexport { TuiAltScreen, type TuiAltScreenOptions } from \"./tui-alt-screen.ts\";\nexport { TuiMainScreen, type TuiMainScreenRenderState } from \"./tui-main-screen.ts\";\n// Utilities\nexport {\n\tgetGraphemeSegmenter,\n\tgetOsc8LinkAtColumn,\n\tgetWordSegmenter,\n\tsliceByColumn,\n\tstripTerminalSequences,\n\ttruncateToWidth,\n\tvisibleWidth,\n\twrapTextWithAnsi,\n} from \"./utils.ts\";\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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","sourcesContent":["// Core TUI interfaces and classes\n\nimport type { CellDimensions, ImageDimensions } from \"./terminal-image.ts\";\nimport { calculateImageCellSize } from \"./terminal-image.ts\";\n\nexport { Marked, type Token, type Tokens } from \"marked\";\n// Fullscreen transcript search\nexport {\n\tAltScreenSearchComponent,\n\ttype AltScreenSearchMatch,\n\ttype AltScreenSearchSegment,\n\tfindAltScreenSearchMatches,\n\tgetAltScreenSearchMatchKey,\n} from \"./alt-screen-search.ts\";\n// Autocomplete support\nexport {\n\ttype AutocompleteItem,\n\ttype AutocompleteProvider,\n\ttype AutocompleteSuggestions,\n\tCombinedAutocompleteProvider,\n\ttype SlashCommand,\n} from \"./autocomplete.ts\";\n// Components\nexport { Box } from \"./components/box.ts\";\nexport { CancellableLoader } from \"./components/cancellable-loader.ts\";\nexport {\n\tEditor,\n\ttype EditorOptions,\n\ttype EditorTheme,\n} from \"./components/editor.ts\";\nexport { HStack } from \"./components/h-stack.ts\";\nexport { Image, type ImageOptions, type ImageTheme } from \"./components/image.ts\";\nexport { Input } from \"./components/input.ts\";\nexport { Loader, type LoaderIndicatorOptions } from \"./components/loader.ts\";\nexport {\n\tclearRenderCache,\n\ttype DefaultTextStyle,\n\tgetMarkdownHighlightCallCount,\n\tMarkdown,\n\ttype MarkdownOptions,\n\ttype MarkdownTheme,\n\tresetMarkdownHighlightCallCount,\n} from \"./components/markdown.ts\";\nexport {\n\tScrollView,\n\ttype ScrollViewOptions,\n\ttype ScrollViewScrollbar,\n\ttype ScrollViewScrollToOptions,\n} from \"./components/scroll-view.ts\";\nexport {\n\ttype SelectItem,\n\tSelectList,\n\ttype SelectListLayoutOptions,\n\ttype SelectListRenderRow,\n\ttype SelectListRowParts,\n\ttype SelectListTheme,\n\ttype SelectListTruncatePrimaryContext,\n} from \"./components/select-list.ts\";\nexport { type SettingItem, SettingsList, type SettingsListTheme } from \"./components/settings-list.ts\";\nexport { Spacer } from \"./components/spacer.ts\";\nexport { Text } from \"./components/text.ts\";\nexport { TruncatedText } from \"./components/truncated-text.ts\";\nexport {\n\ttype StackChild,\n\ttype StackEntry,\n\ttype StackEntryOptions,\n\ttype StackOptions,\n\tVStack,\n} from \"./components/v-stack.ts\";\n// Editor component interface (for custom editors)\nexport type { EditorComponent } from \"./editor-component.ts\";\n// Fuzzy matching\nexport { type FuzzyMatch, fuzzyFilter, fuzzyMatch } from \"./fuzzy.ts\";\n// Atomic image markers (ids only - never image bytes)\nexport {\n\ttype EditorImageState,\n\tformatImageMarker,\n\tIMAGE_MARKER_REGEX,\n\tIMAGE_MARKER_SINGLE,\n\ttype ImageMarkerCanonicalization,\n\tImageMarkerRegistry,\n\ttype ImageMarkerRemoval,\n\timageMarkerId,\n\tisImageMarker,\n} from \"./image-markers.ts\";\n// Keybindings\nexport {\n\tgetKeybindings,\n\ttype Keybinding,\n\ttype KeybindingConflict,\n\ttype KeybindingDefinition,\n\ttype KeybindingDefinitions,\n\ttype Keybindings,\n\ttype KeybindingsConfig,\n\tKeybindingsManager,\n\tsetKeybindings,\n\tTUI_KEYBINDINGS,\n} from \"./keybindings.ts\";\n// Keyboard input handling\nexport {\n\tdecodeKittyPrintable,\n\tisKeyRelease,\n\tisKeyRepeat,\n\tisKittyProtocolActive,\n\tKey,\n\ttype KeyEventType,\n\ttype KeyId,\n\tmatchesKey,\n\tparseKey,\n\tsetKittyProtocolActive,\n} from \"./keys.ts\";\nexport { type EditorPasteState, expandPasteMarkers } from \"./paste-markers.ts\";\n// Input buffering for batch splitting\nexport { StdinBuffer, type StdinBufferEventMap, type StdinBufferOptions } from \"./stdin-buffer.ts\";\n// Terminal interface and implementations\nexport { ProcessTerminal, type ProcessTerminalOptions, type Terminal } from \"./terminal.ts\";\n// Terminal colors\nexport {\n\tparseOsc11BackgroundColor,\n\tparseTerminalColorSchemeReport,\n\ttype RgbColor,\n\ttype TerminalColorScheme,\n} from \"./terminal-colors.ts\";\n// Terminal image support\nexport function calculateImageRows(\n\timageDimensions: ImageDimensions,\n\ttargetWidthCells: number,\n\tcellDimensions: CellDimensions = { widthPx: 9, heightPx: 18 },\n): number {\n\treturn calculateImageCellSize(imageDimensions, targetWidthCells, undefined, cellDimensions).rows;\n}\nexport {\n\tallocateImageId,\n\tbuildKittyPlaceholderRow,\n\ttype CellDimensions,\n\tdeleteAllKittyImages,\n\tdeleteKittyImage,\n\tdetectCapabilities,\n\tencodeITerm2,\n\tencodeKitty,\n\tgetCapabilities,\n\tgetCellDimensions,\n\tgetGifDimensions,\n\tgetImageDimensions,\n\tgetJpegDimensions,\n\tgetPngDimensions,\n\tgetWebpDimensions,\n\thyperlink,\n\ttype ImageDimensions,\n\ttype ImageProtocol,\n\ttype ImageRenderOptions,\n\timageFallback,\n\tKITTY_PLACEHOLDER_MAX,\n\touterKittyGraphicsMode,\n\trenderImage,\n\tresetCapabilitiesCache,\n\tsetCapabilities,\n\tsetCellDimensions,\n\ttype TerminalCapabilities,\n\ttype TmuxPassthroughState,\n\twrapTmuxPassthrough,\n} from \"./terminal-image.ts\";\nexport { sanitizeTerminalLabel, shortenImagePath } from \"./terminal-text.ts\";\nexport {\n\ttype Component,\n\tContainer,\n\tCURSOR_MARKER,\n\tcompositeTuiLine,\n\ttype Focusable,\n\tisFocusable,\n\tisViewportTUI,\n\ttype OverlayAnchor,\n\ttype OverlayHandle,\n\ttype OverlayMargin,\n\ttype OverlayOptions,\n\ttype OverlayUnfocusOptions,\n\ttype SizeValue,\n\tTUI,\n\ttype TuiInputListener,\n\ttype TuiInputListenerResult,\n\ttype TuiMode,\n\ttype TuiStopOptions,\n\ttype ViewportTUI,\n} from \"./tui.ts\";\nexport { TuiAltScreen, type TuiAltScreenOptions } from \"./tui-alt-screen.ts\";\nexport { TuiMainScreen, type TuiMainScreenRenderState } from \"./tui-main-screen.ts\";\n// Utilities\nexport {\n\tgetGraphemeSegmenter,\n\tgetOsc8LinkAtColumn,\n\tgetWordSegmenter,\n\tsliceByColumn,\n\tstripTerminalSequences,\n\ttruncateToWidth,\n\tvisibleWidth,\n\twrapTextWithAnsi,\n} from \"./utils.ts\";\n"]}
@@ -10,6 +10,9 @@ export interface PasteMarkerRemoval {
10
10
  export declare function expandPasteMarkers(text: string, state: EditorPasteState): string;
11
11
  export declare function isPasteMarker(segment: string): boolean;
12
12
  export declare function pasteMarkerId(segment: string): number | undefined;
13
+ /** Segments `text` treating every literal in `validMarkers` as a single atomic segment. */
14
+ export declare function segmentWithMarkers(text: string, baseSegmenter: Intl.Segmenter, validMarkers: ReadonlySet<string>): Iterable<Intl.SegmentData>;
15
+ /** Backward-compatible wrapper: paste markers are just one atomic marker set. */
13
16
  export declare function segmentWithPasteMarkers(text: string, baseSegmenter: Intl.Segmenter, validMarkers: ReadonlySet<string>): Iterable<Intl.SegmentData>;
14
17
  export declare class PasteMarkerRegistry {
15
18
  private entries;
@@ -1 +1 @@
1
- {"version":3,"file":"paste-markers.d.ts","sourceRoot":"","sources":["../src/paste-markers.ts"],"names":[],"mappings":"AAUA,MAAM,WAAW,gBAAgB;IAChC,MAAM,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACpC,OAAO,CAAC,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACtC,YAAY,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,kBAAkB;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,OAAO,CAAC;CACjB;AAiDD,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,gBAAgB,GAAG,MAAM,CAyBhF;AAED,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAEtD;AAED,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAGjE;AAED,wBAAgB,uBAAuB,CACtC,IAAI,EAAE,MAAM,EACZ,aAAa,EAAE,IAAI,CAAC,SAAS,EAC7B,YAAY,EAAE,WAAW,CAAC,MAAM,CAAC,GAC/B,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,CAqB5B;AAED,qBAAa,mBAAmB;IAC/B,OAAO,CAAC,OAAO,CAAuC;IACtD,OAAO,CAAC,YAAY,CAAK;IACzB,OAAO,CAAC,cAAc,CAAK;IAE3B,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM;IAQlE,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,CAAC,MAAM,CAAC;IAQpD,KAAK,IAAI,IAAI;IAKb,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;IAI5B,IAAI,kBAAkB,IAAI,MAAM,CAE/B;IAED,OAAO,CAAC,KAAK,EAAE,gBAAgB,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI;IAOpD,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI;IAQhD,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,kBAAkB;IAmBpD,QAAQ,IAAI,gBAAgB;IAU5B,OAAO,CAAC,KAAK,EAAE,gBAAgB,GAAG,IAAI;CAKtC"}
1
+ {"version":3,"file":"paste-markers.d.ts","sourceRoot":"","sources":["../src/paste-markers.ts"],"names":[],"mappings":"AAUA,MAAM,WAAW,gBAAgB;IAChC,MAAM,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACpC,OAAO,CAAC,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACtC,YAAY,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,kBAAkB;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,OAAO,CAAC;CACjB;AAiDD,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,gBAAgB,GAAG,MAAM,CAyBhF;AAED,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAEtD;AAED,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAGjE;AAED,2FAA2F;AAC3F,wBAAgB,kBAAkB,CACjC,IAAI,EAAE,MAAM,EACZ,aAAa,EAAE,IAAI,CAAC,SAAS,EAC7B,YAAY,EAAE,WAAW,CAAC,MAAM,CAAC,GAC/B,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,CAgC5B;AAED,iFAAiF;AACjF,wBAAgB,uBAAuB,CACtC,IAAI,EAAE,MAAM,EACZ,aAAa,EAAE,IAAI,CAAC,SAAS,EAC7B,YAAY,EAAE,WAAW,CAAC,MAAM,CAAC,GAC/B,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,CAE5B;AAED,qBAAa,mBAAmB;IAC/B,OAAO,CAAC,OAAO,CAAuC;IACtD,OAAO,CAAC,YAAY,CAAK;IACzB,OAAO,CAAC,cAAc,CAAK;IAE3B,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM;IAQlE,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,CAAC,MAAM,CAAC;IAQpD,KAAK,IAAI,IAAI;IAKb,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;IAI5B,IAAI,kBAAkB,IAAI,MAAM,CAE/B;IAED,OAAO,CAAC,KAAK,EAAE,gBAAgB,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI;IAOpD,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI;IAQhD,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,kBAAkB;IAmBpD,QAAQ,IAAI,gBAAgB;IAU5B,OAAO,CAAC,KAAK,EAAE,gBAAgB,GAAG,IAAI;CAKtC"}
@@ -78,16 +78,28 @@ export function pasteMarkerId(segment) {
78
78
  const match = segment.length >= 10 ? PASTE_MARKER_SINGLE.exec(segment) : null;
79
79
  return match ? Number.parseInt(match[1], 10) : undefined;
80
80
  }
81
- export function segmentWithPasteMarkers(text, baseSegmenter, validMarkers) {
82
- if (validMarkers.size === 0 || !text.includes("[paste #"))
81
+ /** Segments `text` treating every literal in `validMarkers` as a single atomic segment. */
82
+ export function segmentWithMarkers(text, baseSegmenter, validMarkers) {
83
+ if (validMarkers.size === 0)
83
84
  return baseSegmenter.segment(text);
84
- const markers = [];
85
- for (const match of text.matchAll(PASTE_MARKER_REGEX)) {
86
- if (validMarkers.has(match[0]))
87
- markers.push({ start: match.index, end: match.index + match[0].length });
85
+ const found = [];
86
+ for (const marker of validMarkers) {
87
+ const start = text.indexOf(marker);
88
+ if (start === -1)
89
+ continue;
90
+ found.push({ start, end: start + marker.length });
88
91
  }
89
- if (markers.length === 0)
92
+ if (found.length === 0)
90
93
  return baseSegmenter.segment(text);
94
+ found.sort((a, b) => a.start - b.start || b.end - a.end);
95
+ // Nested/overlapping literals would desync the single-pass walk below; keep the outermost.
96
+ const markers = [];
97
+ for (const range of found) {
98
+ const previous = markers[markers.length - 1];
99
+ if (previous && range.start < previous.end)
100
+ continue;
101
+ markers.push(range);
102
+ }
91
103
  const result = [];
92
104
  let markerIndex = 0;
93
105
  let marker = markers[0];
@@ -103,6 +115,10 @@ export function segmentWithPasteMarkers(text, baseSegmenter, validMarkers) {
103
115
  }
104
116
  return result;
105
117
  }
118
+ /** Backward-compatible wrapper: paste markers are just one atomic marker set. */
119
+ export function segmentWithPasteMarkers(text, baseSegmenter, validMarkers) {
120
+ return segmentWithMarkers(text, baseSegmenter, validMarkers);
121
+ }
106
122
  export class PasteMarkerRegistry {
107
123
  constructor() {
108
124
  this.entries = new Map();