@pierre/diffs 1.3.0-beta.2 → 1.3.0-beta.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.
- package/dist/components/CodeView.d.ts +4 -0
- package/dist/components/CodeView.d.ts.map +1 -1
- package/dist/components/CodeView.js +38 -0
- package/dist/components/CodeView.js.map +1 -1
- package/dist/components/File.d.ts.map +1 -1
- package/dist/components/File.js +9 -9
- package/dist/components/File.js.map +1 -1
- package/dist/components/FileDiff.d.ts.map +1 -1
- package/dist/components/FileDiff.js +3 -2
- package/dist/components/FileDiff.js.map +1 -1
- package/dist/components/VirtualizedFile.js +6 -1
- package/dist/components/VirtualizedFile.js.map +1 -1
- package/dist/components/VirtualizedFileDiff.js +22 -42
- package/dist/components/VirtualizedFileDiff.js.map +1 -1
- package/dist/components/Virtualizer.js +5 -3
- package/dist/components/Virtualizer.js.map +1 -1
- package/dist/editor/editor.d.ts +7 -1
- package/dist/editor/editor.d.ts.map +1 -1
- package/dist/editor/editor.js +550 -405
- package/dist/editor/editor.js.map +1 -1
- package/dist/editor/editor2.js +6 -0
- package/dist/editor/editor2.js.map +1 -0
- package/dist/editor/pieceTable.d.ts +1 -1
- package/dist/editor/pieceTable.d.ts.map +1 -1
- package/dist/editor/pieceTable.js +2 -22
- package/dist/editor/pieceTable.js.map +1 -1
- package/dist/editor/quickEdit.js +2 -4
- package/dist/editor/quickEdit.js.map +1 -1
- package/dist/editor/searchPanel.d.ts +6 -7
- package/dist/editor/searchPanel.d.ts.map +1 -1
- package/dist/editor/searchPanel.js +102 -137
- package/dist/editor/searchPanel.js.map +1 -1
- package/dist/editor/selection.js +8 -2
- package/dist/editor/selection.js.map +1 -1
- package/dist/editor/sprite.d.ts +7 -0
- package/dist/editor/sprite.d.ts.map +1 -0
- package/dist/editor/sprite.js +38 -0
- package/dist/editor/sprite.js.map +1 -0
- package/dist/editor/textDocument.d.ts +1 -1
- package/dist/editor/textDocument.d.ts.map +1 -1
- package/dist/editor/textDocument.js +2 -2
- package/dist/editor/textDocument.js.map +1 -1
- package/dist/editor/textMeasure.js +3 -3
- package/dist/editor/textMeasure.js.map +1 -1
- package/dist/editor/tokenzier.d.ts +6 -2
- package/dist/editor/tokenzier.d.ts.map +1 -1
- package/dist/editor/tokenzier.js +127 -85
- package/dist/editor/tokenzier.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/react/index.d.ts +2 -2
- package/dist/renderers/DiffHunksRenderer.js +5 -9
- package/dist/renderers/DiffHunksRenderer.js.map +1 -1
- package/dist/ssr/index.d.ts +2 -2
- package/dist/style.js +1 -1
- package/dist/style.js.map +1 -1
- package/dist/types.d.ts +13 -12
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/computeEstimatedDiffHeights.js +9 -20
- package/dist/utils/computeEstimatedDiffHeights.js.map +1 -1
- package/dist/utils/iterateOverDiff.js +147 -182
- package/dist/utils/iterateOverDiff.js.map +1 -1
- package/dist/utils/virtualDiffLayout.d.ts +23 -2
- package/dist/utils/virtualDiffLayout.d.ts.map +1 -1
- package/dist/utils/virtualDiffLayout.js +41 -1
- package/dist/utils/virtualDiffLayout.js.map +1 -1
- package/dist/worker/WorkerPoolManager.js +1 -1
- package/dist/worker/WorkerPoolManager.js.map +1 -1
- package/dist/worker/{wasm-D4DU5jgR.js → wasm-BaDzIkIn.js} +2 -2
- package/dist/worker/wasm-BaDzIkIn.js.map +1 -0
- package/dist/worker/worker-portable.js +294 -292
- package/dist/worker/worker-portable.js.map +1 -1
- package/dist/worker/worker.js +179 -181
- package/dist/worker/worker.js.map +1 -1
- package/package.json +3 -2
- package/dist/editor/css.d.ts +0 -6
- package/dist/editor/css.d.ts.map +0 -1
- package/dist/editor/css.js +0 -218
- package/dist/editor/css.js.map +0 -1
- package/dist/worker/wasm-D4DU5jgR.js.map +0 -1
package/dist/editor/editor.js
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import { getFiletypeFromFileName } from "../utils/getFiletypeFromFileName.js";
|
|
2
2
|
import { isMoveCursorShortcut, isPrimaryModifier, isSafari } from "./platform.js";
|
|
3
3
|
import { resolveEditorCommandFromKeyboardEvent } from "./command.js";
|
|
4
|
-
import
|
|
4
|
+
import editor_default from "./editor2.js";
|
|
5
5
|
import { applyDocumentChangeToLineAnnotations } from "./lineAnnotations.js";
|
|
6
|
-
import {
|
|
7
|
-
import { TextDocument } from "./textDocument.js";
|
|
6
|
+
import { SVGSpriteSheet } from "./sprite.js";
|
|
8
7
|
import { addEventListener, debounce, extend, h, round } from "./utils.js";
|
|
9
8
|
import { QuickEditWidget } from "./quickEdit.js";
|
|
10
9
|
import { SearchPanelWidget } from "./searchPanel.js";
|
|
10
|
+
import { DirectionBackward, DirectionForward, DirectionNone, applyDeleteHardLineForwardToSelections, applyTextChangeToSelections, applyTextReplaceToSelections, applyTransposeToSelections, comparePosition, convertSelection, createSelectionFrom, createSelectionFromAnchorAndFocusOffsets, expandCollapsedSelectionToWord, extendSelection, extendSelections, findNexMatch, getCaretPosition, getDocumentBoundarySelection, getDocumentFullSelection, getSelectionAnchor, getSelectionText, isCollapsedSelection, isLineEditable, mapCursorMove, mapSelectionShift, mergeOverlappingSelections, resolveIndentEdits, selectionIntersects } from "./selection.js";
|
|
11
|
+
import { TextDocument } from "./textDocument.js";
|
|
11
12
|
import { Metrics, getExpandedAsciiTextColumns, getUnicodeMeasurementOffsets, snapTextOffsetToUnicodeBoundary } from "./textMeasure.js";
|
|
12
13
|
import { EditorTokenizer, renderLineTokens } from "./tokenzier.js";
|
|
13
14
|
|
|
@@ -22,7 +23,6 @@ function clampDomOffset(node, offset) {
|
|
|
22
23
|
}
|
|
23
24
|
var Editor = class {
|
|
24
25
|
#options;
|
|
25
|
-
#editMode = "simple";
|
|
26
26
|
#wrap = false;
|
|
27
27
|
#metrics = new Metrics();
|
|
28
28
|
#tokenizer;
|
|
@@ -30,7 +30,8 @@ var Editor = class {
|
|
|
30
30
|
#globalEventDisposes;
|
|
31
31
|
#mouseUpDisposes;
|
|
32
32
|
#detach;
|
|
33
|
-
#
|
|
33
|
+
#fileInstance;
|
|
34
|
+
#fileInstanceType;
|
|
34
35
|
#fileContents;
|
|
35
36
|
#lineAnnotations;
|
|
36
37
|
#textDocument;
|
|
@@ -44,7 +45,8 @@ var Editor = class {
|
|
|
44
45
|
#globalStyleElement;
|
|
45
46
|
#editorStyleElement;
|
|
46
47
|
#themeStyleElement;
|
|
47
|
-
#
|
|
48
|
+
#spriteElement;
|
|
49
|
+
#fileContainer;
|
|
48
50
|
#contentElement;
|
|
49
51
|
#overlayElement;
|
|
50
52
|
#primaryCaretElement;
|
|
@@ -60,14 +62,16 @@ var Editor = class {
|
|
|
60
62
|
#reservedSelections;
|
|
61
63
|
#selections;
|
|
62
64
|
#initSelections;
|
|
65
|
+
#matches;
|
|
63
66
|
#scrollingToLine;
|
|
64
67
|
#scrollingToLineChar;
|
|
68
|
+
#scrollingToLineNoFocus = false;
|
|
65
69
|
#retainSearchPanelFocus = false;
|
|
66
70
|
#emitChange = debounce((fileContents, lineAnnotations) => {
|
|
67
71
|
this.#options.onChange?.(fileContents, lineAnnotations);
|
|
68
72
|
}, 500);
|
|
69
73
|
#onDeferTokenize = (lines, themeType) => {
|
|
70
|
-
this.#
|
|
74
|
+
this.#fileInstance?.applyLineChange?.(lines, themeType);
|
|
71
75
|
if (this.#renderRange !== void 0 && this.#renderRange.totalLines !== Infinity) {
|
|
72
76
|
const { startingLine, totalLines } = this.#renderRange;
|
|
73
77
|
const endLine = Math.min(startingLine + totalLines, this.#textDocument?.lineCount ?? 0);
|
|
@@ -93,83 +97,12 @@ var Editor = class {
|
|
|
93
97
|
});
|
|
94
98
|
component.rerender();
|
|
95
99
|
}
|
|
96
|
-
this.#
|
|
100
|
+
this.#fileInstance = component;
|
|
97
101
|
this.#initialize();
|
|
98
102
|
this.#detach = component.attachEditor(this);
|
|
99
103
|
return () => this.cleanUp();
|
|
100
104
|
}
|
|
101
|
-
|
|
102
|
-
const textDocument = this.#textDocument;
|
|
103
|
-
if (textDocument !== void 0) {
|
|
104
|
-
const resolvedSelections = selections.map((selection) => {
|
|
105
|
-
const start = textDocument.normalizePosition(selection.start);
|
|
106
|
-
const end = textDocument.normalizePosition(selection.end);
|
|
107
|
-
return {
|
|
108
|
-
direction: selection.direction === "none" ? DirectionNone : selection.direction === "backward" ? DirectionBackward : DirectionForward,
|
|
109
|
-
start,
|
|
110
|
-
end
|
|
111
|
-
};
|
|
112
|
-
});
|
|
113
|
-
this.#updateSelections(resolvedSelections);
|
|
114
|
-
this.#scrollToPrimaryCaret();
|
|
115
|
-
} else this.#initSelections = selections;
|
|
116
|
-
}
|
|
117
|
-
focus(options) {
|
|
118
|
-
const preventScroll = options?.preventScroll ?? false;
|
|
119
|
-
const primarySelection = this.#selections?.at(-1);
|
|
120
|
-
if (primarySelection !== void 0) {
|
|
121
|
-
const pos = primarySelection.direction === DirectionBackward ? primarySelection.end : primarySelection.start;
|
|
122
|
-
this.#focus(pos, preventScroll);
|
|
123
|
-
} else this.#focus(void 0, preventScroll);
|
|
124
|
-
}
|
|
125
|
-
cleanUp() {
|
|
126
|
-
this.#tokenizer?.cleanUp();
|
|
127
|
-
this.#tokenizer = void 0;
|
|
128
|
-
this.#globalEventDisposes?.forEach((dispose) => dispose());
|
|
129
|
-
this.#globalEventDisposes = void 0;
|
|
130
|
-
this.#editorEventDisposes?.forEach((dispose) => dispose());
|
|
131
|
-
this.#editorEventDisposes = void 0;
|
|
132
|
-
this.#detach?.();
|
|
133
|
-
this.#detach = void 0;
|
|
134
|
-
this.#component?.setSelectedLines(null);
|
|
135
|
-
this.#component = void 0;
|
|
136
|
-
this.#fileContents = void 0;
|
|
137
|
-
this.#lineAnnotations = void 0;
|
|
138
|
-
this.#textDocument = void 0;
|
|
139
|
-
this.#renderRange = void 0;
|
|
140
|
-
this.#gutterWidthCache = void 0;
|
|
141
|
-
this.#contentWidthCache = void 0;
|
|
142
|
-
this.#lineYCache.clear();
|
|
143
|
-
this.#wrapLineOffsetsCache.clear();
|
|
144
|
-
this.#lastCharX = void 0;
|
|
145
|
-
this.#globalStyleElement?.remove();
|
|
146
|
-
this.#globalStyleElement = void 0;
|
|
147
|
-
this.#editorStyleElement?.remove();
|
|
148
|
-
this.#editorStyleElement = void 0;
|
|
149
|
-
this.#themeStyleElement?.remove();
|
|
150
|
-
this.#themeStyleElement = void 0;
|
|
151
|
-
this.#componentContainer = void 0;
|
|
152
|
-
this.#contentElement?.removeAttribute("contentEditable");
|
|
153
|
-
this.#contentElement = void 0;
|
|
154
|
-
this.#overlayElement?.remove();
|
|
155
|
-
this.#overlayElement = void 0;
|
|
156
|
-
this.#primaryCaretElement?.remove();
|
|
157
|
-
this.#primaryCaretElement = void 0;
|
|
158
|
-
this.#selectionElements?.forEach((el) => el.remove());
|
|
159
|
-
this.#selectionElements?.clear();
|
|
160
|
-
this.#selectionElements = void 0;
|
|
161
|
-
this.#searchPanel?.cleanup();
|
|
162
|
-
this.#searchPanel = void 0;
|
|
163
|
-
this.#quickEdit?.cleanup();
|
|
164
|
-
this.#quickEdit = void 0;
|
|
165
|
-
this.#resizeObserver?.disconnect();
|
|
166
|
-
this.#resizeObserver = void 0;
|
|
167
|
-
this.#shouldIgnoreSelectionChange = false;
|
|
168
|
-
this.#selectionStart = void 0;
|
|
169
|
-
this.#selections = void 0;
|
|
170
|
-
this.#reservedSelections = void 0;
|
|
171
|
-
}
|
|
172
|
-
syncWithRender(highlighter, fileContainer, fileContents, lineAnnotations, renderRange, editMode) {
|
|
105
|
+
syncToRenderedView(highlighter, fileInstanceType, fileContainer, fileContents, lineAnnotations, renderRange) {
|
|
173
106
|
const shadowRoot = fileContainer.shadowRoot;
|
|
174
107
|
if (shadowRoot == null) {
|
|
175
108
|
console.error("[editor] Could not find the shadow root.");
|
|
@@ -182,10 +115,10 @@ var Editor = class {
|
|
|
182
115
|
}
|
|
183
116
|
if (codeElement === void 0) return;
|
|
184
117
|
const contentEl = codeElement.children[1];
|
|
185
|
-
if (contentEl === void 0) return;
|
|
186
|
-
this.#
|
|
187
|
-
this.#wrap = this.#
|
|
188
|
-
if (
|
|
118
|
+
if (contentEl === void 0 || contentEl.dataset.content === void 0) return;
|
|
119
|
+
this.#fileInstanceType = fileInstanceType;
|
|
120
|
+
this.#wrap = this.#fileInstance?.options.overflow === "wrap";
|
|
121
|
+
if (fileInstanceType === "diff" || lineAnnotations !== void 0 && lineAnnotations.length > 0) {
|
|
189
122
|
let startingLine;
|
|
190
123
|
let endLine;
|
|
191
124
|
for (const child of contentEl.children) {
|
|
@@ -193,9 +126,12 @@ var Editor = class {
|
|
|
193
126
|
const line = el.dataset.line;
|
|
194
127
|
const lineType = el.dataset.lineType;
|
|
195
128
|
if (line !== void 0) {
|
|
196
|
-
const
|
|
197
|
-
|
|
198
|
-
|
|
129
|
+
const lineNumber = parseInt(line, 10);
|
|
130
|
+
if (!Number.isNaN(lineNumber)) {
|
|
131
|
+
const lineIndex = lineNumber - 1;
|
|
132
|
+
startingLine ??= lineIndex;
|
|
133
|
+
endLine = lineIndex;
|
|
134
|
+
}
|
|
199
135
|
}
|
|
200
136
|
if (lineType === void 0 || !isLineEditable(lineType)) el.contentEditable = "false";
|
|
201
137
|
}
|
|
@@ -210,14 +146,15 @@ var Editor = class {
|
|
|
210
146
|
bufferAfter: 0
|
|
211
147
|
};
|
|
212
148
|
}
|
|
213
|
-
if (this.#
|
|
214
|
-
this.#
|
|
215
|
-
|
|
149
|
+
if (this.#fileContainer !== fileContainer) {
|
|
150
|
+
this.#fileContainer = fileContainer;
|
|
151
|
+
const codePaddingTop = parseInt(getComputedStyle(codeElement).paddingTop.slice(0, -2), 10);
|
|
152
|
+
this.#codePaddingTop = Number.isNaN(codePaddingTop) ? 0 : codePaddingTop;
|
|
216
153
|
if (this.#globalStyleElement !== void 0) fileContainer.appendChild(this.#globalStyleElement);
|
|
217
154
|
if (this.#editorStyleElement !== void 0) shadowRoot.appendChild(this.#editorStyleElement);
|
|
218
155
|
if (this.#themeStyleElement !== void 0) shadowRoot.appendChild(this.#themeStyleElement);
|
|
219
156
|
}
|
|
220
|
-
if (this.#textDocument === void 0 || this.#fileContents === void 0 || this.#fileContents.name !== fileContents.name) {
|
|
157
|
+
if (this.#textDocument === void 0 || this.#fileContents === void 0 || this.#fileContents.name !== fileContents.name || this.#fileContents.lang !== fileContents.lang) {
|
|
221
158
|
const textDocument = new TextDocument(fileContents.name, fileContents.contents, fileContents.lang ?? getFiletypeFromFileName(fileContents.name));
|
|
222
159
|
this.#fileContents = fileContents;
|
|
223
160
|
this.#textDocument = textDocument;
|
|
@@ -225,16 +162,17 @@ var Editor = class {
|
|
|
225
162
|
this.#tokenizer = new EditorTokenizer({
|
|
226
163
|
highlighter,
|
|
227
164
|
textDocument,
|
|
228
|
-
codeOptions: this.#
|
|
165
|
+
codeOptions: this.#fileInstance?.options ?? {},
|
|
229
166
|
onDeferTokenize: this.#onDeferTokenize,
|
|
230
167
|
setStyle: (css) => {
|
|
231
168
|
this.#themeStyleElement.textContent = css;
|
|
232
|
-
}
|
|
169
|
+
},
|
|
170
|
+
__debug: this.#options.__debug
|
|
233
171
|
});
|
|
234
172
|
this.#shouldIgnoreSelectionChange = false;
|
|
235
173
|
this.#selectionElements?.forEach((el) => el.remove());
|
|
236
174
|
this.#selectionElements?.clear();
|
|
237
|
-
this.#
|
|
175
|
+
this.#fileInstance?.setSelectedLines(null);
|
|
238
176
|
this.#selectionElements = void 0;
|
|
239
177
|
this.#selections = void 0;
|
|
240
178
|
this.#scrollingToLine = void 0;
|
|
@@ -245,11 +183,6 @@ var Editor = class {
|
|
|
245
183
|
this.#quickEdit = void 0;
|
|
246
184
|
}
|
|
247
185
|
if (this.#contentElement !== contentEl) {
|
|
248
|
-
const guttterEl = contentEl.previousElementSibling;
|
|
249
|
-
const targetIsContentElement = (e) => {
|
|
250
|
-
const target = e.composedPath()[0];
|
|
251
|
-
return target === contentEl || contentEl.contains(target);
|
|
252
|
-
};
|
|
253
186
|
this.#metrics.init(contentEl);
|
|
254
187
|
this.#contentElement = extend(contentEl, {
|
|
255
188
|
contentEditable: "true",
|
|
@@ -262,167 +195,14 @@ var Editor = class {
|
|
|
262
195
|
translate: false
|
|
263
196
|
});
|
|
264
197
|
if (this.#overlayElement !== void 0) contentEl.after(this.#overlayElement);
|
|
265
|
-
this.#
|
|
266
|
-
this.#editorEventDisposes = [
|
|
267
|
-
addEventListener(contentEl, "pointerdown", (e) => {
|
|
268
|
-
if (e.pointerType !== "mouse") return;
|
|
269
|
-
if (isSafari() && this.#lineAnnotations !== void 0 && this.#lineAnnotations.length > 0) this.#mouseUpDisposes = [...contentEl.querySelectorAll("[data-line-annotation]")].map((el) => [addEventListener(el, "mouseenter", () => {
|
|
270
|
-
this.#shouldIgnoreSelectionChange = true;
|
|
271
|
-
}), addEventListener(el, "mouseleave", () => {
|
|
272
|
-
this.#shouldIgnoreSelectionChange = false;
|
|
273
|
-
})]).flat();
|
|
274
|
-
this.#isContentMouseDown = true;
|
|
275
|
-
this.#selectionStart = void 0;
|
|
276
|
-
if (e.button === 0 && isPrimaryModifier(e)) this.#reservedSelections = this.#selections?.map((selection) => ({ ...selection }));
|
|
277
|
-
if (e.shiftKey) {
|
|
278
|
-
const primarySelection = this.#selections?.at(-1);
|
|
279
|
-
if (primarySelection !== void 0) {
|
|
280
|
-
const pos = primarySelection.direction === DirectionBackward ? primarySelection.end : primarySelection.start;
|
|
281
|
-
this.#updateWindowSelection({
|
|
282
|
-
start: pos,
|
|
283
|
-
end: pos,
|
|
284
|
-
direction: DirectionNone
|
|
285
|
-
});
|
|
286
|
-
}
|
|
287
|
-
this.#shiftKeyPressed = true;
|
|
288
|
-
}
|
|
289
|
-
}, { passive: true }),
|
|
290
|
-
addEventListener(contentEl, "keydown", (e) => {
|
|
291
|
-
if (e.key === "Escape") {
|
|
292
|
-
e.preventDefault();
|
|
293
|
-
this.#searchPanel?.cleanup();
|
|
294
|
-
this.#searchPanel = void 0;
|
|
295
|
-
this.#retainSearchPanelFocus = false;
|
|
296
|
-
this.#quickEdit?.cleanup();
|
|
297
|
-
this.#quickEdit = void 0;
|
|
298
|
-
if (this.#selections !== void 0 && this.#selections.length > 0) {
|
|
299
|
-
const primarySelection = this.#selections.at(-1);
|
|
300
|
-
if (!isCollapsedSelection(primarySelection) || this.#selections.length > 1) {
|
|
301
|
-
const pos = getCaretPosition(primarySelection);
|
|
302
|
-
this.#updateSelections([{
|
|
303
|
-
start: pos,
|
|
304
|
-
end: pos,
|
|
305
|
-
direction: DirectionNone
|
|
306
|
-
}]);
|
|
307
|
-
this.#focus(pos);
|
|
308
|
-
}
|
|
309
|
-
}
|
|
310
|
-
return;
|
|
311
|
-
}
|
|
312
|
-
if (!targetIsContentElement(e)) return;
|
|
313
|
-
const mvShortcut = isMoveCursorShortcut(e);
|
|
314
|
-
const textDocument = this.#textDocument;
|
|
315
|
-
if (this.#selections !== void 0 && this.#selections.length > 0 && mvShortcut !== void 0 && textDocument !== void 0) {
|
|
316
|
-
if (e.shiftKey) this.#updateSelections(mapSelectionShift(textDocument, this.#selections, mvShortcut));
|
|
317
|
-
else this.#updateSelections(mapCursorMove(textDocument, this.#selections, mvShortcut));
|
|
318
|
-
this.#scrollToPrimaryCaret();
|
|
319
|
-
e.preventDefault();
|
|
320
|
-
return;
|
|
321
|
-
}
|
|
322
|
-
const command = resolveEditorCommandFromKeyboardEvent(e);
|
|
323
|
-
if (command !== void 0) {
|
|
324
|
-
e.preventDefault();
|
|
325
|
-
this.#runCommand(command);
|
|
326
|
-
}
|
|
327
|
-
}),
|
|
328
|
-
addEventListener(contentEl, "copy", (e) => {
|
|
329
|
-
if (!targetIsContentElement(e)) return;
|
|
330
|
-
e.preventDefault();
|
|
331
|
-
e.clipboardData?.setData("text", this.#getSelectionText());
|
|
332
|
-
}),
|
|
333
|
-
addEventListener(contentEl, "cut", (e) => {
|
|
334
|
-
if (!targetIsContentElement(e)) return;
|
|
335
|
-
e.preventDefault();
|
|
336
|
-
e.clipboardData?.setData("text", this.#getSelectionText());
|
|
337
|
-
this.#replaceSelectionText("");
|
|
338
|
-
}),
|
|
339
|
-
addEventListener(contentEl, "paste", (e) => {
|
|
340
|
-
if (!targetIsContentElement(e)) return;
|
|
341
|
-
e.preventDefault();
|
|
342
|
-
const text = e.clipboardData?.getData("text");
|
|
343
|
-
if (text !== void 0) this.#replaceSelectionText(text);
|
|
344
|
-
}),
|
|
345
|
-
addEventListener(contentEl, "beforeinput", (e) => {
|
|
346
|
-
if (!targetIsContentElement(e)) return;
|
|
347
|
-
e.preventDefault();
|
|
348
|
-
this.#handleInput(e.inputType, e.data);
|
|
349
|
-
}),
|
|
350
|
-
addEventListener(contentEl, "compositionstart", (e) => {
|
|
351
|
-
if (!targetIsContentElement(e)) return;
|
|
352
|
-
this.#shouldIgnoreSelectionChange = true;
|
|
353
|
-
}, { passive: true }),
|
|
354
|
-
addEventListener(contentEl, "compositionend", (e) => {
|
|
355
|
-
if (!targetIsContentElement(e)) return;
|
|
356
|
-
this.#shouldIgnoreSelectionChange = false;
|
|
357
|
-
this.#handleInput("insertText", e.data);
|
|
358
|
-
}, { passive: true })
|
|
359
|
-
];
|
|
360
|
-
if (guttterEl !== null && guttterEl.dataset.gutter !== void 0) this.#editorEventDisposes.push(addEventListener(guttterEl, "pointerdown", (e) => {
|
|
361
|
-
let target = e.composedPath()[0];
|
|
362
|
-
if (target?.dataset.lineNumberContent !== void 0) target = target.parentElement ?? void 0;
|
|
363
|
-
const textDocument = this.#textDocument;
|
|
364
|
-
if (target === void 0 || textDocument === void 0) return;
|
|
365
|
-
const lineNumber = target.dataset.columnNumber;
|
|
366
|
-
const lineType = target.dataset.lineType;
|
|
367
|
-
if (lineNumber === void 0 || lineType === void 0 || !isLineEditable(lineType)) return;
|
|
368
|
-
const lineIndex = Number(lineNumber) - 1;
|
|
369
|
-
const selection = {
|
|
370
|
-
start: {
|
|
371
|
-
line: lineIndex,
|
|
372
|
-
character: 0
|
|
373
|
-
},
|
|
374
|
-
end: {
|
|
375
|
-
line: lineIndex,
|
|
376
|
-
character: textDocument.getLineText(lineIndex).length
|
|
377
|
-
},
|
|
378
|
-
direction: DirectionForward
|
|
379
|
-
};
|
|
380
|
-
this.#isGutterMouseDown = true;
|
|
381
|
-
this.#selectionStart = selection;
|
|
382
|
-
this.#updateSelections([selection]);
|
|
383
|
-
this.#focus(selection.end);
|
|
384
|
-
this.#mouseUpDisposes = [addEventListener(document, "mousemove", (e$1) => {
|
|
385
|
-
let target$1 = e$1.composedPath()[0];
|
|
386
|
-
if (target$1?.dataset.lineNumberContent !== void 0) target$1 = target$1?.parentElement ?? void 0;
|
|
387
|
-
else if (target$1?.tagName === "SPAN") target$1 = target$1?.closest("[data-line]");
|
|
388
|
-
if (target$1 === void 0) return;
|
|
389
|
-
const lineNumber$1 = target$1.dataset.columnNumber ?? target$1.dataset.line;
|
|
390
|
-
const lineType$1 = target$1.dataset.lineType;
|
|
391
|
-
if (this.#isGutterMouseDown && this.#textDocument !== void 0 && lineNumber$1 !== void 0 && lineType$1 !== void 0 && isLineEditable(lineType$1)) {
|
|
392
|
-
const lineIndex$1 = Number(lineNumber$1) - 1;
|
|
393
|
-
let selection$1 = {
|
|
394
|
-
start: {
|
|
395
|
-
line: lineIndex$1,
|
|
396
|
-
character: 0
|
|
397
|
-
},
|
|
398
|
-
end: {
|
|
399
|
-
line: lineIndex$1,
|
|
400
|
-
character: this.#textDocument.getLineText(lineIndex$1).length
|
|
401
|
-
},
|
|
402
|
-
direction: DirectionForward
|
|
403
|
-
};
|
|
404
|
-
if (this.#selectionStart !== void 0) selection$1 = createSelectionFrom(this.#selectionStart, selection$1);
|
|
405
|
-
else this.#selectionStart = selection$1;
|
|
406
|
-
this.#updateSelections([selection$1]);
|
|
407
|
-
this.#focus(selection$1.end);
|
|
408
|
-
}
|
|
409
|
-
}, { passive: true })];
|
|
410
|
-
}, { passive: true }));
|
|
411
|
-
this.#resizeObserver?.disconnect();
|
|
412
|
-
this.#resizeObserver = new ResizeObserver(() => {
|
|
413
|
-
requestAnimationFrame(() => {
|
|
414
|
-
this.#handleLayoutResize();
|
|
415
|
-
});
|
|
416
|
-
});
|
|
417
|
-
this.#resizeObserver.observe(contentEl);
|
|
418
|
-
this.#resizeObserver.observe(contentEl.parentElement);
|
|
198
|
+
this.#listenContentElement(contentEl);
|
|
419
199
|
}
|
|
420
200
|
this.#lineYCache.clear();
|
|
421
201
|
this.#wrapLineOffsetsCache.clear();
|
|
422
202
|
this.#lastCharX = void 0;
|
|
423
203
|
this.#lineAnnotations = lineAnnotations;
|
|
424
204
|
this.#renderRange = renderRange;
|
|
425
|
-
this.#tokenizer?.
|
|
205
|
+
this.#tokenizer?.prebuildStateStack(renderRange);
|
|
426
206
|
if (this.#initSelections !== void 0) {
|
|
427
207
|
this.setSelections(this.#initSelections);
|
|
428
208
|
this.#scrollToPrimaryCaret();
|
|
@@ -433,33 +213,121 @@ var Editor = class {
|
|
|
433
213
|
console.log("[diffs/editor] render file:", fileContents.name, "RenderRange:", startingLine + "-" + (startingLine + totalLines), "of", this.#textDocument.lineCount, "lines");
|
|
434
214
|
}
|
|
435
215
|
if (this.#scrollingToLine !== void 0) {
|
|
436
|
-
this.#scrollToLine(this.#scrollingToLine, this.#scrollingToLineChar);
|
|
216
|
+
this.#scrollToLine(this.#scrollingToLine, this.#scrollingToLineChar, this.#scrollingToLineNoFocus);
|
|
437
217
|
this.#scrollingToLine = void 0;
|
|
438
218
|
this.#scrollingToLineChar = void 0;
|
|
439
|
-
|
|
440
|
-
if (this.#retainSearchPanelFocus) {
|
|
441
|
-
|
|
219
|
+
this.#scrollingToLineNoFocus = false;
|
|
220
|
+
} else if (this.#selections !== void 0 && this.#selections.length > 0 && !this.#retainSearchPanelFocus) this.focus({ preventScroll: true });
|
|
221
|
+
if (this.#retainSearchPanelFocus) this.#searchPanel?.focus();
|
|
222
|
+
if (this.#quickEdit !== void 0 && this.#isLineVisible(this.#quickEdit.line) && this.#contentElement !== void 0) this.#quickEdit.render(this.#contentElement);
|
|
223
|
+
}
|
|
224
|
+
postponeBackgroundTokenizeToNextFrame() {
|
|
225
|
+
const tokenizer = this.#tokenizer;
|
|
226
|
+
if (tokenizer !== void 0) {
|
|
227
|
+
tokenizer.pauseBackgroundTokenize();
|
|
442
228
|
requestAnimationFrame(() => {
|
|
443
|
-
|
|
229
|
+
tokenizer.resumeBackgroundTokenize();
|
|
444
230
|
});
|
|
445
231
|
}
|
|
446
|
-
|
|
232
|
+
}
|
|
233
|
+
setSelections(selections) {
|
|
234
|
+
const textDocument = this.#textDocument;
|
|
235
|
+
if (textDocument !== void 0) {
|
|
236
|
+
const resolvedSelections = selections.map((selection) => {
|
|
237
|
+
const start = textDocument.normalizePosition(selection.start);
|
|
238
|
+
const end = textDocument.normalizePosition(selection.end);
|
|
239
|
+
return {
|
|
240
|
+
direction: selection.direction === "none" ? DirectionNone : selection.direction === "backward" ? DirectionBackward : DirectionForward,
|
|
241
|
+
start,
|
|
242
|
+
end
|
|
243
|
+
};
|
|
244
|
+
});
|
|
245
|
+
this.#updateSelections(resolvedSelections);
|
|
246
|
+
this.#scrollToPrimaryCaret();
|
|
247
|
+
} else this.#initSelections = selections;
|
|
248
|
+
}
|
|
249
|
+
focus(options) {
|
|
250
|
+
const preventScroll = options?.preventScroll ?? false;
|
|
251
|
+
const primarySelection = this.#selections?.at(-1);
|
|
252
|
+
if (primarySelection !== void 0) {
|
|
253
|
+
const pos = primarySelection.direction === DirectionBackward ? primarySelection.end : primarySelection.start;
|
|
254
|
+
this.#focus(pos, preventScroll);
|
|
255
|
+
} else this.#focus(void 0, preventScroll);
|
|
256
|
+
}
|
|
257
|
+
cleanUp() {
|
|
258
|
+
this.#tokenizer?.cleanUp();
|
|
259
|
+
this.#tokenizer = void 0;
|
|
260
|
+
this.#globalEventDisposes?.forEach((dispose) => dispose());
|
|
261
|
+
this.#globalEventDisposes = void 0;
|
|
262
|
+
this.#editorEventDisposes?.forEach((dispose) => dispose());
|
|
263
|
+
this.#editorEventDisposes = void 0;
|
|
264
|
+
this.#detach?.();
|
|
265
|
+
this.#detach = void 0;
|
|
266
|
+
this.#fileInstance?.setSelectedLines(null);
|
|
267
|
+
this.#fileInstance = void 0;
|
|
268
|
+
this.#fileContents = void 0;
|
|
269
|
+
this.#lineAnnotations = void 0;
|
|
270
|
+
this.#textDocument = void 0;
|
|
271
|
+
this.#renderRange = void 0;
|
|
272
|
+
this.#gutterWidthCache = void 0;
|
|
273
|
+
this.#contentWidthCache = void 0;
|
|
274
|
+
this.#lineYCache.clear();
|
|
275
|
+
this.#wrapLineOffsetsCache.clear();
|
|
276
|
+
this.#lastCharX = void 0;
|
|
277
|
+
this.#globalStyleElement?.remove();
|
|
278
|
+
this.#globalStyleElement = void 0;
|
|
279
|
+
this.#editorStyleElement?.remove();
|
|
280
|
+
this.#editorStyleElement = void 0;
|
|
281
|
+
this.#themeStyleElement?.remove();
|
|
282
|
+
this.#themeStyleElement = void 0;
|
|
283
|
+
this.#spriteElement?.remove();
|
|
284
|
+
this.#spriteElement = void 0;
|
|
285
|
+
this.#fileContainer = void 0;
|
|
286
|
+
this.#contentElement?.removeAttribute("contentEditable");
|
|
287
|
+
this.#contentElement = void 0;
|
|
288
|
+
this.#overlayElement?.remove();
|
|
289
|
+
this.#overlayElement = void 0;
|
|
290
|
+
this.#primaryCaretElement?.remove();
|
|
291
|
+
this.#primaryCaretElement = void 0;
|
|
292
|
+
this.#selectionElements?.forEach((el) => el.remove());
|
|
293
|
+
this.#selectionElements?.clear();
|
|
294
|
+
this.#selectionElements = void 0;
|
|
295
|
+
this.#searchPanel?.cleanup();
|
|
296
|
+
this.#searchPanel = void 0;
|
|
297
|
+
this.#quickEdit?.cleanup();
|
|
298
|
+
this.#quickEdit = void 0;
|
|
299
|
+
this.#resizeObserver?.disconnect();
|
|
300
|
+
this.#resizeObserver = void 0;
|
|
301
|
+
this.#shouldIgnoreSelectionChange = false;
|
|
302
|
+
this.#selectionStart = void 0;
|
|
303
|
+
this.#selections = void 0;
|
|
304
|
+
this.#reservedSelections = void 0;
|
|
447
305
|
}
|
|
448
306
|
#initialize() {
|
|
307
|
+
this.#globalStyleElement = h("style", {
|
|
308
|
+
dataset: "editorGlobalCss",
|
|
309
|
+
textContent: `
|
|
310
|
+
[data-annotation-slot] {
|
|
311
|
+
user-select: none;
|
|
312
|
+
-webkit-user-select: none;
|
|
313
|
+
}
|
|
314
|
+
`
|
|
315
|
+
});
|
|
449
316
|
this.#editorStyleElement = h("style", {
|
|
450
317
|
dataset: "editorCss",
|
|
451
|
-
textContent:
|
|
318
|
+
textContent: editor_default
|
|
452
319
|
});
|
|
453
320
|
this.#themeStyleElement = h("style", { dataset: "editorThemeCss" });
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
321
|
+
const fragment = document.createElement("div");
|
|
322
|
+
fragment.innerHTML = SVGSpriteSheet;
|
|
323
|
+
const sprite = fragment.firstElementChild;
|
|
324
|
+
this.#spriteElement = sprite instanceof SVGSVGElement ? sprite : void 0;
|
|
458
325
|
this.#overlayElement = h("div", { dataset: "editorOverlay" });
|
|
459
326
|
this.#globalEventDisposes = [
|
|
460
327
|
addEventListener(document, "selectionchange", () => {
|
|
461
|
-
const shadowRoot = this.#
|
|
328
|
+
const shadowRoot = this.#fileContainer?.shadowRoot;
|
|
462
329
|
if (this.#shouldIgnoreSelectionChange || shadowRoot == null) return;
|
|
330
|
+
if (this.#selections !== void 0 && this.#selections.length > 1 && !this.#isContentMouseDown) return;
|
|
463
331
|
const composedRange = document.getSelection()?.getComposedRanges({ shadowRoots: [shadowRoot] })?.[0];
|
|
464
332
|
if (composedRange === void 0 || !this.#rangeBelongsToEditor(composedRange)) return;
|
|
465
333
|
let selection = convertSelection(composedRange, DirectionNone);
|
|
@@ -500,6 +368,169 @@ var Editor = class {
|
|
|
500
368
|
}, { passive: true })
|
|
501
369
|
];
|
|
502
370
|
}
|
|
371
|
+
#listenContentElement(contentEl) {
|
|
372
|
+
const gutterEl = contentEl.previousElementSibling;
|
|
373
|
+
const targetIsContentElement = (e) => {
|
|
374
|
+
const target = e.composedPath()[0];
|
|
375
|
+
return target === contentEl || contentEl.contains(target);
|
|
376
|
+
};
|
|
377
|
+
this.#editorEventDisposes?.forEach((dispose) => dispose());
|
|
378
|
+
this.#editorEventDisposes = [
|
|
379
|
+
addEventListener(contentEl, "pointerdown", (e) => {
|
|
380
|
+
if (e.pointerType !== "mouse") return;
|
|
381
|
+
if (isSafari() && this.#lineAnnotations !== void 0 && this.#lineAnnotations.length > 0) this.#mouseUpDisposes = [...contentEl.querySelectorAll("[data-line-annotation]")].map((el) => [addEventListener(el, "mouseenter", () => {
|
|
382
|
+
this.#shouldIgnoreSelectionChange = true;
|
|
383
|
+
}), addEventListener(el, "mouseleave", () => {
|
|
384
|
+
this.#shouldIgnoreSelectionChange = false;
|
|
385
|
+
})]).flat();
|
|
386
|
+
this.#isContentMouseDown = true;
|
|
387
|
+
this.#selectionStart = void 0;
|
|
388
|
+
if (e.button === 0 && isPrimaryModifier(e)) this.#reservedSelections = this.#selections?.map((selection) => ({ ...selection }));
|
|
389
|
+
if (e.shiftKey) {
|
|
390
|
+
const primarySelection = this.#selections?.at(-1);
|
|
391
|
+
if (primarySelection !== void 0) {
|
|
392
|
+
const pos = primarySelection.direction === DirectionBackward ? primarySelection.end : primarySelection.start;
|
|
393
|
+
this.#setWindowSelection({
|
|
394
|
+
start: pos,
|
|
395
|
+
end: pos,
|
|
396
|
+
direction: DirectionNone
|
|
397
|
+
});
|
|
398
|
+
}
|
|
399
|
+
this.#shiftKeyPressed = true;
|
|
400
|
+
}
|
|
401
|
+
}, { passive: true }),
|
|
402
|
+
addEventListener(contentEl, "keydown", (e) => {
|
|
403
|
+
if (e.key === "Escape") {
|
|
404
|
+
e.preventDefault();
|
|
405
|
+
this.#searchPanel?.cleanup();
|
|
406
|
+
this.#searchPanel = void 0;
|
|
407
|
+
this.#retainSearchPanelFocus = false;
|
|
408
|
+
this.#quickEdit?.cleanup();
|
|
409
|
+
this.#quickEdit = void 0;
|
|
410
|
+
if (this.#selections !== void 0 && this.#selections.length > 0) {
|
|
411
|
+
const primarySelection = this.#selections.at(-1);
|
|
412
|
+
if (!isCollapsedSelection(primarySelection) || this.#selections.length > 1) {
|
|
413
|
+
const pos = getCaretPosition(primarySelection);
|
|
414
|
+
this.#updateSelections([{
|
|
415
|
+
start: pos,
|
|
416
|
+
end: pos,
|
|
417
|
+
direction: DirectionNone
|
|
418
|
+
}]);
|
|
419
|
+
this.#focus(pos);
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
return;
|
|
423
|
+
}
|
|
424
|
+
if (!targetIsContentElement(e)) return;
|
|
425
|
+
const mvShortcut = isMoveCursorShortcut(e);
|
|
426
|
+
const textDocument = this.#textDocument;
|
|
427
|
+
if (this.#selections !== void 0 && this.#selections.length > 0 && mvShortcut !== void 0 && textDocument !== void 0) {
|
|
428
|
+
if (e.shiftKey) this.#updateSelections(mapSelectionShift(textDocument, this.#selections, mvShortcut));
|
|
429
|
+
else this.#updateSelections(mapCursorMove(textDocument, this.#selections, mvShortcut));
|
|
430
|
+
this.#scrollToPrimaryCaret();
|
|
431
|
+
e.preventDefault();
|
|
432
|
+
return;
|
|
433
|
+
}
|
|
434
|
+
const command = resolveEditorCommandFromKeyboardEvent(e);
|
|
435
|
+
if (command !== void 0) {
|
|
436
|
+
e.preventDefault();
|
|
437
|
+
this.#runCommand(command);
|
|
438
|
+
}
|
|
439
|
+
}),
|
|
440
|
+
addEventListener(contentEl, "copy", (e) => {
|
|
441
|
+
if (!targetIsContentElement(e)) return;
|
|
442
|
+
e.preventDefault();
|
|
443
|
+
e.clipboardData?.setData("text", this.#getSelectionText());
|
|
444
|
+
}),
|
|
445
|
+
addEventListener(contentEl, "cut", (e) => {
|
|
446
|
+
if (!targetIsContentElement(e)) return;
|
|
447
|
+
e.preventDefault();
|
|
448
|
+
e.clipboardData?.setData("text", this.#getSelectionText());
|
|
449
|
+
this.#replaceSelectionText("");
|
|
450
|
+
}),
|
|
451
|
+
addEventListener(contentEl, "paste", (e) => {
|
|
452
|
+
if (!targetIsContentElement(e)) return;
|
|
453
|
+
e.preventDefault();
|
|
454
|
+
const text = e.clipboardData?.getData("text");
|
|
455
|
+
if (text !== void 0) this.#replaceSelectionText(text);
|
|
456
|
+
}),
|
|
457
|
+
addEventListener(contentEl, "beforeinput", (e) => {
|
|
458
|
+
if (!targetIsContentElement(e)) return;
|
|
459
|
+
e.preventDefault();
|
|
460
|
+
this.#handleInput(e.inputType, e.data);
|
|
461
|
+
}),
|
|
462
|
+
addEventListener(contentEl, "compositionstart", (e) => {
|
|
463
|
+
if (!targetIsContentElement(e)) return;
|
|
464
|
+
this.#shouldIgnoreSelectionChange = true;
|
|
465
|
+
}, { passive: true }),
|
|
466
|
+
addEventListener(contentEl, "compositionend", (e) => {
|
|
467
|
+
if (!targetIsContentElement(e)) return;
|
|
468
|
+
this.#shouldIgnoreSelectionChange = false;
|
|
469
|
+
this.#handleInput("insertText", e.data);
|
|
470
|
+
}, { passive: true })
|
|
471
|
+
];
|
|
472
|
+
if (gutterEl !== null && gutterEl.dataset.gutter !== void 0) this.#editorEventDisposes.push(addEventListener(gutterEl, "pointerdown", (e) => {
|
|
473
|
+
let target = e.composedPath()[0];
|
|
474
|
+
if (target?.dataset.lineNumberContent !== void 0) target = target.parentElement ?? void 0;
|
|
475
|
+
const textDocument = this.#textDocument;
|
|
476
|
+
if (target === void 0 || textDocument === void 0) return;
|
|
477
|
+
const columnNumber = target.dataset.columnNumber;
|
|
478
|
+
const lineType = target.dataset.lineType;
|
|
479
|
+
if (columnNumber === void 0 || lineType === void 0 || !isLineEditable(lineType)) return;
|
|
480
|
+
const lineNumber = parseInt(columnNumber, 10);
|
|
481
|
+
if (Number.isNaN(lineNumber)) return;
|
|
482
|
+
const line = lineNumber - 1;
|
|
483
|
+
const selection = {
|
|
484
|
+
start: {
|
|
485
|
+
line,
|
|
486
|
+
character: 0
|
|
487
|
+
},
|
|
488
|
+
end: {
|
|
489
|
+
line,
|
|
490
|
+
character: textDocument.getLineText(line).length
|
|
491
|
+
},
|
|
492
|
+
direction: DirectionForward
|
|
493
|
+
};
|
|
494
|
+
this.#isGutterMouseDown = true;
|
|
495
|
+
this.#selectionStart = selection;
|
|
496
|
+
this.#updateSelections([selection]);
|
|
497
|
+
this.#focus(selection.end);
|
|
498
|
+
this.#mouseUpDisposes = [addEventListener(document, "mousemove", (e$1) => {
|
|
499
|
+
let target$1 = e$1.composedPath()[0];
|
|
500
|
+
if (target$1?.dataset.lineNumberContent !== void 0) target$1 = target$1?.parentElement ?? void 0;
|
|
501
|
+
else if (target$1?.tagName === "SPAN") target$1 = target$1?.closest("[data-line]");
|
|
502
|
+
if (target$1 === void 0) return;
|
|
503
|
+
const line$1 = target$1.dataset.columnNumber ?? target$1.dataset.line;
|
|
504
|
+
const lineType$1 = target$1.dataset.lineType;
|
|
505
|
+
if (this.#isGutterMouseDown && this.#textDocument !== void 0 && line$1 !== void 0 && lineType$1 !== void 0 && isLineEditable(lineType$1)) {
|
|
506
|
+
const lineNumber$1 = parseInt(line$1, 10);
|
|
507
|
+
if (Number.isNaN(lineNumber$1)) return;
|
|
508
|
+
const lineIndex = lineNumber$1 - 1;
|
|
509
|
+
let selection$1 = {
|
|
510
|
+
start: {
|
|
511
|
+
line: lineIndex,
|
|
512
|
+
character: 0
|
|
513
|
+
},
|
|
514
|
+
end: {
|
|
515
|
+
line: lineIndex,
|
|
516
|
+
character: this.#textDocument.getLineText(lineIndex).length
|
|
517
|
+
},
|
|
518
|
+
direction: DirectionForward
|
|
519
|
+
};
|
|
520
|
+
if (this.#selectionStart !== void 0) selection$1 = createSelectionFrom(this.#selectionStart, selection$1);
|
|
521
|
+
else this.#selectionStart = selection$1;
|
|
522
|
+
this.#updateSelections([selection$1]);
|
|
523
|
+
this.#focus(selection$1.end);
|
|
524
|
+
}
|
|
525
|
+
}, { passive: true })];
|
|
526
|
+
}, { passive: true }));
|
|
527
|
+
this.#resizeObserver?.disconnect();
|
|
528
|
+
this.#resizeObserver = new ResizeObserver(() => {
|
|
529
|
+
this.#handleLayoutResize();
|
|
530
|
+
});
|
|
531
|
+
this.#resizeObserver.observe(contentEl);
|
|
532
|
+
this.#resizeObserver.observe(contentEl.parentElement);
|
|
533
|
+
}
|
|
503
534
|
#runCommand(command) {
|
|
504
535
|
const textDocument = this.#textDocument;
|
|
505
536
|
if (textDocument === void 0) return;
|
|
@@ -609,7 +640,7 @@ var Editor = class {
|
|
|
609
640
|
}
|
|
610
641
|
#rerender(change, newLineAnnotations, renderRange = this.#renderRange, shouldUpdateBuffer) {
|
|
611
642
|
const tokenizer = this.#tokenizer;
|
|
612
|
-
const component = this.#
|
|
643
|
+
const component = this.#fileInstance;
|
|
613
644
|
const fileContents = this.#fileContents;
|
|
614
645
|
const textDocument = this.#textDocument;
|
|
615
646
|
const contentEl = this.#contentElement;
|
|
@@ -617,21 +648,25 @@ var Editor = class {
|
|
|
617
648
|
if (tokenizer === void 0 || component === void 0 || fileContents === void 0 || textDocument === void 0 || contentEl === void 0 || gutterEl === void 0 || !(gutterEl instanceof HTMLElement) || gutterEl.dataset.gutter === void 0) return;
|
|
618
649
|
tokenizer.stopBackgroundTokenize();
|
|
619
650
|
const t = performance.now();
|
|
620
|
-
const
|
|
651
|
+
const isFileDiff = this.#fileInstanceType === "diff";
|
|
621
652
|
const dirtyLines = tokenizer.tokenize(change, renderRange);
|
|
622
653
|
const t2 = performance.now();
|
|
623
654
|
if (dirtyLines.size > 0) {
|
|
624
655
|
const children = contentEl.children;
|
|
625
656
|
const dirtyLineIndexes = new Set(dirtyLines.keys());
|
|
626
|
-
if (
|
|
657
|
+
if (isFileDiff) for (const child of children) {
|
|
627
658
|
const el = child;
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
const
|
|
631
|
-
if (
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
if (
|
|
659
|
+
const line = el.dataset.line;
|
|
660
|
+
if (line !== void 0) {
|
|
661
|
+
const lineNumber = parseInt(line, 10);
|
|
662
|
+
if (!Number.isNaN(lineNumber)) {
|
|
663
|
+
const lineIndex = lineNumber - 1;
|
|
664
|
+
const tokens = dirtyLines.get(lineIndex);
|
|
665
|
+
if (tokens !== void 0) {
|
|
666
|
+
el.replaceChildren(...renderLineTokens(tokens, tokenizer.themeType));
|
|
667
|
+
dirtyLineIndexes.delete(lineIndex);
|
|
668
|
+
if (dirtyLineIndexes.size === 0) break;
|
|
669
|
+
}
|
|
635
670
|
}
|
|
636
671
|
}
|
|
637
672
|
}
|
|
@@ -639,13 +674,16 @@ var Editor = class {
|
|
|
639
674
|
const startingLine = renderRange?.startingLine ?? 0;
|
|
640
675
|
for (let i = change.startLine - startingLine; i < children.length; i++) {
|
|
641
676
|
const child = children[i];
|
|
642
|
-
if (child
|
|
643
|
-
const
|
|
644
|
-
if (
|
|
645
|
-
const
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
677
|
+
if (child !== void 0 && child.dataset.line !== void 0) {
|
|
678
|
+
const lineNumber = parseInt(child.dataset.line, 10);
|
|
679
|
+
if (!Number.isNaN(lineNumber)) {
|
|
680
|
+
const lineIndex = lineNumber - 1;
|
|
681
|
+
if (dirtyLines.has(lineIndex)) {
|
|
682
|
+
const tokens = dirtyLines.get(lineIndex);
|
|
683
|
+
child.replaceChildren(...renderLineTokens(tokens, tokenizer.themeType));
|
|
684
|
+
dirtyLineIndexes.delete(lineIndex);
|
|
685
|
+
if (dirtyLineIndexes.size === 0) break;
|
|
686
|
+
}
|
|
649
687
|
}
|
|
650
688
|
}
|
|
651
689
|
}
|
|
@@ -678,11 +716,12 @@ var Editor = class {
|
|
|
678
716
|
const children = parent.children;
|
|
679
717
|
for (let i = children.length - 1; i >= 0; i--) {
|
|
680
718
|
const child = children[i];
|
|
681
|
-
const {
|
|
682
|
-
if (
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
719
|
+
const { line, columnNumber, lineAnnotation } = child.dataset;
|
|
720
|
+
if (line === void 0 && columnNumber === void 0 && lineAnnotation === void 0) continue;
|
|
721
|
+
const lineIndex = lineAnnotation !== void 0 ? parseInt(lineAnnotation.split(",")[1], 10) : parseInt(line ?? columnNumber, 10) - 1;
|
|
722
|
+
if (Number.isNaN(lineIndex)) continue;
|
|
723
|
+
if (lineIndex < change.lineCount) break;
|
|
724
|
+
child.remove();
|
|
686
725
|
}
|
|
687
726
|
}
|
|
688
727
|
if (change.lineDelta !== 0) {
|
|
@@ -690,7 +729,8 @@ var Editor = class {
|
|
|
690
729
|
contentEl.style.gridRow = "span " + contentEl.children.length;
|
|
691
730
|
}
|
|
692
731
|
component.applyLineChange?.(dirtyLines, tokenizer.themeType);
|
|
693
|
-
if (change.lineDelta !== 0 ||
|
|
732
|
+
if (change.lineDelta !== 0 || isFileDiff) component.applyLayoutChange(textDocument, newLineAnnotations, shouldUpdateBuffer);
|
|
733
|
+
if (isFileDiff) this.#tokenizer?.stopBackgroundTokenize();
|
|
694
734
|
if (this.#options.__debug === true) console.log(`[diffs/editor] re-render in: ${round(performance.now() - t2)}ms,`, `tokenize in: ${round(t2 - t)}ms (${dirtyLines.size} dirty lines)`);
|
|
695
735
|
}
|
|
696
736
|
#handleInput(inputType, data) {
|
|
@@ -719,40 +759,64 @@ var Editor = class {
|
|
|
719
759
|
}
|
|
720
760
|
}
|
|
721
761
|
#updateSelections(selections) {
|
|
722
|
-
|
|
762
|
+
this.postponeBackgroundTokenizeToNextFrame();
|
|
723
763
|
const gutterBuffer = this.#contentElement?.previousElementSibling;
|
|
724
|
-
const normalizedSelections = mergeOverlappingSelections(selections);
|
|
725
|
-
const primarySelection = normalizedSelections.at(-1);
|
|
726
|
-
this.#selections = normalizedSelections;
|
|
727
764
|
this.#primaryCaretElement = void 0;
|
|
728
|
-
this.#
|
|
765
|
+
this.#fileInstance?.setSelectedLines(null);
|
|
729
766
|
gutterBuffer?.querySelectorAll("[data-active]").forEach((el) => el.removeAttribute("data-active"));
|
|
730
|
-
if (
|
|
731
|
-
|
|
732
|
-
this.#
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
} else if (gutterBuffer !== void 0 && gutterBuffer instanceof HTMLElement) {
|
|
737
|
-
const pos = getCaretPosition(primarySelection);
|
|
738
|
-
gutterBuffer.querySelector(`[data-column-number="${pos.line + 1}"]`)?.setAttribute("data-active", "");
|
|
767
|
+
if (selections.length === 0 && this.#matches === void 0) {
|
|
768
|
+
this.#selections = void 0;
|
|
769
|
+
this.#matches = void 0;
|
|
770
|
+
this.#selectionElements?.forEach((el) => el.remove());
|
|
771
|
+
this.#selectionElements?.clear();
|
|
772
|
+
return;
|
|
739
773
|
}
|
|
740
774
|
const fragment = document.createDocumentFragment();
|
|
741
775
|
const renderCtx = {
|
|
742
776
|
fragment,
|
|
743
777
|
elements: /* @__PURE__ */ new Map()
|
|
744
778
|
};
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
779
|
+
if (selections.length > 0) {
|
|
780
|
+
const normalizedSelections = mergeOverlappingSelections(selections);
|
|
781
|
+
const primarySelection = normalizedSelections.at(-1);
|
|
782
|
+
this.#selections = normalizedSelections;
|
|
783
|
+
if (isCollapsedSelection(primarySelection)) {
|
|
784
|
+
const line = primarySelection.start.line + 1;
|
|
785
|
+
this.#fileInstance?.setSelectedLines({
|
|
786
|
+
start: line,
|
|
787
|
+
end: line
|
|
788
|
+
});
|
|
789
|
+
} else if (gutterBuffer !== void 0 && gutterBuffer instanceof HTMLElement) {
|
|
790
|
+
const pos = getCaretPosition(primarySelection);
|
|
791
|
+
gutterBuffer.querySelector(`[data-column-number="${pos.line + 1}"]`)?.setAttribute("data-active", "");
|
|
792
|
+
}
|
|
793
|
+
for (const selection of normalizedSelections) {
|
|
794
|
+
if (!isCollapsedSelection(selection)) this.#renderSelection(renderCtx, selection, "selection");
|
|
795
|
+
this.#renderCaret(renderCtx, selection, selection === primarySelection);
|
|
796
|
+
}
|
|
797
|
+
if (this.#options.enabledQuickEdit === true && !isCollapsedSelection(primarySelection)) this.#renderQuickEditIcon(renderCtx, primarySelection);
|
|
798
|
+
}
|
|
799
|
+
const textDocument = this.#textDocument;
|
|
800
|
+
if (this.#matches !== void 0 && textDocument !== void 0) {
|
|
801
|
+
const primarySelection = this.#selections?.at(-1);
|
|
802
|
+
const primaryStartOffset = primarySelection !== void 0 ? textDocument.offsetAt(primarySelection.start) : -1;
|
|
803
|
+
const primaryEndOffset = primarySelection !== void 0 ? textDocument.offsetAt(primarySelection.end) : -1;
|
|
804
|
+
for (const [startOffset, endOffset] of this.#matches) {
|
|
805
|
+
const selection = {
|
|
806
|
+
start: textDocument.positionAt(startOffset),
|
|
807
|
+
end: textDocument.positionAt(endOffset),
|
|
808
|
+
direction: DirectionNone
|
|
809
|
+
};
|
|
810
|
+
const isFocused = primaryStartOffset === startOffset && primaryEndOffset === endOffset;
|
|
811
|
+
this.#renderSelection(renderCtx, selection, "match", isFocused);
|
|
812
|
+
}
|
|
748
813
|
}
|
|
749
|
-
if (this.#options.enabledQuickEdit === true && !isCollapsedSelection(primarySelection)) this.#renderQuickEditIcon(renderCtx, primarySelection);
|
|
750
814
|
this.#overlayElement?.appendChild(fragment);
|
|
751
815
|
this.#selectionElements?.forEach((el) => el.remove());
|
|
752
816
|
this.#selectionElements?.clear();
|
|
753
817
|
this.#selectionElements = renderCtx.elements;
|
|
754
818
|
}
|
|
755
|
-
#
|
|
819
|
+
#setWindowSelection(selection) {
|
|
756
820
|
const winSelection = window.getSelection();
|
|
757
821
|
if (winSelection === null) return;
|
|
758
822
|
let { start, end, direction } = selection;
|
|
@@ -777,7 +841,7 @@ var Editor = class {
|
|
|
777
841
|
#focus(position, preventScroll = true) {
|
|
778
842
|
if (position !== void 0) {
|
|
779
843
|
this.#shouldIgnoreSelectionChange = true;
|
|
780
|
-
this.#
|
|
844
|
+
this.#setWindowSelection({
|
|
781
845
|
start: position,
|
|
782
846
|
end: position,
|
|
783
847
|
direction: DirectionNone
|
|
@@ -788,11 +852,9 @@ var Editor = class {
|
|
|
788
852
|
this.#shouldIgnoreSelectionChange = false;
|
|
789
853
|
});
|
|
790
854
|
});
|
|
791
|
-
} else
|
|
792
|
-
this.#contentElement?.focus({ preventScroll });
|
|
793
|
-
});
|
|
855
|
+
} else this.#contentElement?.focus({ preventScroll });
|
|
794
856
|
}
|
|
795
|
-
#scrollToPrimaryCaret() {
|
|
857
|
+
#scrollToPrimaryCaret(noFocus = false) {
|
|
796
858
|
const primaryCaretElement = this.#primaryCaretElement;
|
|
797
859
|
const primarySelection = this.#selections?.at(-1);
|
|
798
860
|
if (primarySelection === void 0) return;
|
|
@@ -801,20 +863,21 @@ var Editor = class {
|
|
|
801
863
|
block: "nearest",
|
|
802
864
|
inline: "nearest"
|
|
803
865
|
});
|
|
804
|
-
this.#focus(primarySelection.direction === DirectionBackward ? primarySelection.end : primarySelection.start);
|
|
866
|
+
if (!noFocus) this.#focus(primarySelection.direction === DirectionBackward ? primarySelection.end : primarySelection.start);
|
|
805
867
|
} else {
|
|
806
868
|
const pos = getCaretPosition(primarySelection);
|
|
807
|
-
this.#scrollToLine(pos.line, pos.character);
|
|
869
|
+
this.#scrollToLine(pos.line, pos.character, noFocus);
|
|
808
870
|
}
|
|
809
871
|
}
|
|
810
872
|
#getScrollMargin() {
|
|
811
|
-
const componentTop = this.#
|
|
873
|
+
const componentTop = this.#fileInstance?.top ?? 0;
|
|
812
874
|
const top = this.#searchPanel !== void 0 ? 48 : 0;
|
|
813
875
|
const start = this.#getGutterWidth() + this.#metrics.ch;
|
|
814
876
|
const end = this.#metrics.ch;
|
|
815
877
|
return `${componentTop + top}px ${end}px 0 ${start}px`;
|
|
816
878
|
}
|
|
817
|
-
#scrollToLine(line, char = 0) {
|
|
879
|
+
#scrollToLine(line, char = 0, noFocus = false) {
|
|
880
|
+
this.postponeBackgroundTokenizeToNextFrame();
|
|
818
881
|
const virtualCaret = h("div", { style: {
|
|
819
882
|
position: "absolute",
|
|
820
883
|
left: "0",
|
|
@@ -832,111 +895,183 @@ var Editor = class {
|
|
|
832
895
|
block: "center",
|
|
833
896
|
inline: "nearest"
|
|
834
897
|
});
|
|
835
|
-
this.#focus({
|
|
898
|
+
if (!noFocus) this.#focus({
|
|
836
899
|
line,
|
|
837
900
|
character: char
|
|
838
901
|
});
|
|
839
|
-
requestAnimationFrame(() => virtualCaret.remove());
|
|
840
902
|
} else {
|
|
841
903
|
const approximateLineY = ((this.#lineAnnotations ?? []).filter((annotation) => annotation.lineNumber < line).length + line) * this.#metrics.lineHeight;
|
|
842
904
|
virtualCaret.style.top = approximateLineY + "px";
|
|
843
|
-
this.#
|
|
905
|
+
this.#fileContainer?.shadowRoot?.appendChild(virtualCaret);
|
|
844
906
|
this.#scrollingToLine = line;
|
|
845
907
|
this.#scrollingToLineChar = char;
|
|
908
|
+
this.#scrollingToLineNoFocus = noFocus;
|
|
846
909
|
virtualCaret.scrollIntoView({
|
|
847
910
|
block: "center",
|
|
848
911
|
inline: "nearest"
|
|
849
912
|
});
|
|
850
|
-
requestAnimationFrame(() => virtualCaret.remove());
|
|
851
913
|
}
|
|
914
|
+
virtualCaret.remove();
|
|
852
915
|
}
|
|
853
|
-
#renderSelection(renderCtx, selection) {
|
|
916
|
+
#renderSelection(renderCtx, selection, type, isFocused) {
|
|
854
917
|
if (this.#textDocument === void 0) return;
|
|
855
918
|
const { start, end } = selection;
|
|
856
|
-
for (let
|
|
857
|
-
if (!this.#isLineVisible(
|
|
858
|
-
const
|
|
859
|
-
const
|
|
860
|
-
const
|
|
919
|
+
for (let line = start.line; line <= end.line; line++) {
|
|
920
|
+
if (!this.#isLineVisible(line)) continue;
|
|
921
|
+
const isLastLine = line === end.line;
|
|
922
|
+
const lineText = this.#textDocument.getLineText(line);
|
|
923
|
+
const startChar = line === start.line ? start.character : 0;
|
|
924
|
+
const endChar = isLastLine ? end.character : lineText.length;
|
|
861
925
|
if (this.#wrap) {
|
|
862
|
-
const paddingInline = this.#metrics.ch;
|
|
863
926
|
const contentWidth = this.#getContentWidth();
|
|
864
|
-
if (2 *
|
|
865
|
-
this.#renderWrappedSelection(renderCtx,
|
|
927
|
+
if (2 * this.#metrics.ch + this.#metrics.measureTextWidth(lineText) > contentWidth) {
|
|
928
|
+
this.#renderWrappedSelection(renderCtx, line, lineText, startChar, endChar, isLastLine, type, isFocused);
|
|
866
929
|
continue;
|
|
867
930
|
}
|
|
868
931
|
}
|
|
869
932
|
let left = 0;
|
|
870
933
|
let width = 0;
|
|
871
|
-
if (startChar ===
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
width = endChar === startChar ? 0 : this.#getCharX(ln, endChar)[0] - left;
|
|
877
|
-
}
|
|
878
|
-
this.#renderSelectionRange(renderCtx, selection, ln, 0, startChar, endChar, width, left);
|
|
934
|
+
if (startChar === 0) left = this.#getGutterWidth() + this.#metrics.ch;
|
|
935
|
+
else left = this.#getCharX(line, startChar)[0];
|
|
936
|
+
if (startChar === endChar) width = isLastLine ? 0 : this.#metrics.ch;
|
|
937
|
+
else width = this.#getCharX(line, endChar)[0] - left + (isLastLine ? 0 : this.#metrics.ch);
|
|
938
|
+
this.#renderSelectionBlock(renderCtx, line, 0, left, width, type, isFocused);
|
|
879
939
|
}
|
|
880
940
|
}
|
|
881
|
-
#renderWrappedSelection(renderCtx,
|
|
941
|
+
#renderWrappedSelection(renderCtx, line, lineText, startChar, endChar, isLastLine, type, isFocused = false) {
|
|
882
942
|
const wrapOffsets = this.#wrapLineText(line);
|
|
883
943
|
const segmentCount = wrapOffsets.length - 1;
|
|
884
|
-
const
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
const
|
|
888
|
-
const segmentEnd = wrapOffsets[w + 1];
|
|
944
|
+
const offsetLeft = this.#getGutterWidth() + this.#metrics.ch;
|
|
945
|
+
for (let wrapLine = 0; wrapLine < segmentCount; wrapLine++) {
|
|
946
|
+
const segmentStart = wrapOffsets[wrapLine];
|
|
947
|
+
const segmentEnd = wrapOffsets[wrapLine + 1];
|
|
889
948
|
const wrapStartChar = Math.max(startChar, segmentStart);
|
|
890
949
|
const wrapEndChar = Math.min(endChar, segmentEnd);
|
|
891
950
|
if (wrapStartChar > wrapEndChar) continue;
|
|
892
|
-
if (wrapStartChar === wrapEndChar) {
|
|
893
|
-
const isAtLineStart = wrapStartChar === 0 && w === 0;
|
|
894
|
-
const isAtLineEnd = wrapEndChar === lineText.length && w === lastSegmentIndex;
|
|
895
|
-
if (!isAtLineStart && !isAtLineEnd) continue;
|
|
896
|
-
}
|
|
897
951
|
let segmentLeft;
|
|
898
952
|
let segmentWidth;
|
|
899
|
-
if (wrapStartChar === 0
|
|
900
|
-
|
|
901
|
-
segmentWidth = line === selection.end.line ? 0 : paddingInline;
|
|
902
|
-
} else {
|
|
953
|
+
if (wrapStartChar === 0) segmentLeft = offsetLeft;
|
|
954
|
+
else {
|
|
903
955
|
const prefixInSegment = lineText.slice(segmentStart, wrapStartChar);
|
|
904
956
|
const prefixAsciiColumns = getExpandedAsciiTextColumns(prefixInSegment, this.#metrics.tabSize);
|
|
905
957
|
segmentLeft = offsetLeft + (prefixAsciiColumns !== -1 ? prefixAsciiColumns * this.#metrics.ch : this.#metrics.measureTextWidth(prefixInSegment));
|
|
906
|
-
if (wrapStartChar === wrapEndChar) segmentWidth = 0;
|
|
907
|
-
else {
|
|
908
|
-
const selectionInSegment = lineText.slice(wrapStartChar, wrapEndChar);
|
|
909
|
-
const selectionAsciiWidth = getExpandedAsciiTextColumns(selectionInSegment, this.#metrics.tabSize);
|
|
910
|
-
segmentWidth = selectionAsciiWidth !== -1 ? selectionAsciiWidth * this.#metrics.ch : this.#metrics.measureTextWidth(selectionInSegment);
|
|
911
|
-
}
|
|
912
958
|
}
|
|
913
|
-
|
|
959
|
+
if (wrapStartChar === wrapEndChar) segmentWidth = wrapLine === segmentCount - 1 ? 0 : this.#metrics.ch;
|
|
960
|
+
else {
|
|
961
|
+
const selectionInSegment = lineText.slice(wrapStartChar, wrapEndChar);
|
|
962
|
+
const selectionAsciiWidth = getExpandedAsciiTextColumns(selectionInSegment, this.#metrics.tabSize);
|
|
963
|
+
segmentWidth = selectionAsciiWidth !== -1 ? selectionAsciiWidth * this.#metrics.ch : this.#metrics.measureTextWidth(selectionInSegment);
|
|
964
|
+
if (!isLastLine && wrapLine === segmentCount - 1) segmentWidth += this.#metrics.ch;
|
|
965
|
+
}
|
|
966
|
+
this.#renderSelectionBlock(renderCtx, line, wrapLine, segmentLeft, segmentWidth, type, isFocused);
|
|
914
967
|
}
|
|
915
968
|
}
|
|
916
|
-
#
|
|
917
|
-
|
|
918
|
-
const
|
|
969
|
+
#renderSelectionBlock(renderCtx, line, wrapLine, left, width, type, isFocused = false) {
|
|
970
|
+
if (width === 0) return;
|
|
971
|
+
const { ch, lineHeight } = this.#metrics;
|
|
972
|
+
const y = this.#getLineY(line) + wrapLine * lineHeight;
|
|
973
|
+
const css = `width:${width}px;transform:translateX(${left}px) translateY(${y}px);`;
|
|
974
|
+
const cacheKey = `${type}-block-${left}-${y}-${width}-${isFocused ? "f" : ""}`;
|
|
919
975
|
const selectionEls = this.#selectionElements;
|
|
920
|
-
|
|
921
|
-
|
|
976
|
+
const rounded = (this.#options.roundedSelection ?? true) && type === "selection";
|
|
977
|
+
const addRoundedCorner = (line$1, wrapLine$1, left$1, radius) => {
|
|
978
|
+
const top = this.#getLineY(line$1) + wrapLine$1 * lineHeight;
|
|
979
|
+
const css$1 = `width:${ch}px;transform:translateX(${left$1}px) translateY(${top}px);`;
|
|
980
|
+
const dataset = {
|
|
981
|
+
selectionCorner: "",
|
|
982
|
+
[radius]: ""
|
|
983
|
+
};
|
|
984
|
+
const cacheKeyPrefix = `${type}-block-${left$1}-${top}-1ch`;
|
|
985
|
+
let cacheKey$1 = cacheKeyPrefix + "-" + radius;
|
|
986
|
+
if (radius === "rbl") {
|
|
987
|
+
const prevCornerKey = cacheKeyPrefix + "-rtl";
|
|
988
|
+
const prevCorner = renderCtx.elements.get(prevCornerKey);
|
|
989
|
+
if (prevCorner !== void 0) {
|
|
990
|
+
prevCorner.remove();
|
|
991
|
+
renderCtx.elements.delete(prevCornerKey);
|
|
992
|
+
cacheKey$1 += "-rtl";
|
|
993
|
+
dataset.rtl = "";
|
|
994
|
+
}
|
|
995
|
+
}
|
|
996
|
+
let cornerEl = renderCtx.elements.get(cacheKey$1);
|
|
997
|
+
if (cornerEl !== void 0) return;
|
|
998
|
+
if (selectionEls?.has(cacheKey$1) === true) {
|
|
999
|
+
cornerEl = selectionEls.get(cacheKey$1);
|
|
1000
|
+
selectionEls.delete(cacheKey$1);
|
|
1001
|
+
} else cornerEl = h("div", {
|
|
1002
|
+
dataset: "selectionRange",
|
|
1003
|
+
style: { cssText: css$1 },
|
|
1004
|
+
children: [h("div", { dataset })]
|
|
1005
|
+
}, renderCtx.fragment);
|
|
1006
|
+
renderCtx.elements.set(cacheKey$1, cornerEl);
|
|
1007
|
+
};
|
|
1008
|
+
const addRadiusStyle = (element) => {
|
|
1009
|
+
const end = left + width;
|
|
1010
|
+
const dataset = element.dataset;
|
|
1011
|
+
const previousSelectionRange = renderCtx.previousSelectionRange;
|
|
1012
|
+
if (previousSelectionRange === void 0 || previousSelectionRange.line !== line || previousSelectionRange.wrapLine !== wrapLine) renderCtx.previousSelectionRange = {
|
|
1013
|
+
element,
|
|
1014
|
+
line,
|
|
1015
|
+
wrapLine,
|
|
1016
|
+
left,
|
|
1017
|
+
width
|
|
1018
|
+
};
|
|
1019
|
+
if (previousSelectionRange === void 0 || end <= previousSelectionRange.left) [
|
|
1020
|
+
"rtl",
|
|
1021
|
+
"rtr",
|
|
1022
|
+
"rbl",
|
|
1023
|
+
"rbr"
|
|
1024
|
+
].forEach((key) => {
|
|
1025
|
+
dataset[key] = "";
|
|
1026
|
+
});
|
|
1027
|
+
else {
|
|
1028
|
+
const prevLine = previousSelectionRange.line;
|
|
1029
|
+
const prevWrapLine = previousSelectionRange.wrapLine;
|
|
1030
|
+
const prevLeft = previousSelectionRange.left;
|
|
1031
|
+
const prevDataset = previousSelectionRange.element.dataset;
|
|
1032
|
+
const prevEnd = prevLeft + previousSelectionRange.width;
|
|
1033
|
+
if (prevLeft > left) addRoundedCorner(prevLine, prevWrapLine, prevLeft - ch, "rbr");
|
|
1034
|
+
delete prevDataset.rbl;
|
|
1035
|
+
delete dataset.rtl;
|
|
1036
|
+
delete dataset.rtr;
|
|
1037
|
+
if (end >= prevEnd) delete prevDataset.rbr;
|
|
1038
|
+
if (end > prevEnd) {
|
|
1039
|
+
addRoundedCorner(prevLine, prevWrapLine, prevEnd, "rbl");
|
|
1040
|
+
dataset.rtr = "";
|
|
1041
|
+
}
|
|
1042
|
+
if (end < prevEnd) addRoundedCorner(line, wrapLine, end, "rtl");
|
|
1043
|
+
if (left < prevLeft) dataset.rtl = "";
|
|
1044
|
+
dataset.rbl = "";
|
|
1045
|
+
dataset.rbr = "";
|
|
1046
|
+
}
|
|
1047
|
+
};
|
|
1048
|
+
let rangeEl = renderCtx.elements.get(cacheKey);
|
|
1049
|
+
if (rangeEl !== void 0) {
|
|
1050
|
+
if (rounded) addRadiusStyle(rangeEl);
|
|
1051
|
+
return;
|
|
1052
|
+
}
|
|
922
1053
|
if (selectionEls?.has(cacheKey) === true) {
|
|
923
1054
|
rangeEl = selectionEls.get(cacheKey);
|
|
924
1055
|
selectionEls.delete(cacheKey);
|
|
925
|
-
} else
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
1056
|
+
} else {
|
|
1057
|
+
rangeEl = h("div", {
|
|
1058
|
+
dataset: type + "Range",
|
|
1059
|
+
style: { cssText: css }
|
|
1060
|
+
}, renderCtx.fragment);
|
|
1061
|
+
if (type === "match" && isFocused === true) rangeEl.dataset.focus = "";
|
|
1062
|
+
}
|
|
1063
|
+
if (rounded) addRadiusStyle(rangeEl);
|
|
929
1064
|
renderCtx.elements.set(cacheKey, rangeEl);
|
|
930
1065
|
}
|
|
931
1066
|
#renderCaret(renderCtx, selection, isPrimary) {
|
|
932
1067
|
const { line, character } = getCaretPosition(selection);
|
|
933
1068
|
if (!this.#isLineVisible(line)) return;
|
|
934
1069
|
const [left, wrapLine] = this.#getCharX(line, character);
|
|
935
|
-
const cacheKey = "caret-" + line + "
|
|
1070
|
+
const cacheKey = "caret-" + line + "/" + wrapLine + ":" + character;
|
|
936
1071
|
if (renderCtx.elements.has(cacheKey)) return;
|
|
937
1072
|
const caretEl = h("div", {
|
|
938
1073
|
dataset: "caret",
|
|
939
|
-
style: { transform: `translateY(${this.#getLineY(line) + wrapLine * this.#metrics.lineHeight}px)
|
|
1074
|
+
style: { transform: `translateX(${left - 1}px) translateY(${this.#getLineY(line) + wrapLine * this.#metrics.lineHeight}px)` }
|
|
940
1075
|
}, renderCtx.fragment);
|
|
941
1076
|
renderCtx.elements.set(cacheKey, caretEl);
|
|
942
1077
|
if (isPrimary) {
|
|
@@ -962,7 +1097,7 @@ var Editor = class {
|
|
|
962
1097
|
cleanUpQuickEdit();
|
|
963
1098
|
const textDocument = this.#textDocument;
|
|
964
1099
|
const renderQuickEdit = this.#options.renderQuickEdit;
|
|
965
|
-
const fileContainer = this.#
|
|
1100
|
+
const fileContainer = this.#fileContainer;
|
|
966
1101
|
if (textDocument === void 0 || renderQuickEdit === void 0 || fileContainer == null) return;
|
|
967
1102
|
const line$1 = selection.end.line;
|
|
968
1103
|
const lineText = textDocument.getLineText(line$1);
|
|
@@ -1001,48 +1136,60 @@ var Editor = class {
|
|
|
1001
1136
|
#renderSearchPanel() {
|
|
1002
1137
|
this.#searchPanel?.cleanup();
|
|
1003
1138
|
const textDocument = this.#textDocument;
|
|
1004
|
-
const preElement = this.#
|
|
1139
|
+
const preElement = this.#fileContainer?.shadowRoot?.querySelector("pre");
|
|
1140
|
+
const selections = this.#selections;
|
|
1005
1141
|
if (textDocument === void 0 || preElement == null) return;
|
|
1006
1142
|
let defaultQuery = "";
|
|
1007
1143
|
let initialMatch = void 0;
|
|
1008
|
-
const selections = this.#selections;
|
|
1009
1144
|
if (selections !== void 0 && selections.length > 0) {
|
|
1010
1145
|
let primarySelection = selections.at(-1);
|
|
1011
1146
|
if (isCollapsedSelection(primarySelection)) {
|
|
1012
1147
|
primarySelection = expandCollapsedSelectionToWord(textDocument, primarySelection);
|
|
1013
1148
|
this.#updateSelections([...selections.slice(0, -1), primarySelection]);
|
|
1014
1149
|
const selectionText = textDocument.getText(primarySelection);
|
|
1015
|
-
if (!selectionText.includes("\n")) {
|
|
1150
|
+
if (selectionText !== "" && !selectionText.includes("\n")) {
|
|
1016
1151
|
defaultQuery = selectionText;
|
|
1017
1152
|
initialMatch = [textDocument.offsetAt(primarySelection.start), textDocument.offsetAt(primarySelection.end)];
|
|
1018
1153
|
}
|
|
1019
1154
|
}
|
|
1020
1155
|
}
|
|
1156
|
+
const scrollToMatch = ([startOffset, endOffset], retainFocus) => {
|
|
1157
|
+
const nextSelection = createSelectionFromAnchorAndFocusOffsets(textDocument, startOffset, endOffset);
|
|
1158
|
+
this.#updateSelections([nextSelection]);
|
|
1159
|
+
this.#scrollToPrimaryCaret(true);
|
|
1160
|
+
this.#retainSearchPanelFocus = retainFocus;
|
|
1161
|
+
};
|
|
1021
1162
|
this.#searchPanel = new SearchPanelWidget({
|
|
1022
1163
|
textDocument,
|
|
1023
1164
|
containerElement: preElement,
|
|
1024
1165
|
defaultQuery,
|
|
1025
1166
|
initialMatch,
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
if (
|
|
1029
|
-
|
|
1030
|
-
this.#updateSelections([
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1167
|
+
scrollToMatch,
|
|
1168
|
+
onUpdate: (allMatches) => {
|
|
1169
|
+
if (allMatches.length === 0) {
|
|
1170
|
+
this.#matches = void 0;
|
|
1171
|
+
this.#updateSelections(this.#selections ?? []);
|
|
1172
|
+
return;
|
|
1173
|
+
}
|
|
1174
|
+
this.#matches = allMatches;
|
|
1175
|
+
const primarySelection = this.#selections?.at(-1);
|
|
1176
|
+
let searchOffset = 0;
|
|
1177
|
+
let nextMatch;
|
|
1178
|
+
if (primarySelection !== void 0) searchOffset = textDocument.offsetAt(primarySelection.start);
|
|
1179
|
+
for (const m of allMatches) if (m[0] >= searchOffset) {
|
|
1180
|
+
nextMatch = m;
|
|
1181
|
+
break;
|
|
1041
1182
|
}
|
|
1183
|
+
if (nextMatch !== void 0) scrollToMatch(nextMatch, true);
|
|
1184
|
+
this.#matches = allMatches;
|
|
1185
|
+
this.#updateSelections(this.#selections ?? []);
|
|
1186
|
+
return nextMatch;
|
|
1042
1187
|
},
|
|
1043
1188
|
onClose: () => {
|
|
1044
1189
|
this.#searchPanel = void 0;
|
|
1045
1190
|
this.#retainSearchPanelFocus = false;
|
|
1191
|
+
this.#matches = void 0;
|
|
1192
|
+
this.#updateSelections(this.#selections ?? []);
|
|
1046
1193
|
}
|
|
1047
1194
|
});
|
|
1048
1195
|
this.#retainSearchPanelFocus = false;
|
|
@@ -1137,17 +1284,15 @@ var Editor = class {
|
|
|
1137
1284
|
this.#rerender(change, newLineAnnotations, renderRange, shouldUpdateBuffer);
|
|
1138
1285
|
if (selections !== void 0) {
|
|
1139
1286
|
this.#updateSelections(selections);
|
|
1140
|
-
this
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
block: "nearest",
|
|
1144
|
-
inline: "nearest"
|
|
1145
|
-
});
|
|
1146
|
-
else if (selections.length > 0) {
|
|
1147
|
-
const pos = getCaretPosition(selections.at(-1));
|
|
1148
|
-
this.#scrollToLine(pos.line, pos.character);
|
|
1149
|
-
}
|
|
1287
|
+
if (this.#primaryCaretElement !== void 0) this.#primaryCaretElement.scrollIntoView({
|
|
1288
|
+
block: "nearest",
|
|
1289
|
+
inline: "nearest"
|
|
1150
1290
|
});
|
|
1291
|
+
else if (selections.length > 0) {
|
|
1292
|
+
const pos = getCaretPosition(selections.at(-1));
|
|
1293
|
+
this.#scrollToLine(pos.line, pos.character);
|
|
1294
|
+
}
|
|
1295
|
+
this.focus({ preventScroll: true });
|
|
1151
1296
|
}
|
|
1152
1297
|
}
|
|
1153
1298
|
#applyChangeToLineAnnotations(change) {
|
|
@@ -1162,17 +1307,17 @@ var Editor = class {
|
|
|
1162
1307
|
#getLineElement(line) {
|
|
1163
1308
|
const contentElement = this.#contentElement;
|
|
1164
1309
|
if (contentElement === void 0) return;
|
|
1165
|
-
if (this.#renderRange !== void 0 && this.#
|
|
1310
|
+
if (this.#renderRange !== void 0 && this.#fileInstanceType === "file") {
|
|
1166
1311
|
const { startingLine } = this.#renderRange;
|
|
1167
1312
|
const { children } = contentElement;
|
|
1168
1313
|
for (let i = line - startingLine; i <= children.length; i++) {
|
|
1169
1314
|
const child = children[i];
|
|
1170
1315
|
const lineNumber = child?.dataset.line;
|
|
1171
1316
|
const lineType = child?.dataset.lineType;
|
|
1172
|
-
if (lineNumber !== void 0 && lineType !== void 0 && isLineEditable(lineType) &&
|
|
1317
|
+
if (lineNumber !== void 0 && lineType !== void 0 && isLineEditable(lineType) && parseInt(lineNumber, 10) === line + 1) return child;
|
|
1173
1318
|
}
|
|
1174
1319
|
}
|
|
1175
|
-
if (this.#
|
|
1320
|
+
if (this.#fileInstanceType === "diff") return contentElement.querySelector(`[data-line="${line + 1}"]:not([data-line-type="change-deletion"])`) ?? void 0;
|
|
1176
1321
|
return contentElement.querySelector(`[data-line="${line + 1}"]`) ?? void 0;
|
|
1177
1322
|
}
|
|
1178
1323
|
#getGutterWidth() {
|
|
@@ -1180,7 +1325,7 @@ var Editor = class {
|
|
|
1180
1325
|
if (gutterElement == null || !(gutterElement instanceof HTMLElement) || !gutterElement.hasAttribute("data-gutter")) return 0;
|
|
1181
1326
|
if (this.#gutterWidthCache === void 0) {
|
|
1182
1327
|
const diffsColumnNumberWidth = this.#contentElement?.parentElement?.style.getPropertyValue("--diffs-column-number-width");
|
|
1183
|
-
if (diffsColumnNumberWidth !== void 0 && diffsColumnNumberWidth.length > 2 && diffsColumnNumberWidth.endsWith("px")) this.#gutterWidthCache =
|
|
1328
|
+
if (diffsColumnNumberWidth !== void 0 && diffsColumnNumberWidth.length > 2 && diffsColumnNumberWidth.endsWith("px")) this.#gutterWidthCache = parseInt(diffsColumnNumberWidth.slice(0, -2), 10);
|
|
1184
1329
|
else this.#gutterWidthCache = gutterElement.offsetWidth;
|
|
1185
1330
|
}
|
|
1186
1331
|
return this.#gutterWidthCache;
|
|
@@ -1189,7 +1334,7 @@ var Editor = class {
|
|
|
1189
1334
|
if (this.#contentElement === void 0) return 0;
|
|
1190
1335
|
if (this.#contentWidthCache === void 0) {
|
|
1191
1336
|
const diffsColumnContentWidth = this.#contentElement.parentElement?.style.getPropertyValue("--diffs-column-content-width");
|
|
1192
|
-
if (diffsColumnContentWidth !== void 0 && diffsColumnContentWidth.length > 2 && diffsColumnContentWidth.endsWith("px")) this.#contentWidthCache =
|
|
1337
|
+
if (diffsColumnContentWidth !== void 0 && diffsColumnContentWidth.length > 2 && diffsColumnContentWidth.endsWith("px")) this.#contentWidthCache = parseFloat(diffsColumnContentWidth.slice(0, -2));
|
|
1193
1338
|
else this.#contentWidthCache = this.#contentElement.offsetWidth;
|
|
1194
1339
|
}
|
|
1195
1340
|
return this.#contentWidthCache;
|