@code-yeongyu/senpi-tui 2026.7.26 → 2026.7.28-3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/dist/components/editor.d.ts +16 -6
  2. package/dist/components/editor.d.ts.map +1 -1
  3. package/dist/components/editor.js +56 -120
  4. package/dist/components/editor.js.map +1 -1
  5. package/dist/components/image.d.ts.map +1 -1
  6. package/dist/components/image.js +7 -1
  7. package/dist/components/image.js.map +1 -1
  8. package/dist/editor-component.d.ts +18 -0
  9. package/dist/editor-component.d.ts.map +1 -1
  10. package/dist/editor-component.js.map +1 -1
  11. package/dist/index.d.ts +3 -2
  12. package/dist/index.d.ts.map +1 -1
  13. package/dist/index.js +3 -2
  14. package/dist/index.js.map +1 -1
  15. package/dist/paste-markers.d.ts +29 -0
  16. package/dist/paste-markers.d.ts.map +1 -0
  17. package/dist/paste-markers.js +185 -0
  18. package/dist/paste-markers.js.map +1 -0
  19. package/dist/terminal-capabilities.d.ts +18 -0
  20. package/dist/terminal-capabilities.d.ts.map +1 -0
  21. package/dist/terminal-capabilities.js +62 -0
  22. package/dist/terminal-capabilities.js.map +1 -0
  23. package/dist/terminal-image.d.ts +31 -6
  24. package/dist/terminal-image.d.ts.map +1 -1
  25. package/dist/terminal-image.js +137 -92
  26. package/dist/terminal-image.js.map +1 -1
  27. package/dist/tmux-focus.d.ts +8 -0
  28. package/dist/tmux-focus.d.ts.map +1 -0
  29. package/dist/tmux-focus.js +14 -0
  30. package/dist/tmux-focus.js.map +1 -0
  31. package/dist/tmux-image-capability.d.ts +17 -0
  32. package/dist/tmux-image-capability.d.ts.map +1 -0
  33. package/dist/tmux-image-capability.js +61 -0
  34. package/dist/tmux-image-capability.js.map +1 -0
  35. package/dist/tmux-image-probe.d.ts +39 -0
  36. package/dist/tmux-image-probe.d.ts.map +1 -0
  37. package/dist/tmux-image-probe.js +121 -0
  38. package/dist/tmux-image-probe.js.map +1 -0
  39. package/dist/tui.d.ts +3 -0
  40. package/dist/tui.d.ts.map +1 -1
  41. package/dist/tui.js +63 -33
  42. package/dist/tui.js.map +1 -1
  43. package/dist/utils.d.ts.map +1 -1
  44. package/dist/utils.js +19 -0
  45. package/dist/utils.js.map +1 -1
  46. package/package.json +1 -1
@@ -1,4 +1,5 @@
1
1
  import type { AutocompleteProvider } from "../autocomplete.ts";
2
+ import { type EditorPasteState } from "../paste-markers.ts";
2
3
  import { type Component, type Focusable, type TUI } from "../tui.ts";
3
4
  import { type SelectListTheme } from "./select-list.ts";
4
5
  /**
@@ -59,8 +60,7 @@ export declare class Editor implements Component, Focusable {
59
60
  private autocompleteRequestTask;
60
61
  private autocompleteStartToken;
61
62
  private autocompleteRequestId;
62
- private pastes;
63
- private pasteCounter;
63
+ private pasteMarkers;
64
64
  private pasteBuffer;
65
65
  private isInPaste;
66
66
  private history;
@@ -77,10 +77,9 @@ export declare class Editor implements Component, Focusable {
77
77
  onChange?: (text: string) => void;
78
78
  disableSubmit: boolean;
79
79
  constructor(tui: TUI, theme: EditorTheme, options?: EditorOptions);
80
- /** Set of currently valid paste IDs, for marker-aware segmentation. */
81
- private validPasteIds;
82
- /** Segment text with paste-marker awareness, only merging markers with valid IDs. */
80
+ /** Segment text with paste-marker awareness, only merging exact canonical markers. */
83
81
  private segment;
