@pierre/diffs 1.3.0-beta.2 → 1.3.0-beta.4
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 +2 -2
- package/dist/components/File.d.ts.map +1 -1
- package/dist/components/File.js +13 -13
- package/dist/components/File.js.map +1 -1
- package/dist/components/FileDiff.d.ts +7 -4
- package/dist/components/FileDiff.d.ts.map +1 -1
- package/dist/components/FileDiff.js +57 -47
- package/dist/components/FileDiff.js.map +1 -1
- package/dist/components/UnresolvedFile.d.ts.map +1 -1
- package/dist/components/UnresolvedFile.js +1 -1
- package/dist/components/VirtualizedFile.d.ts +1 -1
- package/dist/components/VirtualizedFile.d.ts.map +1 -1
- package/dist/components/VirtualizedFile.js +13 -4
- package/dist/components/VirtualizedFile.js.map +1 -1
- package/dist/components/VirtualizedFileDiff.d.ts +2 -1
- package/dist/components/VirtualizedFileDiff.d.ts.map +1 -1
- package/dist/components/VirtualizedFileDiff.js +36 -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/components/VirtulizerDevelopment.d.ts.map +1 -1
- package/dist/editor/editStack.d.ts +1 -1
- package/dist/editor/editor.d.ts +14 -6
- package/dist/editor/editor.d.ts.map +1 -1
- package/dist/editor/editor.js +745 -553
- 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/lineAnnotations.d.ts +2 -1
- package/dist/editor/lineAnnotations.d.ts.map +1 -1
- package/dist/editor/lineAnnotations.js +111 -1
- package/dist/editor/lineAnnotations.js.map +1 -1
- package/dist/editor/marker.d.ts +33 -0
- package/dist/editor/marker.d.ts.map +1 -0
- package/dist/editor/marker.js +185 -0
- package/dist/editor/marker.js.map +1 -0
- package/dist/editor/pieceTable.d.ts +3 -3
- package/dist/editor/pieceTable.d.ts.map +1 -1
- package/dist/editor/pieceTable.js +44 -33
- package/dist/editor/pieceTable.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 +103 -138
- package/dist/editor/searchPanel.js.map +1 -1
- package/dist/editor/selection.d.ts +19 -3
- package/dist/editor/selection.d.ts.map +1 -1
- package/dist/editor/selection.js +196 -39
- package/dist/editor/selection.js.map +1 -1
- package/dist/editor/{quickEdit.d.ts → selectionAction.d.ts} +8 -8
- package/dist/editor/selectionAction.d.ts.map +1 -0
- package/dist/editor/{quickEdit.js → selectionAction.js} +19 -21
- package/dist/editor/selectionAction.js.map +1 -0
- package/dist/editor/sprite.d.ts +8 -0
- package/dist/editor/sprite.d.ts.map +1 -0
- package/dist/editor/sprite.js +45 -0
- package/dist/editor/sprite.js.map +1 -0
- package/dist/editor/textDocument.d.ts +5 -5
- package/dist/editor/textDocument.d.ts.map +1 -1
- package/dist/editor/textDocument.js +9 -9
- 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 +135 -85
- package/dist/editor/tokenzier.js.map +1 -1
- package/dist/editor/utils.d.ts +3 -1
- package/dist/editor/utils.d.ts.map +1 -1
- package/dist/editor/utils.js +16 -1
- package/dist/editor/utils.js.map +1 -1
- package/dist/highlighter/shared_highlighter.js +3 -29
- package/dist/highlighter/shared_highlighter.js.map +1 -1
- package/dist/highlighter/themes/attachResolvedThemes.js +4 -3
- package/dist/highlighter/themes/attachResolvedThemes.js.map +1 -1
- package/dist/highlighter/themes/cleanUpResolvedThemes.js +3 -2
- package/dist/highlighter/themes/cleanUpResolvedThemes.js.map +1 -1
- package/dist/highlighter/themes/constants.d.ts +1 -7
- package/dist/highlighter/themes/constants.d.ts.map +1 -1
- package/dist/highlighter/themes/constants.js +1 -4
- package/dist/highlighter/themes/constants.js.map +1 -1
- package/dist/highlighter/themes/getResolvedOrResolveTheme.js +2 -2
- package/dist/highlighter/themes/getResolvedOrResolveTheme.js.map +1 -1
- package/dist/highlighter/themes/getResolvedThemes.js +2 -8
- package/dist/highlighter/themes/getResolvedThemes.js.map +1 -1
- package/dist/highlighter/themes/hasResolvedThemes.js +2 -3
- package/dist/highlighter/themes/hasResolvedThemes.js.map +1 -1
- package/dist/highlighter/themes/registerCustomCSSVariableTheme.js +1 -1
- package/dist/highlighter/themes/registerCustomTheme.d.ts +5 -3
- package/dist/highlighter/themes/registerCustomTheme.d.ts.map +1 -1
- package/dist/highlighter/themes/registerCustomTheme.js +15 -5
- package/dist/highlighter/themes/registerCustomTheme.js.map +1 -1
- package/dist/highlighter/themes/resolveTheme.js +6 -27
- package/dist/highlighter/themes/resolveTheme.js.map +1 -1
- package/dist/highlighter/themes/resolveThemes.js +5 -12
- package/dist/highlighter/themes/resolveThemes.js.map +1 -1
- package/dist/highlighter/themes/themeResolution.d.ts +8 -0
- package/dist/highlighter/themes/themeResolution.d.ts.map +1 -0
- package/dist/highlighter/themes/themeResolution.js +22 -0
- package/dist/highlighter/themes/themeResolution.js.map +1 -0
- package/dist/highlighter/themes/themeResolver.d.ts +8 -0
- package/dist/highlighter/themes/themeResolver.d.ts.map +1 -0
- package/dist/highlighter/themes/themeResolver.js +8 -0
- package/dist/highlighter/themes/themeResolver.js.map +1 -0
- package/dist/index.d.ts +4 -4
- package/dist/index.js +3 -3
- package/dist/react/index.d.ts +2 -2
- package/dist/react/jsx.d.ts.map +1 -1
- package/dist/react/utils/useFileDiffInstance.js +1 -0
- package/dist/react/utils/useFileDiffInstance.js.map +1 -1
- package/dist/renderers/DiffHunksRenderer.d.ts +4 -1
- package/dist/renderers/DiffHunksRenderer.d.ts.map +1 -1
- package/dist/renderers/DiffHunksRenderer.js +139 -19
- package/dist/renderers/DiffHunksRenderer.js.map +1 -1
- package/dist/renderers/FileRenderer.d.ts +2 -2
- package/dist/renderers/FileRenderer.d.ts.map +1 -1
- package/dist/renderers/FileRenderer.js +5 -5
- package/dist/renderers/FileRenderer.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 +19 -16
- 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/getHighlighterThemeStyles.js +16 -12
- package/dist/utils/getHighlighterThemeStyles.js.map +1 -1
- package/dist/utils/iterateOverDiff.js +147 -182
- package/dist/utils/iterateOverDiff.js.map +1 -1
- package/dist/utils/parsePatchFiles.js +93 -4
- package/dist/utils/parsePatchFiles.js.map +1 -1
- package/dist/utils/updateDiffHunks.d.ts +13 -0
- package/dist/utils/updateDiffHunks.d.ts.map +1 -0
- package/dist/utils/updateDiffHunks.js +171 -0
- package/dist/utils/updateDiffHunks.js.map +1 -0
- package/dist/utils/virtualDiffLayout.d.ts +24 -2
- package/dist/utils/virtualDiffLayout.d.ts.map +1 -1
- package/dist/utils/virtualDiffLayout.js +49 -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 +1021 -314
- package/dist/worker/worker-portable.js.map +1 -1
- package/dist/worker/worker.js +202 -196
- package/dist/worker/worker.js.map +1 -1
- package/package.json +4 -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/editor/quickEdit.d.ts.map +0 -1
- package/dist/editor/quickEdit.js.map +0 -1
- package/dist/worker/wasm-D4DU5jgR.js.map +0 -1
package/dist/editor/editor.js
CHANGED
|
@@ -1,36 +1,30 @@
|
|
|
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
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
4
|
+
import editor_default from "./editor2.js";
|
|
5
|
+
import { addEventListener, clampDomOffset, extend, getLineNumberAttr, h, round } from "./utils.js";
|
|
6
|
+
import { applyDocumentChangeToLineAnnotations, renderLineAnnotations } from "./lineAnnotations.js";
|
|
7
|
+
import { DirectionBackward, DirectionForward, DirectionNone, applyDeleteHardLineForwardToSelections, applyDeleteSoftLineBackwardToSelections, applyDeleteWordBackwardToSelections, 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";
|
|
8
|
+
import { MarkerManager, markerSeverityDatasetKey } from "./marker.js";
|
|
9
|
+
import { createSpriteElement } from "./sprite.js";
|
|
10
10
|
import { SearchPanelWidget } from "./searchPanel.js";
|
|
11
|
+
import { SelectionActionWidget } from "./selectionAction.js";
|
|
12
|
+
import { TextDocument } from "./textDocument.js";
|
|
11
13
|
import { Metrics, getExpandedAsciiTextColumns, getUnicodeMeasurementOffsets, snapTextOffsetToUnicodeBoundary } from "./textMeasure.js";
|
|
12
14
|
import { EditorTokenizer, renderLineTokens } from "./tokenzier.js";
|
|
13
15
|
|
|
14
16
|
//#region src/editor/editor.ts
|
|
15
|
-
function clampDomOffset(node, offset) {
|
|
16
|
-
if (node.nodeType === 3) {
|
|
17
|
-
const length = node.textContent?.length ?? 0;
|
|
18
|
-
return Math.max(0, Math.min(offset, length));
|
|
19
|
-
}
|
|
20
|
-
if (node.nodeType === 1) return Math.max(0, Math.min(offset, node.childNodes.length));
|
|
21
|
-
return 0;
|
|
22
|
-
}
|
|
23
17
|
var Editor = class {
|
|
24
18
|
#options;
|
|
25
|
-
#editMode = "simple";
|
|
26
19
|
#wrap = false;
|
|
27
20
|
#metrics = new Metrics();
|
|
28
21
|
#tokenizer;
|
|
22
|
+
#markerManager;
|
|
29
23
|
#editorEventDisposes;
|
|
30
24
|
#globalEventDisposes;
|
|
31
|
-
#
|
|
25
|
+
#selectEventDisposes;
|
|
32
26
|
#detach;
|
|
33
|
-
#
|
|
27
|
+
#fileInstance;
|
|
34
28
|
#fileContents;
|
|
35
29
|
#lineAnnotations;
|
|
36
30
|
#textDocument;
|
|
@@ -40,16 +34,19 @@ var Editor = class {
|
|
|
40
34
|
#contentWidthCache;
|
|
41
35
|
#lineYCache = /* @__PURE__ */ new Map();
|
|
42
36
|
#wrapLineOffsetsCache = /* @__PURE__ */ new Map();
|
|
43
|
-
#
|
|
37
|
+
#lastAccessedLineElement;
|
|
38
|
+
#lastAccessedCharX;
|
|
44
39
|
#globalStyleElement;
|
|
45
40
|
#editorStyleElement;
|
|
46
41
|
#themeStyleElement;
|
|
47
|
-
#
|
|
42
|
+
#spriteElement;
|
|
43
|
+
#fileContainer;
|
|
44
|
+
#gutterElement;
|
|
48
45
|
#contentElement;
|
|
49
46
|
#overlayElement;
|
|
50
47
|
#primaryCaretElement;
|
|
51
|
-
#
|
|
52
|
-
#
|
|
48
|
+
#overlayElements;
|
|
49
|
+
#selectionAction;
|
|
53
50
|
#searchPanel;
|
|
54
51
|
#resizeObserver;
|
|
55
52
|
#shouldIgnoreSelectionChange = false;
|
|
@@ -60,14 +57,13 @@ var Editor = class {
|
|
|
60
57
|
#reservedSelections;
|
|
61
58
|
#selections;
|
|
62
59
|
#initSelections;
|
|
60
|
+
#matches;
|
|
63
61
|
#scrollingToLine;
|
|
64
62
|
#scrollingToLineChar;
|
|
63
|
+
#scrollingToLineNoFocus = false;
|
|
65
64
|
#retainSearchPanelFocus = false;
|
|
66
|
-
#emitChange = debounce((fileContents, lineAnnotations) => {
|
|
67
|
-
this.#options.onChange?.(fileContents, lineAnnotations);
|
|
68
|
-
}, 500);
|
|
69
65
|
#onDeferTokenize = (lines, themeType) => {
|
|
70
|
-
this.#
|
|
66
|
+
this.#fileInstance?.updateRenderCache(lines, themeType);
|
|
71
67
|
if (this.#renderRange !== void 0 && this.#renderRange.totalLines !== Infinity) {
|
|
72
68
|
const { startingLine, totalLines } = this.#renderRange;
|
|
73
69
|
const endLine = Math.min(startingLine + totalLines, this.#textDocument?.lineCount ?? 0);
|
|
@@ -81,143 +77,52 @@ var Editor = class {
|
|
|
81
77
|
this.#options = options;
|
|
82
78
|
}
|
|
83
79
|
edit(component) {
|
|
84
|
-
const { useTokenTransformer, enableGutterUtility, enableLineSelection, expandUnchanged, lineHoverHighlight,...rest } = component.options;
|
|
85
|
-
if (useTokenTransformer !== true || enableGutterUtility === true || enableLineSelection === true || expandUnchanged !== true && Object.hasOwn(component, "fileDiff") || lineHoverHighlight !== "disabled") {
|
|
80
|
+
const { useTokenTransformer, enableGutterUtility, enableLineSelection, expandUnchanged, diffStyle, lineHoverHighlight,...rest } = component.options;
|
|
81
|
+
if (useTokenTransformer !== true || enableGutterUtility === true || enableLineSelection === true || expandUnchanged !== true && Object.hasOwn(component, "fileDiff") || diffStyle === "unified" || lineHoverHighlight !== "disabled") {
|
|
86
82
|
component.setOptions({
|
|
87
83
|
...rest,
|
|
88
84
|
useTokenTransformer: true,
|
|
89
85
|
enableGutterUtility: false,
|
|
90
86
|
enableLineSelection: false,
|
|
91
87
|
expandUnchanged: true,
|
|
88
|
+
diffStyle: "split",
|
|
92
89
|
lineHoverHighlight: "disabled"
|
|
93
90
|
});
|
|
94
91
|
component.rerender();
|
|
95
92
|
}
|
|
96
|
-
this.#
|
|
93
|
+
this.#fileInstance = component;
|
|
97
94
|
this.#initialize();
|
|
98
95
|
this.#detach = component.attachEditor(this);
|
|
99
96
|
return () => this.cleanUp();
|
|
100
97
|
}
|
|
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) {
|
|
98
|
+
syncToRenderedView(highlighter, fileContainer, fileContents, didFileChange, lineAnnotations, renderRange) {
|
|
173
99
|
const shadowRoot = fileContainer.shadowRoot;
|
|
174
100
|
if (shadowRoot == null) {
|
|
175
101
|
console.error("[editor] Could not find the shadow root.");
|
|
176
102
|
return;
|
|
177
103
|
}
|
|
178
104
|
let codeElement;
|
|
105
|
+
let gutterEl;
|
|
106
|
+
let contentEl;
|
|
179
107
|
for (const el of shadowRoot.querySelectorAll("[data-code]")) if (el.dataset.deletions === void 0) {
|
|
180
108
|
codeElement = el;
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
this.#editMode = editMode ?? "simple";
|
|
187
|
-
this.#wrap = this.#component?.options.overflow === "wrap";
|
|
188
|
-
if (editMode === "advanced" || (lineAnnotations?.length ?? 0) > 0) {
|
|
189
|
-
let startingLine;
|
|
190
|
-
let endLine;
|
|
191
|
-
for (const child of contentEl.children) {
|
|
192
|
-
const el = child;
|
|
193
|
-
const line = el.dataset.line;
|
|
194
|
-
const lineType = el.dataset.lineType;
|
|
195
|
-
if (line !== void 0) {
|
|
196
|
-
const lineIndex = Number(line) - 1;
|
|
197
|
-
startingLine ??= lineIndex;
|
|
198
|
-
endLine = lineIndex;
|
|
199
|
-
}
|
|
200
|
-
if (lineType === void 0 || !isLineEditable(lineType)) el.contentEditable = "false";
|
|
201
|
-
}
|
|
202
|
-
if (endLine !== void 0 && renderRange !== void 0) {
|
|
203
|
-
const { startingLine: startingLine$1, totalLines } = renderRange;
|
|
204
|
-
endLine = Math.max(endLine, startingLine$1 + totalLines);
|
|
109
|
+
for (const child of el.children) {
|
|
110
|
+
const el$1 = child;
|
|
111
|
+
const { gutter, content } = el$1.dataset;
|
|
112
|
+
if (gutter !== void 0) gutterEl = el$1;
|
|
113
|
+
else if (content !== void 0) contentEl = el$1;
|
|
205
114
|
}
|
|
206
|
-
|
|
207
|
-
startingLine,
|
|
208
|
-
totalLines: endLine - startingLine,
|
|
209
|
-
bufferBefore: 0,
|
|
210
|
-
bufferAfter: 0
|
|
211
|
-
};
|
|
115
|
+
break;
|
|
212
116
|
}
|
|
213
|
-
if (
|
|
214
|
-
|
|
215
|
-
this.#
|
|
117
|
+
if (codeElement === void 0 || contentEl === void 0) return;
|
|
118
|
+
if (this.#fileContainer !== fileContainer) {
|
|
119
|
+
this.#fileContainer = fileContainer;
|
|
216
120
|
if (this.#globalStyleElement !== void 0) fileContainer.appendChild(this.#globalStyleElement);
|
|
217
121
|
if (this.#editorStyleElement !== void 0) shadowRoot.appendChild(this.#editorStyleElement);
|
|
218
122
|
if (this.#themeStyleElement !== void 0) shadowRoot.appendChild(this.#themeStyleElement);
|
|
123
|
+
if (this.#spriteElement !== void 0) shadowRoot.prepend(this.#spriteElement);
|
|
219
124
|
}
|
|
220
|
-
if (this.#textDocument === void 0 || this.#fileContents === void 0 ||
|
|
125
|
+
if (this.#textDocument === void 0 || this.#fileContents === void 0 || didFileChange) {
|
|
221
126
|
const textDocument = new TextDocument(fileContents.name, fileContents.contents, fileContents.lang ?? getFiletypeFromFileName(fileContents.name));
|
|
222
127
|
this.#fileContents = fileContents;
|
|
223
128
|
this.#textDocument = textDocument;
|
|
@@ -225,32 +130,33 @@ var Editor = class {
|
|
|
225
130
|
this.#tokenizer = new EditorTokenizer({
|
|
226
131
|
highlighter,
|
|
227
132
|
textDocument,
|
|
228
|
-
codeOptions: this.#
|
|
133
|
+
codeOptions: this.#fileInstance?.options ?? {},
|
|
229
134
|
onDeferTokenize: this.#onDeferTokenize,
|
|
230
135
|
setStyle: (css) => {
|
|
231
136
|
this.#themeStyleElement.textContent = css;
|
|
232
|
-
}
|
|
137
|
+
},
|
|
138
|
+
__debug: this.#options.__debug
|
|
233
139
|
});
|
|
140
|
+
this.#fileInstance?.setSelectedLines(null);
|
|
234
141
|
this.#shouldIgnoreSelectionChange = false;
|
|
235
|
-
this.#
|
|
236
|
-
this.#
|
|
237
|
-
this.#
|
|
238
|
-
this.#selectionElements = void 0;
|
|
142
|
+
this.#overlayElements?.forEach((el) => el.remove());
|
|
143
|
+
this.#overlayElements?.clear();
|
|
144
|
+
this.#overlayElements = void 0;
|
|
239
145
|
this.#selections = void 0;
|
|
240
146
|
this.#scrollingToLine = void 0;
|
|
241
147
|
this.#reservedSelections = void 0;
|
|
242
148
|
this.#searchPanel?.cleanup();
|
|
243
149
|
this.#searchPanel = void 0;
|
|
244
|
-
this.#
|
|
245
|
-
this.#
|
|
150
|
+
this.#selectionAction?.cleanup();
|
|
151
|
+
this.#selectionAction = void 0;
|
|
246
152
|
}
|
|
247
153
|
if (this.#contentElement !== contentEl) {
|
|
248
|
-
|
|
249
|
-
const
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
this.#
|
|
154
|
+
if (this.#contentElement !== void 0 && this.#options.__debug === true) console.log("[diffs/editor] full re-render triggered !!!");
|
|
155
|
+
const codePaddingTop = parseInt(getComputedStyle(codeElement).paddingTop.slice(0, -2), 10);
|
|
156
|
+
this.#codePaddingTop = Number.isNaN(codePaddingTop) ? 0 : codePaddingTop;
|
|
157
|
+
this.#gutterWidthCache = void 0;
|
|
158
|
+
this.#contentWidthCache = void 0;
|
|
159
|
+
this.#gutterElement = gutterEl;
|
|
254
160
|
this.#contentElement = extend(contentEl, {
|
|
255
161
|
contentEditable: "true",
|
|
256
162
|
role: "textbox",
|
|
@@ -262,204 +168,159 @@ var Editor = class {
|
|
|
262
168
|
translate: false
|
|
263
169
|
});
|
|
264
170
|
if (this.#overlayElement !== void 0) contentEl.after(this.#overlayElement);
|
|
265
|
-
this.#
|
|
266
|
-
this.#
|
|
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);
|
|
171
|
+
this.#metrics.init(contentEl);
|
|
172
|
+
this.#listenContentElement(contentEl, gutterEl);
|
|
419
173
|
}
|
|
420
174
|
this.#lineYCache.clear();
|
|
421
175
|
this.#wrapLineOffsetsCache.clear();
|
|
422
|
-
this.#
|
|
176
|
+
this.#lastAccessedLineElement = void 0;
|
|
177
|
+
this.#lastAccessedCharX = void 0;
|
|
178
|
+
this.#wrap = this.#fileInstance?.options.overflow === "wrap";
|
|
423
179
|
this.#lineAnnotations = lineAnnotations;
|
|
424
180
|
this.#renderRange = renderRange;
|
|
425
|
-
this.#tokenizer?.
|
|
181
|
+
this.#tokenizer?.prebuildStateStack(renderRange);
|
|
426
182
|
if (this.#initSelections !== void 0) {
|
|
427
183
|
this.setSelections(this.#initSelections);
|
|
428
184
|
this.#scrollToPrimaryCaret();
|
|
429
185
|
this.#initSelections = void 0;
|
|
430
|
-
} else if (this.#selections !== void 0
|
|
186
|
+
} else if (this.#selections !== void 0 || this.#matches !== void 0 || this.#markerManager !== void 0) this.#updateSelections(this.#selections ?? []);
|
|
431
187
|
if (this.#options.__debug === true && renderRange !== void 0) {
|
|
432
188
|
const { startingLine, totalLines } = renderRange;
|
|
433
189
|
console.log("[diffs/editor] render file:", fileContents.name, "RenderRange:", startingLine + "-" + (startingLine + totalLines), "of", this.#textDocument.lineCount, "lines");
|
|
434
190
|
}
|
|
435
|
-
if (this.#scrollingToLine !== void 0)
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
191
|
+
if (this.#scrollingToLine !== void 0) this.#scrollToLine(this.#scrollingToLine, this.#scrollingToLineChar, this.#scrollingToLineNoFocus);
|
|
192
|
+
else if (this.#selections !== void 0 && this.#selections.length > 0 && !this.#retainSearchPanelFocus) this.focus({ preventScroll: true });
|
|
193
|
+
if (this.#retainSearchPanelFocus) this.#searchPanel?.focus();
|
|
194
|
+
if (this.#selectionAction !== void 0 && this.#isLineVisible(this.#selectionAction.line) && this.#contentElement !== void 0) this.#selectionAction.render(this.#contentElement);
|
|
195
|
+
}
|
|
196
|
+
postponeBackgroundTokenizeToNextFrame() {
|
|
197
|
+
const tokenizer = this.#tokenizer;
|
|
198
|
+
if (tokenizer !== void 0) {
|
|
199
|
+
tokenizer.pauseBackgroundTokenize();
|
|
442
200
|
requestAnimationFrame(() => {
|
|
443
|
-
|
|
201
|
+
tokenizer.resumeBackgroundTokenize();
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
setSelections(selections) {
|
|
206
|
+
const textDocument = this.#textDocument;
|
|
207
|
+
if (textDocument !== void 0) {
|
|
208
|
+
const resolvedSelections = selections.map((selection) => {
|
|
209
|
+
const start = textDocument.normalizePosition(selection.start);
|
|
210
|
+
const end = textDocument.normalizePosition(selection.end);
|
|
211
|
+
return {
|
|
212
|
+
direction: selection.direction === "none" ? DirectionNone : selection.direction === "backward" ? DirectionBackward : DirectionForward,
|
|
213
|
+
start,
|
|
214
|
+
end
|
|
215
|
+
};
|
|
444
216
|
});
|
|
217
|
+
this.#updateSelections(resolvedSelections);
|
|
218
|
+
this.#scrollToPrimaryCaret();
|
|
219
|
+
} else this.#initSelections = selections;
|
|
220
|
+
}
|
|
221
|
+
setMarkers(markers) {
|
|
222
|
+
const textDocument = this.#textDocument;
|
|
223
|
+
if (textDocument === void 0) throw new Error("Text document is not initialized");
|
|
224
|
+
if (markers.length === 0) {
|
|
225
|
+
this.#markerManager?.cleanup();
|
|
226
|
+
this.#markerManager = void 0;
|
|
227
|
+
this.#updateSelections(this.#selections ?? []);
|
|
228
|
+
return;
|
|
445
229
|
}
|
|
446
|
-
|
|
230
|
+
this.#markerManager ??= new MarkerManager({
|
|
231
|
+
getLineHeight: () => this.#metrics.lineHeight,
|
|
232
|
+
getFileContainer: () => this.#fileContainer,
|
|
233
|
+
getCharX: (line, character) => this.#getCharX(line, character),
|
|
234
|
+
getLineY: (line) => this.#getLineY(line),
|
|
235
|
+
isMouseDown: () => this.#isContentMouseDown || this.#isGutterMouseDown
|
|
236
|
+
});
|
|
237
|
+
this.#markerManager.setMarkers(markers, textDocument);
|
|
238
|
+
if (this.#contentElement !== void 0) this.#markerManager.listenHover(this.#contentElement);
|
|
239
|
+
this.#updateSelections(this.#selections ?? []);
|
|
240
|
+
}
|
|
241
|
+
focus(options) {
|
|
242
|
+
const preventScroll = options?.preventScroll ?? false;
|
|
243
|
+
const primarySelection = this.#selections?.at(-1);
|
|
244
|
+
if (primarySelection !== void 0) {
|
|
245
|
+
const pos = primarySelection.direction === DirectionBackward ? primarySelection.end : primarySelection.start;
|
|
246
|
+
this.#focus(pos, preventScroll);
|
|
247
|
+
} else this.#focus(void 0, preventScroll);
|
|
248
|
+
}
|
|
249
|
+
cleanUp() {
|
|
250
|
+
this.#tokenizer?.cleanUp();
|
|
251
|
+
this.#tokenizer = void 0;
|
|
252
|
+
this.#globalEventDisposes?.forEach((dispose) => dispose());
|
|
253
|
+
this.#globalEventDisposes = void 0;
|
|
254
|
+
this.#editorEventDisposes?.forEach((dispose) => dispose());
|
|
255
|
+
this.#editorEventDisposes = void 0;
|
|
256
|
+
this.#selectEventDisposes?.forEach((dispose) => dispose());
|
|
257
|
+
this.#selectEventDisposes = void 0;
|
|
258
|
+
this.#markerManager?.cleanup();
|
|
259
|
+
this.#markerManager = void 0;
|
|
260
|
+
this.#detach?.();
|
|
261
|
+
this.#detach = void 0;
|
|
262
|
+
this.#fileInstance?.setSelectedLines(null);
|
|
263
|
+
this.#fileInstance = void 0;
|
|
264
|
+
this.#fileContents = void 0;
|
|
265
|
+
this.#lineAnnotations = void 0;
|
|
266
|
+
this.#textDocument = void 0;
|
|
267
|
+
this.#renderRange = void 0;
|
|
268
|
+
this.#gutterWidthCache = void 0;
|
|
269
|
+
this.#contentWidthCache = void 0;
|
|
270
|
+
this.#lineYCache.clear();
|
|
271
|
+
this.#wrapLineOffsetsCache.clear();
|
|
272
|
+
this.#lastAccessedLineElement = void 0;
|
|
273
|
+
this.#lastAccessedCharX = void 0;
|
|
274
|
+
this.#globalStyleElement?.remove();
|
|
275
|
+
this.#globalStyleElement = void 0;
|
|
276
|
+
this.#editorStyleElement?.remove();
|
|
277
|
+
this.#editorStyleElement = void 0;
|
|
278
|
+
this.#themeStyleElement?.remove();
|
|
279
|
+
this.#themeStyleElement = void 0;
|
|
280
|
+
this.#spriteElement?.remove();
|
|
281
|
+
this.#spriteElement = void 0;
|
|
282
|
+
this.#fileContainer = void 0;
|
|
283
|
+
this.#gutterElement = void 0;
|
|
284
|
+
this.#contentElement?.removeAttribute("contentEditable");
|
|
285
|
+
this.#contentElement = void 0;
|
|
286
|
+
this.#overlayElement?.remove();
|
|
287
|
+
this.#overlayElement = void 0;
|
|
288
|
+
this.#overlayElements?.forEach((el) => el.remove());
|
|
289
|
+
this.#overlayElements = void 0;
|
|
290
|
+
this.#primaryCaretElement = void 0;
|
|
291
|
+
this.#searchPanel?.cleanup();
|
|
292
|
+
this.#searchPanel = void 0;
|
|
293
|
+
this.#selectionAction?.cleanup();
|
|
294
|
+
this.#selectionAction = void 0;
|
|
295
|
+
this.#resizeObserver?.disconnect();
|
|
296
|
+
this.#resizeObserver = void 0;
|
|
297
|
+
this.#shouldIgnoreSelectionChange = false;
|
|
298
|
+
this.#selectionStart = void 0;
|
|
299
|
+
this.#selections = void 0;
|
|
300
|
+
this.#reservedSelections = void 0;
|
|
447
301
|
}
|
|
448
302
|
#initialize() {
|
|
303
|
+
this.#globalStyleElement = h("style", {
|
|
304
|
+
dataset: "editorGlobalCss",
|
|
305
|
+
textContent: `
|
|
306
|
+
[data-annotation-slot] {
|
|
307
|
+
user-select: none;
|
|
308
|
+
-webkit-user-select: none;
|
|
309
|
+
}
|
|
310
|
+
`
|
|
311
|
+
});
|
|
449
312
|
this.#editorStyleElement = h("style", {
|
|
450
313
|
dataset: "editorCss",
|
|
451
|
-
textContent:
|
|
314
|
+
textContent: editor_default
|
|
452
315
|
});
|
|
453
316
|
this.#themeStyleElement = h("style", { dataset: "editorThemeCss" });
|
|
454
|
-
this.#
|
|
455
|
-
dataset: "editorGlobalCss",
|
|
456
|
-
textContent: editorGlobalCSS
|
|
457
|
-
});
|
|
317
|
+
this.#spriteElement = createSpriteElement();
|
|
458
318
|
this.#overlayElement = h("div", { dataset: "editorOverlay" });
|
|
459
319
|
this.#globalEventDisposes = [
|
|
460
320
|
addEventListener(document, "selectionchange", () => {
|
|
461
|
-
const shadowRoot = this.#
|
|
321
|
+
const shadowRoot = this.#fileContainer?.shadowRoot;
|
|
462
322
|
if (this.#shouldIgnoreSelectionChange || shadowRoot == null) return;
|
|
323
|
+
if (this.#selections !== void 0 && this.#selections.length > 1 && !this.#isContentMouseDown) return;
|
|
463
324
|
const composedRange = document.getSelection()?.getComposedRanges({ shadowRoots: [shadowRoot] })?.[0];
|
|
464
325
|
if (composedRange === void 0 || !this.#rangeBelongsToEditor(composedRange)) return;
|
|
465
326
|
let selection = convertSelection(composedRange, DirectionNone);
|
|
@@ -477,8 +338,8 @@ var Editor = class {
|
|
|
477
338
|
}, { passive: true }),
|
|
478
339
|
addEventListener(document, "pointerup", (e) => {
|
|
479
340
|
if (e.pointerType !== "mouse") return;
|
|
480
|
-
this.#
|
|
481
|
-
this.#
|
|
341
|
+
this.#selectEventDisposes?.forEach((dispose) => dispose());
|
|
342
|
+
this.#selectEventDisposes = void 0;
|
|
482
343
|
if (this.#isGutterMouseDown) {
|
|
483
344
|
this.#isGutterMouseDown = false;
|
|
484
345
|
this.#focus();
|
|
@@ -488,8 +349,8 @@ var Editor = class {
|
|
|
488
349
|
this.#shiftKeyPressed = false;
|
|
489
350
|
this.#selectionStart = void 0;
|
|
490
351
|
this.#reservedSelections = void 0;
|
|
491
|
-
this.#
|
|
492
|
-
if (key.startsWith("
|
|
352
|
+
this.#overlayElements?.forEach((el, key) => {
|
|
353
|
+
if (key.startsWith("selectionActionIcon-")) el.dataset.visible = "true";
|
|
493
354
|
});
|
|
494
355
|
}, { passive: true }),
|
|
495
356
|
addEventListener(document, "keydown", (e) => {
|
|
@@ -500,6 +361,176 @@ var Editor = class {
|
|
|
500
361
|
}, { passive: true })
|
|
501
362
|
];
|
|
502
363
|
}
|
|
364
|
+
#listenContentElement(contentEl, gutterEl) {
|
|
365
|
+
const targetIsContentElement = (e) => {
|
|
366
|
+
const target = e.composedPath()[0];
|
|
367
|
+
return target !== void 0 && (target === contentEl || contentEl.contains(target));
|
|
368
|
+
};
|
|
369
|
+
this.#editorEventDisposes?.forEach((dispose) => dispose());
|
|
370
|
+
this.#editorEventDisposes = [
|
|
371
|
+
addEventListener(contentEl, "pointerdown", (e) => {
|
|
372
|
+
if (e.pointerType !== "mouse") return;
|
|
373
|
+
this.#markerManager?.removePopup();
|
|
374
|
+
if (isSafari() && this.#lineAnnotations !== void 0 && this.#lineAnnotations.length > 0) this.#selectEventDisposes = [...contentEl.querySelectorAll("[data-line-annotation]")].map((el) => [addEventListener(el, "mouseenter", () => {
|
|
375
|
+
this.#shouldIgnoreSelectionChange = true;
|
|
376
|
+
}), addEventListener(el, "mouseleave", () => {
|
|
377
|
+
this.#shouldIgnoreSelectionChange = false;
|
|
378
|
+
})]).flat();
|
|
379
|
+
this.#isContentMouseDown = true;
|
|
380
|
+
this.#selectionStart = void 0;
|
|
381
|
+
if (e.button === 0 && isPrimaryModifier(e)) this.#reservedSelections = this.#selections?.map((selection) => ({ ...selection }));
|
|
382
|
+
if (e.shiftKey) {
|
|
383
|
+
const primarySelection = this.#selections?.at(-1);
|
|
384
|
+
if (primarySelection !== void 0) {
|
|
385
|
+
const pos = primarySelection.direction === DirectionBackward ? primarySelection.end : primarySelection.start;
|
|
386
|
+
this.#setWindowSelection({
|
|
387
|
+
start: pos,
|
|
388
|
+
end: pos,
|
|
389
|
+
direction: DirectionNone
|
|
390
|
+
});
|
|
391
|
+
}
|
|
392
|
+
this.#shiftKeyPressed = true;
|
|
393
|
+
}
|
|
394
|
+
}, { passive: true }),
|
|
395
|
+
addEventListener(contentEl, "keydown", (e) => {
|
|
396
|
+
if (e.key === "Escape") {
|
|
397
|
+
e.preventDefault();
|
|
398
|
+
this.#searchPanel?.cleanup();
|
|
399
|
+
this.#searchPanel = void 0;
|
|
400
|
+
this.#retainSearchPanelFocus = false;
|
|
401
|
+
this.#selectionAction?.cleanup();
|
|
402
|
+
this.#selectionAction = void 0;
|
|
403
|
+
if (this.#selections !== void 0 && this.#selections.length > 0) {
|
|
404
|
+
const primarySelection = this.#selections.at(-1);
|
|
405
|
+
if (!isCollapsedSelection(primarySelection) || this.#selections.length > 1) {
|
|
406
|
+
const pos = getCaretPosition(primarySelection);
|
|
407
|
+
this.#updateSelections([{
|
|
408
|
+
start: pos,
|
|
409
|
+
end: pos,
|
|
410
|
+
direction: DirectionNone
|
|
411
|
+
}]);
|
|
412
|
+
this.#focus(pos);
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
return;
|
|
416
|
+
}
|
|
417
|
+
if (!targetIsContentElement(e)) return;
|
|
418
|
+
const mvShortcut = isMoveCursorShortcut(e);
|
|
419
|
+
const textDocument = this.#textDocument;
|
|
420
|
+
if (this.#selections !== void 0 && this.#selections.length > 0 && mvShortcut !== void 0 && textDocument !== void 0) {
|
|
421
|
+
if (e.shiftKey) this.#updateSelections(mapSelectionShift(textDocument, this.#selections, mvShortcut));
|
|
422
|
+
else this.#updateSelections(mapCursorMove(textDocument, this.#selections, mvShortcut));
|
|
423
|
+
this.#scrollToPrimaryCaret();
|
|
424
|
+
e.preventDefault();
|
|
425
|
+
return;
|
|
426
|
+
}
|
|
427
|
+
const command = resolveEditorCommandFromKeyboardEvent(e);
|
|
428
|
+
if (command !== void 0) {
|
|
429
|
+
e.preventDefault();
|
|
430
|
+
this.#runCommand(command);
|
|
431
|
+
}
|
|
432
|
+
}),
|
|
433
|
+
addEventListener(contentEl, "copy", (e) => {
|
|
434
|
+
if (!targetIsContentElement(e)) return;
|
|
435
|
+
e.preventDefault();
|
|
436
|
+
e.clipboardData?.setData("text", this.#getSelectionText());
|
|
437
|
+
}),
|
|
438
|
+
addEventListener(contentEl, "cut", (e) => {
|
|
439
|
+
if (!targetIsContentElement(e)) return;
|
|
440
|
+
e.preventDefault();
|
|
441
|
+
e.clipboardData?.setData("text", this.#getSelectionText());
|
|
442
|
+
this.#replaceSelectionText("");
|
|
443
|
+
}),
|
|
444
|
+
addEventListener(contentEl, "paste", (e) => {
|
|
445
|
+
if (!targetIsContentElement(e)) return;
|
|
446
|
+
e.preventDefault();
|
|
447
|
+
const text = e.clipboardData?.getData("text");
|
|
448
|
+
if (text !== void 0) this.#replaceSelectionText(text);
|
|
449
|
+
}),
|
|
450
|
+
addEventListener(contentEl, "beforeinput", (e) => {
|
|
451
|
+
if (!targetIsContentElement(e)) return;
|
|
452
|
+
e.preventDefault();
|
|
453
|
+
this.#handleInput(e.inputType, e.data);
|
|
454
|
+
}),
|
|
455
|
+
addEventListener(contentEl, "drop", (e) => {
|
|
456
|
+
if (!targetIsContentElement(e)) return;
|
|
457
|
+
e.preventDefault();
|
|
458
|
+
}),
|
|
459
|
+
addEventListener(contentEl, "compositionstart", (e) => {
|
|
460
|
+
if (!targetIsContentElement(e)) return;
|
|
461
|
+
this.#shouldIgnoreSelectionChange = true;
|
|
462
|
+
}, { passive: true }),
|
|
463
|
+
addEventListener(contentEl, "compositionend", (e) => {
|
|
464
|
+
if (!targetIsContentElement(e)) return;
|
|
465
|
+
this.#shouldIgnoreSelectionChange = false;
|
|
466
|
+
this.#handleInput("insertText", e.data);
|
|
467
|
+
}, { passive: true })
|
|
468
|
+
];
|
|
469
|
+
if (gutterEl !== void 0) {
|
|
470
|
+
const resolveGutterTarget = (eventTarget, includeContentLine = false) => {
|
|
471
|
+
let target = eventTarget;
|
|
472
|
+
if (target?.dataset.lineNumberContent !== void 0) target = target.parentElement ?? void 0;
|
|
473
|
+
else if (includeContentLine && target?.tagName === "SPAN") target = target.closest("[data-line]");
|
|
474
|
+
return target;
|
|
475
|
+
};
|
|
476
|
+
const resolveEditableLine = (target) => {
|
|
477
|
+
if (target === void 0) return;
|
|
478
|
+
const lineType = target.dataset.lineType;
|
|
479
|
+
const lineNumber = getLineNumberAttr(target) ?? getLineNumberAttr(target, "columnNumber");
|
|
480
|
+
if (lineNumber === void 0 || lineType === void 0 || !isLineEditable(lineType)) return;
|
|
481
|
+
return lineNumber - 1;
|
|
482
|
+
};
|
|
483
|
+
this.#editorEventDisposes.push(addEventListener(gutterEl, "pointerdown", (e) => {
|
|
484
|
+
const textDocument = this.#textDocument;
|
|
485
|
+
const lineIndex = resolveEditableLine(resolveGutterTarget(e.composedPath()[0]));
|
|
486
|
+
if (lineIndex === void 0 || textDocument === void 0) return;
|
|
487
|
+
this.#markerManager?.removePopup();
|
|
488
|
+
const selection = {
|
|
489
|
+
start: {
|
|
490
|
+
line: lineIndex,
|
|
491
|
+
character: 0
|
|
492
|
+
},
|
|
493
|
+
end: {
|
|
494
|
+
line: lineIndex,
|
|
495
|
+
character: textDocument.getLineText(lineIndex).length
|
|
496
|
+
},
|
|
497
|
+
direction: DirectionForward
|
|
498
|
+
};
|
|
499
|
+
this.#isGutterMouseDown = true;
|
|
500
|
+
this.#selectionStart = selection;
|
|
501
|
+
this.#updateSelections([selection]);
|
|
502
|
+
this.#focus(selection.end);
|
|
503
|
+
this.#selectEventDisposes = [addEventListener(document, "mousemove", (e$1) => {
|
|
504
|
+
if (!this.#isGutterMouseDown) return;
|
|
505
|
+
const textDocument$1 = this.#textDocument;
|
|
506
|
+
const lineIndex$1 = resolveEditableLine(resolveGutterTarget(e$1.composedPath()[0], true));
|
|
507
|
+
if (lineIndex$1 === void 0 || textDocument$1 === void 0) return;
|
|
508
|
+
let selection$1 = {
|
|
509
|
+
start: {
|
|
510
|
+
line: lineIndex$1,
|
|
511
|
+
character: 0
|
|
512
|
+
},
|
|
513
|
+
end: {
|
|
514
|
+
line: lineIndex$1,
|
|
515
|
+
character: textDocument$1.getLineText(lineIndex$1).length
|
|
516
|
+
},
|
|
517
|
+
direction: DirectionForward
|
|
518
|
+
};
|
|
519
|
+
if (this.#selectionStart !== void 0) selection$1 = createSelectionFrom(this.#selectionStart, selection$1);
|
|
520
|
+
else this.#selectionStart = selection$1;
|
|
521
|
+
this.#updateSelections([selection$1]);
|
|
522
|
+
this.#focus(selection$1.end);
|
|
523
|
+
}, { passive: true })];
|
|
524
|
+
}, { passive: true }));
|
|
525
|
+
}
|
|
526
|
+
this.#markerManager?.listenHover(contentEl);
|
|
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;
|
|
@@ -509,17 +540,16 @@ var Editor = class {
|
|
|
509
540
|
break;
|
|
510
541
|
case "findNextMatch": {
|
|
511
542
|
const selections = this.#selections;
|
|
512
|
-
|
|
513
|
-
if (selections === void 0 || textDocument$1 === void 0) break;
|
|
543
|
+
if (selections === void 0) break;
|
|
514
544
|
if (selections.some(isCollapsedSelection)) {
|
|
515
545
|
const expanded = selections.map((sel) => {
|
|
516
|
-
if (isCollapsedSelection(sel)) return expandCollapsedSelectionToWord(textDocument
|
|
546
|
+
if (isCollapsedSelection(sel)) return expandCollapsedSelectionToWord(textDocument, sel);
|
|
517
547
|
return sel;
|
|
518
548
|
});
|
|
519
549
|
this.#updateSelections(expanded);
|
|
520
550
|
this.focus();
|
|
521
551
|
} else {
|
|
522
|
-
const nextMatch = findNexMatch(textDocument
|
|
552
|
+
const nextMatch = findNexMatch(textDocument, selections);
|
|
523
553
|
if (nextMatch !== void 0) {
|
|
524
554
|
this.#updateSelections(nextMatch);
|
|
525
555
|
this.#scrollToPrimaryCaret();
|
|
@@ -597,50 +627,40 @@ var Editor = class {
|
|
|
597
627
|
const gutterWidthChanged = this.#getGutterWidth() !== prevGutterWidth;
|
|
598
628
|
const contentWidthChanged = this.#getContentWidth() !== prevContentWidth;
|
|
599
629
|
if (!gutterWidthChanged && !contentWidthChanged) return;
|
|
600
|
-
this.#
|
|
630
|
+
this.#lastAccessedLineElement = void 0;
|
|
631
|
+
this.#lastAccessedCharX = void 0;
|
|
601
632
|
if (contentWidthChanged && (this.#wrap || lineAnnotations > 0)) {
|
|
602
633
|
this.#lineYCache.clear();
|
|
603
634
|
this.#wrapLineOffsetsCache.clear();
|
|
604
635
|
}
|
|
605
|
-
if (this.#selections !== void 0) {
|
|
606
|
-
this.#updateSelections(this.#selections);
|
|
607
|
-
this.focus();
|
|
636
|
+
if (this.#selections !== void 0 || this.#matches !== void 0 || this.#markerManager !== void 0) {
|
|
637
|
+
this.#updateSelections(this.#selections ?? []);
|
|
638
|
+
if (this.#selections !== void 0) this.focus();
|
|
608
639
|
}
|
|
640
|
+
this.#markerManager?.removePopup();
|
|
609
641
|
}
|
|
610
642
|
#rerender(change, newLineAnnotations, renderRange = this.#renderRange, shouldUpdateBuffer) {
|
|
611
643
|
const tokenizer = this.#tokenizer;
|
|
612
|
-
const
|
|
644
|
+
const fileInstance = this.#fileInstance;
|
|
613
645
|
const fileContents = this.#fileContents;
|
|
614
646
|
const textDocument = this.#textDocument;
|
|
647
|
+
const gutterEl = this.#gutterElement;
|
|
615
648
|
const contentEl = this.#contentElement;
|
|
616
|
-
|
|
617
|
-
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;
|
|
649
|
+
if (tokenizer === void 0 || fileInstance === void 0 || fileContents === void 0 || textDocument === void 0 || contentEl === void 0) return;
|
|
618
650
|
tokenizer.stopBackgroundTokenize();
|
|
619
651
|
const t = performance.now();
|
|
620
|
-
const isAdvancedMode = this.#editMode === "advanced";
|
|
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
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
const
|
|
631
|
-
if (
|
|
632
|
-
|
|
633
|
-
dirtyLineIndexes.delete(lineIndex);
|
|
634
|
-
if (dirtyLineIndexes.size === 0) break;
|
|
635
|
-
}
|
|
636
|
-
}
|
|
637
|
-
}
|
|
638
|
-
else {
|
|
639
|
-
const startingLine = renderRange?.startingLine ?? 0;
|
|
640
|
-
for (let i = change.startLine - startingLine; i < children.length; i++) {
|
|
641
|
-
const child = children[i];
|
|
642
|
-
if (child?.dataset.line !== void 0) {
|
|
643
|
-
const lineIndex = Number(child.dataset.line) - 1;
|
|
657
|
+
const startingLine = renderRange?.startingLine ?? 0;
|
|
658
|
+
for (let i = change.startLine - startingLine; i < children.length; i++) {
|
|
659
|
+
const child = children[i];
|
|
660
|
+
if (child !== void 0) {
|
|
661
|
+
const lineNumber = getLineNumberAttr(child);
|
|
662
|
+
if (lineNumber !== void 0) {
|
|
663
|
+
const lineIndex = lineNumber - 1;
|
|
644
664
|
if (dirtyLines.has(lineIndex)) {
|
|
645
665
|
const tokens = dirtyLines.get(lineIndex);
|
|
646
666
|
child.replaceChildren(...renderLineTokens(tokens, tokenizer.themeType));
|
|
@@ -661,7 +681,7 @@ var Editor = class {
|
|
|
661
681
|
},
|
|
662
682
|
children: renderLineTokens(tokens, tokenizer.themeType)
|
|
663
683
|
}, contentEl);
|
|
664
|
-
h("div", {
|
|
684
|
+
if (gutterEl !== void 0) h("div", {
|
|
665
685
|
dataset: {
|
|
666
686
|
lineType: "context",
|
|
667
687
|
columnNumber: lineNumber,
|
|
@@ -674,23 +694,30 @@ var Editor = class {
|
|
|
674
694
|
}, gutterEl);
|
|
675
695
|
}
|
|
676
696
|
}
|
|
677
|
-
if (change.lineDelta < 0) for (const
|
|
678
|
-
const
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
697
|
+
if (change.lineDelta < 0) for (const children of [contentEl.children, gutterEl?.children ?? []]) for (let i = children.length - 1; i >= 0; i--) {
|
|
698
|
+
const child = children[i];
|
|
699
|
+
const lineNumber = getLineNumberAttr(child) ?? getLineNumberAttr(child, "columnNumber");
|
|
700
|
+
if (lineNumber === void 0) continue;
|
|
701
|
+
if (lineNumber - 1 < change.lineCount) break;
|
|
702
|
+
child.remove();
|
|
703
|
+
}
|
|
704
|
+
const isDiff = Object.hasOwn(fileInstance, "fileDiff");
|
|
705
|
+
const didLineCountChange = change.lineDelta !== 0;
|
|
706
|
+
if (didLineCountChange) {
|
|
707
|
+
let gridRow = contentEl.children.length;
|
|
708
|
+
for (const child of contentEl.children) {
|
|
709
|
+
const { bufferSize } = child.dataset;
|
|
710
|
+
if (bufferSize !== void 0) gridRow += parseInt(bufferSize) - 1;
|
|
686
711
|
}
|
|
712
|
+
contentEl.style.gridRow = "span " + gridRow;
|
|
713
|
+
if (gutterEl !== void 0) gutterEl.style.gridRow = "span " + gridRow;
|
|
687
714
|
}
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
715
|
+
fileInstance.updateRenderCache(dirtyLines, tokenizer.themeType, isDiff ? !didLineCountChange : void 0);
|
|
716
|
+
if (didLineCountChange) fileInstance.applyDocumentChange(textDocument, newLineAnnotations, shouldUpdateBuffer);
|
|
717
|
+
if (newLineAnnotations !== void 0) {
|
|
718
|
+
this.#lineAnnotations = newLineAnnotations;
|
|
719
|
+
renderLineAnnotations(newLineAnnotations, contentEl, gutterEl);
|
|
691
720
|
}
|
|
692
|
-
component.applyLineChange?.(dirtyLines, tokenizer.themeType);
|
|
693
|
-
if (change.lineDelta !== 0 || isAdvancedMode) component.applyLayoutChange(textDocument, newLineAnnotations, shouldUpdateBuffer);
|
|
694
721
|
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
722
|
}
|
|
696
723
|
#handleInput(inputType, data) {
|
|
@@ -707,52 +734,40 @@ var Editor = class {
|
|
|
707
734
|
case "deleteContentForward":
|
|
708
735
|
this.#deleteSelectionText(true);
|
|
709
736
|
break;
|
|
737
|
+
case "deleteSoftLineBackward":
|
|
738
|
+
this.#deleteSoftLineBackward();
|
|
739
|
+
break;
|
|
710
740
|
case "deleteHardLineForward":
|
|
711
741
|
this.#deleteHardLineForward();
|
|
712
742
|
break;
|
|
743
|
+
case "deleteWordBackward":
|
|
744
|
+
this.#deleteWordBackward();
|
|
745
|
+
break;
|
|
713
746
|
case "insertTranspose":
|
|
714
747
|
this.#insertTranspose();
|
|
715
748
|
break;
|
|
716
749
|
default:
|
|
717
|
-
console.warn(`[diffs] Unknown input type: ${inputType}
|
|
750
|
+
console.warn(`[diffs] Unknown input type: ${inputType}`, data);
|
|
718
751
|
break;
|
|
719
752
|
}
|
|
720
753
|
}
|
|
721
|
-
#
|
|
722
|
-
if (
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
this.#component?.setSelectedLines(null);
|
|
729
|
-
gutterBuffer?.querySelectorAll("[data-active]").forEach((el) => el.removeAttribute("data-active"));
|
|
730
|
-
if (isCollapsedSelection(primarySelection)) {
|
|
731
|
-
const line = primarySelection.start.line + 1;
|
|
732
|
-
this.#component?.setSelectedLines({
|
|
733
|
-
start: line,
|
|
734
|
-
end: line
|
|
754
|
+
#focus(position, preventScroll = true) {
|
|
755
|
+
if (position !== void 0) {
|
|
756
|
+
this.#shouldIgnoreSelectionChange = true;
|
|
757
|
+
this.#setWindowSelection({
|
|
758
|
+
start: position,
|
|
759
|
+
end: position,
|
|
760
|
+
direction: DirectionNone
|
|
735
761
|
});
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
elements: /* @__PURE__ */ new Map()
|
|
744
|
-
};
|
|
745
|
-
for (const selection of normalizedSelections) {
|
|
746
|
-
if (!isCollapsedSelection(selection)) this.#renderSelection(renderCtx, selection);
|
|
747
|
-
this.#renderCaret(renderCtx, selection, selection === primarySelection);
|
|
748
|
-
}
|
|
749
|
-
if (this.#options.enabledQuickEdit === true && !isCollapsedSelection(primarySelection)) this.#renderQuickEditIcon(renderCtx, primarySelection);
|
|
750
|
-
this.#overlayElement?.appendChild(fragment);
|
|
751
|
-
this.#selectionElements?.forEach((el) => el.remove());
|
|
752
|
-
this.#selectionElements?.clear();
|
|
753
|
-
this.#selectionElements = renderCtx.elements;
|
|
762
|
+
requestAnimationFrame(() => {
|
|
763
|
+
this.#contentElement?.focus({ preventScroll });
|
|
764
|
+
requestAnimationFrame(() => {
|
|
765
|
+
this.#shouldIgnoreSelectionChange = false;
|
|
766
|
+
});
|
|
767
|
+
});
|
|
768
|
+
} else this.#contentElement?.focus({ preventScroll });
|
|
754
769
|
}
|
|
755
|
-
#
|
|
770
|
+
#setWindowSelection(selection) {
|
|
756
771
|
const winSelection = window.getSelection();
|
|
757
772
|
if (winSelection === null) return;
|
|
758
773
|
let { start, end, direction } = selection;
|
|
@@ -774,25 +789,7 @@ var Editor = class {
|
|
|
774
789
|
console.error("[diffs/editor] failed to update window selection:", err);
|
|
775
790
|
}
|
|
776
791
|
}
|
|
777
|
-
#
|
|
778
|
-
if (position !== void 0) {
|
|
779
|
-
this.#shouldIgnoreSelectionChange = true;
|
|
780
|
-
this.#updateWindowSelection({
|
|
781
|
-
start: position,
|
|
782
|
-
end: position,
|
|
783
|
-
direction: DirectionNone
|
|
784
|
-
});
|
|
785
|
-
requestAnimationFrame(() => {
|
|
786
|
-
this.#contentElement?.focus({ preventScroll });
|
|
787
|
-
requestAnimationFrame(() => {
|
|
788
|
-
this.#shouldIgnoreSelectionChange = false;
|
|
789
|
-
});
|
|
790
|
-
});
|
|
791
|
-
} else requestAnimationFrame(() => {
|
|
792
|
-
this.#contentElement?.focus({ preventScroll });
|
|
793
|
-
});
|
|
794
|
-
}
|
|
795
|
-
#scrollToPrimaryCaret() {
|
|
792
|
+
#scrollToPrimaryCaret(noFocus = false) {
|
|
796
793
|
const primaryCaretElement = this.#primaryCaretElement;
|
|
797
794
|
const primarySelection = this.#selections?.at(-1);
|
|
798
795
|
if (primarySelection === void 0) return;
|
|
@@ -801,20 +798,21 @@ var Editor = class {
|
|
|
801
798
|
block: "nearest",
|
|
802
799
|
inline: "nearest"
|
|
803
800
|
});
|
|
804
|
-
this.#focus(primarySelection.direction === DirectionBackward ? primarySelection.end : primarySelection.start);
|
|
801
|
+
if (!noFocus) this.#focus(primarySelection.direction === DirectionBackward ? primarySelection.end : primarySelection.start);
|
|
805
802
|
} else {
|
|
806
803
|
const pos = getCaretPosition(primarySelection);
|
|
807
|
-
this.#scrollToLine(pos.line, pos.character);
|
|
804
|
+
this.#scrollToLine(pos.line, pos.character, noFocus);
|
|
808
805
|
}
|
|
809
806
|
}
|
|
810
807
|
#getScrollMargin() {
|
|
811
|
-
const componentTop = this.#
|
|
808
|
+
const componentTop = this.#fileInstance?.top ?? 0;
|
|
812
809
|
const top = this.#searchPanel !== void 0 ? 48 : 0;
|
|
813
810
|
const start = this.#getGutterWidth() + this.#metrics.ch;
|
|
814
811
|
const end = this.#metrics.ch;
|
|
815
812
|
return `${componentTop + top}px ${end}px 0 ${start}px`;
|
|
816
813
|
}
|
|
817
|
-
#scrollToLine(line, char = 0) {
|
|
814
|
+
#scrollToLine(line, char = 0, noFocus = false) {
|
|
815
|
+
this.postponeBackgroundTokenizeToNextFrame();
|
|
818
816
|
const virtualCaret = h("div", { style: {
|
|
819
817
|
position: "absolute",
|
|
820
818
|
left: "0",
|
|
@@ -832,111 +830,259 @@ var Editor = class {
|
|
|
832
830
|
block: "center",
|
|
833
831
|
inline: "nearest"
|
|
834
832
|
});
|
|
835
|
-
this.#focus({
|
|
833
|
+
if (!noFocus) this.#focus({
|
|
836
834
|
line,
|
|
837
835
|
character: char
|
|
838
836
|
});
|
|
839
|
-
|
|
837
|
+
this.#scrollingToLine = void 0;
|
|
838
|
+
this.#scrollingToLineChar = void 0;
|
|
839
|
+
this.#scrollingToLineNoFocus = false;
|
|
840
840
|
} else {
|
|
841
|
-
|
|
841
|
+
let yFix = 0;
|
|
842
|
+
if (this.#scrollingToLine === line && this.#contentElement !== void 0) for (let i = this.#contentElement.childElementCount - 1; i >= 0; i--) {
|
|
843
|
+
const child = this.#contentElement.children[i];
|
|
844
|
+
const lineType = child.dataset.lineType;
|
|
845
|
+
const lineNumber = getLineNumberAttr(child);
|
|
846
|
+
if (lineType !== void 0 && isLineEditable(lineType) && lineNumber !== void 0) {
|
|
847
|
+
yFix = (line - lineNumber) * this.#metrics.lineHeight;
|
|
848
|
+
break;
|
|
849
|
+
}
|
|
850
|
+
}
|
|
851
|
+
const approximateLineY = ((this.#lineAnnotations ?? []).filter((annotation) => annotation.lineNumber < line).length + line) * this.#metrics.lineHeight + yFix;
|
|
842
852
|
virtualCaret.style.top = approximateLineY + "px";
|
|
843
|
-
this.#
|
|
844
|
-
this.#scrollingToLine = line;
|
|
845
|
-
this.#scrollingToLineChar = char;
|
|
853
|
+
this.#fileContainer?.shadowRoot?.appendChild(virtualCaret);
|
|
846
854
|
virtualCaret.scrollIntoView({
|
|
847
855
|
block: "center",
|
|
848
856
|
inline: "nearest"
|
|
849
857
|
});
|
|
850
|
-
|
|
858
|
+
if (this.#scrollingToLine === line && yFix === 0) {
|
|
859
|
+
this.#scrollingToLine = void 0;
|
|
860
|
+
this.#scrollingToLineChar = void 0;
|
|
861
|
+
this.#scrollingToLineNoFocus = false;
|
|
862
|
+
} else {
|
|
863
|
+
this.#scrollingToLine = line;
|
|
864
|
+
this.#scrollingToLineChar = char;
|
|
865
|
+
this.#scrollingToLineNoFocus = noFocus;
|
|
866
|
+
}
|
|
867
|
+
}
|
|
868
|
+
virtualCaret.remove();
|
|
869
|
+
}
|
|
870
|
+
#updateSelections(selections) {
|
|
871
|
+
this.postponeBackgroundTokenizeToNextFrame();
|
|
872
|
+
this.#primaryCaretElement = void 0;
|
|
873
|
+
this.#fileInstance?.setSelectedLines(null);
|
|
874
|
+
this.#gutterElement?.querySelectorAll("[data-active]").forEach((el) => el.removeAttribute("data-active"));
|
|
875
|
+
if (selections.length === 0 && this.#matches === void 0 && this.#markerManager === void 0) {
|
|
876
|
+
this.#selections = void 0;
|
|
877
|
+
this.#overlayElements?.forEach((el) => el.remove());
|
|
878
|
+
this.#overlayElements?.clear();
|
|
879
|
+
return;
|
|
880
|
+
}
|
|
881
|
+
const fragment = document.createDocumentFragment();
|
|
882
|
+
const renderCtx = {
|
|
883
|
+
fragment,
|
|
884
|
+
elements: /* @__PURE__ */ new Map()
|
|
885
|
+
};
|
|
886
|
+
if (selections.length > 0) {
|
|
887
|
+
const normalizedSelections = mergeOverlappingSelections(selections);
|
|
888
|
+
const primarySelection = normalizedSelections.at(-1);
|
|
889
|
+
this.#selections = normalizedSelections;
|
|
890
|
+
if (isCollapsedSelection(primarySelection)) {
|
|
891
|
+
const line = primarySelection.start.line + 1;
|
|
892
|
+
this.#fileInstance?.setSelectedLines({
|
|
893
|
+
start: line,
|
|
894
|
+
end: line
|
|
895
|
+
});
|
|
896
|
+
} else if (this.#gutterElement !== void 0) {
|
|
897
|
+
const pos = getCaretPosition(primarySelection);
|
|
898
|
+
this.#gutterElement.querySelector(`[data-column-number="${pos.line + 1}"]`)?.setAttribute("data-active", "");
|
|
899
|
+
}
|
|
900
|
+
for (const selection of normalizedSelections) {
|
|
901
|
+
if (!isCollapsedSelection(selection)) this.#renderSelection(renderCtx, "selection", selection);
|
|
902
|
+
this.#renderCaret(renderCtx, selection, selection === primarySelection);
|
|
903
|
+
}
|
|
904
|
+
if (this.#options.enabledSelectionAction === true && !isCollapsedSelection(primarySelection)) this.#renderSelectionActionIcon(renderCtx, primarySelection);
|
|
905
|
+
}
|
|
906
|
+
const textDocument = this.#textDocument;
|
|
907
|
+
if (this.#matches !== void 0 && textDocument !== void 0) {
|
|
908
|
+
const primarySelection = this.#selections?.at(-1);
|
|
909
|
+
const primaryStartOffset = primarySelection !== void 0 ? textDocument.offsetAt(primarySelection.start) : -1;
|
|
910
|
+
const primaryEndOffset = primarySelection !== void 0 ? textDocument.offsetAt(primarySelection.end) : -1;
|
|
911
|
+
for (const [startOffset, endOffset] of this.#matches) {
|
|
912
|
+
const range = {
|
|
913
|
+
start: textDocument.positionAt(startOffset),
|
|
914
|
+
end: textDocument.positionAt(endOffset)
|
|
915
|
+
};
|
|
916
|
+
const isFocused = primaryStartOffset === startOffset && primaryEndOffset === endOffset;
|
|
917
|
+
this.#renderSelection(renderCtx, "match", range, isFocused ? "focus" : void 0);
|
|
918
|
+
}
|
|
851
919
|
}
|
|
920
|
+
if (this.#markerManager !== void 0 && textDocument !== void 0) for (const marker of this.#markerManager.markers) this.#renderSelection(renderCtx, "marker", marker, markerSeverityDatasetKey(marker.severity));
|
|
921
|
+
this.#overlayElement?.appendChild(fragment);
|
|
922
|
+
this.#overlayElements?.forEach((el) => el.remove());
|
|
923
|
+
this.#overlayElements?.clear();
|
|
924
|
+
this.#overlayElements = renderCtx.elements;
|
|
852
925
|
}
|
|
853
|
-
#renderSelection(renderCtx,
|
|
926
|
+
#renderSelection(renderCtx, type, range, extraDataset) {
|
|
854
927
|
if (this.#textDocument === void 0) return;
|
|
855
|
-
const { start, end } =
|
|
856
|
-
for (let
|
|
857
|
-
if (!this.#isLineVisible(
|
|
858
|
-
const
|
|
859
|
-
const
|
|
860
|
-
const
|
|
928
|
+
const { start, end } = range;
|
|
929
|
+
for (let line = start.line; line <= end.line; line++) {
|
|
930
|
+
if (!this.#isLineVisible(line)) continue;
|
|
931
|
+
const isLastLine = line === end.line;
|
|
932
|
+
const lineText = this.#textDocument.getLineText(line);
|
|
933
|
+
const startChar = line === start.line ? start.character : 0;
|
|
934
|
+
const endChar = isLastLine ? end.character : lineText.length;
|
|
861
935
|
if (this.#wrap) {
|
|
862
|
-
const paddingInline = this.#metrics.ch;
|
|
863
936
|
const contentWidth = this.#getContentWidth();
|
|
864
|
-
if (2 *
|
|
865
|
-
this.#renderWrappedSelection(renderCtx,
|
|
937
|
+
if (2 * this.#metrics.ch + this.#metrics.measureTextWidth(lineText) > contentWidth) {
|
|
938
|
+
this.#renderWrappedSelection(renderCtx, line, lineText, startChar, endChar, isLastLine, type, extraDataset);
|
|
866
939
|
continue;
|
|
867
940
|
}
|
|
868
941
|
}
|
|
869
942
|
let left = 0;
|
|
870
943
|
let width = 0;
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
this.#renderSelectionRange(renderCtx, selection, ln, 0, startChar, endChar, width, left);
|
|
944
|
+
let paddingEnd = 0;
|
|
945
|
+
if (startChar === 0) left = this.#getGutterWidth() + this.#metrics.ch;
|
|
946
|
+
else left = this.#getCharX(line, startChar)[0];
|
|
947
|
+
if (!isLastLine && type === "selection") paddingEnd = this.#metrics.ch;
|
|
948
|
+
if (startChar === endChar) width = paddingEnd;
|
|
949
|
+
else width = this.#getCharX(line, endChar)[0] - left + paddingEnd;
|
|
950
|
+
this.#renderSelectionBlock(renderCtx, type, line, 0, left, width, extraDataset);
|
|
879
951
|
}
|
|
880
952
|
}
|
|
881
|
-
#renderWrappedSelection(renderCtx,
|
|
953
|
+
#renderWrappedSelection(renderCtx, line, lineText, startChar, endChar, isLastLine, type, extraDataset) {
|
|
882
954
|
const wrapOffsets = this.#wrapLineText(line);
|
|
883
955
|
const segmentCount = wrapOffsets.length - 1;
|
|
884
|
-
const
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
const
|
|
888
|
-
const segmentEnd = wrapOffsets[w + 1];
|
|
956
|
+
const offsetLeft = this.#getGutterWidth() + this.#metrics.ch;
|
|
957
|
+
for (let wrapLine = 0; wrapLine < segmentCount; wrapLine++) {
|
|
958
|
+
const segmentStart = wrapOffsets[wrapLine];
|
|
959
|
+
const segmentEnd = wrapOffsets[wrapLine + 1];
|
|
889
960
|
const wrapStartChar = Math.max(startChar, segmentStart);
|
|
890
961
|
const wrapEndChar = Math.min(endChar, segmentEnd);
|
|
891
962
|
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
963
|
let segmentLeft;
|
|
898
964
|
let segmentWidth;
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
} else {
|
|
965
|
+
let paddingEnd = 0;
|
|
966
|
+
if (wrapStartChar === 0) segmentLeft = offsetLeft;
|
|
967
|
+
else {
|
|
903
968
|
const prefixInSegment = lineText.slice(segmentStart, wrapStartChar);
|
|
904
969
|
const prefixAsciiColumns = getExpandedAsciiTextColumns(prefixInSegment, this.#metrics.tabSize);
|
|
905
970
|
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
971
|
}
|
|
913
|
-
|
|
972
|
+
if (!isLastLine && wrapLine === segmentCount - 1 && type === "selection") paddingEnd = this.#metrics.ch;
|
|
973
|
+
if (wrapStartChar === wrapEndChar) segmentWidth = paddingEnd;
|
|
974
|
+
else {
|
|
975
|
+
const selectionInSegment = lineText.slice(wrapStartChar, wrapEndChar);
|
|
976
|
+
const selectionAsciiWidth = getExpandedAsciiTextColumns(selectionInSegment, this.#metrics.tabSize);
|
|
977
|
+
segmentWidth = selectionAsciiWidth !== -1 ? selectionAsciiWidth * this.#metrics.ch : this.#metrics.measureTextWidth(selectionInSegment);
|
|
978
|
+
segmentWidth += paddingEnd;
|
|
979
|
+
}
|
|
980
|
+
this.#renderSelectionBlock(renderCtx, type, line, wrapLine, segmentLeft, segmentWidth, extraDataset);
|
|
914
981
|
}
|
|
915
982
|
}
|
|
916
|
-
#
|
|
917
|
-
|
|
918
|
-
const
|
|
919
|
-
const
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
983
|
+
#renderSelectionBlock(renderCtx, type, line, wrapLine, left, width, extraDataset) {
|
|
984
|
+
if (width === 0) return;
|
|
985
|
+
const { ch, lineHeight } = this.#metrics;
|
|
986
|
+
const y = this.#getLineY(line) + wrapLine * lineHeight;
|
|
987
|
+
const css = `width:${width}px;transform:translateX(${left}px) translateY(${y}px);`;
|
|
988
|
+
const cacheKey = `${type}-${left}-${y}-${width}${extraDataset ?? ""}`;
|
|
989
|
+
const overlayEls = this.#overlayElements;
|
|
990
|
+
const rounded = (this.#options.roundedSelection ?? true) && type === "selection";
|
|
991
|
+
const addRoundedCorner = (line$1, wrapLine$1, left$1, radius) => {
|
|
992
|
+
const top = this.#getLineY(line$1) + wrapLine$1 * lineHeight;
|
|
993
|
+
const css$1 = `width:${ch}px;transform:translateX(${left$1}px) translateY(${top}px);`;
|
|
994
|
+
const dataset = {
|
|
995
|
+
selectionCorner: "",
|
|
996
|
+
[radius]: ""
|
|
997
|
+
};
|
|
998
|
+
const cacheKeyPrefix = `${type}-block-${left$1}-${top}-1ch`;
|
|
999
|
+
let cacheKey$1 = cacheKeyPrefix + "-" + radius;
|
|
1000
|
+
if (radius === "rbl") {
|
|
1001
|
+
const prevCornerKey = cacheKeyPrefix + "-rtl";
|
|
1002
|
+
const prevCorner = renderCtx.elements.get(prevCornerKey);
|
|
1003
|
+
if (prevCorner !== void 0) {
|
|
1004
|
+
prevCorner.remove();
|
|
1005
|
+
renderCtx.elements.delete(prevCornerKey);
|
|
1006
|
+
cacheKey$1 += "-rtl";
|
|
1007
|
+
dataset.rtl = "";
|
|
1008
|
+
}
|
|
1009
|
+
}
|
|
1010
|
+
let cornerEl = renderCtx.elements.get(cacheKey$1);
|
|
1011
|
+
if (cornerEl !== void 0) return;
|
|
1012
|
+
if (overlayEls?.has(cacheKey$1) === true) {
|
|
1013
|
+
cornerEl = overlayEls.get(cacheKey$1);
|
|
1014
|
+
overlayEls.delete(cacheKey$1);
|
|
1015
|
+
} else cornerEl = h("div", {
|
|
1016
|
+
dataset: "selectionRange",
|
|
1017
|
+
style: { cssText: css$1 },
|
|
1018
|
+
children: [h("div", { dataset })]
|
|
1019
|
+
}, renderCtx.fragment);
|
|
1020
|
+
renderCtx.elements.set(cacheKey$1, cornerEl);
|
|
1021
|
+
};
|
|
1022
|
+
const addRadiusStyle = (element) => {
|
|
1023
|
+
const end = left + width;
|
|
1024
|
+
const dataset = element.dataset;
|
|
1025
|
+
const previousSelectionRange = renderCtx.previousSelectionRange;
|
|
1026
|
+
if (previousSelectionRange === void 0 || previousSelectionRange.line !== line || previousSelectionRange.wrapLine !== wrapLine) renderCtx.previousSelectionRange = {
|
|
1027
|
+
element,
|
|
1028
|
+
line,
|
|
1029
|
+
wrapLine,
|
|
1030
|
+
left,
|
|
1031
|
+
width
|
|
1032
|
+
};
|
|
1033
|
+
if (previousSelectionRange === void 0 || end <= previousSelectionRange.left) [
|
|
1034
|
+
"rtl",
|
|
1035
|
+
"rtr",
|
|
1036
|
+
"rbl",
|
|
1037
|
+
"rbr"
|
|
1038
|
+
].forEach((key) => {
|
|
1039
|
+
dataset[key] = "";
|
|
1040
|
+
});
|
|
1041
|
+
else {
|
|
1042
|
+
const prevLine = previousSelectionRange.line;
|
|
1043
|
+
const prevWrapLine = previousSelectionRange.wrapLine;
|
|
1044
|
+
const prevLeft = previousSelectionRange.left;
|
|
1045
|
+
const prevDataset = previousSelectionRange.element.dataset;
|
|
1046
|
+
const prevEnd = prevLeft + previousSelectionRange.width;
|
|
1047
|
+
if (prevLeft > left) addRoundedCorner(prevLine, prevWrapLine, prevLeft - ch, "rbr");
|
|
1048
|
+
delete prevDataset.rbl;
|
|
1049
|
+
delete dataset.rtl;
|
|
1050
|
+
delete dataset.rtr;
|
|
1051
|
+
if (end >= prevEnd) delete prevDataset.rbr;
|
|
1052
|
+
if (end > prevEnd) {
|
|
1053
|
+
addRoundedCorner(prevLine, prevWrapLine, prevEnd, "rbl");
|
|
1054
|
+
dataset.rtr = "";
|
|
1055
|
+
}
|
|
1056
|
+
if (end < prevEnd) addRoundedCorner(line, wrapLine, end, "rtl");
|
|
1057
|
+
if (left < prevLeft) dataset.rtl = "";
|
|
1058
|
+
dataset.rbl = "";
|
|
1059
|
+
dataset.rbr = "";
|
|
1060
|
+
}
|
|
1061
|
+
};
|
|
1062
|
+
let rangeEl = renderCtx.elements.get(cacheKey);
|
|
1063
|
+
if (rangeEl !== void 0) {
|
|
1064
|
+
if (rounded) addRadiusStyle(rangeEl);
|
|
1065
|
+
return;
|
|
1066
|
+
}
|
|
1067
|
+
if (overlayEls?.has(cacheKey) === true) {
|
|
1068
|
+
rangeEl = overlayEls.get(cacheKey);
|
|
1069
|
+
overlayEls.delete(cacheKey);
|
|
925
1070
|
} else rangeEl = h("div", {
|
|
926
|
-
dataset: "
|
|
1071
|
+
dataset: extraDataset ? [type + "Range", extraDataset] : type + "Range",
|
|
927
1072
|
style: { cssText: css }
|
|
928
1073
|
}, renderCtx.fragment);
|
|
1074
|
+
if (rounded) addRadiusStyle(rangeEl);
|
|
929
1075
|
renderCtx.elements.set(cacheKey, rangeEl);
|
|
930
1076
|
}
|
|
931
1077
|
#renderCaret(renderCtx, selection, isPrimary) {
|
|
932
1078
|
const { line, character } = getCaretPosition(selection);
|
|
933
1079
|
if (!this.#isLineVisible(line)) return;
|
|
934
1080
|
const [left, wrapLine] = this.#getCharX(line, character);
|
|
935
|
-
const cacheKey = "caret-" + line + "
|
|
1081
|
+
const cacheKey = "caret-" + line + "/" + wrapLine + ":" + character;
|
|
936
1082
|
if (renderCtx.elements.has(cacheKey)) return;
|
|
937
1083
|
const caretEl = h("div", {
|
|
938
1084
|
dataset: "caret",
|
|
939
|
-
style: { transform: `translateY(${this.#getLineY(line) + wrapLine * this.#metrics.lineHeight}px)
|
|
1085
|
+
style: { transform: `translateX(${left - 1}px) translateY(${this.#getLineY(line) + wrapLine * this.#metrics.lineHeight}px)` }
|
|
940
1086
|
}, renderCtx.fragment);
|
|
941
1087
|
renderCtx.elements.set(cacheKey, caretEl);
|
|
942
1088
|
if (isPrimary) {
|
|
@@ -944,29 +1090,29 @@ var Editor = class {
|
|
|
944
1090
|
this.#primaryCaretElement = caretEl;
|
|
945
1091
|
}
|
|
946
1092
|
}
|
|
947
|
-
#
|
|
1093
|
+
#renderSelectionActionIcon(renderCtx, selection) {
|
|
948
1094
|
const line = getCaretPosition(selection).line;
|
|
949
1095
|
if (!this.#isLineVisible(line)) return;
|
|
950
1096
|
const [left, wrapLine] = this.#getCharX(line, 0);
|
|
951
|
-
const cacheKey = "
|
|
1097
|
+
const cacheKey = "selectionActionIcon-" + line + "(" + wrapLine + ")";
|
|
952
1098
|
if (renderCtx.elements.has(cacheKey)) return;
|
|
953
|
-
const
|
|
954
|
-
const
|
|
955
|
-
this.#
|
|
956
|
-
this.#
|
|
1099
|
+
const selectionActionIcon = SelectionActionWidget.renderIcon(left, this.#getLineY(line) + wrapLine * this.#metrics.lineHeight, renderCtx.fragment, () => {
|
|
1100
|
+
const cleanUpSelectionAction = () => {
|
|
1101
|
+
this.#selectionAction?.cleanup();
|
|
1102
|
+
this.#selectionAction = void 0;
|
|
957
1103
|
};
|
|
958
1104
|
const handleWidgetDomResize = () => {
|
|
959
1105
|
this.#lineYCache.clear();
|
|
960
1106
|
if (this.#selections !== void 0) this.#updateSelections(this.#selections);
|
|
961
1107
|
};
|
|
962
|
-
|
|
1108
|
+
cleanUpSelectionAction();
|
|
963
1109
|
const textDocument = this.#textDocument;
|
|
964
|
-
const
|
|
965
|
-
const fileContainer = this.#
|
|
966
|
-
if (textDocument === void 0 ||
|
|
1110
|
+
const renderSelectionAction = this.#options.renderSelectionAction;
|
|
1111
|
+
const fileContainer = this.#fileContainer;
|
|
1112
|
+
if (textDocument === void 0 || renderSelectionAction === void 0 || fileContainer == null) return;
|
|
967
1113
|
const line$1 = selection.end.line;
|
|
968
1114
|
const lineText = textDocument.getLineText(line$1);
|
|
969
|
-
const
|
|
1115
|
+
const selectionActionElement = renderSelectionAction({
|
|
970
1116
|
textDocument,
|
|
971
1117
|
selection,
|
|
972
1118
|
applyEdits: (edits) => {
|
|
@@ -980,7 +1126,7 @@ var Editor = class {
|
|
|
980
1126
|
this.#replaceSelectionText(text);
|
|
981
1127
|
},
|
|
982
1128
|
close: () => {
|
|
983
|
-
|
|
1129
|
+
cleanUpSelectionAction();
|
|
984
1130
|
handleWidgetDomResize();
|
|
985
1131
|
this.#scrollToPrimaryCaret();
|
|
986
1132
|
}
|
|
@@ -992,57 +1138,68 @@ var Editor = class {
|
|
|
992
1138
|
else if (charCode === 9) leadingWhitespaces += this.#metrics.tabSize;
|
|
993
1139
|
else break;
|
|
994
1140
|
}
|
|
995
|
-
this.#
|
|
1141
|
+
this.#selectionAction = new SelectionActionWidget(line$1, selectionActionElement, fileContainer, leadingWhitespaces, handleWidgetDomResize);
|
|
996
1142
|
this.#updateSelections([selection]);
|
|
997
|
-
if (this.#isLineVisible(line$1) && this.#contentElement !== void 0) this.#
|
|
1143
|
+
if (this.#isLineVisible(line$1) && this.#contentElement !== void 0) this.#selectionAction.render(this.#contentElement);
|
|
998
1144
|
});
|
|
999
|
-
renderCtx.elements.set(cacheKey,
|
|
1145
|
+
renderCtx.elements.set(cacheKey, selectionActionIcon);
|
|
1000
1146
|
}
|
|
1001
1147
|
#renderSearchPanel() {
|
|
1002
1148
|
this.#searchPanel?.cleanup();
|
|
1003
1149
|
const textDocument = this.#textDocument;
|
|
1004
|
-
const preElement = this.#
|
|
1150
|
+
const preElement = this.#fileContainer?.shadowRoot?.querySelector("pre");
|
|
1151
|
+
const selections = this.#selections;
|
|
1005
1152
|
if (textDocument === void 0 || preElement == null) return;
|
|
1006
1153
|
let defaultQuery = "";
|
|
1007
1154
|
let initialMatch = void 0;
|
|
1008
|
-
const selections = this.#selections;
|
|
1009
1155
|
if (selections !== void 0 && selections.length > 0) {
|
|
1010
1156
|
let primarySelection = selections.at(-1);
|
|
1011
1157
|
if (isCollapsedSelection(primarySelection)) {
|
|
1012
1158
|
primarySelection = expandCollapsedSelectionToWord(textDocument, primarySelection);
|
|
1013
1159
|
this.#updateSelections([...selections.slice(0, -1), primarySelection]);
|
|
1014
1160
|
const selectionText = textDocument.getText(primarySelection);
|
|
1015
|
-
if (!selectionText.includes("\n")) {
|
|
1161
|
+
if (selectionText !== "" && !selectionText.includes("\n")) {
|
|
1016
1162
|
defaultQuery = selectionText;
|
|
1017
1163
|
initialMatch = [textDocument.offsetAt(primarySelection.start), textDocument.offsetAt(primarySelection.end)];
|
|
1018
1164
|
}
|
|
1019
1165
|
}
|
|
1020
1166
|
}
|
|
1167
|
+
const scrollToMatch = ([startOffset, endOffset], retainFocus) => {
|
|
1168
|
+
const nextSelection = createSelectionFromAnchorAndFocusOffsets(textDocument, startOffset, endOffset);
|
|
1169
|
+
this.#updateSelections([nextSelection]);
|
|
1170
|
+
this.#scrollToPrimaryCaret(true);
|
|
1171
|
+
this.#retainSearchPanelFocus = retainFocus;
|
|
1172
|
+
};
|
|
1021
1173
|
this.#searchPanel = new SearchPanelWidget({
|
|
1022
1174
|
textDocument,
|
|
1023
1175
|
containerElement: preElement,
|
|
1024
1176
|
defaultQuery,
|
|
1025
1177
|
initialMatch,
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
if (
|
|
1029
|
-
|
|
1030
|
-
this.#updateSelections([
|
|
1031
|
-
|
|
1032
|
-
if (retainFocus === true) {
|
|
1033
|
-
this.#retainSearchPanelFocus = true;
|
|
1034
|
-
requestAnimationFrame(() => {
|
|
1035
|
-
this.#searchPanel?.focus();
|
|
1036
|
-
});
|
|
1037
|
-
}
|
|
1038
|
-
} else if (kind === "findAll" || kind === "replaceAll") {
|
|
1039
|
-
const { line, character } = textDocument.positionAt(startOffset);
|
|
1040
|
-
this.#scrollToLine(line, character);
|
|
1178
|
+
scrollToMatch,
|
|
1179
|
+
onUpdate: (allMatches) => {
|
|
1180
|
+
if (allMatches.length === 0) {
|
|
1181
|
+
this.#matches = void 0;
|
|
1182
|
+
this.#updateSelections(this.#selections ?? []);
|
|
1183
|
+
return;
|
|
1041
1184
|
}
|
|
1185
|
+
this.#matches = allMatches;
|
|
1186
|
+
const primarySelection = this.#selections?.at(-1);
|
|
1187
|
+
let searchOffset = 0;
|
|
1188
|
+
let nextMatch;
|
|
1189
|
+
if (primarySelection !== void 0) searchOffset = textDocument.offsetAt(primarySelection.start);
|
|
1190
|
+
for (const m of allMatches) if (m[0] >= searchOffset) {
|
|
1191
|
+
nextMatch = m;
|
|
1192
|
+
break;
|
|
1193
|
+
}
|
|
1194
|
+
if (nextMatch !== void 0) scrollToMatch(nextMatch, true);
|
|
1195
|
+
else this.#updateSelections(this.#selections ?? []);
|
|
1196
|
+
return nextMatch;
|
|
1042
1197
|
},
|
|
1043
1198
|
onClose: () => {
|
|
1044
1199
|
this.#searchPanel = void 0;
|
|
1045
1200
|
this.#retainSearchPanelFocus = false;
|
|
1201
|
+
this.#matches = void 0;
|
|
1202
|
+
this.#updateSelections(this.#selections ?? []);
|
|
1046
1203
|
}
|
|
1047
1204
|
});
|
|
1048
1205
|
this.#retainSearchPanelFocus = false;
|
|
@@ -1072,21 +1229,44 @@ var Editor = class {
|
|
|
1072
1229
|
if (selections === void 0 || textDocument === void 0) return;
|
|
1073
1230
|
const primarySelection = selections.at(-1);
|
|
1074
1231
|
if (primarySelection === void 0) return;
|
|
1075
|
-
|
|
1232
|
+
let edit;
|
|
1233
|
+
if (isCollapsedSelection(primarySelection)) {
|
|
1076
1234
|
const offset = textDocument.offsetAt(primarySelection.start);
|
|
1077
1235
|
const nextOffset = forward ? Math.min(textDocument.getText().length, offset + 1) : Math.max(0, offset - 1);
|
|
1078
|
-
|
|
1236
|
+
edit = {
|
|
1079
1237
|
start: Math.min(offset, nextOffset),
|
|
1080
1238
|
end: Math.max(offset, nextOffset),
|
|
1081
1239
|
text: ""
|
|
1082
1240
|
};
|
|
1083
|
-
}
|
|
1241
|
+
} else edit = {
|
|
1084
1242
|
start: textDocument.offsetAt(primarySelection.start),
|
|
1085
1243
|
end: textDocument.offsetAt(primarySelection.end),
|
|
1086
1244
|
text: ""
|
|
1087
1245
|
};
|
|
1088
1246
|
this.#applyResolvedTextEdit(edit);
|
|
1089
1247
|
}
|
|
1248
|
+
#deleteSoftLineBackward() {
|
|
1249
|
+
const selections = this.#selections;
|
|
1250
|
+
const textDocument = this.#textDocument;
|
|
1251
|
+
if (selections === void 0 || textDocument === void 0) return;
|
|
1252
|
+
const { nextSelections, change } = applyDeleteSoftLineBackwardToSelections(textDocument, selections, this.#wrap ? (line, character) => {
|
|
1253
|
+
const wrapOffsets = this.#wrapLineText(line);
|
|
1254
|
+
for (let w = 0; w + 1 < wrapOffsets.length; w++) {
|
|
1255
|
+
const segmentStart = wrapOffsets[w];
|
|
1256
|
+
const segmentEnd = wrapOffsets[w + 1];
|
|
1257
|
+
if (character >= segmentStart && character <= segmentEnd) return segmentStart;
|
|
1258
|
+
}
|
|
1259
|
+
return 0;
|
|
1260
|
+
} : void 0, this.#lineAnnotations);
|
|
1261
|
+
if (change !== void 0) this.#applyChange(change, nextSelections, this.#applyChangeToLineAnnotations(change));
|
|
1262
|
+
}
|
|
1263
|
+
#deleteWordBackward() {
|
|
1264
|
+
const selections = this.#selections;
|
|
1265
|
+
const textDocument = this.#textDocument;
|
|
1266
|
+
if (selections === void 0 || textDocument === void 0) return;
|
|
1267
|
+
const { nextSelections, change } = applyDeleteWordBackwardToSelections(textDocument, selections, this.#lineAnnotations);
|
|
1268
|
+
if (change !== void 0) this.#applyChange(change, nextSelections, this.#applyChangeToLineAnnotations(change));
|
|
1269
|
+
}
|
|
1090
1270
|
#deleteHardLineForward() {
|
|
1091
1271
|
const selections = this.#selections;
|
|
1092
1272
|
const textDocument = this.#textDocument;
|
|
@@ -1112,9 +1292,11 @@ var Editor = class {
|
|
|
1112
1292
|
const onChange = this.#options.onChange;
|
|
1113
1293
|
if (fileContents !== void 0 && textDocument !== void 0 && onChange !== void 0) {
|
|
1114
1294
|
const { contents: _,...file } = fileContents;
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1295
|
+
Object.defineProperty(file, "contents", {
|
|
1296
|
+
enumerable: true,
|
|
1297
|
+
get: () => textDocument.getText()
|
|
1298
|
+
});
|
|
1299
|
+
onChange(file, newLineAnnotations ?? this.#lineAnnotations);
|
|
1118
1300
|
}
|
|
1119
1301
|
if (change.lineDelta !== 0) {
|
|
1120
1302
|
for (const line of this.#lineYCache.keys()) if (line >= change.startLine) this.#lineYCache.delete(line);
|
|
@@ -1122,7 +1304,7 @@ var Editor = class {
|
|
|
1122
1304
|
if (this.#wrap) {
|
|
1123
1305
|
for (const line of this.#wrapLineOffsetsCache.keys()) if (line >= change.startLine) this.#wrapLineOffsetsCache.delete(line);
|
|
1124
1306
|
}
|
|
1125
|
-
this.#
|
|
1307
|
+
this.#lastAccessedCharX = void 0;
|
|
1126
1308
|
let renderRange = this.#renderRange;
|
|
1127
1309
|
let shouldUpdateBuffer;
|
|
1128
1310
|
if (renderRange !== void 0 && selections !== void 0 && selections.length > 0) {
|
|
@@ -1137,17 +1319,15 @@ var Editor = class {
|
|
|
1137
1319
|
this.#rerender(change, newLineAnnotations, renderRange, shouldUpdateBuffer);
|
|
1138
1320
|
if (selections !== void 0) {
|
|
1139
1321
|
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
|
-
}
|
|
1322
|
+
if (this.#primaryCaretElement !== void 0) this.#primaryCaretElement.scrollIntoView({
|
|
1323
|
+
block: "nearest",
|
|
1324
|
+
inline: "nearest"
|
|
1150
1325
|
});
|
|
1326
|
+
else if (selections.length > 0) {
|
|
1327
|
+
const pos = getCaretPosition(selections.at(-1));
|
|
1328
|
+
this.#scrollToLine(pos.line, pos.character);
|
|
1329
|
+
}
|
|
1330
|
+
this.focus({ preventScroll: true });
|
|
1151
1331
|
}
|
|
1152
1332
|
}
|
|
1153
1333
|
#applyChangeToLineAnnotations(change) {
|
|
@@ -1160,28 +1340,40 @@ var Editor = class {
|
|
|
1160
1340
|
}
|
|
1161
1341
|
}
|
|
1162
1342
|
#getLineElement(line) {
|
|
1343
|
+
const lastAccessed = this.#lastAccessedLineElement;
|
|
1344
|
+
if (lastAccessed !== void 0 && lastAccessed[0] === line) return lastAccessed[1];
|
|
1163
1345
|
const contentElement = this.#contentElement;
|
|
1164
1346
|
if (contentElement === void 0) return;
|
|
1165
|
-
|
|
1347
|
+
let lineElement = null;
|
|
1348
|
+
if (this.#renderRange !== void 0) {
|
|
1166
1349
|
const { startingLine } = this.#renderRange;
|
|
1167
1350
|
const { children } = contentElement;
|
|
1168
1351
|
for (let i = line - startingLine; i <= children.length; i++) {
|
|
1169
1352
|
const child = children[i];
|
|
1170
|
-
|
|
1171
|
-
const
|
|
1172
|
-
|
|
1353
|
+
if (child === void 0) break;
|
|
1354
|
+
const lineNumber = getLineNumberAttr(child);
|
|
1355
|
+
const lineType = child.dataset.lineType;
|
|
1356
|
+
if (lineNumber !== void 0 && lineNumber === line + 1 && lineType !== void 0 && isLineEditable(lineType)) {
|
|
1357
|
+
lineElement = child;
|
|
1358
|
+
break;
|
|
1359
|
+
}
|
|
1173
1360
|
}
|
|
1174
1361
|
}
|
|
1175
|
-
|
|
1176
|
-
|
|
1362
|
+
lineElement ??= contentElement.querySelector(`[data-line="${line + 1}"]`);
|
|
1363
|
+
if (lineElement !== null) {
|
|
1364
|
+
if (lastAccessed !== void 0) {
|
|
1365
|
+
lastAccessed[0] = line;
|
|
1366
|
+
lastAccessed[1] = lineElement;
|
|
1367
|
+
} else this.#lastAccessedLineElement = [line, lineElement];
|
|
1368
|
+
return lineElement;
|
|
1369
|
+
}
|
|
1177
1370
|
}
|
|
1178
1371
|
#getGutterWidth() {
|
|
1179
|
-
|
|
1180
|
-
if (gutterElement == null || !(gutterElement instanceof HTMLElement) || !gutterElement.hasAttribute("data-gutter")) return 0;
|
|
1372
|
+
if (this.#gutterElement === void 0) return 0;
|
|
1181
1373
|
if (this.#gutterWidthCache === void 0) {
|
|
1182
1374
|
const diffsColumnNumberWidth = this.#contentElement?.parentElement?.style.getPropertyValue("--diffs-column-number-width");
|
|
1183
|
-
if (diffsColumnNumberWidth !== void 0 && diffsColumnNumberWidth.length > 2 && diffsColumnNumberWidth.endsWith("px")) this.#gutterWidthCache =
|
|
1184
|
-
else this.#gutterWidthCache = gutterElement.offsetWidth;
|
|
1375
|
+
if (diffsColumnNumberWidth !== void 0 && diffsColumnNumberWidth.length > 2 && diffsColumnNumberWidth.endsWith("px")) this.#gutterWidthCache = parseInt(diffsColumnNumberWidth.slice(0, -2), 10);
|
|
1376
|
+
else this.#gutterWidthCache = this.#gutterElement.offsetWidth;
|
|
1185
1377
|
}
|
|
1186
1378
|
return this.#gutterWidthCache;
|
|
1187
1379
|
}
|
|
@@ -1189,7 +1381,7 @@ var Editor = class {
|
|
|
1189
1381
|
if (this.#contentElement === void 0) return 0;
|
|
1190
1382
|
if (this.#contentWidthCache === void 0) {
|
|
1191
1383
|
const diffsColumnContentWidth = this.#contentElement.parentElement?.style.getPropertyValue("--diffs-column-content-width");
|
|
1192
|
-
if (diffsColumnContentWidth !== void 0 && diffsColumnContentWidth.length > 2 && diffsColumnContentWidth.endsWith("px")) this.#contentWidthCache =
|
|
1384
|
+
if (diffsColumnContentWidth !== void 0 && diffsColumnContentWidth.length > 2 && diffsColumnContentWidth.endsWith("px")) this.#contentWidthCache = parseFloat(diffsColumnContentWidth.slice(0, -2));
|
|
1193
1385
|
else this.#contentWidthCache = this.#contentElement.offsetWidth;
|
|
1194
1386
|
}
|
|
1195
1387
|
return this.#contentWidthCache;
|
|
@@ -1204,7 +1396,7 @@ var Editor = class {
|
|
|
1204
1396
|
return y;
|
|
1205
1397
|
}
|
|
1206
1398
|
#getCharX(line, char) {
|
|
1207
|
-
if (this.#
|
|
1399
|
+
if (this.#lastAccessedCharX !== void 0 && this.#lastAccessedCharX[0] === line && this.#lastAccessedCharX[1] === char) return [this.#lastAccessedCharX[2], this.#lastAccessedCharX[3]];
|
|
1208
1400
|
const lineText = this.#textDocument?.getLineText(line);
|
|
1209
1401
|
const offsetLeft = this.#getGutterWidth() + this.#metrics.ch;
|
|
1210
1402
|
if (lineText === void 0 || lineText.length === 0 || char <= 0) return [offsetLeft, 0];
|
|
@@ -1232,12 +1424,12 @@ var Editor = class {
|
|
|
1232
1424
|
}
|
|
1233
1425
|
}
|
|
1234
1426
|
}
|
|
1235
|
-
if (this.#
|
|
1236
|
-
this.#
|
|
1237
|
-
this.#
|
|
1238
|
-
this.#
|
|
1239
|
-
this.#
|
|
1240
|
-
} else this.#
|
|
1427
|
+
if (this.#lastAccessedCharX !== void 0) {
|
|
1428
|
+
this.#lastAccessedCharX[0] = line;
|
|
1429
|
+
this.#lastAccessedCharX[1] = char;
|
|
1430
|
+
this.#lastAccessedCharX[2] = left;
|
|
1431
|
+
this.#lastAccessedCharX[3] = wrapLine;
|
|
1432
|
+
} else this.#lastAccessedCharX = [
|
|
1241
1433
|
line,
|
|
1242
1434
|
char,
|
|
1243
1435
|
left,
|