@ashx-j/lunr-tui 0.2.26 → 0.2.28
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +22 -0
- package/README.md +11 -11
- package/dist/components/editor.d.ts +2 -1
- package/dist/components/editor.d.ts.map +1 -1
- package/dist/components/editor.js +56 -30
- package/dist/components/editor.js.map +1 -1
- package/dist/components/settings-list.d.ts +7 -2
- package/dist/components/settings-list.d.ts.map +1 -1
- package/dist/components/settings-list.js +36 -0
- package/dist/components/settings-list.js.map +1 -1
- package/dist/undo-stack.d.ts +5 -3
- package/dist/undo-stack.d.ts.map +1 -1
- package/dist/undo-stack.js +8 -4
- package/dist/undo-stack.js.map +1 -1
- package/package.json +1 -1
|
@@ -106,7 +106,7 @@ function segmentWithMarkers(text, baseSegmenter, families) {
|
|
|
106
106
|
*/
|
|
107
107
|
export function wordWrapLine(line, maxWidth, preSegmented) {
|
|
108
108
|
if (!line || maxWidth <= 0) {
|
|
109
|
-
return [{ text: "", startIndex: 0, endIndex:
|
|
109
|
+
return [{ text: "", startIndex: 0, endIndex: line.length }];
|
|
110
110
|
}
|
|
111
111
|
const lineWidth = visibleWidth(line);
|
|
112
112
|
if (lineWidth <= maxWidth) {
|
|
@@ -148,11 +148,17 @@ export function wordWrapLine(line, maxWidth, preSegmented) {
|
|
|
148
148
|
wrapOppIndex = -1;
|
|
149
149
|
}
|
|
150
150
|
if (gWidth > maxWidth) {
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
151
|
+
const subSegments = [...graphemeSegmenter.segment(grapheme)];
|
|
152
|
+
if (subSegments.length === 1) {
|
|
153
|
+
// Keep the source range even when this grapheme cannot occupy its two cells.
|
|
154
|
+
chunks.push({ text: "�", startIndex: charIndex, endIndex: charIndex + grapheme.length });
|
|
155
|
+
chunkStart = charIndex + grapheme.length;
|
|
156
|
+
currentWidth = 0;
|
|
157
|
+
wrapOppIndex = -1;
|
|
158
|
+
continue;
|
|
159
|
+
}
|
|
160
|
+
// Split a multi-grapheme atomic marker visually, while keeping editing atomic.
|
|
161
|
+
const subChunks = wordWrapLine(grapheme, maxWidth, subSegments);
|
|
156
162
|
for (let j = 0; j < subChunks.length - 1; j++) {
|
|
157
163
|
const sc = subChunks[j];
|
|
158
164
|
chunks.push({ text: sc.text, startIndex: charIndex + sc.startIndex, endIndex: charIndex + sc.endIndex });
|
|
@@ -184,7 +190,9 @@ export function wordWrapLine(line, maxWidth, preSegmented) {
|
|
|
184
190
|
}
|
|
185
191
|
}
|
|
186
192
|
// Push final chunk.
|
|
187
|
-
|
|
193
|
+
if (chunkStart < line.length || chunks.length === 0) {
|
|
194
|
+
chunks.push({ text: line.slice(chunkStart), startIndex: chunkStart, endIndex: line.length });
|
|
195
|
+
}
|
|
188
196
|
return chunks;
|
|
189
197
|
}
|
|
190
198
|
const SLASH_COMMAND_SELECT_LIST_LAYOUT = {
|
|
@@ -262,7 +270,11 @@ export class Editor {
|
|
|
262
270
|
// to.
|
|
263
271
|
snappedFromCursorCol = null;
|
|
264
272
|
// Undo support
|
|
265
|
-
|
|
273
|
+
// Attachment maps are copied only when membership changes; snapshots share file metadata.
|
|
274
|
+
undoStack = new UndoStack((snapshot) => ({
|
|
275
|
+
state: structuredClone(snapshot.state),
|
|
276
|
+
images: snapshot.images,
|
|
277
|
+
}));
|
|
266
278
|
onSubmit;
|
|
267
279
|
onChange;
|
|
268
280
|
disableSubmit = false;
|
|
@@ -400,6 +412,8 @@ export class Editor {
|
|
|
400
412
|
// No cached state to invalidate currently
|
|
401
413
|
}
|
|
402
414
|
render(width) {
|
|
415
|
+
if (width <= 0)
|
|
416
|
+
return [];
|
|
403
417
|
const maxPadding = Math.max(0, Math.floor((width - 1) / 2));
|
|
404
418
|
const paddingX = Math.min(this.paddingX, maxPadding);
|
|
405
419
|
const contentWidth = Math.max(1, width - paddingX * 2);
|
|
@@ -494,7 +508,7 @@ export class Editor {
|
|
|
494
508
|
if (linesBelow > 0) {
|
|
495
509
|
const indicator = `─── ↓ ${linesBelow} more `;
|
|
496
510
|
const remaining = width - visibleWidth(indicator);
|
|
497
|
-
result.push(this.borderColor(indicator + "─".repeat(Math.max(0, remaining))));
|
|
511
|
+
result.push(this.borderColor(truncateToWidth(indicator + "─".repeat(Math.max(0, remaining)), width, "")));
|
|
498
512
|
}
|
|
499
513
|
else {
|
|
500
514
|
result.push(horizontal.repeat(width));
|
|
@@ -815,18 +829,14 @@ export class Editor {
|
|
|
815
829
|
if (isLastChunk) {
|
|
816
830
|
// Last chunk: cursor belongs here if >= startIndex
|
|
817
831
|
hasCursorInChunk = cursorPos >= chunk.startIndex;
|
|
818
|
-
adjustedCursorPos = cursorPos - chunk.startIndex;
|
|
832
|
+
adjustedCursorPos = Math.min(cursorPos - chunk.startIndex, chunk.text.length);
|
|
819
833
|
}
|
|
820
834
|
else {
|
|
821
835
|
// Non-last chunk: cursor belongs here if in range [startIndex, endIndex)
|
|
822
836
|
// But we need to handle the visual position in the trimmed text
|
|
823
837
|
hasCursorInChunk = cursorPos >= chunk.startIndex && cursorPos < chunk.endIndex;
|
|
824
838
|
if (hasCursorInChunk) {
|
|
825
|
-
adjustedCursorPos = cursorPos - chunk.startIndex;
|
|
826
|
-
// Clamp to text length (in case cursor was in trimmed whitespace)
|
|
827
|
-
if (adjustedCursorPos > chunk.text.length) {
|
|
828
|
-
adjustedCursorPos = chunk.text.length;
|
|
829
|
-
}
|
|
839
|
+
adjustedCursorPos = Math.min(cursorPos - chunk.startIndex, chunk.text.length);
|
|
830
840
|
}
|
|
831
841
|
}
|
|
832
842
|
}
|
|
@@ -846,6 +856,14 @@ export class Editor {
|
|
|
846
856
|
}
|
|
847
857
|
}
|
|
848
858
|
}
|
|
859
|
+
// At one column there is no spare cell for an end cursor.
|
|
860
|
+
if (contentWidth === 1) {
|
|
861
|
+
const cursorLine = layoutLines.find((line) => line.hasCursor);
|
|
862
|
+
if (cursorLine?.text && cursorLine.cursorPos === cursorLine.text.length) {
|
|
863
|
+
cursorLine.hasCursor = false;
|
|
864
|
+
layoutLines.splice(layoutLines.indexOf(cursorLine) + 1, 0, { text: "", hasCursor: true, cursorPos: 0 });
|
|
865
|
+
}
|
|
866
|
+
}
|
|
849
867
|
return layoutLines;
|
|
850
868
|
}
|
|
851
869
|
getText() {
|
|
@@ -876,16 +894,14 @@ export class Editor {
|
|
|
876
894
|
this.cancelAutocomplete();
|
|
877
895
|
this.lastAction = null;
|
|
878
896
|
this.exitHistoryBrowsing();
|
|
879
|
-
this.pastes.clear();
|
|
880
|
-
this.pasteCounter = 0;
|
|
881
|
-
this.images.clear();
|
|
882
|
-
this.imageCounter = 0;
|
|
883
|
-
// Keep submittedImages: submitValue() snapshots chips, then setText("") runs.
|
|
884
897
|
const normalized = this.normalizeText(text);
|
|
885
|
-
// Push undo snapshot if content differs (makes programmatic changes undoable)
|
|
886
898
|
if (this.getText() !== normalized) {
|
|
887
899
|
this.pushUndoSnapshot();
|
|
888
900
|
}
|
|
901
|
+
this.pastes.clear();
|
|
902
|
+
this.pasteCounter = 0;
|
|
903
|
+
this.images = new Map();
|
|
904
|
+
// Keep submittedImages: submitValue() snapshots chips, then setText("") runs.
|
|
889
905
|
this.setTextInternal(normalized);
|
|
890
906
|
}
|
|
891
907
|
/**
|
|
@@ -913,7 +929,9 @@ export class Editor {
|
|
|
913
929
|
this.exitHistoryBrowsing();
|
|
914
930
|
this.imageCounter++;
|
|
915
931
|
const id = this.imageCounter;
|
|
916
|
-
|
|
932
|
+
const images = new Map(this.images);
|
|
933
|
+
images.set(id, { id, path: attachment.path, mimeType: attachment.mimeType });
|
|
934
|
+
this.images = images;
|
|
917
935
|
this.insertTextAtCursorInternal(formatImageMarker(id));
|
|
918
936
|
return id;
|
|
919
937
|
}
|
|
@@ -922,13 +940,14 @@ export class Editor {
|
|
|
922
940
|
* Used by /edit so `[image_n]` stays a chip instead of becoming a path.
|
|
923
941
|
*/
|
|
924
942
|
restoreImageMarkers(attachments) {
|
|
925
|
-
|
|
943
|
+
const images = new Map();
|
|
926
944
|
this.imageCounter = 0;
|
|
927
945
|
for (const attachment of attachments) {
|
|
928
|
-
|
|
946
|
+
images.set(attachment.id, { ...attachment });
|
|
929
947
|
if (attachment.id > this.imageCounter)
|
|
930
948
|
this.imageCounter = attachment.id;
|
|
931
949
|
}
|
|
950
|
+
this.images = images;
|
|
932
951
|
}
|
|
933
952
|
/** Pending image chips still in the editor, in first-appearance order. */
|
|
934
953
|
getPendingImages() {
|
|
@@ -945,7 +964,7 @@ export class Editor {
|
|
|
945
964
|
takePendingImages() {
|
|
946
965
|
const pending = this.submittedImages.length > 0 ? this.submittedImages : this.getPendingImages();
|
|
947
966
|
this.submittedImages = [];
|
|
948
|
-
this.images
|
|
967
|
+
this.images = new Map();
|
|
949
968
|
this.imageCounter = 0;
|
|
950
969
|
return pending;
|
|
951
970
|
}
|
|
@@ -1148,7 +1167,7 @@ export class Editor {
|
|
|
1148
1167
|
this.state = { lines: [""], cursorLine: 0, cursorCol: 0 };
|
|
1149
1168
|
this.pastes.clear();
|
|
1150
1169
|
this.pasteCounter = 0;
|
|
1151
|
-
this.images
|
|
1170
|
+
this.images = new Map();
|
|
1152
1171
|
this.imageCounter = 0;
|
|
1153
1172
|
this.exitHistoryBrowsing();
|
|
1154
1173
|
this.scrollOffset = 0;
|
|
@@ -1192,7 +1211,9 @@ export class Editor {
|
|
|
1192
1211
|
}
|
|
1193
1212
|
else if (isImageSegmented) {
|
|
1194
1213
|
const targetId = Number(isImageSegmented[1]);
|
|
1195
|
-
this.images
|
|
1214
|
+
const images = new Map(this.images);
|
|
1215
|
+
images.delete(targetId);
|
|
1216
|
+
this.images = images;
|
|
1196
1217
|
}
|
|
1197
1218
|
line = this.state.lines[this.state.cursorLine] || "";
|
|
1198
1219
|
const before = line.slice(0, this.state.cursorCol - graphemeLength);
|
|
@@ -1501,7 +1522,9 @@ export class Editor {
|
|
|
1501
1522
|
const graphemeLength = firstGrapheme ? firstGrapheme.segment.length : 1;
|
|
1502
1523
|
const deletedImage = firstGrapheme ? IMAGE_MARKER_SINGLE.exec(firstGrapheme.segment) : null;
|
|
1503
1524
|
if (deletedImage) {
|
|
1504
|
-
this.images
|
|
1525
|
+
const images = new Map(this.images);
|
|
1526
|
+
images.delete(Number(deletedImage[1]));
|
|
1527
|
+
this.images = images;
|
|
1505
1528
|
}
|
|
1506
1529
|
const before = currentLine.slice(0, this.state.cursorCol);
|
|
1507
1530
|
const after = currentLine.slice(this.state.cursorCol + graphemeLength);
|
|
@@ -1784,14 +1807,17 @@ export class Editor {
|
|
|
1784
1807
|
}
|
|
1785
1808
|
}
|
|
1786
1809
|
pushUndoSnapshot() {
|
|
1787
|
-
this.undoStack.push(this.state);
|
|
1810
|
+
this.undoStack.push({ state: this.state, images: this.images });
|
|
1788
1811
|
}
|
|
1789
1812
|
undo() {
|
|
1790
1813
|
this.exitHistoryBrowsing();
|
|
1791
1814
|
const snapshot = this.undoStack.pop();
|
|
1792
1815
|
if (!snapshot)
|
|
1793
1816
|
return;
|
|
1794
|
-
Object.assign(this.state, snapshot);
|
|
1817
|
+
Object.assign(this.state, snapshot.state);
|
|
1818
|
+
this.images = snapshot.images;
|
|
1819
|
+
for (const id of this.images.keys())
|
|
1820
|
+
this.imageCounter = Math.max(this.imageCounter, id);
|
|
1795
1821
|
this.lastAction = null;
|
|
1796
1822
|
this.preferredVisualCol = null;
|
|
1797
1823
|
if (this.onChange) {
|