82
+ private removePasteMarker;
84
83
  getPaddingX(): number;
85
84
  setPaddingX(padding: number): void;
86
85
  getAutocompleteMaxVisible(): number;
@@ -104,7 +103,6 @@ export declare class Editor implements Component, Focusable {
104
103
  handleInput(data: string): void;
105
104
  private layoutText;
106
105
  getText(): string;
107
- private expandPasteMarkers;
108
106
  /**
109
107
  * Get text with paste markers expanded to their actual content.
110
108
  * Use this when you need the full content (e.g., for external editor).
@@ -116,6 +114,18 @@ export declare class Editor implements Component, Focusable {
116
114
  col: number;
117
115
  };
118
116
  setText(text: string): void;
117
+ /**
118
+ * Snapshot the large-paste registry (marker id -> stored body) so it can be
119
+ * transferred to another editor instance alongside getText().
120
+ */
121
+ getPasteState(): EditorPasteState;
122
+ /**
123
+ * Install a paste registry snapshot taken from another editor instance.
124
+ * Call after setText() with the source editor's raw text: entries whose
125
+ * markers are not present in the current text are dropped, and the paste
126
+ * counter is raised so future paste ids cannot collide.
127
+ */
128
+ setPasteState(state: EditorPasteState): void;
119
129
  /**
120
130
  * Insert text at the current cursor position.
121
131
  * Used for programmatic insertion (e.g., clipboard image markers).
@@ -1 +1 @@
1
- {"version":3,"file":"editor.d.ts","sourceRoot":"","sources":["../../src/components/editor.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"editor.d.ts","sourceRoot":"","sources":["../../src/components/editor.ts"],"names":[],"mappings":"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"}
@@ -1,6 +1,7 @@
1
1
  import { getKeybindings } from "../keybindings.js";
2
2
  import { decodePrintableKey, matchesKey } from "../keys.js";
3
3
  import { KillRing } from "../kill-ring.js";
4
+ import { isPasteMarker, PasteMarkerRegistry, pasteMarkerId, segmentWithPasteMarkers, } from "../paste-markers.js";
4
5
  import { CURSOR_MARKER } from "../tui.js";
5
6
  import { UndoStack } from "../undo-stack.js";
6
7
  import { cjkBreakRegex, getGraphemeSegmenter, getWordSegmenter, isWhitespaceChar, sliceByColumn, visibleWidth, } from "../utils.js";
@@ -8,66 +9,6 @@ import { findWordBackward, findWordForward } from "../word-navigation.js";
8
9
  import { SelectList } from "./select-list.js";
9
10
  const graphemeSegmenter = getGraphemeSegmenter();
10
11
  const wordSegmenter = getWordSegmenter();
11
- /** Regex matching paste markers like `[paste #1 +123 lines]` or `[paste #2 1234 chars]`. */
12
- const PASTE_MARKER_REGEX = /\[paste #(\d+)( (\+\d+ lines|\d+ chars))?\]/g;
13
- /** Non-global version for single-segment testing. */
14
- const PASTE_MARKER_SINGLE = /^\[paste #(\d+)( (\+\d+ lines|\d+ chars))?\]$/;
15
- /** Check if a segment is a paste marker (i.e. was merged by segmentWithMarkers). */
16
- function isPasteMarker(segment) {
17
- return segment.length >= 10 && PASTE_MARKER_SINGLE.test(segment);
18
- }
19
- /**
20
- * A segmenter that wraps Intl.Segmenter and merges graphemes that fall
21
- * within paste markers into single atomic segments. This makes cursor
22
- * movement, deletion, word-wrap, etc. treat paste markers as single units.
23
- *
24
- * Only markers whose numeric ID exists in `validIds` are merged.
25
- */
26
- function segmentWithMarkers(text, baseSegmenter, validIds) {
27
- // Fast path: no paste markers in the text or no valid IDs.
28
- if (validIds.size === 0 || !text.includes("[paste #")) {
29
- return baseSegmenter.segment(text);
30
- }
31
- // Find all marker spans with valid IDs.
32
- const markers = [];
33
- for (const m of text.matchAll(PASTE_MARKER_REGEX)) {
34
- const id = Number.parseInt(m[1], 10);
35
- if (!validIds.has(id))
36
- continue;
37
- markers.push({ start: m.index, end: m.index + m[0].length });
38
- }
39
- if (markers.length === 0) {
40
- return baseSegmenter.segment(text);
41
- }
42
- // Build merged segment list.
43
- const baseSegments = baseSegmenter.segment(text);
44
- const result = [];
45
- let markerIdx = 0;
46
- for (const seg of baseSegments) {
47
- // Skip past markers that are entirely before this segment.
48
- while (markerIdx < markers.length && markers[markerIdx].end <= seg.index) {
49
- markerIdx++;
50
- }
51
- const marker = markerIdx < markers.length ? markers[markerIdx] : null;
52
- if (marker && seg.index >= marker.start && seg.index < marker.end) {
53
- // This segment falls inside a marker.
54
- // If this is the first segment of the marker, emit a merged segment.
55
- if (seg.index === marker.start) {
56
- const markerText = text.slice(marker.start, marker.end);
57
- result.push({
58
- segment: markerText,
59
- index: marker.start,
60
- input: text,
61
- });
62
- }
63
- // Otherwise skip (already merged into the first segment).
64
- }
65
- else {
66
- result.push(seg);
67
- }
68
- }
69
- return result;
70
- }
71
12
  function isPrintableAsciiText(text) {
72
13
  for (let i = 0; i < text.length; i++) {
73
14
  const code = text.charCodeAt(i);
@@ -258,8 +199,7 @@ export class Editor {
258
199
  this.autocompleteStartToken = 0;
259
200
  this.autocompleteRequestId = 0;
260
201
  // Paste tracking for large pastes
261
- this.pastes = new Map();
262
- this.pasteCounter = 0;
202
+ this.pasteMarkers = new PasteMarkerRegistry();
263
203
  // Bracketed paste mode buffering
264
204
  this.pasteBuffer = "";
265
205
  this.isInPaste = false;
@@ -292,13 +232,16 @@ export class Editor {
292
232
  const maxVisible = options.autocompleteMaxVisible ?? 5;
293
233
  this.autocompleteMaxVisible = Number.isFinite(maxVisible) ? Math.max(3, Math.min(20, Math.floor(maxVisible))) : 5;
294
234
  }
295
- /** Set of currently valid paste IDs, for marker-aware segmentation. */
296
- validPasteIds() {
297
- return new Set(this.pastes.keys());
298
- }
299
- /** Segment text with paste-marker awareness, only merging markers with valid IDs. */
235
+ /** Segment text with paste-marker awareness, only merging exact canonical markers. */
300
236
  segment(text, mode) {
301
- return segmentWithMarkers(text, mode === "word" ? wordSegmenter : graphemeSegmenter, this.validPasteIds());
237
+ return segmentWithPasteMarkers(text, mode === "word" ? wordSegmenter : graphemeSegmenter, this.pasteMarkers.authorizedMarkers(text));
238
+ }
239
+ removePasteMarker(id) {
240
+ const removal = this.pasteMarkers.remove(id, this.getText());
241
+ if (!removal.removed)
242
+ return false;
243
+ this.state.lines = removal.text.split("\n");
244
+ return true;
302
245
  }
303
246
  getPaddingX() {
304
247
  return this.paddingX;
@@ -879,20 +822,12 @@ export class Editor {
879
822
  getText() {
880
823
  return this.state.lines.join("\n");
881
824
  }
882
- expandPasteMarkers(text) {
883
- let result = text;
884
- for (const [pasteId, pasteContent] of this.pastes) {
885
- const markerRegex = new RegExp(`\\[paste #${pasteId}( (\\+\\d+ lines|\\d+ chars))?\\]`, "g");
886
- result = result.replace(markerRegex, () => pasteContent);
887
- }
888
- return result;
889
- }
890
825
  /**
891
826
  * Get text with paste markers expanded to their actual content.
892
827
  * Use this when you need the full content (e.g., for external editor).
893
828
  */
894
829
  getExpandedText() {
895
- return this.expandPasteMarkers(this.state.lines.join("\n"));
830
+ return this.pasteMarkers.expand(this.state.lines.join("\n"));
896
831
  }
897
832
  getLines() {
898
833
  return [...this.state.lines];
@@ -905,14 +840,30 @@ export class Editor {
905
840
  this.lastAction = null;
906
841
  this.exitHistoryBrowsing();
907
842
  const normalized = this.normalizeText(text);
843
+ const previousText = this.getText();
908
844
  // Push undo snapshot if content differs (makes programmatic changes undoable)
909
- if (this.getText() !== normalized) {
845
+ if (previousText !== normalized) {
910
846
  this.pushUndoSnapshot();
911
847
  }
912
- this.pastes.clear();
913
- this.pasteCounter = 0;
848
+ this.pasteMarkers.prune(normalized, previousText);
914
849
  this.setTextInternal(normalized);
915
850
  }
851
+ /**
852
+ * Snapshot the large-paste registry (marker id -> stored body) so it can be
853
+ * transferred to another editor instance alongside getText().
854
+ */
855
+ getPasteState() {
856
+ return this.pasteMarkers.snapshot();
857
+ }
858
+ /**
859
+ * Install a paste registry snapshot taken from another editor instance.
860
+ * Call after setText() with the source editor's raw text: entries whose
861
+ * markers are not present in the current text are dropped, and the paste
862
+ * counter is raised so future paste ids cannot collide.
863
+ */
864
+ setPasteState(state) {
865
+ this.pasteMarkers.install(state, this.getText());
866
+ }
916
867
  /**
917
868
  * Insert text at the current cursor position.
918
869
  * Used for programmatic insertion (e.g., clipboard image markers).
@@ -1069,14 +1020,7 @@ export class Editor {
1069
1020
  // Check if this is a large paste (> 10 lines or > 1000 characters)
1070
1021
  const totalChars = filteredText.length;
1071
1022
  if (pastedLines.length > 10 || totalChars > 1000) {
1072
- // Store the paste and insert a marker
1073
- this.pasteCounter++;
1074
- const pasteId = this.pasteCounter;
1075
- this.pastes.set(pasteId, filteredText);
1076
- // Insert marker like "[paste #1 +123 lines]" or "[paste #1 1234 chars]"
1077
- const marker = pastedLines.length > 10
1078
- ? `[paste #${pasteId} +${pastedLines.length} lines]`
1079
- : `[paste #${pasteId} ${totalChars} chars]`;
1023
+ const marker = this.pasteMarkers.add(filteredText, pastedLines.length, totalChars);
1080
1024
  this.insertTextAtCursorInternal(marker);
1081
1025
  return;
1082
1026
  }
@@ -1120,10 +1064,9 @@ export class Editor {
1120
1064
  }
1121
1065
  submitValue() {
1122
1066
  this.cancelAutocomplete();
1123
- const result = this.expandPasteMarkers(this.state.lines.join("\n")).trim();
1067
+ const result = this.pasteMarkers.expand(this.state.lines.join("\n")).trim();
1124
1068
  this.state = { lines: [""], cursorLine: 0, cursorCol: 0 };
1125
- this.pastes.clear();
1126
- this.pasteCounter = 0;
1069
+ this.pasteMarkers.clear();
1127
1070
  this.exitHistoryBrowsing();
1128
1071
  this.scrollOffset = 0;
1129
1072
  this.undoStack.clear();
@@ -1145,33 +1088,18 @@ export class Editor {
1145
1088
  const graphemes = [...this.segment(beforeCursor, "grapheme")];
1146
1089
  const lastGrapheme = graphemes[graphemes.length - 1];
1147
1090
  const graphemeLength = lastGrapheme ? lastGrapheme.segment.length : 1;
1148
- const isPastedSegmented = PASTE_MARKER_SINGLE.exec(lastGrapheme.segment);
1149
- if (isPastedSegmented) {
1150
- // This contains the id part e.g 4 from [paste #4 +123 lines]
1151
- const targetId = Number(isPastedSegmented[1]);
1152
- this.pastes.delete(targetId);
1153
- this.pasteCounter--;
1154
- // Shift registry entries down in ascending id order, independent
1155
- // of marker order in the text ([paste #3] becomes [paste #2] when
1156
- // [paste #1] is removed).
1157
- const higherIds = [...this.pastes.keys()].filter((id) => id > targetId).sort((a, b) => a - b);
1158
- for (const id of higherIds) {
1159
- this.pastes.set(id - 1, this.pastes.get(id));
1160
- this.pastes.delete(id);
1161
- }
1162
- // Renumber markers with ids greater than the removed one.
1163
- this.state.lines = this.state.lines.map((line) => line.replace(PASTE_MARKER_REGEX, (fullMatch, idGroup, suffixGroup) => {
1164
- const x = Number(idGroup);
1165
- if (x <= targetId)
1166
- return fullMatch;
1167
- return `[paste #${x - 1}${suffixGroup}]`;
1168
- }));
1091
+ const targetId = pasteMarkerId(lastGrapheme?.segment ?? "");
1092
+ if (targetId !== undefined) {
1093
+ this.removePasteMarker(targetId);
1094
+ this.setCursorCol(Math.max(0, this.state.cursorCol - graphemeLength));
1095
+ }
1096
+ else {
1097
+ line = this.state.lines[this.state.cursorLine] || "";
1098
+ const before = line.slice(0, this.state.cursorCol - graphemeLength);
1099
+ const after = line.slice(this.state.cursorCol);
1100
+ this.state.lines[this.state.cursorLine] = before + after;
1101
+ this.setCursorCol(this.state.cursorCol - graphemeLength);
1169
1102
  }
1170
- line = this.state.lines[this.state.cursorLine] || "";
1171
- const before = line.slice(0, this.state.cursorCol - graphemeLength);
1172
- const after = line.slice(this.state.cursorCol);
1173
- this.state.lines[this.state.cursorLine] = before + after;
1174
- this.setCursorCol(this.state.cursorCol - graphemeLength);
1175
1103
  }
1176
1104
  else if (this.state.cursorLine > 0) {
1177
1105
  this.pushUndoSnapshot();
@@ -1471,6 +1399,12 @@ export class Editor {
1471
1399
  // Find the first grapheme at cursor
1472
1400
  const graphemes = [...this.segment(afterCursor, "grapheme")];
1473
1401
  const firstGrapheme = graphemes[0];
1402
+ const markerId = firstGrapheme && isPasteMarker(firstGrapheme.segment) ? pasteMarkerId(firstGrapheme.segment) : undefined;
1403
+ if (markerId !== undefined) {
1404
+ this.removePasteMarker(markerId);
1405
+ this.onChange?.(this.getText());
1406
+ return;
1407
+ }
1474
1408
  const graphemeLength = firstGrapheme ? firstGrapheme.segment.length : 1;
1475
1409
  const before = currentLine.slice(0, this.state.cursorCol);
1476
1410
  const after = currentLine.slice(this.state.cursorCol + graphemeLength);
@@ -1753,7 +1687,10 @@ export class Editor {
1753
1687
  }
1754
1688
  }
1755
1689
  pushUndoSnapshot() {
1756
- this.undoStack.push({ state: this.state, pastes: this.pastes, pasteCounter: this.pasteCounter });
1690
+ this.undoStack.push({
1691
+ state: this.state,
1692
+ pasteState: this.pasteMarkers.snapshot(),
1693
+ });
1757
1694
  }
1758
1695
  undo() {
1759
1696
  this.exitHistoryBrowsing();
@@ -1761,8 +1698,7 @@ export class Editor {
1761
1698
  if (!snapshot)
1762
1699
  return;
1763
1700
  Object.assign(this.state, snapshot.state);
1764
- this.pastes = snapshot.pastes;
1765
- this.pasteCounter = snapshot.pasteCounter;
1701
+ this.pasteMarkers.restore(snapshot.pasteState);
1766
1702
  this.lastAction = null;
1767
1703
  this.preferredVisualCol = null;
1768
1704
  if (this.onChange) {