@pierre/diffs 1.3.0-beta.9 → 1.3.0-rc.2
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/README.md +9 -0
- package/dist/components/CodeView.d.ts +12 -13
- package/dist/components/CodeView.d.ts.map +1 -1
- package/dist/components/CodeView.js +50 -58
- package/dist/components/CodeView.js.map +1 -1
- package/dist/components/File.d.ts +10 -3
- package/dist/components/File.d.ts.map +1 -1
- package/dist/components/File.js +41 -10
- package/dist/components/File.js.map +1 -1
- package/dist/components/FileDiff.d.ts +37 -6
- package/dist/components/FileDiff.d.ts.map +1 -1
- package/dist/components/FileDiff.js +202 -19
- package/dist/components/FileDiff.js.map +1 -1
- package/dist/components/UnresolvedFile.d.ts.map +1 -1
- package/dist/components/UnresolvedFile.js +7 -2
- package/dist/components/UnresolvedFile.js.map +1 -1
- package/dist/components/VirtualizedFile.d.ts +2 -1
- package/dist/components/VirtualizedFile.d.ts.map +1 -1
- package/dist/components/VirtualizedFile.js +9 -5
- package/dist/components/VirtualizedFile.js.map +1 -1
- package/dist/components/VirtualizedFileDiff.d.ts +14 -0
- package/dist/components/VirtualizedFileDiff.d.ts.map +1 -1
- package/dist/components/VirtualizedFileDiff.js +61 -3
- package/dist/components/VirtualizedFileDiff.js.map +1 -1
- package/dist/components/Virtualizer.d.ts +14 -2
- package/dist/components/Virtualizer.d.ts.map +1 -1
- package/dist/components/Virtualizer.js +27 -2
- package/dist/components/Virtualizer.js.map +1 -1
- package/dist/edit/index.d.ts +5 -0
- package/dist/edit/index.js +3 -0
- package/dist/editor/command.d.ts +1 -1
- package/dist/editor/command.d.ts.map +1 -1
- package/dist/editor/command.js +11 -0
- package/dist/editor/command.js.map +1 -1
- package/dist/editor/editStack.d.ts +6 -2
- package/dist/editor/editStack.d.ts.map +1 -1
- package/dist/editor/editStack.js +53 -12
- package/dist/editor/editStack.js.map +1 -1
- package/dist/editor/editor.d.ts +51 -23
- package/dist/editor/editor.d.ts.map +1 -1
- package/dist/editor/editor.js +977 -241
- package/dist/editor/editor.js.map +1 -1
- package/dist/editor/editor2.js +1 -1
- package/dist/editor/languages.d.ts +26 -0
- package/dist/editor/languages.d.ts.map +1 -0
- package/dist/editor/languages.js +363 -0
- package/dist/editor/languages.js.map +1 -0
- package/dist/editor/lineAnnotations.d.ts.map +1 -1
- package/dist/editor/lineAnnotations.js +25 -26
- package/dist/editor/lineAnnotations.js.map +1 -1
- package/dist/editor/marker.d.ts +5 -3
- package/dist/editor/marker.d.ts.map +1 -1
- package/dist/editor/marker.js +111 -91
- package/dist/editor/marker.js.map +1 -1
- package/dist/editor/matchBrackets.d.ts +3 -2
- package/dist/editor/matchBrackets.d.ts.map +1 -1
- package/dist/editor/matchBrackets.js +2 -10
- package/dist/editor/matchBrackets.js.map +1 -1
- package/dist/editor/pieceTable.d.ts +2 -1
- package/dist/editor/pieceTable.d.ts.map +1 -1
- package/dist/editor/pieceTable.js +103 -39
- package/dist/editor/pieceTable.js.map +1 -1
- package/dist/editor/platform.js +2 -0
- package/dist/editor/platform.js.map +1 -1
- package/dist/editor/popover.d.ts +25 -5
- package/dist/editor/popover.d.ts.map +1 -1
- package/dist/editor/popover.js +60 -14
- package/dist/editor/popover.js.map +1 -1
- package/dist/editor/searchPanel.d.ts.map +1 -1
- package/dist/editor/searchPanel.js +9 -2
- package/dist/editor/searchPanel.js.map +1 -1
- package/dist/editor/selection.d.ts +31 -11
- package/dist/editor/selection.d.ts.map +1 -1
- package/dist/editor/selection.js +198 -70
- package/dist/editor/selection.js.map +1 -1
- package/dist/editor/selectionAction.d.ts +4 -3
- package/dist/editor/selectionAction.d.ts.map +1 -1
- package/dist/editor/selectionAction.js +9 -5
- package/dist/editor/selectionAction.js.map +1 -1
- package/dist/editor/stateStorage.d.ts +15 -0
- package/dist/editor/stateStorage.d.ts.map +1 -0
- package/dist/editor/stateStorage.js +65 -0
- package/dist/editor/stateStorage.js.map +1 -0
- package/dist/editor/textDocument.d.ts +12 -77
- package/dist/editor/textDocument.d.ts.map +1 -1
- package/dist/editor/textDocument.js +76 -34
- package/dist/editor/textDocument.js.map +1 -1
- package/dist/editor/textMeasure.d.ts +7 -12
- package/dist/editor/textMeasure.d.ts.map +1 -1
- package/dist/editor/textMeasure.js +40 -32
- package/dist/editor/textMeasure.js.map +1 -1
- package/dist/editor/{tokenzier.d.ts → tokenizer.d.ts} +3 -3
- package/dist/editor/tokenizer.d.ts.map +1 -0
- package/dist/editor/{tokenzier.js → tokenizer.js} +170 -50
- package/dist/editor/tokenizer.js.map +1 -0
- package/dist/editor/utils.js +1 -1
- package/dist/editor/utils.js.map +1 -1
- package/dist/index.d.ts +4 -3
- package/dist/index.js +6 -5
- package/dist/managers/InteractionManager.d.ts +18 -7
- package/dist/managers/InteractionManager.d.ts.map +1 -1
- package/dist/managers/InteractionManager.js +154 -99
- package/dist/managers/InteractionManager.js.map +1 -1
- package/dist/managers/UniversalRenderingManager.d.ts.map +1 -1
- package/dist/managers/UniversalRenderingManager.js +1 -2
- package/dist/managers/UniversalRenderingManager.js.map +1 -1
- package/dist/react/CodeView.d.ts +13 -13
- package/dist/react/CodeView.d.ts.map +1 -1
- package/dist/react/CodeView.js +37 -28
- package/dist/react/CodeView.js.map +1 -1
- package/dist/react/EditContext.d.ts +20 -0
- package/dist/react/EditContext.d.ts.map +1 -0
- package/dist/react/EditContext.js +20 -0
- package/dist/react/EditContext.js.map +1 -0
- package/dist/react/File.d.ts +2 -1
- package/dist/react/File.d.ts.map +1 -1
- package/dist/react/File.js +3 -2
- package/dist/react/File.js.map +1 -1
- package/dist/react/FileDiff.d.ts +2 -2
- package/dist/react/FileDiff.d.ts.map +1 -1
- package/dist/react/FileDiff.js +3 -2
- package/dist/react/FileDiff.js.map +1 -1
- package/dist/react/MultiFileDiff.d.ts +2 -2
- package/dist/react/MultiFileDiff.d.ts.map +1 -1
- package/dist/react/MultiFileDiff.js +3 -2
- package/dist/react/MultiFileDiff.js.map +1 -1
- package/dist/react/PatchDiff.d.ts +2 -2
- package/dist/react/PatchDiff.d.ts.map +1 -1
- package/dist/react/PatchDiff.js +3 -2
- package/dist/react/PatchDiff.js.map +1 -1
- package/dist/react/UnresolvedFile.d.ts +1 -1
- package/dist/react/UnresolvedFile.js.map +1 -1
- package/dist/react/index.d.ts +4 -4
- package/dist/react/index.js +3 -3
- package/dist/react/types.d.ts +9 -1
- package/dist/react/types.d.ts.map +1 -1
- package/dist/react/utils/useFileDiffInstance.d.ts +5 -3
- package/dist/react/utils/useFileDiffInstance.d.ts.map +1 -1
- package/dist/react/utils/useFileDiffInstance.js +24 -34
- package/dist/react/utils/useFileDiffInstance.js.map +1 -1
- package/dist/react/utils/useFileInstance.d.ts +5 -3
- package/dist/react/utils/useFileInstance.d.ts.map +1 -1
- package/dist/react/utils/useFileInstance.js +23 -33
- package/dist/react/utils/useFileInstance.js.map +1 -1
- package/dist/react/utils/useUnresolvedFileInstance.js +4 -4
- package/dist/react/utils/useUnresolvedFileInstance.js.map +1 -1
- package/dist/renderers/DiffHunksRenderer.d.ts +41 -1
- package/dist/renderers/DiffHunksRenderer.d.ts.map +1 -1
- package/dist/renderers/DiffHunksRenderer.js +167 -29
- package/dist/renderers/DiffHunksRenderer.js.map +1 -1
- package/dist/renderers/FileRenderer.d.ts +20 -1
- package/dist/renderers/FileRenderer.d.ts.map +1 -1
- package/dist/renderers/FileRenderer.js +119 -29
- package/dist/renderers/FileRenderer.js.map +1 -1
- package/dist/ssr/index.d.ts +2 -2
- package/dist/ssr/preloadDiffs.d.ts.map +1 -1
- package/dist/ssr/preloadDiffs.js +3 -1
- package/dist/ssr/preloadDiffs.js.map +1 -1
- package/dist/ssr/preloadFile.d.ts.map +1 -1
- package/dist/ssr/preloadFile.js +2 -0
- package/dist/ssr/preloadFile.js.map +1 -1
- package/dist/style.js +1 -1
- package/dist/types.d.ts +192 -42
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/annotationHelpers.d.ts +20 -0
- package/dist/utils/annotationHelpers.d.ts.map +1 -0
- package/dist/utils/annotationHelpers.js +29 -0
- package/dist/utils/annotationHelpers.js.map +1 -0
- package/dist/utils/computeFileOffsets.d.ts.map +1 -1
- package/dist/utils/computeFileOffsets.js +34 -5
- package/dist/utils/computeFileOffsets.js.map +1 -1
- package/dist/utils/editSessionHunks.d.ts +66 -0
- package/dist/utils/editSessionHunks.d.ts.map +1 -0
- package/dist/utils/editSessionHunks.js +437 -0
- package/dist/utils/editSessionHunks.js.map +1 -0
- package/dist/utils/getDiffHunksRendererOptions.d.ts.map +1 -1
- package/dist/utils/getDiffHunksRendererOptions.js +2 -1
- package/dist/utils/getDiffHunksRendererOptions.js.map +1 -1
- package/dist/utils/getFileRendererOptions.d.ts.map +1 -1
- package/dist/utils/getFileRendererOptions.js +2 -1
- package/dist/utils/getFileRendererOptions.js.map +1 -1
- package/dist/utils/getHunkSideBoundaries.d.ts +7 -0
- package/dist/utils/getHunkSideBoundaries.d.ts.map +1 -0
- package/dist/utils/getHunkSideBoundaries.js +12 -0
- package/dist/utils/getHunkSideBoundaries.js.map +1 -0
- package/dist/utils/getTotalLineCountFromHunks.d.ts.map +1 -1
- package/dist/utils/getTotalLineCountFromHunks.js +2 -1
- package/dist/utils/getTotalLineCountFromHunks.js.map +1 -1
- package/dist/utils/hydratePartialDiff.d.ts.map +1 -1
- package/dist/utils/hydratePartialDiff.js +4 -3
- package/dist/utils/hydratePartialDiff.js.map +1 -1
- package/dist/utils/isGutterUtilityPath.d.ts +5 -0
- package/dist/utils/isGutterUtilityPath.d.ts.map +1 -0
- package/dist/utils/isGutterUtilityPath.js +12 -0
- package/dist/utils/isGutterUtilityPath.js.map +1 -0
- package/dist/utils/iterateOverDiff.d.ts.map +1 -1
- package/dist/utils/iterateOverDiff.js +17 -12
- package/dist/utils/iterateOverDiff.js.map +1 -1
- package/dist/utils/parseMergeConflictDiffFromFile.d.ts.map +1 -1
- package/dist/utils/parseMergeConflictDiffFromFile.js +9 -6
- package/dist/utils/parseMergeConflictDiffFromFile.js.map +1 -1
- package/dist/utils/parsePatchFiles.d.ts.map +1 -1
- package/dist/utils/parsePatchFiles.js +6 -3
- package/dist/utils/parsePatchFiles.js.map +1 -1
- package/dist/utils/realignChangeContent.d.ts +33 -0
- package/dist/utils/realignChangeContent.d.ts.map +1 -0
- package/dist/utils/realignChangeContent.js +148 -0
- package/dist/utils/realignChangeContent.js.map +1 -0
- package/dist/utils/renderDiffWithHighlighter.js +1 -1
- package/dist/utils/resolveRegion.d.ts.map +1 -1
- package/dist/utils/resolveRegion.js +18 -2
- package/dist/utils/resolveRegion.js.map +1 -1
- package/dist/utils/shouldUseTokenTransformer.d.ts +7 -3
- package/dist/utils/shouldUseTokenTransformer.d.ts.map +1 -1
- package/dist/utils/shouldUseTokenTransformer.js +1 -1
- package/dist/utils/shouldUseTokenTransformer.js.map +1 -1
- package/dist/utils/updateDiffHunks.d.ts +8 -2
- package/dist/utils/updateDiffHunks.d.ts.map +1 -1
- package/dist/utils/updateDiffHunks.js +9 -7
- package/dist/utils/updateDiffHunks.js.map +1 -1
- package/dist/utils/virtualDiffLayout.d.ts +42 -2
- package/dist/utils/virtualDiffLayout.d.ts.map +1 -1
- package/dist/utils/virtualDiffLayout.js +101 -7
- package/dist/utils/virtualDiffLayout.js.map +1 -1
- package/dist/worker/WorkerPoolManager.d.ts +2 -1
- package/dist/worker/WorkerPoolManager.d.ts.map +1 -1
- package/dist/worker/WorkerPoolManager.js +3 -0
- package/dist/worker/WorkerPoolManager.js.map +1 -1
- package/dist/worker/worker-portable.js +60 -20
- package/dist/worker/worker-portable.js.map +1 -1
- package/dist/worker/worker.js +61 -19
- package/dist/worker/worker.js.map +1 -1
- package/package.json +10 -7
- package/dist/editor/index.d.ts +0 -3
- package/dist/editor/index.js +0 -3
- package/dist/editor/tokenzier.d.ts.map +0 -1
- package/dist/editor/tokenzier.js.map +0 -1
- package/dist/react/EditorContext.d.ts +0 -15
- package/dist/react/EditorContext.d.ts.map +0 -1
- package/dist/react/EditorContext.js +0 -23
- package/dist/react/EditorContext.js.map +0 -1
package/dist/editor/editor.js
CHANGED
|
@@ -1,21 +1,24 @@
|
|
|
1
1
|
import { dequeueRender, queueRender } from "../managers/UniversalRenderingManager.js";
|
|
2
|
+
import { isGutterUtilityPath } from "../utils/isGutterUtilityPath.js";
|
|
2
3
|
import { getFiletypeFromFileName } from "../utils/getFiletypeFromFileName.js";
|
|
3
4
|
import { isMoveCursorShortcut, isPrimaryModifier, isSafari } from "./platform.js";
|
|
4
5
|
import { resolveEditorCommandFromKeyboardEvent, resolveFindAgainShortcut } from "./command.js";
|
|
5
|
-
import { EditStack } from "./editStack.js";
|
|
6
6
|
import editor_default from "./editor2.js";
|
|
7
|
+
import { EditStack } from "./editStack.js";
|
|
8
|
+
import { resolveBlockCommentEdits, resolveCommentConfig, resolveLineCommentEdits } from "./languages.js";
|
|
7
9
|
import { addEventListener, clampDomOffset, extend, getLineNumberAttr, h, round } from "./utils.js";
|
|
8
10
|
import { applyDocumentChangeToLineAnnotations, renderLineAnnotations } from "./lineAnnotations.js";
|
|
9
11
|
import { PopoverManager } from "./popover.js";
|
|
10
|
-
import { applyDeleteCharacterToSelections, applyDeleteHardLineForwardToSelections, applyDeleteSoftLineBackwardToSelections, applyDeleteWordBackwardToSelections, applyTextChangeToSelections, applyTextReplaceToSelections, applyTransposeToSelections, comparePosition, convertSelection, createSelectionFrom, createSelectionFromAnchorAndFocusOffsets, expandCollapsedSelectionToWord, extendSelection, extendSelections,
|
|
12
|
+
import { applyDeleteCharacterToSelections, applyDeleteHardLineForwardToSelections, applyDeleteSoftLineBackwardToSelections, applyDeleteWordBackwardToSelections, applyTextChangeToSelections, applyTextReplaceToSelections, applyTransposeToSelections, comparePosition, convertSelection, createSelectionFrom, createSelectionFromAnchorAndFocusOffsets, expandCollapsedSelectionToWord, extendSelection, extendSelections, findNextMatch, getAutoSurroundReplacementTexts, getCaretPosition, getDocumentBoundarySelection, getDocumentFullSelection, getSelectedLineBlocks, getSelectionAnchor, getSelectionClipboardTexts, getSelectionText, isCollapsedSelection, isLineEditable, mapCursorMove, mapSelectionShift, mergeOverlappingSelections, remapSelectionsAfterEdits, resolveIndentEdits, resolveSelectionCut, selectionIntersects, shiftSelectionLines } from "./selection.js";
|
|
11
13
|
import { MarkerRenderer, markerSeverityDatasetKey } from "./marker.js";
|
|
12
14
|
import { findBracketMatchRanges } from "./matchBrackets.js";
|
|
13
15
|
import { createSpriteElement } from "./sprite.js";
|
|
14
16
|
import { SearchPanelWidget } from "./searchPanel.js";
|
|
15
17
|
import { SelectionActionWidget } from "./selectionAction.js";
|
|
18
|
+
import { cloneEditorState, createStateStorage } from "./stateStorage.js";
|
|
16
19
|
import { TextDocument } from "./textDocument.js";
|
|
17
20
|
import { Metrics, getExpandedAsciiTextColumns, getUnicodeMeasurementOffsets, snapTextOffsetToUnicodeBoundary } from "./textMeasure.js";
|
|
18
|
-
import { EditorTokenizer, renderLineTokens } from "./
|
|
21
|
+
import { EditorTokenizer, renderLineTokens } from "./tokenizer.js";
|
|
19
22
|
//#region src/editor/editor.ts
|
|
20
23
|
function getShadowRootRange(shadowRoot) {
|
|
21
24
|
const selection = shadowRoot.getSelection?.();
|
|
@@ -29,16 +32,38 @@ function getShadowRootRange(shadowRoot) {
|
|
|
29
32
|
endOffset: range.endOffset
|
|
30
33
|
};
|
|
31
34
|
}
|
|
35
|
+
function requirePersistedCacheKey(file) {
|
|
36
|
+
if (typeof file.cacheKey !== "string" || file.cacheKey.length === 0) throw new Error(`Editor persistState requires a non-empty file.cacheKey for "${file.name}". Provide a unique, stable cacheKey for every editable file.`);
|
|
37
|
+
return file.cacheKey;
|
|
38
|
+
}
|
|
39
|
+
function isPromise(value) {
|
|
40
|
+
return typeof value === "object" && value !== null && "then" in value && typeof value.then === "function";
|
|
41
|
+
}
|
|
32
42
|
const MAX_EDIT_WIDEN_WINDOW_MULTIPLE = 2;
|
|
43
|
+
const MAX_WRAP_OFFSETS_CACHE_LINES = 1e4;
|
|
44
|
+
const SELECTION_ACTION_POPOVER_PLACEMENT_KEY = "selection-action";
|
|
45
|
+
const MULTI_SELECTION_CLIPBOARD_TYPE = "application/vnd.pierre.diffs-selections+json";
|
|
33
46
|
var Editor = class {
|
|
34
47
|
#options;
|
|
35
48
|
#metrics = new Metrics();
|
|
36
49
|
#tokenizer;
|
|
37
50
|
#popoverManager;
|
|
51
|
+
#textDocumentCache = /* @__PURE__ */ new Map();
|
|
52
|
+
#stateStorage;
|
|
53
|
+
#stateStorageOption;
|
|
54
|
+
#pendingStateWrites = /* @__PURE__ */ new Map();
|
|
55
|
+
#pendingStateRestore;
|
|
56
|
+
#stateRestoreGeneration = 0;
|
|
57
|
+
#restoreStateOnNextSync = false;
|
|
38
58
|
#editorEventDisposes;
|
|
39
59
|
#globalEventDisposes;
|
|
40
60
|
#selectEventDisposes;
|
|
41
61
|
#detach;
|
|
62
|
+
#attachState = {
|
|
63
|
+
generation: 0,
|
|
64
|
+
callback: void 0,
|
|
65
|
+
delivered: false
|
|
66
|
+
};
|
|
42
67
|
#contentOffset;
|
|
43
68
|
#gutterWidthCache;
|
|
44
69
|
#contentWidthCache;
|
|
@@ -66,9 +91,11 @@ var Editor = class {
|
|
|
66
91
|
#markerRenderer;
|
|
67
92
|
#searchPanel;
|
|
68
93
|
#selectionAction;
|
|
94
|
+
#canMountSelectionAction = true;
|
|
69
95
|
#shouldIgnoreSelectionChange = false;
|
|
70
96
|
#suppressNativeSelectionSync = false;
|
|
71
97
|
#contentHasFocus = false;
|
|
98
|
+
#replacementFocusRequest;
|
|
72
99
|
#isComposing = false;
|
|
73
100
|
#isGutterMouseDown = false;
|
|
74
101
|
#isContentMouseDown = false;
|
|
@@ -87,13 +114,13 @@ var Editor = class {
|
|
|
87
114
|
#fontRemeasureScheduled = false;
|
|
88
115
|
#themeSelectionRefreshFrame;
|
|
89
116
|
#onDeferTokenize = (lines, themeType) => {
|
|
90
|
-
this.#fileInstance?.updateRenderCache(lines, themeType
|
|
117
|
+
this.#fileInstance?.updateRenderCache(lines, themeType);
|
|
91
118
|
if (this.#renderRange !== void 0 && this.#renderRange.totalLines !== Infinity) {
|
|
92
119
|
const { startingLine, totalLines } = this.#renderRange;
|
|
93
120
|
const endLine = Math.min(startingLine + totalLines, this.#textDocument?.lineCount ?? 0);
|
|
94
121
|
for (const [line, tokens] of lines) if (line >= startingLine && line < endLine) {
|
|
95
122
|
const lineElement = this.#getLineElement(line);
|
|
96
|
-
if (lineElement !== void 0) lineElement.replaceChildren(...renderLineTokens(tokens
|
|
123
|
+
if (lineElement !== void 0) lineElement.replaceChildren(...renderLineTokens(tokens));
|
|
97
124
|
}
|
|
98
125
|
}
|
|
99
126
|
};
|
|
@@ -101,47 +128,56 @@ var Editor = class {
|
|
|
101
128
|
this.#options = options;
|
|
102
129
|
}
|
|
103
130
|
setOptions(options) {
|
|
104
|
-
this.#options
|
|
131
|
+
const previousStorageOption = this.#options.persistStateStorage ?? "inMemory";
|
|
132
|
+
const nextOptions = {
|
|
105
133
|
...this.#options,
|
|
106
134
|
...options
|
|
107
135
|
};
|
|
136
|
+
if (nextOptions.persistState === true && this.#fileInstance?.type === "file") {
|
|
137
|
+
const file = this.#fileInstance.__getCurrentFile?.() ?? this.#fileInfo;
|
|
138
|
+
if (file !== void 0) requirePersistedCacheKey(file);
|
|
139
|
+
}
|
|
140
|
+
this.#options = nextOptions;
|
|
141
|
+
if (this.#options.persistState !== true) {
|
|
142
|
+
this.#textDocumentCache.clear();
|
|
143
|
+
this.#stateRestoreGeneration++;
|
|
144
|
+
this.#restoreStateOnNextSync = false;
|
|
145
|
+
}
|
|
146
|
+
if ((this.#options.persistStateStorage ?? "inMemory") !== previousStorageOption) {
|
|
147
|
+
this.#stateRestoreGeneration++;
|
|
148
|
+
this.#stateStorage = void 0;
|
|
149
|
+
this.#stateStorageOption = void 0;
|
|
150
|
+
this.#pendingStateWrites.clear();
|
|
151
|
+
}
|
|
108
152
|
}
|
|
109
153
|
edit(fileInstance) {
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
...rest,
|
|
114
|
-
useTokenTransformer: true,
|
|
115
|
-
enableGutterUtility: false,
|
|
116
|
-
enableLineSelection: false,
|
|
117
|
-
expandUnchanged: true,
|
|
118
|
-
lineHoverHighlight: "disabled"
|
|
119
|
-
});
|
|
120
|
-
fileInstance.rerender();
|
|
154
|
+
if (this.#options.persistState === true && fileInstance.type === "file") {
|
|
155
|
+
const file = fileInstance.__getCurrentFile?.();
|
|
156
|
+
if (file !== void 0) requirePersistedCacheKey(file);
|
|
121
157
|
}
|
|
158
|
+
this.#invalidateOnAttach();
|
|
122
159
|
this.#fileInstance = fileInstance;
|
|
123
160
|
this.#initialize();
|
|
124
161
|
this.#detach = fileInstance.attachEditor(this);
|
|
125
162
|
return () => this.cleanUp();
|
|
126
163
|
}
|
|
127
164
|
/**
|
|
128
|
-
* Apply edits to current attached file.
|
|
165
|
+
* Apply edits to current attached file. Every edit joins the undo timeline:
|
|
166
|
+
* a programmatic edit must leave the document and its history exactly as
|
|
167
|
+
* the same edit typed by the user would (history equivalence — see
|
|
168
|
+
* TextDocument.applyResolvedEdits), so it is undoable like any other edit.
|
|
169
|
+
*
|
|
170
|
+
* @param updateHistory Whether to record caller selection snapshots for
|
|
171
|
+
* exact undo/redo restoration. Defaults to true. When false, live selections
|
|
172
|
+
* are remapped during replay and the text edit still joins the undo timeline.
|
|
129
173
|
*/
|
|
130
|
-
applyEdits(edits, updateHistory =
|
|
174
|
+
applyEdits(edits, updateHistory = true) {
|
|
131
175
|
const textDocument = this.#textDocument;
|
|
132
176
|
if (textDocument == null) throw new Error("Editor is not attached");
|
|
133
177
|
const wasFocused = this.#contentHasFocus;
|
|
134
178
|
const selectionsBefore = this.#selections;
|
|
135
179
|
const selectionOffsetsBefore = selectionsBefore?.map((selection) => [textDocument.offsetAt(selection.start), textDocument.offsetAt(selection.end)]);
|
|
136
|
-
const resolvedEditOffsets = selectionsBefore === void 0 ? void 0 : edits.
|
|
137
|
-
const a = textDocument.offsetAt(edit.range.start);
|
|
138
|
-
const b = textDocument.offsetAt(edit.range.end);
|
|
139
|
-
return {
|
|
140
|
-
start: Math.min(a, b),
|
|
141
|
-
end: Math.max(a, b),
|
|
142
|
-
text: edit.newText
|
|
143
|
-
};
|
|
144
|
-
}).sort((a, b) => a.start - b.start);
|
|
180
|
+
const resolvedEditOffsets = selectionsBefore === void 0 ? void 0 : textDocument.resolveEdits(edits).sort((a, b) => a.start - b.start);
|
|
145
181
|
const change = textDocument.applyEdits(edits, updateHistory, selectionsBefore);
|
|
146
182
|
if (change === void 0) return;
|
|
147
183
|
let nextSelections;
|
|
@@ -167,45 +203,58 @@ var Editor = class {
|
|
|
167
203
|
redo() {
|
|
168
204
|
this.#runCommand("redo");
|
|
169
205
|
}
|
|
206
|
+
getFile() {
|
|
207
|
+
const fileInfo = this.#fileInfo;
|
|
208
|
+
const textDocument = this.#textDocument;
|
|
209
|
+
if (fileInfo === void 0 || textDocument === void 0) return;
|
|
210
|
+
const file = { ...fileInfo };
|
|
211
|
+
Object.defineProperty(file, "contents", {
|
|
212
|
+
enumerable: true,
|
|
213
|
+
get: () => textDocument.getText()
|
|
214
|
+
});
|
|
215
|
+
return file;
|
|
216
|
+
}
|
|
217
|
+
getText() {
|
|
218
|
+
return this.#textDocument?.getText() ?? "";
|
|
219
|
+
}
|
|
170
220
|
getState() {
|
|
171
|
-
const
|
|
172
|
-
if (fileRef === void 0) throw new Error("Editor is not attached");
|
|
221
|
+
const fileInstance = this.#fileInstance;
|
|
173
222
|
return {
|
|
174
|
-
file: {
|
|
175
|
-
...fileRef,
|
|
176
|
-
cacheKey: "edited-at-" + Date.now()
|
|
177
|
-
},
|
|
178
223
|
selections: this.#selections,
|
|
179
|
-
|
|
180
|
-
renderRange: this.#renderRange
|
|
224
|
+
view: fileInstance != null ? { scrollLeft: fileInstance.getCodeScrollLeft() } : void 0
|
|
181
225
|
};
|
|
182
226
|
}
|
|
183
|
-
setState({
|
|
184
|
-
this.#
|
|
185
|
-
this.#
|
|
186
|
-
this.#
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
lineAnnotations,
|
|
193
|
-
renderRange
|
|
194
|
-
});
|
|
227
|
+
setState({ selections, view }) {
|
|
228
|
+
if (this.#fileInstance === void 0 || this.#textDocument === void 0) throw new Error("Editor is not attached");
|
|
229
|
+
this.#canMountSelectionAction = false;
|
|
230
|
+
this.#updateSelections(selections ?? []);
|
|
231
|
+
if (view != null) {
|
|
232
|
+
this.#fileInstance.setCodeScrollLeft(view.scrollLeft);
|
|
233
|
+
return;
|
|
234
|
+
}
|
|
235
|
+
this.#scrollToPrimaryCaret();
|
|
195
236
|
}
|
|
196
237
|
setSelections(selections) {
|
|
197
238
|
const textDocument = this.#textDocument;
|
|
198
239
|
if (textDocument === void 0) throw new Error("Text document is not initialized");
|
|
199
240
|
const resolvedSelections = selections.map((selection) => {
|
|
200
|
-
|
|
201
|
-
|
|
241
|
+
let start = textDocument.normalizePosition(selection.start);
|
|
242
|
+
let end = textDocument.normalizePosition(selection.end);
|
|
243
|
+
let direction = selection.direction === "none" ? 0 : selection.direction === "backward" ? -1 : 1;
|
|
244
|
+
if (comparePosition(start, end) > 0) {
|
|
245
|
+
[start, end] = [end, start];
|
|
246
|
+
if (direction !== 0) direction = direction === 1 ? -1 : 1;
|
|
247
|
+
}
|
|
202
248
|
return {
|
|
203
|
-
direction
|
|
249
|
+
direction,
|
|
204
250
|
start,
|
|
205
251
|
end
|
|
206
252
|
};
|
|
207
253
|
});
|
|
254
|
+
this.#canMountSelectionAction = false;
|
|
208
255
|
this.#updateSelections(resolvedSelections);
|
|
256
|
+
const primarySelection = resolvedSelections.at(-1);
|
|
257
|
+
if (primarySelection !== void 0) this.#revealLineIfCollapsed(getCaretPosition(primarySelection).line);
|
|
209
258
|
this.#scrollToPrimaryCaret();
|
|
210
259
|
}
|
|
211
260
|
setMarkers(markers) {
|
|
@@ -232,6 +281,19 @@ var Editor = class {
|
|
|
232
281
|
}
|
|
233
282
|
focus(options) {
|
|
234
283
|
const preventScroll = options?.preventScroll ?? false;
|
|
284
|
+
const lineNumber = options?.lineNumber;
|
|
285
|
+
if (lineNumber === "first-visible" || typeof lineNumber === "number") {
|
|
286
|
+
const textDocument = this.#textDocument;
|
|
287
|
+
if (textDocument == null || this.#fileInstance == null) return;
|
|
288
|
+
const targetLineNumber = lineNumber === "first-visible" ? this.#getFirstVisibleLineNumber(options?.offset) : lineNumber;
|
|
289
|
+
if (targetLineNumber == null) return;
|
|
290
|
+
const position = textDocument.normalizePosition({
|
|
291
|
+
line: targetLineNumber - 1,
|
|
292
|
+
character: lineNumber === "first-visible" ? 0 : options?.character ?? 0
|
|
293
|
+
});
|
|
294
|
+
this.#focusAtPosition(position, preventScroll);
|
|
295
|
+
return;
|
|
296
|
+
}
|
|
235
297
|
const primarySelection = this.#selections?.at(-1);
|
|
236
298
|
if (primarySelection !== void 0) {
|
|
237
299
|
const pos = primarySelection.direction === -1 ? primarySelection.end : primarySelection.start;
|
|
@@ -239,9 +301,19 @@ var Editor = class {
|
|
|
239
301
|
} else this.#focus(void 0, preventScroll);
|
|
240
302
|
}
|
|
241
303
|
blur() {
|
|
304
|
+
this.#replacementFocusRequest = void 0;
|
|
305
|
+
this.#contentHasFocus = false;
|
|
306
|
+
this.#shouldIgnoreSelectionChange = false;
|
|
242
307
|
this.#contentElement?.blur();
|
|
243
308
|
}
|
|
244
309
|
cleanUp(recycle = false) {
|
|
310
|
+
this.#invalidateOnAttach();
|
|
311
|
+
if (!recycle) this.#attachState.delivered = false;
|
|
312
|
+
const hadFileInstance = this.#fileInstance != null;
|
|
313
|
+
const shouldRestoreState = this.#isStatePersistenceEnabled;
|
|
314
|
+
this.#stateRestoreGeneration++;
|
|
315
|
+
this.#persistCurrentState();
|
|
316
|
+
if (hadFileInstance) this.#restoreStateOnNextSync = shouldRestoreState;
|
|
245
317
|
dequeueRender(this.#handleCustomPasteEvent);
|
|
246
318
|
this.#tokenizer?.cleanUp();
|
|
247
319
|
this.#tokenizer = void 0;
|
|
@@ -255,7 +327,7 @@ var Editor = class {
|
|
|
255
327
|
this.#editorEventDisposes = void 0;
|
|
256
328
|
this.#selectEventDisposes?.forEach((dispose) => dispose());
|
|
257
329
|
this.#selectEventDisposes = void 0;
|
|
258
|
-
this.#detach?.();
|
|
330
|
+
this.#detach?.(recycle);
|
|
259
331
|
this.#detach = void 0;
|
|
260
332
|
this.#gutterWidthCache = void 0;
|
|
261
333
|
this.#contentWidthCache = void 0;
|
|
@@ -277,6 +349,7 @@ var Editor = class {
|
|
|
277
349
|
this.#gutterElement = void 0;
|
|
278
350
|
this.#contentElement?.removeAttribute("contentEditable");
|
|
279
351
|
this.#contentElement = void 0;
|
|
352
|
+
this.#replacementFocusRequest = void 0;
|
|
280
353
|
this.#contentHasFocus = false;
|
|
281
354
|
this.#overlayElement?.remove();
|
|
282
355
|
this.#overlayElement = void 0;
|
|
@@ -288,6 +361,24 @@ var Editor = class {
|
|
|
288
361
|
this.#themeSelectionRefreshFrame = void 0;
|
|
289
362
|
}
|
|
290
363
|
this.#resetState();
|
|
364
|
+
this.#fileInstance = void 0;
|
|
365
|
+
}
|
|
366
|
+
/** @internal Capture outgoing state and substitute cached text before render. */
|
|
367
|
+
__prepareFile(file) {
|
|
368
|
+
if (this.#options.persistState !== true) return file;
|
|
369
|
+
const cacheKey = requirePersistedCacheKey(file);
|
|
370
|
+
const fileInfo = this.#fileInfo;
|
|
371
|
+
const languageId = file.lang ?? getFiletypeFromFileName(file.name);
|
|
372
|
+
if (fileInfo !== void 0 && (requirePersistedCacheKey(fileInfo) !== cacheKey || fileInfo.name !== file.name || this.#textDocument?.languageId !== languageId)) {
|
|
373
|
+
this.#stateRestoreGeneration++;
|
|
374
|
+
this.#persistCurrentState();
|
|
375
|
+
}
|
|
376
|
+
const textDocument = this.#getCachedTextDocument(file, cacheKey);
|
|
377
|
+
if (textDocument === void 0 || textDocument.getText() === file.contents) return file;
|
|
378
|
+
return {
|
|
379
|
+
...file,
|
|
380
|
+
contents: textDocument.getText()
|
|
381
|
+
};
|
|
291
382
|
}
|
|
292
383
|
/** @internal */
|
|
293
384
|
__postponeBgTokenizeToNextFrame() {
|
|
@@ -300,7 +391,15 @@ var Editor = class {
|
|
|
300
391
|
}
|
|
301
392
|
}
|
|
302
393
|
/** @internal */
|
|
394
|
+
__captureFocusForDOMReplacement() {
|
|
395
|
+
const contentElement = this.#contentElement;
|
|
396
|
+
const shadowActiveElement = this.#fileContainer?.shadowRoot?.activeElement;
|
|
397
|
+
if (contentElement != null && (this.#contentHasFocus || shadowActiveElement === contentElement || shadowActiveElement != null && contentElement.contains(shadowActiveElement))) this.#replacementFocusRequest = {};
|
|
398
|
+
}
|
|
399
|
+
/** @internal */
|
|
303
400
|
__syncRenderView = (highlighter, fileContainer, fileOrDiff, lineAnnotations, renderRange) => {
|
|
401
|
+
const fileInstance = this.#fileInstance;
|
|
402
|
+
if (fileInstance == null) return;
|
|
304
403
|
const shadowRoot = fileContainer.shadowRoot;
|
|
305
404
|
if (shadowRoot == null) {
|
|
306
405
|
console.error("[editor] Could not find the shadow root.");
|
|
@@ -319,7 +418,10 @@ var Editor = class {
|
|
|
319
418
|
}
|
|
320
419
|
break;
|
|
321
420
|
}
|
|
322
|
-
if (codeElement === void 0 || contentEl === void 0)
|
|
421
|
+
if (codeElement === void 0 || contentEl === void 0) {
|
|
422
|
+
this.#replacementFocusRequest = void 0;
|
|
423
|
+
return;
|
|
424
|
+
}
|
|
323
425
|
this.#getPopoverManager().setViewportElements(fileContainer, codeElement);
|
|
324
426
|
if (this.#fileContainer !== fileContainer) {
|
|
325
427
|
this.#fileContainer = fileContainer;
|
|
@@ -328,28 +430,42 @@ var Editor = class {
|
|
|
328
430
|
if (this.#themeStyleElement !== void 0) shadowRoot.appendChild(this.#themeStyleElement);
|
|
329
431
|
if (this.#spriteElement !== void 0) shadowRoot.prepend(this.#spriteElement);
|
|
330
432
|
}
|
|
331
|
-
|
|
433
|
+
const shouldRebuildDocument = this.#textDocument === void 0 || this.#fileInfo === void 0 || this.#fileInfo.name !== fileOrDiff.name || this.#fileInfo.lang !== fileOrDiff.lang || this.#fileInfo.cacheKey !== fileOrDiff.cacheKey;
|
|
434
|
+
const persistedCacheKey = this.#isStatePersistenceEnabled ? requirePersistedCacheKey(fileOrDiff) : void 0;
|
|
435
|
+
let persistedStateTarget;
|
|
436
|
+
if (shouldRebuildDocument) {
|
|
437
|
+
this.#invalidateOnAttach();
|
|
332
438
|
let contents = "";
|
|
333
439
|
if ("contents" in fileOrDiff) contents = fileOrDiff.contents;
|
|
334
440
|
else contents = fileOrDiff.additionLines.join("");
|
|
335
441
|
const editStack = new EditStack({ maxEntries: this.#options.historyMaxEntries });
|
|
336
|
-
const textDocument = new TextDocument(fileOrDiff.name, contents, fileOrDiff.lang ?? getFiletypeFromFileName(fileOrDiff.name), 0, editStack);
|
|
337
442
|
const { name, lang, cacheKey } = fileOrDiff;
|
|
443
|
+
const languageId = lang ?? getFiletypeFromFileName(fileOrDiff.name);
|
|
444
|
+
const textDocument = (persistedCacheKey !== void 0 ? this.#getCachedTextDocument(fileOrDiff, persistedCacheKey) : void 0) ?? new TextDocument(fileOrDiff.name, contents, languageId, 0, editStack);
|
|
338
445
|
this.#fileInfo = {
|
|
339
446
|
name,
|
|
340
447
|
lang,
|
|
341
448
|
cacheKey
|
|
342
449
|
};
|
|
343
450
|
this.#textDocument = textDocument;
|
|
451
|
+
if (persistedCacheKey !== void 0) {
|
|
452
|
+
this.#textDocumentCache.set(persistedCacheKey, textDocument);
|
|
453
|
+
persistedStateTarget = {
|
|
454
|
+
cacheKey: persistedCacheKey,
|
|
455
|
+
textDocument
|
|
456
|
+
};
|
|
457
|
+
}
|
|
344
458
|
this.#tokenizer?.cleanUp();
|
|
345
459
|
this.#tokenizer = void 0;
|
|
346
460
|
this.#resetState();
|
|
461
|
+
this.#wrapLineOffsetsCache.clear();
|
|
347
462
|
this.#selections = this.#initSelections;
|
|
348
|
-
requestAnimationFrame(() => {
|
|
349
|
-
this.#options.onAttach?.(this, this.#fileInstance);
|
|
350
|
-
});
|
|
351
463
|
if (this.#textDocument !== void 0 && this.#options.__debug === true) console.log("[diffs/editor] text document rebuilt from", fileOrDiff.name);
|
|
352
464
|
}
|
|
465
|
+
if (persistedStateTarget === void 0 && this.#restoreStateOnNextSync && persistedCacheKey !== void 0 && this.#textDocument !== void 0) persistedStateTarget = {
|
|
466
|
+
cacheKey: persistedCacheKey,
|
|
467
|
+
textDocument: this.#textDocument
|
|
468
|
+
};
|
|
353
469
|
const textDocument = this.#textDocument;
|
|
354
470
|
if (this.#tokenizer == null && textDocument != null) this.#tokenizer = new EditorTokenizer({
|
|
355
471
|
highlighter,
|
|
@@ -381,11 +497,12 @@ var Editor = class {
|
|
|
381
497
|
this.#listenContentElement(contentEl, gutterEl);
|
|
382
498
|
if (this.#contentElement !== void 0 && this.#options.__debug === true) console.log("[diffs/editor] full re-render triggered !!!");
|
|
383
499
|
}
|
|
500
|
+
if (this.#replacementFocusRequest != null) this.#replacementFocusRequest.target = contentEl;
|
|
384
501
|
if (contentEl.ariaLabel !== fileOrDiff.name) contentEl.ariaLabel = fileOrDiff.name;
|
|
385
|
-
if (lineAnnotations !== void 0 && lineAnnotations.length > 0 || this.#isDiff
|
|
502
|
+
if (lineAnnotations !== void 0 && lineAnnotations.length > 0 || this.#isDiff) for (const child of this.#contentElement.children) {
|
|
386
503
|
const el = child;
|
|
387
|
-
const { lineAnnotation, lineType } = el.dataset;
|
|
388
|
-
if (lineAnnotation !== void 0 || lineType === "change-deletion") el.setAttribute("contenteditable", "false");
|
|
504
|
+
const { lineAnnotation, lineType, separator } = el.dataset;
|
|
505
|
+
if (lineAnnotation !== void 0 || separator !== void 0 || lineType === "change-deletion") el.setAttribute("contenteditable", "false");
|
|
389
506
|
}
|
|
390
507
|
this.#resetCache();
|
|
391
508
|
this.#tokenizer?.syncTheme(this.#fileInstance?.options ?? {});
|
|
@@ -393,19 +510,140 @@ var Editor = class {
|
|
|
393
510
|
this.#renderRange = renderRange;
|
|
394
511
|
this.#viewportWindowLines = renderRange?.totalLines;
|
|
395
512
|
this.#tokenizer?.prebuildStateStack(renderRange);
|
|
396
|
-
this.#markerRenderer?.
|
|
513
|
+
this.#markerRenderer?.removePopover();
|
|
397
514
|
if (this.#selections !== void 0 || this.#matches !== void 0 || this.#markerRenderer !== void 0) this.#updateSelections(this.#selections ?? []);
|
|
398
515
|
if (this.#initSelections !== void 0 && this.#primaryCaretElement !== void 0) {
|
|
399
516
|
this.#initSelections = void 0;
|
|
400
517
|
this.#scrollToPrimaryCaret(false, "center");
|
|
401
518
|
} else if (this.#scrollingToLine !== void 0) this.#scrollToLine(this.#scrollingToLine, this.#scrollingToLineChar, this.#scrollingToLineNoFocus);
|
|
402
|
-
else if (this.#
|
|
519
|
+
else if (this.#replacementFocusRequest !== void 0) this.#restoreReplacementFocus();
|
|
520
|
+
else if (this.#selections !== void 0 && this.#selections.length > 0 && this.#contentHasFocus && !this.#retainSearchPanelFocus) this.focus({ preventScroll: true });
|
|
403
521
|
if (this.#retainSearchPanelFocus) this.#searchPanel?.focus();
|
|
404
522
|
if (this.#options.__debug === true && renderRange !== void 0) {
|
|
405
523
|
const { startingLine, totalLines } = renderRange;
|
|
406
524
|
console.log("[diffs/editor] render file:", fileOrDiff.name, "RenderRange:", startingLine + "-" + (startingLine + totalLines), "of", this.#textDocument?.lineCount, "lines");
|
|
407
525
|
}
|
|
526
|
+
if (persistedStateTarget !== void 0) {
|
|
527
|
+
this.#restoreStateOnNextSync = false;
|
|
528
|
+
this.#restorePersistedState(persistedStateTarget.cacheKey, persistedStateTarget.textDocument);
|
|
529
|
+
}
|
|
530
|
+
this.#scheduleOnAttach(fileInstance);
|
|
408
531
|
};
|
|
532
|
+
get #isStatePersistenceEnabled() {
|
|
533
|
+
return this.#options.persistState === true && this.#fileInstance?.type === "file";
|
|
534
|
+
}
|
|
535
|
+
#getCachedTextDocument(file, cacheKey) {
|
|
536
|
+
const textDocument = this.#textDocumentCache.get(cacheKey);
|
|
537
|
+
const languageId = file.lang ?? getFiletypeFromFileName(file.name);
|
|
538
|
+
return textDocument?.languageId === languageId ? textDocument : void 0;
|
|
539
|
+
}
|
|
540
|
+
#getStateStorage() {
|
|
541
|
+
const option = this.#options.persistStateStorage ?? "inMemory";
|
|
542
|
+
if (this.#stateStorage === void 0 || this.#stateStorageOption !== option) {
|
|
543
|
+
this.#stateStorage = createStateStorage(option);
|
|
544
|
+
this.#stateStorageOption = option;
|
|
545
|
+
}
|
|
546
|
+
return this.#stateStorage;
|
|
547
|
+
}
|
|
548
|
+
#persistCurrentState() {
|
|
549
|
+
const fileInfo = this.#fileInfo;
|
|
550
|
+
const textDocument = this.#textDocument;
|
|
551
|
+
if (!this.#isStatePersistenceEnabled || fileInfo === void 0 || textDocument === void 0) return;
|
|
552
|
+
const cacheKey = requirePersistedCacheKey(fileInfo);
|
|
553
|
+
this.#textDocumentCache.set(cacheKey, textDocument);
|
|
554
|
+
let storage;
|
|
555
|
+
try {
|
|
556
|
+
storage = this.#getStateStorage();
|
|
557
|
+
} catch {
|
|
558
|
+
return;
|
|
559
|
+
}
|
|
560
|
+
const state = cloneEditorState(this.getState());
|
|
561
|
+
const pendingRestore = this.#pendingStateRestore;
|
|
562
|
+
if (pendingRestore?.cacheKey === cacheKey && pendingRestore.textDocument === textDocument) {
|
|
563
|
+
this.#pendingStateRestore = void 0;
|
|
564
|
+
if (textDocument.version === pendingRestore.documentVersion && this.#selections === pendingRestore.selections && state.view?.scrollLeft === pendingRestore.view?.scrollLeft) return;
|
|
565
|
+
this.#writeState(storage, cacheKey, state, pendingRestore.completion);
|
|
566
|
+
return;
|
|
567
|
+
}
|
|
568
|
+
this.#writeState(storage, cacheKey, state);
|
|
569
|
+
}
|
|
570
|
+
#writeState(storage, cacheKey, state, waitFor) {
|
|
571
|
+
const previousWrite = this.#pendingStateWrites.get(cacheKey);
|
|
572
|
+
if (waitFor !== void 0 || previousWrite !== void 0) {
|
|
573
|
+
let pending = waitFor ?? Promise.resolve();
|
|
574
|
+
if (previousWrite !== void 0) pending = pending.then(() => previousWrite);
|
|
575
|
+
this.#trackStateWrite(cacheKey, pending.then(() => storage.set(cacheKey, state)));
|
|
576
|
+
return;
|
|
577
|
+
}
|
|
578
|
+
let result;
|
|
579
|
+
try {
|
|
580
|
+
result = storage.set(cacheKey, state);
|
|
581
|
+
} catch {
|
|
582
|
+
return;
|
|
583
|
+
}
|
|
584
|
+
if (!isPromise(result)) return;
|
|
585
|
+
this.#trackStateWrite(cacheKey, result);
|
|
586
|
+
}
|
|
587
|
+
#trackStateWrite(cacheKey, result) {
|
|
588
|
+
const pending = result.catch(() => {});
|
|
589
|
+
this.#pendingStateWrites.set(cacheKey, pending);
|
|
590
|
+
pending.finally(() => {
|
|
591
|
+
if (this.#pendingStateWrites.get(cacheKey) === pending) this.#pendingStateWrites.delete(cacheKey);
|
|
592
|
+
});
|
|
593
|
+
}
|
|
594
|
+
#restorePersistedState(cacheKey, textDocument) {
|
|
595
|
+
const generation = ++this.#stateRestoreGeneration;
|
|
596
|
+
const documentVersion = textDocument.version;
|
|
597
|
+
const selections = this.#selections;
|
|
598
|
+
const view = this.getState().view;
|
|
599
|
+
const applyState = (state) => {
|
|
600
|
+
const currentView = this.getState().view;
|
|
601
|
+
if (state === void 0 || generation !== this.#stateRestoreGeneration || this.#textDocument !== textDocument || textDocument.version !== documentVersion || this.#selections !== selections || currentView?.scrollLeft !== view?.scrollLeft || this.#fileInfo === void 0 || requirePersistedCacheKey(this.#fileInfo) !== cacheKey) return;
|
|
602
|
+
this.setState(cloneEditorState(state));
|
|
603
|
+
};
|
|
604
|
+
const readState = () => {
|
|
605
|
+
let result;
|
|
606
|
+
try {
|
|
607
|
+
result = this.#getStateStorage().get(cacheKey);
|
|
608
|
+
} catch {
|
|
609
|
+
return;
|
|
610
|
+
}
|
|
611
|
+
if (isPromise(result)) return result.then(applyState).catch(() => {});
|
|
612
|
+
else try {
|
|
613
|
+
applyState(result);
|
|
614
|
+
} catch {}
|
|
615
|
+
};
|
|
616
|
+
const pendingWrite = this.#pendingStateWrites.get(cacheKey);
|
|
617
|
+
const result = pendingWrite === void 0 ? readState() : pendingWrite.then(readState);
|
|
618
|
+
if (isPromise(result)) {
|
|
619
|
+
const pendingRestore = {
|
|
620
|
+
cacheKey,
|
|
621
|
+
textDocument,
|
|
622
|
+
documentVersion,
|
|
623
|
+
selections,
|
|
624
|
+
view,
|
|
625
|
+
completion: result.catch(() => {})
|
|
626
|
+
};
|
|
627
|
+
this.#pendingStateRestore = pendingRestore;
|
|
628
|
+
pendingRestore.completion.finally(() => {
|
|
629
|
+
if (this.#pendingStateRestore === pendingRestore) this.#pendingStateRestore = void 0;
|
|
630
|
+
});
|
|
631
|
+
}
|
|
632
|
+
}
|
|
633
|
+
#isLineRenderable(line) {
|
|
634
|
+
return this.#fileInstance?.isLineRenderable?.(line + 1) ?? true;
|
|
635
|
+
}
|
|
636
|
+
get #resolveRenderableLine() {
|
|
637
|
+
const fileInstance = this.#fileInstance;
|
|
638
|
+
if (fileInstance?.getNearestRenderableLine == null) return;
|
|
639
|
+
return (line, direction) => {
|
|
640
|
+
const nearest = fileInstance.getNearestRenderableLine(line + 1, direction);
|
|
641
|
+
return nearest == null ? void 0 : nearest - 1;
|
|
642
|
+
};
|
|
643
|
+
}
|
|
644
|
+
#revealLineIfCollapsed(line) {
|
|
645
|
+
if (!this.#isLineRenderable(line)) this.#fileInstance?.revealLine?.(line + 1);
|
|
646
|
+
}
|
|
409
647
|
get #diffSyle() {
|
|
410
648
|
return this.#fileInstance?.options.diffStyle ?? "split";
|
|
411
649
|
}
|
|
@@ -417,21 +655,24 @@ var Editor = class {
|
|
|
417
655
|
}
|
|
418
656
|
#getPopoverManager() {
|
|
419
657
|
return this.#popoverManager ??= new PopoverManager({
|
|
420
|
-
hasActivePopover: () => this.#selectionAction !== void 0,
|
|
421
|
-
updateActivePopover: () =>
|
|
658
|
+
hasActivePopover: () => this.#selectionAction !== void 0 || this.#markerRenderer?.isPopoverVisible() === true,
|
|
659
|
+
updateActivePopover: () => {
|
|
660
|
+
this.#updateSelectionActionPopover();
|
|
661
|
+
this.#markerRenderer?.updatePopoverPosition();
|
|
662
|
+
}
|
|
422
663
|
});
|
|
423
664
|
}
|
|
424
665
|
#resetCache() {
|
|
425
666
|
this.#lineYCache.clear();
|
|
426
|
-
this.#wrapLineOffsetsCache.clear();
|
|
427
667
|
this.#lineElementsCache.clear();
|
|
428
668
|
this.#lastAccessedCharX = void 0;
|
|
429
669
|
}
|
|
430
670
|
#resetState() {
|
|
431
|
-
this.#
|
|
671
|
+
this.#setEditorActiveLineSafe(null);
|
|
432
672
|
this.#gutterWidthCache = void 0;
|
|
433
673
|
this.#contentWidthCache = void 0;
|
|
434
674
|
this.#shouldIgnoreSelectionChange = false;
|
|
675
|
+
this.#suppressNativeSelectionSync = false;
|
|
435
676
|
this.#overlayElements?.forEach((el) => el.remove());
|
|
436
677
|
this.#overlayElements = void 0;
|
|
437
678
|
this.#selections = void 0;
|
|
@@ -443,6 +684,33 @@ var Editor = class {
|
|
|
443
684
|
this.#searchPanel = void 0;
|
|
444
685
|
this.#selectionAction?.cleanup();
|
|
445
686
|
this.#selectionAction = void 0;
|
|
687
|
+
this.#canMountSelectionAction = true;
|
|
688
|
+
}
|
|
689
|
+
#invalidateOnAttach() {
|
|
690
|
+
const attachState = this.#attachState;
|
|
691
|
+
attachState.generation++;
|
|
692
|
+
if (attachState.callback != null) {
|
|
693
|
+
dequeueRender(attachState.callback);
|
|
694
|
+
attachState.callback = void 0;
|
|
695
|
+
}
|
|
696
|
+
}
|
|
697
|
+
#scheduleOnAttach(fileInstance) {
|
|
698
|
+
const attachState = this.#attachState;
|
|
699
|
+
const textDocument = this.#textDocument;
|
|
700
|
+
if (attachState.delivered || attachState.callback != null || textDocument == null) return;
|
|
701
|
+
const { generation } = attachState;
|
|
702
|
+
const callback = () => {
|
|
703
|
+
if (attachState.callback !== callback) return;
|
|
704
|
+
attachState.callback = void 0;
|
|
705
|
+
if (generation !== attachState.generation || this.#fileInstance !== fileInstance || this.#textDocument !== textDocument) return;
|
|
706
|
+
const contentElement = this.#contentElement;
|
|
707
|
+
const shadowRoot = this.#fileContainer?.shadowRoot;
|
|
708
|
+
if (contentElement == null || shadowRoot == null || !shadowRoot.contains(contentElement)) return;
|
|
709
|
+
attachState.delivered = true;
|
|
710
|
+
this.#options.onAttach?.(this, fileInstance);
|
|
711
|
+
};
|
|
712
|
+
attachState.callback = callback;
|
|
713
|
+
queueRender(callback);
|
|
446
714
|
}
|
|
447
715
|
#initialize() {
|
|
448
716
|
this.#globalStyleElement = h("style", {
|
|
@@ -461,7 +729,26 @@ var Editor = class {
|
|
|
461
729
|
this.#themeStyleElement = h("style", { dataset: "editorThemeCss" });
|
|
462
730
|
this.#spriteElement = createSpriteElement();
|
|
463
731
|
this.#overlayElement = h("div", { dataset: "editorOverlay" });
|
|
732
|
+
const replacementFocusTargetIsContent = (event) => {
|
|
733
|
+
const target = event.composedPath()[0];
|
|
734
|
+
return target instanceof Node && this.#contentElement?.contains(target) === true;
|
|
735
|
+
};
|
|
736
|
+
const cancelReplacementFocus = () => {
|
|
737
|
+
if (this.#replacementFocusRequest == null) return;
|
|
738
|
+
this.#replacementFocusRequest = void 0;
|
|
739
|
+
this.#contentHasFocus = false;
|
|
740
|
+
this.#shouldIgnoreSelectionChange = false;
|
|
741
|
+
};
|
|
464
742
|
this.#globalEventDisposes = [
|
|
743
|
+
addEventListener(document, "focusin", (event) => {
|
|
744
|
+
if (!replacementFocusTargetIsContent(event)) cancelReplacementFocus();
|
|
745
|
+
}, { passive: true }),
|
|
746
|
+
addEventListener(document, "pointerdown", (event) => {
|
|
747
|
+
if (!replacementFocusTargetIsContent(event)) queueMicrotask(cancelReplacementFocus);
|
|
748
|
+
}, {
|
|
749
|
+
capture: true,
|
|
750
|
+
passive: true
|
|
751
|
+
}),
|
|
465
752
|
addEventListener(document, "selectionchange", () => {
|
|
466
753
|
const shadowRoot = this.#fileContainer?.shadowRoot;
|
|
467
754
|
if (this.#shouldIgnoreSelectionChange || this.#suppressNativeSelectionSync || shadowRoot == null || !this.#contentHasFocus) return;
|
|
@@ -514,6 +801,12 @@ var Editor = class {
|
|
|
514
801
|
this.#selectEventDisposes?.forEach((dispose) => dispose());
|
|
515
802
|
this.#selectEventDisposes = disposes;
|
|
516
803
|
}
|
|
804
|
+
#isLineSelectionEnabled() {
|
|
805
|
+
return this.#fileInstance?.options.enableLineSelection === true;
|
|
806
|
+
}
|
|
807
|
+
#preserveEditorSelectionsForGutterGesture() {
|
|
808
|
+
this.#suppressNativeSelectionSync = this.#selections !== void 0;
|
|
809
|
+
}
|
|
517
810
|
#listenContentElement(contentEl, gutterEl) {
|
|
518
811
|
const { onFocus, onBlur } = this.#options;
|
|
519
812
|
const targetIsContentElement = (e) => {
|
|
@@ -528,10 +821,15 @@ var Editor = class {
|
|
|
528
821
|
if (!this.#isContentMouseDown && !this.#shouldIgnoreSelectionChange && this.#selections !== void 0 && this.#selections.length > 0) this.#setWindowSelection(this.#selections.at(-1));
|
|
529
822
|
}, { passive: true }),
|
|
530
823
|
addEventListener(contentEl, "blur", () => {
|
|
824
|
+
if (this.#replacementFocusRequest?.target === contentEl) {
|
|
825
|
+
this.#replacementFocusRequest = void 0;
|
|
826
|
+
this.#shouldIgnoreSelectionChange = false;
|
|
827
|
+
}
|
|
531
828
|
this.#contentHasFocus = false;
|
|
532
829
|
onBlur?.();
|
|
533
830
|
}, { passive: true }),
|
|
534
831
|
addEventListener(contentEl, "pointerdown", (e) => {
|
|
832
|
+
this.#canMountSelectionAction = true;
|
|
535
833
|
this.#suppressNativeSelectionSync = false;
|
|
536
834
|
if (e.pointerType !== "mouse") return;
|
|
537
835
|
if (this.#isDeletedLineTarget(e)) {
|
|
@@ -540,7 +838,7 @@ var Editor = class {
|
|
|
540
838
|
return;
|
|
541
839
|
}
|
|
542
840
|
this.#setDeletedTextSelectionActive(false);
|
|
543
|
-
this.#markerRenderer?.
|
|
841
|
+
this.#markerRenderer?.removePopover();
|
|
544
842
|
if (isSafari() && this.#lineAnnotations !== void 0 && this.#lineAnnotations.length > 0) {
|
|
545
843
|
const annotationDisposes = [...contentEl.querySelectorAll("[data-line-annotation]")].map((el) => [addEventListener(el, "mouseenter", () => {
|
|
546
844
|
this.#shouldIgnoreSelectionChange = true;
|
|
@@ -573,27 +871,21 @@ var Editor = class {
|
|
|
573
871
|
this.#retainSearchPanelFocus = false;
|
|
574
872
|
this.#selectionAction?.cleanup();
|
|
575
873
|
this.#selectionAction = void 0;
|
|
576
|
-
|
|
577
|
-
const primarySelection = this.#selections.at(-1);
|
|
578
|
-
if (!isCollapsedSelection(primarySelection) || this.#selections.length > 1) {
|
|
579
|
-
const pos = getCaretPosition(primarySelection);
|
|
580
|
-
this.#updateSelections([{
|
|
581
|
-
start: pos,
|
|
582
|
-
end: pos,
|
|
583
|
-
direction: 0
|
|
584
|
-
}]);
|
|
585
|
-
this.#focus(pos);
|
|
586
|
-
}
|
|
587
|
-
}
|
|
874
|
+
this.#runCommand("simplifySelection");
|
|
588
875
|
return;
|
|
589
876
|
}
|
|
590
877
|
if (!targetIsContentElement(e)) return;
|
|
878
|
+
this.#canMountSelectionAction = true;
|
|
591
879
|
this.#suppressNativeSelectionSync = false;
|
|
592
880
|
const mvShortcut = isMoveCursorShortcut(e);
|
|
593
881
|
const textDocument = this.#textDocument;
|
|
594
882
|
if (this.#selections !== void 0 && this.#selections.length > 0 && mvShortcut !== void 0 && textDocument !== void 0) {
|
|
595
|
-
|
|
596
|
-
|
|
883
|
+
const cursorMoveOptions = {
|
|
884
|
+
getSoftLineOffsets: this.#isWrap ? (line) => this.#wrapLineText(line) : void 0,
|
|
885
|
+
resolveRenderableLine: this.#resolveRenderableLine
|
|
886
|
+
};
|
|
887
|
+
if (e.shiftKey) this.#updateSelections(mapSelectionShift(textDocument, this.#selections, mvShortcut, cursorMoveOptions));
|
|
888
|
+
else this.#updateSelections(mapCursorMove(textDocument, this.#selections, mvShortcut, cursorMoveOptions));
|
|
597
889
|
this.#scrollToPrimaryCaret();
|
|
598
890
|
e.preventDefault();
|
|
599
891
|
return;
|
|
@@ -626,19 +918,34 @@ var Editor = class {
|
|
|
626
918
|
addEventListener(contentEl, "copy", (e) => {
|
|
627
919
|
if (!targetIsContentElement(e)) return;
|
|
628
920
|
e.preventDefault();
|
|
629
|
-
e.clipboardData?.setData("text", this.#
|
|
921
|
+
if (this.#isDeletedTextSelectionActive()) e.clipboardData?.setData("text", this.#deletedTextForClipboard());
|
|
922
|
+
else this.#writeSelectionClipboardData(e.clipboardData, this.#getSelectionText(), this.#getSelectionClipboardTexts());
|
|
630
923
|
}),
|
|
631
924
|
addEventListener(contentEl, "cut", (e) => {
|
|
632
925
|
if (!targetIsContentElement(e)) return;
|
|
633
926
|
e.preventDefault();
|
|
634
|
-
e.clipboardData?.setData("text", this.#
|
|
927
|
+
if (this.#isDeletedTextSelectionActive()) e.clipboardData?.setData("text", this.#deletedTextForClipboard());
|
|
928
|
+
else {
|
|
929
|
+
const selectionTexts = this.#getSelectionClipboardTexts();
|
|
930
|
+
this.#writeSelectionClipboardData(e.clipboardData, this.#cutSelectionText(), selectionTexts);
|
|
931
|
+
}
|
|
635
932
|
}),
|
|
636
933
|
addEventListener(contentEl, "paste", (e) => {
|
|
637
934
|
if (!targetIsContentElement(e)) return;
|
|
638
935
|
e.preventDefault();
|
|
639
|
-
const
|
|
936
|
+
const clipboardData = e.clipboardData;
|
|
640
937
|
const textDocument = this.#textDocument;
|
|
641
|
-
if (
|
|
938
|
+
if (clipboardData === null || textDocument === void 0) return;
|
|
939
|
+
let text = clipboardData.getData("text");
|
|
940
|
+
const selectionCount = this.#selections?.length ?? 0;
|
|
941
|
+
if (selectionCount > 1) {
|
|
942
|
+
const multiSelectionText = clipboardData.getData(MULTI_SELECTION_CLIPBOARD_TYPE);
|
|
943
|
+
if (multiSelectionText !== void 0) try {
|
|
944
|
+
const selectionTexts = JSON.parse(multiSelectionText);
|
|
945
|
+
if (Array.isArray(selectionTexts) && selectionTexts.length === selectionCount) text = selectionTexts;
|
|
946
|
+
} catch {}
|
|
947
|
+
}
|
|
948
|
+
this.#replaceSelectionText(Array.isArray(text) ? text.map((t) => textDocument.normalizeEol(t)) : textDocument.normalizeEol(text), void 0, true, "document");
|
|
642
949
|
}),
|
|
643
950
|
addEventListener(contentEl, "beforeinput", (e) => {
|
|
644
951
|
if (!targetIsContentElement(e)) return;
|
|
@@ -665,9 +972,20 @@ var Editor = class {
|
|
|
665
972
|
];
|
|
666
973
|
const deletionsCode = this.#fileContainer?.shadowRoot?.querySelector("[data-deletions]");
|
|
667
974
|
if (deletionsCode != null) this.#editorEventDisposes.push(addEventListener(deletionsCode, "pointerdown", (e) => {
|
|
668
|
-
const
|
|
975
|
+
const path = e.composedPath();
|
|
976
|
+
if (isGutterUtilityPath(path)) {
|
|
977
|
+
this.#preserveEditorSelectionsForGutterGesture();
|
|
978
|
+
return;
|
|
979
|
+
}
|
|
980
|
+
const target = path[0];
|
|
669
981
|
const gutterRow = target instanceof HTMLElement ? target.closest("[data-column-number]") : null;
|
|
670
|
-
if (gutterRow instanceof HTMLElement
|
|
982
|
+
if (gutterRow instanceof HTMLElement) {
|
|
983
|
+
if (this.#isLineSelectionEnabled()) {
|
|
984
|
+
this.#preserveEditorSelectionsForGutterGesture();
|
|
985
|
+
return;
|
|
986
|
+
}
|
|
987
|
+
if (this.#beginDeletionGutterSelection(gutterRow, deletionsCode, e.pointerType === "mouse")) return;
|
|
988
|
+
}
|
|
671
989
|
this.#setDeletedTextSelectionActive(true);
|
|
672
990
|
if (this.#selections !== void 0) this.#updateSelections([]);
|
|
673
991
|
}, { passive: true }));
|
|
@@ -686,7 +1004,16 @@ var Editor = class {
|
|
|
686
1004
|
return lineNumber - 1;
|
|
687
1005
|
};
|
|
688
1006
|
this.#editorEventDisposes.push(addEventListener(gutterEl, "pointerdown", (e) => {
|
|
689
|
-
const
|
|
1007
|
+
const path = e.composedPath();
|
|
1008
|
+
if (isGutterUtilityPath(path)) {
|
|
1009
|
+
this.#preserveEditorSelectionsForGutterGesture();
|
|
1010
|
+
return;
|
|
1011
|
+
}
|
|
1012
|
+
const gutterRow = resolveGutterTarget(path[0]);
|
|
1013
|
+
if (gutterRow !== void 0 && this.#isLineSelectionEnabled()) {
|
|
1014
|
+
this.#preserveEditorSelectionsForGutterGesture();
|
|
1015
|
+
return;
|
|
1016
|
+
}
|
|
690
1017
|
if (gutterRow?.dataset.lineType === "change-deletion") {
|
|
691
1018
|
const code = gutterRow.closest("[data-code]");
|
|
692
1019
|
if (code != null) this.#beginDeletionGutterSelection(gutterRow, code, e.pointerType === "mouse");
|
|
@@ -696,7 +1023,8 @@ var Editor = class {
|
|
|
696
1023
|
const textDocument = this.#textDocument;
|
|
697
1024
|
const lineIndex = resolveEditableLine(gutterRow);
|
|
698
1025
|
if (lineIndex === void 0 || textDocument === void 0) return;
|
|
699
|
-
this.#
|
|
1026
|
+
this.#canMountSelectionAction = true;
|
|
1027
|
+
this.#markerRenderer?.removePopover();
|
|
700
1028
|
const selection = this.#spanLineSelection(lineIndex, lineIndex, textDocument);
|
|
701
1029
|
this.#isGutterMouseDown = true;
|
|
702
1030
|
this.#selectionStart = selection;
|
|
@@ -726,8 +1054,17 @@ var Editor = class {
|
|
|
726
1054
|
#handleCustomPasteEvent = async () => {
|
|
727
1055
|
const clipboard = this.#options.clipboard;
|
|
728
1056
|
if (clipboard !== void 0) {
|
|
729
|
-
|
|
730
|
-
this.#
|
|
1057
|
+
let text = await clipboard.readText();
|
|
1058
|
+
const selectionCount = this.#selections?.length ?? 0;
|
|
1059
|
+
if (selectionCount > 1) {
|
|
1060
|
+
const multiSelectionText = await clipboard.readText(MULTI_SELECTION_CLIPBOARD_TYPE);
|
|
1061
|
+
try {
|
|
1062
|
+
const selectionTexts = JSON.parse(multiSelectionText);
|
|
1063
|
+
if (Array.isArray(selectionTexts) && selectionTexts.length === selectionCount) text = selectionTexts;
|
|
1064
|
+
} catch {}
|
|
1065
|
+
}
|
|
1066
|
+
const textDocument = this.#textDocument;
|
|
1067
|
+
if (textDocument !== void 0) this.#replaceSelectionText(Array.isArray(text) ? text.map((t) => textDocument.normalizeEol(t)) : textDocument.normalizeEol(text), void 0, true, "document");
|
|
731
1068
|
}
|
|
732
1069
|
};
|
|
733
1070
|
#computeContentOffset(contentEl) {
|
|
@@ -763,9 +1100,11 @@ var Editor = class {
|
|
|
763
1100
|
this.#updateSelections(expanded);
|
|
764
1101
|
this.focus();
|
|
765
1102
|
} else {
|
|
766
|
-
const nextMatch =
|
|
1103
|
+
const nextMatch = findNextMatch(textDocument, selections);
|
|
767
1104
|
if (nextMatch !== void 0) {
|
|
768
1105
|
this.#updateSelections(nextMatch);
|
|
1106
|
+
const primaryMatch = nextMatch.at(-1);
|
|
1107
|
+
if (primaryMatch !== void 0) this.#revealLineIfCollapsed(getCaretPosition(primaryMatch).line);
|
|
769
1108
|
this.#scrollToPrimaryCaret();
|
|
770
1109
|
}
|
|
771
1110
|
}
|
|
@@ -775,18 +1114,74 @@ var Editor = class {
|
|
|
775
1114
|
case "moveLineDown":
|
|
776
1115
|
this.#moveSelectedLines(command === "moveLineUp" ? -1 : 1);
|
|
777
1116
|
break;
|
|
1117
|
+
case "copyLineUp":
|
|
1118
|
+
case "copyLineDown":
|
|
1119
|
+
this.#copySelectedLines(command === "copyLineUp" ? -1 : 1);
|
|
1120
|
+
break;
|
|
1121
|
+
case "simplifySelection": {
|
|
1122
|
+
const selections = this.#selections;
|
|
1123
|
+
const primarySelection = selections?.at(-1);
|
|
1124
|
+
if (selections === void 0 || primarySelection === void 0) break;
|
|
1125
|
+
if (selections.length > 1) {
|
|
1126
|
+
this.#updateSelections([primarySelection]);
|
|
1127
|
+
this.#focus(getCaretPosition(primarySelection));
|
|
1128
|
+
} else if (!isCollapsedSelection(primarySelection)) {
|
|
1129
|
+
const caret = getCaretPosition(primarySelection);
|
|
1130
|
+
this.#updateSelections([{
|
|
1131
|
+
start: caret,
|
|
1132
|
+
end: caret,
|
|
1133
|
+
direction: 0
|
|
1134
|
+
}]);
|
|
1135
|
+
this.#focus(caret);
|
|
1136
|
+
}
|
|
1137
|
+
break;
|
|
1138
|
+
}
|
|
1139
|
+
case "insertBlankLine":
|
|
1140
|
+
this.#insertBlankLine();
|
|
1141
|
+
break;
|
|
1142
|
+
case "deleteHardLineForward":
|
|
1143
|
+
this.#deleteHardLineForward();
|
|
1144
|
+
break;
|
|
1145
|
+
case "toggleComment":
|
|
1146
|
+
case "toggleBlockComment": {
|
|
1147
|
+
const selections = this.#selections;
|
|
1148
|
+
if (selections === void 0) break;
|
|
1149
|
+
const { lineComment, blockComment } = resolveCommentConfig(textDocument.languageId, this.#options.languageCommentConfig);
|
|
1150
|
+
if (command === "toggleComment" && lineComment !== null) {
|
|
1151
|
+
this.#applyCommandEdits(resolveLineCommentEdits(textDocument, selections, lineComment));
|
|
1152
|
+
break;
|
|
1153
|
+
}
|
|
1154
|
+
const linewise = command === "toggleComment";
|
|
1155
|
+
const result = resolveBlockCommentEdits(textDocument, selections, blockComment, linewise);
|
|
1156
|
+
if (result !== void 0) this.#applyCommandEdits(result.edits, linewise ? void 0 : (document) => result.nextSelectionOffsets.map(([start, end, direction]) => ({
|
|
1157
|
+
start: document.positionAt(start),
|
|
1158
|
+
end: document.positionAt(end),
|
|
1159
|
+
direction
|
|
1160
|
+
})));
|
|
1161
|
+
break;
|
|
1162
|
+
}
|
|
778
1163
|
case "indent":
|
|
779
1164
|
case "outdent":
|
|
1165
|
+
case "indentLess":
|
|
1166
|
+
case "indentMore":
|
|
780
1167
|
if (this.#selections !== void 0) {
|
|
781
1168
|
const edits = [];
|
|
782
1169
|
const nextSelections = [];
|
|
1170
|
+
const editedLines = /* @__PURE__ */ new Set();
|
|
783
1171
|
const sameLineIndents = [];
|
|
784
1172
|
for (const selection of this.#selections) {
|
|
785
1173
|
const startLine = selection.start.line;
|
|
786
|
-
const outdent = command === "outdent";
|
|
787
|
-
|
|
1174
|
+
const outdent = command === "outdent" || command === "indentLess";
|
|
1175
|
+
const lineBased = command === "indentLess" || command === "indentMore";
|
|
1176
|
+
if (startLine !== selection.end.line || outdent || lineBased) {
|
|
788
1177
|
const ret = resolveIndentEdits(textDocument, selection, this.#metrics.tabSize, outdent);
|
|
789
|
-
|
|
1178
|
+
for (const edit of ret[0]) {
|
|
1179
|
+
const line = edit.range.start.line;
|
|
1180
|
+
if (!editedLines.has(line)) {
|
|
1181
|
+
editedLines.add(line);
|
|
1182
|
+
edits.push(edit);
|
|
1183
|
+
}
|
|
1184
|
+
}
|
|
790
1185
|
nextSelections.push(ret[1]);
|
|
791
1186
|
} else {
|
|
792
1187
|
const text = textDocument.charAt({
|
|
@@ -838,17 +1233,19 @@ var Editor = class {
|
|
|
838
1233
|
const fullSelection = getDocumentFullSelection(textDocument);
|
|
839
1234
|
this.#updateSelections([fullSelection]);
|
|
840
1235
|
this.focus();
|
|
841
|
-
const
|
|
842
|
-
|
|
1236
|
+
const renderedLineRanges = this.#getRenderedEditableLineRanges();
|
|
1237
|
+
const firstRenderedLine = renderedLineRanges[0]?.[0];
|
|
1238
|
+
const lastRenderedLine = renderedLineRanges.at(-1)?.[1];
|
|
1239
|
+
if (firstRenderedLine !== void 0 && lastRenderedLine !== void 0) {
|
|
843
1240
|
this.#suppressNativeSelectionSync = true;
|
|
844
1241
|
this.#setWindowSelection({
|
|
845
1242
|
start: {
|
|
846
|
-
line:
|
|
1243
|
+
line: firstRenderedLine,
|
|
847
1244
|
character: 0
|
|
848
1245
|
},
|
|
849
1246
|
end: {
|
|
850
|
-
line:
|
|
851
|
-
character: textDocument.getLineLength(
|
|
1247
|
+
line: lastRenderedLine,
|
|
1248
|
+
character: textDocument.getLineLength(lastRenderedLine)
|
|
852
1249
|
},
|
|
853
1250
|
direction: 1
|
|
854
1251
|
});
|
|
@@ -858,8 +1255,9 @@ var Editor = class {
|
|
|
858
1255
|
case "moveCursorToDocStart":
|
|
859
1256
|
case "moveCursorToDocEnd":
|
|
860
1257
|
{
|
|
861
|
-
const
|
|
862
|
-
this.#updateSelections([
|
|
1258
|
+
const boundarySelection = getDocumentBoundarySelection(textDocument, command === "moveCursorToDocEnd", this.#isDiff);
|
|
1259
|
+
this.#updateSelections([boundarySelection]);
|
|
1260
|
+
this.#revealLineIfCollapsed(getCaretPosition(boundarySelection).line);
|
|
863
1261
|
this.#scrollToPrimaryCaret();
|
|
864
1262
|
}
|
|
865
1263
|
break;
|
|
@@ -869,25 +1267,191 @@ var Editor = class {
|
|
|
869
1267
|
const atEnd = command === "expandSelectionDocEnd";
|
|
870
1268
|
const selections = this.#selections;
|
|
871
1269
|
if (selections !== void 0) {
|
|
872
|
-
|
|
1270
|
+
const boundarySelection = getDocumentBoundarySelection(textDocument, atEnd, this.#isDiff);
|
|
1271
|
+
this.#updateSelections(extendSelections(selections, boundarySelection));
|
|
1272
|
+
this.#revealLineIfCollapsed(getCaretPosition(boundarySelection).line);
|
|
873
1273
|
this.#scrollToPrimaryCaret();
|
|
874
1274
|
}
|
|
875
1275
|
}
|
|
876
1276
|
break;
|
|
877
1277
|
case "undo":
|
|
878
|
-
if (this.#textDocument?.canUndo === true) {
|
|
879
|
-
const undoResult = this.#textDocument.undo();
|
|
880
|
-
if (undoResult !== void 0) this.#applyChange(...undoResult);
|
|
881
|
-
}
|
|
882
|
-
break;
|
|
883
1278
|
case "redo":
|
|
884
|
-
|
|
885
|
-
const redoResult = this.#textDocument.redo();
|
|
886
|
-
if (redoResult !== void 0) this.#applyChange(...redoResult);
|
|
887
|
-
}
|
|
1279
|
+
this.#applyHistoryChange(command);
|
|
888
1280
|
break;
|
|
889
1281
|
}
|
|
890
1282
|
}
|
|
1283
|
+
#applyHistoryChange(command) {
|
|
1284
|
+
const textDocument = this.#textDocument;
|
|
1285
|
+
if (textDocument === void 0) return;
|
|
1286
|
+
if (command === "undo" && !textDocument.canUndo || command === "redo" && !textDocument.canRedo) return;
|
|
1287
|
+
const selections = this.#selections;
|
|
1288
|
+
const selectionOffsets = selections?.map((selection) => [textDocument.offsetAt(selection.start), textDocument.offsetAt(selection.end)]);
|
|
1289
|
+
const result = command === "undo" ? textDocument.undo() : textDocument.redo();
|
|
1290
|
+
if (result === void 0) return;
|
|
1291
|
+
const [change, recordedSelections, lineAnnotations, selectionEdits] = result;
|
|
1292
|
+
const nextSelections = recordedSelections ?? (selections !== void 0 && selectionOffsets !== void 0 && selectionEdits !== void 0 ? remapSelectionsAfterEdits(textDocument, selections, selectionOffsets, selectionEdits) : void 0);
|
|
1293
|
+
this.#applyChange(change, nextSelections, lineAnnotations);
|
|
1294
|
+
}
|
|
1295
|
+
/** Applies one undoable command batch and records its resulting selections. */
|
|
1296
|
+
#applyCommandEdits(edits, resolveNextSelections) {
|
|
1297
|
+
const textDocument = this.#textDocument;
|
|
1298
|
+
const selections = this.#selections;
|
|
1299
|
+
if (textDocument === void 0 || selections === void 0) return;
|
|
1300
|
+
const remapSelections = resolveNextSelections === void 0;
|
|
1301
|
+
const selectionOffsets = remapSelections ? selections.map((selection) => [textDocument.offsetAt(selection.start), textDocument.offsetAt(selection.end)]) : void 0;
|
|
1302
|
+
const resolvedEdits = remapSelections ? edits.map((edit) => {
|
|
1303
|
+
const start = textDocument.offsetAt(edit.range.start);
|
|
1304
|
+
const end = textDocument.offsetAt(edit.range.end);
|
|
1305
|
+
return {
|
|
1306
|
+
start: Math.min(start, end),
|
|
1307
|
+
end: Math.max(start, end),
|
|
1308
|
+
text: edit.newText
|
|
1309
|
+
};
|
|
1310
|
+
}).sort((a, b) => {
|
|
1311
|
+
const startOrder = a.start - b.start;
|
|
1312
|
+
return startOrder !== 0 ? startOrder : a.end - b.end;
|
|
1313
|
+
}) : void 0;
|
|
1314
|
+
const change = textDocument.applyEdits(edits, true, selections, void 0, true);
|
|
1315
|
+
if (change === void 0) return;
|
|
1316
|
+
const nextSelections = remapSelections ? remapSelectionsAfterEdits(textDocument, selections, selectionOffsets, resolvedEdits) : resolveNextSelections(textDocument);
|
|
1317
|
+
textDocument.setLastUndoSelectionsAfter(nextSelections);
|
|
1318
|
+
this.#applyChange(change, nextSelections, this.#applyChangeToLineAnnotations(change));
|
|
1319
|
+
}
|
|
1320
|
+
/** Copies selected line blocks and keeps the selection in the requested copy. */
|
|
1321
|
+
#copySelectedLines(direction) {
|
|
1322
|
+
const textDocument = this.#textDocument;
|
|
1323
|
+
const selections = this.#selections;
|
|
1324
|
+
if (textDocument === void 0 || selections === void 0) return;
|
|
1325
|
+
const blocks = getSelectedLineBlocks(selections);
|
|
1326
|
+
if (blocks.length === 0) return;
|
|
1327
|
+
const copiedLinesBefore = [];
|
|
1328
|
+
let copiedLineCount = 0;
|
|
1329
|
+
const edits = [];
|
|
1330
|
+
for (const block of blocks) {
|
|
1331
|
+
copiedLinesBefore.push(copiedLineCount);
|
|
1332
|
+
const blockLineCount = block.endLine - block.startLine + 1;
|
|
1333
|
+
copiedLineCount += blockLineCount;
|
|
1334
|
+
const text = textDocument.getText({
|
|
1335
|
+
start: {
|
|
1336
|
+
line: block.startLine,
|
|
1337
|
+
character: 0
|
|
1338
|
+
},
|
|
1339
|
+
end: {
|
|
1340
|
+
line: block.endLine,
|
|
1341
|
+
character: textDocument.getLineLength(block.endLine)
|
|
1342
|
+
}
|
|
1343
|
+
});
|
|
1344
|
+
if (direction > 0) {
|
|
1345
|
+
const position = {
|
|
1346
|
+
line: block.startLine,
|
|
1347
|
+
character: 0
|
|
1348
|
+
};
|
|
1349
|
+
edits.push({
|
|
1350
|
+
range: {
|
|
1351
|
+
start: position,
|
|
1352
|
+
end: position
|
|
1353
|
+
},
|
|
1354
|
+
newText: text + textDocument.eol
|
|
1355
|
+
});
|
|
1356
|
+
} else if (block.endLine < textDocument.lineCount - 1) {
|
|
1357
|
+
const position = {
|
|
1358
|
+
line: block.endLine + 1,
|
|
1359
|
+
character: 0
|
|
1360
|
+
};
|
|
1361
|
+
edits.push({
|
|
1362
|
+
range: {
|
|
1363
|
+
start: position,
|
|
1364
|
+
end: position
|
|
1365
|
+
},
|
|
1366
|
+
newText: text + textDocument.eol
|
|
1367
|
+
});
|
|
1368
|
+
} else {
|
|
1369
|
+
const position = {
|
|
1370
|
+
line: block.endLine,
|
|
1371
|
+
character: textDocument.getLineLength(block.endLine)
|
|
1372
|
+
};
|
|
1373
|
+
edits.push({
|
|
1374
|
+
range: {
|
|
1375
|
+
start: position,
|
|
1376
|
+
end: position
|
|
1377
|
+
},
|
|
1378
|
+
newText: textDocument.eol + text
|
|
1379
|
+
});
|
|
1380
|
+
}
|
|
1381
|
+
}
|
|
1382
|
+
const nextSelections = selections.map((selection) => {
|
|
1383
|
+
const line = selection.start.line;
|
|
1384
|
+
let low = 0;
|
|
1385
|
+
let high = blocks.length - 1;
|
|
1386
|
+
while (low <= high) {
|
|
1387
|
+
const middle = low + high >>> 1;
|
|
1388
|
+
const block = blocks[middle];
|
|
1389
|
+
if (line < block.startLine) high = middle - 1;
|
|
1390
|
+
else if (line > block.endLine) low = middle + 1;
|
|
1391
|
+
else {
|
|
1392
|
+
low = middle;
|
|
1393
|
+
break;
|
|
1394
|
+
}
|
|
1395
|
+
}
|
|
1396
|
+
const blockIndex = Math.max(0, low <= high ? low : high);
|
|
1397
|
+
const block = blocks[blockIndex];
|
|
1398
|
+
const shift = copiedLinesBefore[blockIndex] + (direction > 0 ? block.endLine - block.startLine + 1 : 0);
|
|
1399
|
+
return {
|
|
1400
|
+
start: {
|
|
1401
|
+
...selection.start,
|
|
1402
|
+
line: selection.start.line + shift
|
|
1403
|
+
},
|
|
1404
|
+
end: {
|
|
1405
|
+
...selection.end,
|
|
1406
|
+
line: selection.end.line + shift
|
|
1407
|
+
},
|
|
1408
|
+
direction: selection.direction
|
|
1409
|
+
};
|
|
1410
|
+
});
|
|
1411
|
+
this.#applyCommandEdits(edits, () => nextSelections);
|
|
1412
|
+
}
|
|
1413
|
+
/** Inserts an indented blank line after each selection's final line. */
|
|
1414
|
+
#insertBlankLine() {
|
|
1415
|
+
const textDocument = this.#textDocument;
|
|
1416
|
+
const selections = this.#selections;
|
|
1417
|
+
if (textDocument === void 0 || selections === void 0) return;
|
|
1418
|
+
const selectionLines = selections.map((selection) => getCaretPosition(selection).line);
|
|
1419
|
+
const targetLines = Array.from(new Set(selectionLines)).sort((a, b) => a - b);
|
|
1420
|
+
const targetIndex = /* @__PURE__ */ new Map();
|
|
1421
|
+
const indents = /* @__PURE__ */ new Map();
|
|
1422
|
+
const edits = [];
|
|
1423
|
+
for (let index = 0; index < targetLines.length; index++) {
|
|
1424
|
+
const line = targetLines[index];
|
|
1425
|
+
const lineText = textDocument.getLineText(line);
|
|
1426
|
+
const indent = /^\s*/.exec(lineText)?.[0] ?? "";
|
|
1427
|
+
targetIndex.set(line, index);
|
|
1428
|
+
indents.set(line, indent);
|
|
1429
|
+
const position = {
|
|
1430
|
+
line,
|
|
1431
|
+
character: textDocument.getLineLength(line)
|
|
1432
|
+
};
|
|
1433
|
+
edits.push({
|
|
1434
|
+
range: {
|
|
1435
|
+
start: position,
|
|
1436
|
+
end: position
|
|
1437
|
+
},
|
|
1438
|
+
newText: textDocument.eol + indent
|
|
1439
|
+
});
|
|
1440
|
+
}
|
|
1441
|
+
const nextSelections = selections.map((_, index) => {
|
|
1442
|
+
const line = selectionLines[index];
|
|
1443
|
+
const position = {
|
|
1444
|
+
line: line + 1 + targetIndex.get(line),
|
|
1445
|
+
character: indents.get(line).length
|
|
1446
|
+
};
|
|
1447
|
+
return {
|
|
1448
|
+
start: position,
|
|
1449
|
+
end: position,
|
|
1450
|
+
direction: 0
|
|
1451
|
+
};
|
|
1452
|
+
});
|
|
1453
|
+
this.#applyCommandEdits(edits, () => nextSelections);
|
|
1454
|
+
}
|
|
891
1455
|
#moveSelectedLines(direction) {
|
|
892
1456
|
const textDocument = this.#textDocument;
|
|
893
1457
|
const selections = this.#selections;
|
|
@@ -956,15 +1520,15 @@ var Editor = class {
|
|
|
956
1520
|
this.#lineElementsCache.clear();
|
|
957
1521
|
this.#lastAccessedCharX = void 0;
|
|
958
1522
|
this.#metrics.clearTextWidthCache();
|
|
959
|
-
if (contentWidthChanged
|
|
960
|
-
this.#lineYCache.clear();
|
|
1523
|
+
if (contentWidthChanged) {
|
|
961
1524
|
this.#wrapLineOffsetsCache.clear();
|
|
1525
|
+
if (this.#isWrap || lineAnnotations > 0) this.#lineYCache.clear();
|
|
962
1526
|
}
|
|
963
1527
|
if (this.#selections !== void 0 || this.#matches !== void 0 || this.#markerRenderer !== void 0) {
|
|
964
1528
|
this.#updateSelections(this.#selections ?? []);
|
|
965
|
-
if (this.#selections !== void 0) this.focus();
|
|
1529
|
+
if (this.#selections !== void 0 && this.#contentHasFocus) this.focus();
|
|
966
1530
|
}
|
|
967
|
-
this.#markerRenderer?.
|
|
1531
|
+
this.#markerRenderer?.removePopover();
|
|
968
1532
|
this.#computeContentOffset(this.#contentElement);
|
|
969
1533
|
};
|
|
970
1534
|
#remeasureMetricsOnFontLoad() {
|
|
@@ -977,8 +1541,9 @@ var Editor = class {
|
|
|
977
1541
|
this.#gutterWidthCache = void 0;
|
|
978
1542
|
this.#contentWidthCache = void 0;
|
|
979
1543
|
this.#resetCache();
|
|
1544
|
+
this.#wrapLineOffsetsCache.clear();
|
|
980
1545
|
if (this.#selections !== void 0 || this.#matches !== void 0 || this.#markerRenderer !== void 0) this.#updateSelections(this.#selections ?? []);
|
|
981
|
-
this.#markerRenderer?.
|
|
1546
|
+
this.#markerRenderer?.removePopover();
|
|
982
1547
|
});
|
|
983
1548
|
}
|
|
984
1549
|
#rerender(change, newLineAnnotations, renderRange = this.#renderRange, shouldUpdateBuffer) {
|
|
@@ -994,45 +1559,57 @@ var Editor = class {
|
|
|
994
1559
|
const t2 = performance.now();
|
|
995
1560
|
if (dirtyLines.size > 0) {
|
|
996
1561
|
const children = contentEl.children;
|
|
997
|
-
const dirtyLineIndexes = new Set(
|
|
998
|
-
const
|
|
999
|
-
for (let i =
|
|
1562
|
+
const dirtyLineIndexes = /* @__PURE__ */ new Set();
|
|
1563
|
+
for (const lineIndex of dirtyLines.keys()) if (this.#isLineRenderable(lineIndex)) dirtyLineIndexes.add(lineIndex);
|
|
1564
|
+
for (let i = 0; i < children.length; i++) {
|
|
1000
1565
|
const child = children[i];
|
|
1001
1566
|
if (child !== void 0) {
|
|
1002
1567
|
const lineNumber = getLineNumberAttr(child);
|
|
1003
1568
|
const lineType = child.dataset.lineType;
|
|
1004
1569
|
if (lineNumber === void 0 || lineType === "change-deletion") continue;
|
|
1005
1570
|
const lineIndex = lineNumber - 1;
|
|
1006
|
-
if (
|
|
1571
|
+
if (dirtyLineIndexes.has(lineIndex)) {
|
|
1007
1572
|
const tokens = dirtyLines.get(lineIndex);
|
|
1008
|
-
child.replaceChildren(...renderLineTokens(tokens
|
|
1573
|
+
child.replaceChildren(...renderLineTokens(tokens));
|
|
1009
1574
|
dirtyLineIndexes.delete(lineIndex);
|
|
1010
1575
|
if (dirtyLineIndexes.size === 0) break;
|
|
1011
1576
|
}
|
|
1012
1577
|
}
|
|
1013
1578
|
}
|
|
1014
|
-
if (dirtyLineIndexes.size > 0)
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
}
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1579
|
+
if (dirtyLineIndexes.size > 0) {
|
|
1580
|
+
let lastRenderedLineNumber = 0;
|
|
1581
|
+
for (let i = children.length - 1; i >= 0; i--) {
|
|
1582
|
+
const child = children[i];
|
|
1583
|
+
const lineNumber = getLineNumberAttr(child);
|
|
1584
|
+
if (lineNumber !== void 0 && child.dataset.lineType !== "change-deletion") {
|
|
1585
|
+
lastRenderedLineNumber = lineNumber;
|
|
1586
|
+
break;
|
|
1587
|
+
}
|
|
1588
|
+
}
|
|
1589
|
+
for (const lineIndex of dirtyLineIndexes) {
|
|
1590
|
+
if (lineIndex < lastRenderedLineNumber) continue;
|
|
1591
|
+
const tokens = dirtyLines.get(lineIndex);
|
|
1592
|
+
const lineNumber = String(lineIndex + 1);
|
|
1593
|
+
h("div", {
|
|
1594
|
+
dataset: {
|
|
1595
|
+
line: lineNumber,
|
|
1596
|
+
lineType: "context",
|
|
1597
|
+
lineIndex: lineIndex.toString()
|
|
1598
|
+
},
|
|
1599
|
+
children: renderLineTokens(tokens)
|
|
1600
|
+
}, contentEl);
|
|
1601
|
+
if (gutterEl !== void 0) h("div", {
|
|
1602
|
+
dataset: {
|
|
1603
|
+
lineType: "context",
|
|
1604
|
+
columnNumber: lineNumber,
|
|
1605
|
+
lineIndex: lineIndex.toString()
|
|
1606
|
+
},
|
|
1607
|
+
children: [h("span", {
|
|
1608
|
+
dataset: { lineNumberContent: "" },
|
|
1609
|
+
textContent: lineNumber
|
|
1610
|
+
})]
|
|
1611
|
+
}, gutterEl);
|
|
1612
|
+
}
|
|
1036
1613
|
}
|
|
1037
1614
|
}
|
|
1038
1615
|
if (change.lineDelta < 0) for (const children of [contentEl.children, gutterEl?.children ?? []]) for (let i = children.length - 1; i >= 0; i--) {
|
|
@@ -1053,9 +1630,12 @@ var Editor = class {
|
|
|
1053
1630
|
contentEl.style.gridRow = "span " + gridRow;
|
|
1054
1631
|
if (gutterEl !== void 0) gutterEl.style.gridRow = "span " + gridRow;
|
|
1055
1632
|
}
|
|
1056
|
-
fileInstance.updateRenderCache(dirtyLines, tokenizer.themeType,
|
|
1633
|
+
fileInstance.updateRenderCache(dirtyLines, tokenizer.themeType, {
|
|
1634
|
+
shouldRefreshDiffsView: this.#isDiff && !didLineCountChange,
|
|
1635
|
+
lineCountChangeInFlight: didLineCountChange
|
|
1636
|
+
});
|
|
1057
1637
|
if (didLineCountChange) fileInstance.applyDocumentChange(textDocument, newLineAnnotations, shouldUpdateBuffer);
|
|
1058
|
-
if (this.#isDiff &&
|
|
1638
|
+
if (didLineCountChange || this.#isDiff && this.#diffSyle === "unified") this.#resetCache();
|
|
1059
1639
|
if (newLineAnnotations !== void 0) {
|
|
1060
1640
|
this.#lineAnnotations = newLineAnnotations;
|
|
1061
1641
|
renderLineAnnotations(newLineAnnotations, contentEl, gutterEl);
|
|
@@ -1075,7 +1655,7 @@ var Editor = class {
|
|
|
1075
1655
|
case "insertCompositionText": break;
|
|
1076
1656
|
case "insertLineBreak":
|
|
1077
1657
|
case "insertParagraph":
|
|
1078
|
-
this.#replaceSelectionText("\n");
|
|
1658
|
+
this.#replaceSelectionText(this.#textDocument?.eol ?? "\n");
|
|
1079
1659
|
break;
|
|
1080
1660
|
case "deleteContentBackward":
|
|
1081
1661
|
this.#deleteSelectionText();
|
|
@@ -1087,9 +1667,6 @@ var Editor = class {
|
|
|
1087
1667
|
case "deleteHardLineBackward":
|
|
1088
1668
|
this.#deleteSoftLineBackward();
|
|
1089
1669
|
break;
|
|
1090
|
-
case "deleteHardLineForward":
|
|
1091
|
-
this.#deleteHardLineForward();
|
|
1092
|
-
break;
|
|
1093
1670
|
case "deleteWordBackward":
|
|
1094
1671
|
this.#deleteWordBackward();
|
|
1095
1672
|
break;
|
|
@@ -1101,7 +1678,7 @@ var Editor = class {
|
|
|
1101
1678
|
break;
|
|
1102
1679
|
}
|
|
1103
1680
|
}
|
|
1104
|
-
#focus(position, preventScroll = true) {
|
|
1681
|
+
#focus(position, preventScroll = true, shouldFocus) {
|
|
1105
1682
|
this.#contentHasFocus = true;
|
|
1106
1683
|
if (position !== void 0) {
|
|
1107
1684
|
this.#shouldIgnoreSelectionChange = true;
|
|
@@ -1110,13 +1687,115 @@ var Editor = class {
|
|
|
1110
1687
|
end: position,
|
|
1111
1688
|
direction: 0
|
|
1112
1689
|
});
|
|
1113
|
-
|
|
1690
|
+
queueRender(() => {
|
|
1691
|
+
if (shouldFocus?.() === false || !this.#contentHasFocus) {
|
|
1692
|
+
this.#shouldIgnoreSelectionChange = false;
|
|
1693
|
+
return;
|
|
1694
|
+
}
|
|
1114
1695
|
this.#contentElement?.focus({ preventScroll });
|
|
1115
|
-
|
|
1696
|
+
queueRender(() => {
|
|
1116
1697
|
this.#shouldIgnoreSelectionChange = false;
|
|
1117
1698
|
});
|
|
1118
1699
|
});
|
|
1119
|
-
} else this.#contentElement?.focus({ preventScroll });
|
|
1700
|
+
} else if (shouldFocus?.() !== false) this.#contentElement?.focus({ preventScroll });
|
|
1701
|
+
else this.#contentHasFocus = false;
|
|
1702
|
+
}
|
|
1703
|
+
#restoreReplacementFocus(position) {
|
|
1704
|
+
const request = this.#replacementFocusRequest;
|
|
1705
|
+
if (request == null) return;
|
|
1706
|
+
if (this.#retainSearchPanelFocus) {
|
|
1707
|
+
this.#replacementFocusRequest = void 0;
|
|
1708
|
+
this.#contentHasFocus = false;
|
|
1709
|
+
this.#shouldIgnoreSelectionChange = false;
|
|
1710
|
+
return;
|
|
1711
|
+
}
|
|
1712
|
+
const contentElement = this.#contentElement;
|
|
1713
|
+
if (contentElement == null || !this.#replacementFocusIsAvailable(contentElement)) {
|
|
1714
|
+
this.#replacementFocusRequest = void 0;
|
|
1715
|
+
this.#contentHasFocus = false;
|
|
1716
|
+
return;
|
|
1717
|
+
}
|
|
1718
|
+
const shouldFocus = () => {
|
|
1719
|
+
if (this.#replacementFocusRequest !== request) return false;
|
|
1720
|
+
const shouldRestore = this.#replacementFocusIsAvailable(contentElement);
|
|
1721
|
+
this.#replacementFocusRequest = void 0;
|
|
1722
|
+
return shouldRestore;
|
|
1723
|
+
};
|
|
1724
|
+
if (position != null) {
|
|
1725
|
+
this.#focus(position, true, shouldFocus);
|
|
1726
|
+
return;
|
|
1727
|
+
}
|
|
1728
|
+
const primarySelection = this.#selections?.at(-1);
|
|
1729
|
+
if (primarySelection == null) {
|
|
1730
|
+
this.#focus(void 0, true, shouldFocus);
|
|
1731
|
+
return;
|
|
1732
|
+
}
|
|
1733
|
+
const primaryPosition = primarySelection.direction === -1 ? primarySelection.end : primarySelection.start;
|
|
1734
|
+
this.#focus(primaryPosition, true, shouldFocus);
|
|
1735
|
+
}
|
|
1736
|
+
#replacementFocusIsAvailable(contentElement) {
|
|
1737
|
+
const fileContainer = this.#fileContainer;
|
|
1738
|
+
const shadowRoot = fileContainer?.shadowRoot;
|
|
1739
|
+
if (fileContainer == null || shadowRoot == null || this.#contentElement !== contentElement || !shadowRoot.contains(contentElement)) return false;
|
|
1740
|
+
const { activeElement: shadowActiveElement } = shadowRoot;
|
|
1741
|
+
if (shadowActiveElement === contentElement || shadowActiveElement != null && contentElement.contains(shadowActiveElement)) return true;
|
|
1742
|
+
if (shadowActiveElement != null) return false;
|
|
1743
|
+
const { ownerDocument } = fileContainer;
|
|
1744
|
+
const { activeElement } = ownerDocument;
|
|
1745
|
+
return activeElement == null || activeElement === ownerDocument.body || activeElement === ownerDocument.documentElement || activeElement === fileContainer;
|
|
1746
|
+
}
|
|
1747
|
+
#getFirstVisibleLineNumber(offset = 0) {
|
|
1748
|
+
const contentElement = this.#contentElement;
|
|
1749
|
+
const fileContainer = this.#fileContainer;
|
|
1750
|
+
if (this.#textDocument == null || contentElement == null || fileContainer == null) return;
|
|
1751
|
+
const viewport = this.#fileInstance?.getEditorViewport?.() ?? this.#getDefaultEditorViewport(fileContainer);
|
|
1752
|
+
let viewportTop;
|
|
1753
|
+
let viewportBottom;
|
|
1754
|
+
if (viewport instanceof HTMLElement) {
|
|
1755
|
+
const viewportRect = viewport.getBoundingClientRect();
|
|
1756
|
+
viewportTop = viewportRect.top;
|
|
1757
|
+
viewportBottom = viewportRect.bottom;
|
|
1758
|
+
} else {
|
|
1759
|
+
const viewportWindow = viewport.defaultView;
|
|
1760
|
+
if (viewportWindow == null) return;
|
|
1761
|
+
viewportTop = 0;
|
|
1762
|
+
viewportBottom = viewportWindow.innerHeight;
|
|
1763
|
+
}
|
|
1764
|
+
const stickyHeader = fileContainer.shadowRoot?.querySelector("[data-diffs-header][data-sticky]");
|
|
1765
|
+
if (stickyHeader != null) viewportTop = Math.max(viewportTop, stickyHeader.getBoundingClientRect().bottom);
|
|
1766
|
+
if (Number.isFinite(offset)) viewportTop += Math.max(0, offset);
|
|
1767
|
+
if (viewportBottom <= viewportTop) return;
|
|
1768
|
+
for (const child of contentElement.children) {
|
|
1769
|
+
const row = child;
|
|
1770
|
+
const lineNumber = getLineNumberAttr(row);
|
|
1771
|
+
const lineType = row.dataset.lineType;
|
|
1772
|
+
if (lineNumber == null || lineType == null || !isLineEditable(lineType)) continue;
|
|
1773
|
+
const rowRect = row.getBoundingClientRect();
|
|
1774
|
+
if (rowRect.bottom <= rowRect.top) continue;
|
|
1775
|
+
if (rowRect.top >= viewportTop && rowRect.top < viewportBottom) return lineNumber;
|
|
1776
|
+
}
|
|
1777
|
+
}
|
|
1778
|
+
#getDefaultEditorViewport(fileContainer) {
|
|
1779
|
+
const ownerDocument = fileContainer.ownerDocument;
|
|
1780
|
+
let element = fileContainer.parentElement;
|
|
1781
|
+
while (element != null && element !== ownerDocument.body && element !== ownerDocument.documentElement) {
|
|
1782
|
+
const overflowY = element.ownerDocument.defaultView?.getComputedStyle(element).overflowY;
|
|
1783
|
+
if (overflowY === "auto" || overflowY === "scroll" || overflowY === "overlay") return element;
|
|
1784
|
+
element = element.parentElement;
|
|
1785
|
+
}
|
|
1786
|
+
return ownerDocument;
|
|
1787
|
+
}
|
|
1788
|
+
#focusAtPosition(position, preventScroll) {
|
|
1789
|
+
const selection = {
|
|
1790
|
+
start: position,
|
|
1791
|
+
end: position,
|
|
1792
|
+
direction: 0
|
|
1793
|
+
};
|
|
1794
|
+
this.#canMountSelectionAction = false;
|
|
1795
|
+
this.#updateSelections([selection]);
|
|
1796
|
+
this.#revealLineIfCollapsed(position.line);
|
|
1797
|
+
if (preventScroll) this.#focus(position, true);
|
|
1798
|
+
else this.#scrollToPrimaryCaret();
|
|
1120
1799
|
}
|
|
1121
1800
|
#setWindowSelection(selection) {
|
|
1122
1801
|
const winSelection = window.getSelection();
|
|
@@ -1149,7 +1828,11 @@ var Editor = class {
|
|
|
1149
1828
|
block: scrollPosition,
|
|
1150
1829
|
inline: "nearest"
|
|
1151
1830
|
});
|
|
1152
|
-
if (!noFocus)
|
|
1831
|
+
if (!noFocus) {
|
|
1832
|
+
const position = primarySelection.direction === -1 ? primarySelection.end : primarySelection.start;
|
|
1833
|
+
if (this.#replacementFocusRequest !== void 0) this.#restoreReplacementFocus(position);
|
|
1834
|
+
else this.#focus(position);
|
|
1835
|
+
}
|
|
1153
1836
|
} else {
|
|
1154
1837
|
const pos = getCaretPosition(primarySelection);
|
|
1155
1838
|
this.#scrollToLine(pos.line, pos.character, noFocus);
|
|
@@ -1179,10 +1862,14 @@ var Editor = class {
|
|
|
1179
1862
|
block: "center",
|
|
1180
1863
|
inline: "nearest"
|
|
1181
1864
|
});
|
|
1182
|
-
if (!noFocus)
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1865
|
+
if (!noFocus) {
|
|
1866
|
+
const position = {
|
|
1867
|
+
line,
|
|
1868
|
+
character: char
|
|
1869
|
+
};
|
|
1870
|
+
if (this.#replacementFocusRequest !== void 0) this.#restoreReplacementFocus(position);
|
|
1871
|
+
else this.#focus(position);
|
|
1872
|
+
}
|
|
1186
1873
|
this.#scrollingToLine = void 0;
|
|
1187
1874
|
this.#scrollingToLineChar = void 0;
|
|
1188
1875
|
this.#scrollingToLineFixed = false;
|
|
@@ -1196,7 +1883,7 @@ var Editor = class {
|
|
|
1196
1883
|
block: "center",
|
|
1197
1884
|
inline: "nearest"
|
|
1198
1885
|
});
|
|
1199
|
-
if (modelLinePosition.height > 0) {
|
|
1886
|
+
if (modelLinePosition.height > 0 && this.#isLineRenderable(line)) {
|
|
1200
1887
|
this.#scrollingToLine = line;
|
|
1201
1888
|
this.#scrollingToLineChar = char;
|
|
1202
1889
|
this.#scrollingToLineNoFocus = noFocus;
|
|
@@ -1223,7 +1910,7 @@ var Editor = class {
|
|
|
1223
1910
|
block: "center",
|
|
1224
1911
|
inline: "nearest"
|
|
1225
1912
|
});
|
|
1226
|
-
if (this.#scrollingToLine === line && (yFix === 0 || this.#scrollingToLineFixed)) {
|
|
1913
|
+
if (this.#scrollingToLine === line && (yFix === 0 || this.#scrollingToLineFixed) || !this.#isLineRenderable(line)) {
|
|
1227
1914
|
this.#scrollingToLine = void 0;
|
|
1228
1915
|
this.#scrollingToLineChar = void 0;
|
|
1229
1916
|
this.#scrollingToLineFixed = false;
|
|
@@ -1277,7 +1964,7 @@ var Editor = class {
|
|
|
1277
1964
|
}
|
|
1278
1965
|
this.#setDeletedTextSelectionActive(true);
|
|
1279
1966
|
this.#updateSelections([]);
|
|
1280
|
-
|
|
1967
|
+
this.#setEditorActiveLineSafe(getLineNumberAttr(focusContent) ?? null, true, "deletions");
|
|
1281
1968
|
const lo = Math.min(anchorIndex, focusIndex);
|
|
1282
1969
|
const hi = Math.max(anchorIndex, focusIndex);
|
|
1283
1970
|
this.#deletedSelectionText = lo < 0 ? "" : rows.slice(lo, hi + 1).filter((row) => row.getAttribute("data-line-type") === "change-deletion").map((row) => row.textContent ?? "").join("\n");
|
|
@@ -1315,19 +2002,18 @@ var Editor = class {
|
|
|
1315
2002
|
if (pre == null) return;
|
|
1316
2003
|
if (active) {
|
|
1317
2004
|
pre.setAttribute("data-deleted-text-selection", "");
|
|
1318
|
-
|
|
2005
|
+
this.#setEditorActiveLineSafe(null);
|
|
1319
2006
|
this.#deletedSelectionText = "";
|
|
1320
2007
|
} else {
|
|
1321
2008
|
pre.removeAttribute("data-deleted-text-selection");
|
|
1322
2009
|
this.#deletedSelectionText = "";
|
|
1323
2010
|
}
|
|
1324
2011
|
}
|
|
1325
|
-
#
|
|
2012
|
+
#setEditorActiveLineSafe(lineNumber, lineNumberOnly = false, side = "additions") {
|
|
1326
2013
|
try {
|
|
1327
|
-
this.#fileInstance?.
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
lineNumberOnly
|
|
2014
|
+
this.#fileInstance?.setEditorActiveLine(lineNumber, {
|
|
2015
|
+
lineNumberOnly,
|
|
2016
|
+
side
|
|
1331
2017
|
});
|
|
1332
2018
|
} catch {}
|
|
1333
2019
|
}
|
|
@@ -1341,7 +2027,7 @@ var Editor = class {
|
|
|
1341
2027
|
#updateSelections(selections) {
|
|
1342
2028
|
this.__postponeBgTokenizeToNextFrame();
|
|
1343
2029
|
this.#primaryCaretElement = void 0;
|
|
1344
|
-
this.#
|
|
2030
|
+
this.#setEditorActiveLineSafe(null);
|
|
1345
2031
|
if (selections.length === 0 && this.#matches === void 0 && this.#markerRenderer === void 0) {
|
|
1346
2032
|
this.#selections = void 0;
|
|
1347
2033
|
this.#overlayElements?.forEach((el) => el.remove());
|
|
@@ -1361,10 +2047,7 @@ var Editor = class {
|
|
|
1361
2047
|
this.#selections = normalizedSelections;
|
|
1362
2048
|
const hasNonEmptySelection = normalizedSelections.some((selection) => !isCollapsedSelection(selection));
|
|
1363
2049
|
const caretLine = getCaretPosition(primarySelection).line + 1;
|
|
1364
|
-
this.#
|
|
1365
|
-
start: caretLine,
|
|
1366
|
-
end: caretLine
|
|
1367
|
-
}, hasNonEmptySelection);
|
|
2050
|
+
this.#setEditorActiveLineSafe(caretLine, hasNonEmptySelection);
|
|
1368
2051
|
for (const selection of normalizedSelections) {
|
|
1369
2052
|
if (!isCollapsedSelection(selection)) this.#renderSelection(renderCtx, "selection", selection);
|
|
1370
2053
|
this.#renderCaret(renderCtx, selection, selection === primarySelection);
|
|
@@ -1374,16 +2057,50 @@ var Editor = class {
|
|
|
1374
2057
|
}
|
|
1375
2058
|
const textDocument = this.#textDocument;
|
|
1376
2059
|
if (this.#matches !== void 0 && textDocument !== void 0) {
|
|
2060
|
+
const matches = this.#matches;
|
|
2061
|
+
const renderRange = this.#renderRange;
|
|
2062
|
+
const renderedLineRanges = renderRange !== void 0 && Number.isFinite(renderRange.totalLines) || this.#isDiff && this.#fileInstance?.options.expandUnchanged !== true ? this.#getRenderedEditableLineRanges() : void 0;
|
|
1377
2063
|
const primarySelection = this.#selections?.at(-1);
|
|
1378
2064
|
const primaryStartOffset = primarySelection !== void 0 ? textDocument.offsetAt(primarySelection.start) : -1;
|
|
1379
2065
|
const primaryEndOffset = primarySelection !== void 0 ? textDocument.offsetAt(primarySelection.end) : -1;
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
2066
|
+
let firstMatchIndex = 0;
|
|
2067
|
+
const rangeCount = renderedLineRanges?.length ?? 1;
|
|
2068
|
+
for (let rangeIndex = 0; rangeIndex < rangeCount; rangeIndex++) {
|
|
2069
|
+
let visibleEndOffset = Infinity;
|
|
2070
|
+
const lineRange = renderedLineRanges?.[rangeIndex];
|
|
2071
|
+
if (lineRange !== void 0) {
|
|
2072
|
+
const [firstLine, lastLine] = lineRange;
|
|
2073
|
+
const visibleStartOffset = textDocument.offsetAt({
|
|
2074
|
+
line: firstLine,
|
|
2075
|
+
character: 0
|
|
2076
|
+
});
|
|
2077
|
+
const endLine = lastLine + 1;
|
|
2078
|
+
visibleEndOffset = endLine < textDocument.lineCount ? textDocument.offsetAt({
|
|
2079
|
+
line: endLine,
|
|
2080
|
+
character: 0
|
|
2081
|
+
}) : textDocument.offsetAt({
|
|
2082
|
+
line: endLine - 1,
|
|
2083
|
+
character: textDocument.getLineLength(endLine - 1)
|
|
2084
|
+
});
|
|
2085
|
+
let low = firstMatchIndex;
|
|
2086
|
+
let high = matches.length;
|
|
2087
|
+
while (low < high) {
|
|
2088
|
+
const middle = low + Math.floor((high - low) / 2);
|
|
2089
|
+
if (matches[middle][1] <= visibleStartOffset) low = middle + 1;
|
|
2090
|
+
else high = middle;
|
|
2091
|
+
}
|
|
2092
|
+
firstMatchIndex = low;
|
|
2093
|
+
}
|
|
2094
|
+
for (; firstMatchIndex < matches.length; firstMatchIndex++) {
|
|
2095
|
+
const [startOffset, endOffset] = matches[firstMatchIndex];
|
|
2096
|
+
if (startOffset >= visibleEndOffset) break;
|
|
2097
|
+
const range = {
|
|
2098
|
+
start: textDocument.positionAt(startOffset),
|
|
2099
|
+
end: textDocument.positionAt(endOffset)
|
|
2100
|
+
};
|
|
2101
|
+
const isFocused = primaryStartOffset === startOffset && primaryEndOffset === endOffset;
|
|
2102
|
+
this.#renderSelection(renderCtx, "match", range, isFocused ? "focus" : void 0);
|
|
2103
|
+
}
|
|
1387
2104
|
}
|
|
1388
2105
|
}
|
|
1389
2106
|
if (this.#markerRenderer !== void 0 && textDocument !== void 0) for (const marker of this.#markerRenderer.markers) this.#renderSelection(renderCtx, "marker", marker, markerSeverityDatasetKey(marker.severity));
|
|
@@ -1396,7 +2113,14 @@ var Editor = class {
|
|
|
1396
2113
|
#renderSelection(renderCtx, type, range, extraDataset) {
|
|
1397
2114
|
if (this.#textDocument === void 0) return;
|
|
1398
2115
|
const { start, end } = range;
|
|
1399
|
-
|
|
2116
|
+
let firstLine = start.line;
|
|
2117
|
+
let endLine = end.line + 1;
|
|
2118
|
+
if (this.#renderRange !== void 0) {
|
|
2119
|
+
const { startingLine, totalLines } = this.#renderRange;
|
|
2120
|
+
firstLine = Math.max(firstLine, startingLine);
|
|
2121
|
+
endLine = Math.min(endLine, startingLine + totalLines);
|
|
2122
|
+
}
|
|
2123
|
+
for (let line = firstLine; line < endLine; line++) {
|
|
1400
2124
|
if (!this.#isLineVisible(line)) continue;
|
|
1401
2125
|
const isLastLine = line === end.line;
|
|
1402
2126
|
const startChar = line === start.line ? start.character : 0;
|
|
@@ -1453,8 +2177,10 @@ var Editor = class {
|
|
|
1453
2177
|
const rounded = (this.#options.roundedSelection ?? true) && type === "selection";
|
|
1454
2178
|
const addRoundedCorner = (line, wrapLine, left, radius) => {
|
|
1455
2179
|
const top = this.#getLineY(line) + wrapLine * lineHeight;
|
|
1456
|
-
const
|
|
1457
|
-
|
|
2180
|
+
const lineElement = this.#getLineElement(line);
|
|
2181
|
+
let cornerBg = "initial";
|
|
2182
|
+
if (lineElement !== void 0 && (lineElement.dataset.lineType === "change-addition" || lineElement.dataset.selectedLine !== void 0)) cornerBg = getComputedStyle(lineElement).getPropertyValue("--diffs-line-bg");
|
|
2183
|
+
const css = `width:${ch}px;transform:translateX(${left}px) translateY(${top}px);--diffs-selection-corner-bg:${cornerBg}`;
|
|
1458
2184
|
const dataset = {
|
|
1459
2185
|
selectionCorner: "",
|
|
1460
2186
|
[radius]: ""
|
|
@@ -1573,13 +2299,14 @@ var Editor = class {
|
|
|
1573
2299
|
return;
|
|
1574
2300
|
}
|
|
1575
2301
|
if (this.#selectionAction === void 0) {
|
|
2302
|
+
if (!this.#canMountSelectionAction) return;
|
|
1576
2303
|
const getActiveSelection = () => this.#selections?.at(-1) ?? primarySelection;
|
|
1577
2304
|
const selectionActionElement = renderSelectionAction({
|
|
1578
2305
|
textDocument,
|
|
1579
2306
|
get selection() {
|
|
1580
2307
|
return getActiveSelection();
|
|
1581
2308
|
},
|
|
1582
|
-
applyEdits: (edits) => this.applyEdits(edits
|
|
2309
|
+
applyEdits: (edits) => this.applyEdits(edits),
|
|
1583
2310
|
getSelectionText: () => this.#textDocument?.getText(getActiveSelection()) ?? "",
|
|
1584
2311
|
replaceSelectionText: (text) => {
|
|
1585
2312
|
this.#replaceSelectionText(text, [getActiveSelection()]);
|
|
@@ -1590,7 +2317,7 @@ var Editor = class {
|
|
|
1590
2317
|
}
|
|
1591
2318
|
});
|
|
1592
2319
|
this.#selectionAction = new SelectionActionWidget(selectionActionElement, overlayElement, () => this.#updateSelectionActionPopover());
|
|
1593
|
-
this.#getPopoverManager().resetPlacement();
|
|
2320
|
+
this.#getPopoverManager().resetPlacement(SELECTION_ACTION_POPOVER_PLACEMENT_KEY);
|
|
1594
2321
|
}
|
|
1595
2322
|
const lineHeight = this.#metrics.lineHeight;
|
|
1596
2323
|
const isBackward = primarySelection.direction === -1;
|
|
@@ -1624,17 +2351,19 @@ var Editor = class {
|
|
|
1624
2351
|
const atDocumentEdge = isBackward ? head.line < 3 : head.line >= lineCount - 3;
|
|
1625
2352
|
const canUseFallback = this.#isLineVisible(fallback.anchor.line);
|
|
1626
2353
|
const popoverManager = this.#getPopoverManager();
|
|
2354
|
+
const viewport = popoverManager.getPlacementBounds();
|
|
1627
2355
|
const useFallback = canUseFallback && popoverManager.choosePlacement({
|
|
1628
2356
|
preferred: preferredGeometry,
|
|
1629
2357
|
fallback: fallbackGeometry,
|
|
1630
|
-
viewport
|
|
2358
|
+
viewport,
|
|
1631
2359
|
popoverHeight,
|
|
1632
|
-
atDocumentEdge
|
|
2360
|
+
atDocumentEdge,
|
|
2361
|
+
placementKey: SELECTION_ACTION_POPOVER_PLACEMENT_KEY
|
|
1633
2362
|
}) === "fallback";
|
|
1634
|
-
if (!canUseFallback) popoverManager.setPlacement("preferred");
|
|
2363
|
+
if (!canUseFallback) popoverManager.setPlacement("preferred", SELECTION_ACTION_POPOVER_PLACEMENT_KEY);
|
|
1635
2364
|
const { placeAbove } = useFallback ? fallback : preferred;
|
|
1636
2365
|
const { left, anchorTop } = useFallback ? fallbackGeometry : preferredGeometry;
|
|
1637
|
-
this.#selectionAction.reposition(left, anchorTop, this.#getGutterWidth(), placeAbove);
|
|
2366
|
+
this.#selectionAction.reposition(left, anchorTop, this.#getGutterWidth(), placeAbove, viewport);
|
|
1638
2367
|
}
|
|
1639
2368
|
#openSearchPanel(mode) {
|
|
1640
2369
|
if (this.#searchPanel !== void 0) {
|
|
@@ -1666,6 +2395,7 @@ var Editor = class {
|
|
|
1666
2395
|
const scrollToMatch = ([startOffset, endOffset], retainFocus) => {
|
|
1667
2396
|
const nextSelection = createSelectionFromAnchorAndFocusOffsets(textDocument, startOffset, endOffset);
|
|
1668
2397
|
this.#updateSelections([nextSelection]);
|
|
2398
|
+
this.#revealLineIfCollapsed(getCaretPosition(nextSelection).line);
|
|
1669
2399
|
this.#scrollToPrimaryCaret(true);
|
|
1670
2400
|
this.#retainSearchPanelFocus = retainFocus;
|
|
1671
2401
|
};
|
|
@@ -1732,6 +2462,18 @@ var Editor = class {
|
|
|
1732
2462
|
if (textDocument === void 0 || selections === void 0) return "";
|
|
1733
2463
|
return getSelectionText(textDocument, selections);
|
|
1734
2464
|
}
|
|
2465
|
+
#getSelectionClipboardTexts() {
|
|
2466
|
+
const textDocument = this.#textDocument;
|
|
2467
|
+
const selections = this.#selections;
|
|
2468
|
+
if (textDocument === void 0 || selections === void 0) return [];
|
|
2469
|
+
return getSelectionClipboardTexts(textDocument, selections);
|
|
2470
|
+
}
|
|
2471
|
+
/** Writes both the portable text and the selection pairing metadata. */
|
|
2472
|
+
#writeSelectionClipboardData(clipboardData, text, selectionTexts) {
|
|
2473
|
+
if (clipboardData === null) return;
|
|
2474
|
+
clipboardData.setData("text", text);
|
|
2475
|
+
if (selectionTexts.length > 1) clipboardData.setData(MULTI_SELECTION_CLIPBOARD_TYPE, JSON.stringify(selectionTexts));
|
|
2476
|
+
}
|
|
1735
2477
|
#cutSelectionText() {
|
|
1736
2478
|
const textDocument = this.#textDocument;
|
|
1737
2479
|
const selections = this.#selections;
|
|
@@ -1762,15 +2504,15 @@ var Editor = class {
|
|
|
1762
2504
|
textDocument.setLastUndoSelectionsAfter(nextSelections);
|
|
1763
2505
|
this.#applyChange(change, nextSelections, this.#applyChangeToLineAnnotations(change));
|
|
1764
2506
|
}
|
|
1765
|
-
#replaceSelectionText(text, selections = this.#selections, undoBoundary = false) {
|
|
2507
|
+
#replaceSelectionText(text, selections = this.#selections, undoBoundary = false, textOrder = "selection") {
|
|
1766
2508
|
if (selections === void 0) return;
|
|
1767
2509
|
const textDocument = this.#textDocument;
|
|
1768
2510
|
const primarySelection = selections.at(-1);
|
|
1769
2511
|
if (textDocument === void 0 || primarySelection === void 0) return;
|
|
1770
|
-
const { nextSelections, change } = Array.isArray(text) && text.length === selections.length ? applyTextReplaceToSelections(textDocument, selections, text, this.#lineAnnotations, undoBoundary) : applyTextChangeToSelections(textDocument, selections, {
|
|
2512
|
+
const { nextSelections, change } = Array.isArray(text) && text.length === selections.length ? applyTextReplaceToSelections(textDocument, selections, text, this.#lineAnnotations, undoBoundary, textOrder) : applyTextChangeToSelections(textDocument, selections, {
|
|
1771
2513
|
start: textDocument.offsetAt(primarySelection.start),
|
|
1772
2514
|
end: textDocument.offsetAt(primarySelection.end),
|
|
1773
|
-
text: Array.isArray(text) ? text.join(
|
|
2515
|
+
text: Array.isArray(text) ? text.join(textDocument.eol) : text
|
|
1774
2516
|
}, this.#lineAnnotations, void 0, undoBoundary);
|
|
1775
2517
|
if (change !== void 0) this.#applyChange(change, nextSelections, this.#applyChangeToLineAnnotations(change));
|
|
1776
2518
|
}
|
|
@@ -1817,26 +2559,16 @@ var Editor = class {
|
|
|
1817
2559
|
const { nextSelections, change } = applyTransposeToSelections(textDocument, selections, this.#lineAnnotations);
|
|
1818
2560
|
if (change !== void 0) this.#applyChange(change, nextSelections, this.#applyChangeToLineAnnotations(change));
|
|
1819
2561
|
}
|
|
1820
|
-
#getFileRef() {
|
|
1821
|
-
const fileInfo = this.#fileInfo;
|
|
1822
|
-
const textDocument = this.#textDocument;
|
|
1823
|
-
if (fileInfo === void 0 || textDocument === void 0) return;
|
|
1824
|
-
const file = { ...fileInfo };
|
|
1825
|
-
Object.defineProperty(file, "contents", {
|
|
1826
|
-
enumerable: true,
|
|
1827
|
-
get: () => textDocument.getText()
|
|
1828
|
-
});
|
|
1829
|
-
return file;
|
|
1830
|
-
}
|
|
1831
2562
|
#applyChange(change, newSelections, newLineAnnotations, options) {
|
|
1832
|
-
const fileRef = this
|
|
2563
|
+
const fileRef = this.getFile();
|
|
1833
2564
|
const onChange = this.#options.onChange;
|
|
1834
2565
|
if (fileRef !== void 0 && onChange !== void 0) onChange(fileRef, newLineAnnotations ?? this.#lineAnnotations);
|
|
1835
2566
|
if (change.lineDelta !== 0 || this.#isWrap) {
|
|
1836
2567
|
for (const line of this.#lineYCache.keys()) if (line >= change.startLine) this.#lineYCache.delete(line);
|
|
1837
2568
|
}
|
|
1838
|
-
if (this.#
|
|
1839
|
-
|
|
2569
|
+
if (this.#wrapLineOffsetsCache.size > 0) {
|
|
2570
|
+
if (change.lineDelta === 0 && (change.changedLineRanges.length === 1 || change.changedLineChanges?.every(([, , editLineDelta]) => editLineDelta === 0) === true)) for (const [rangeStart, rangeEnd] of change.changedLineRanges) for (let line = rangeStart; line <= rangeEnd; line++) this.#wrapLineOffsetsCache.delete(line);
|
|
2571
|
+
else for (const line of this.#wrapLineOffsetsCache.keys()) if (line >= change.startLine) this.#wrapLineOffsetsCache.delete(line);
|
|
1840
2572
|
}
|
|
1841
2573
|
this.#lastAccessedCharX = void 0;
|
|
1842
2574
|
let renderRange = this.#renderRange;
|
|
@@ -1847,7 +2579,7 @@ var Editor = class {
|
|
|
1847
2579
|
if (primarySelection.end.line >= renderRangeEndLine) {
|
|
1848
2580
|
const widenedTotalLines = primarySelection.end.line - renderRange.startingLine + 1;
|
|
1849
2581
|
const maxWidenLines = this.#viewportWindowLines === void 0 || this.#viewportWindowLines === Infinity ? Infinity : this.#viewportWindowLines * MAX_EDIT_WIDEN_WINDOW_MULTIPLE;
|
|
1850
|
-
if (change.startLine <= renderRangeEndLine && widenedTotalLines <= maxWidenLines) {
|
|
2582
|
+
if (change.startLine <= renderRangeEndLine && widenedTotalLines <= maxWidenLines && this.#isLineRenderable(primarySelection.end.line)) {
|
|
1851
2583
|
if (primarySelection.end.line > renderRangeEndLine) shouldUpdateBuffer = true;
|
|
1852
2584
|
renderRange = {
|
|
1853
2585
|
...renderRange,
|
|
@@ -1862,6 +2594,8 @@ var Editor = class {
|
|
|
1862
2594
|
if (newSelections !== void 0) {
|
|
1863
2595
|
this.#updateSelections(newSelections);
|
|
1864
2596
|
if (options?.skipFocus !== true) {
|
|
2597
|
+
const revealTarget = newSelections.at(-1);
|
|
2598
|
+
if (revealTarget !== void 0) this.#revealLineIfCollapsed(getCaretPosition(revealTarget).line);
|
|
1865
2599
|
if (this.#primaryCaretElement !== void 0) requestAnimationFrame(() => {
|
|
1866
2600
|
this.#primaryCaretElement?.scrollIntoView({
|
|
1867
2601
|
block: "nearest",
|
|
@@ -1885,39 +2619,31 @@ var Editor = class {
|
|
|
1885
2619
|
}
|
|
1886
2620
|
}
|
|
1887
2621
|
}
|
|
1888
|
-
#
|
|
1889
|
-
const lineElement = this.#getLineElement(line);
|
|
1890
|
-
if (lineElement === void 0) return;
|
|
1891
|
-
if (navigator.userAgent.includes("jsdom")) return;
|
|
1892
|
-
const backgroundColor = getComputedStyle(lineElement, "::after").backgroundColor;
|
|
1893
|
-
return backgroundColor === "" || backgroundColor === "transparent" || backgroundColor === "rgba(0, 0, 0, 0)" ? void 0 : backgroundColor;
|
|
1894
|
-
}
|
|
1895
|
-
#getRenderedEditableLineRange() {
|
|
2622
|
+
#getRenderedEditableLineRanges() {
|
|
1896
2623
|
const contentElement = this.#contentElement;
|
|
1897
|
-
if (contentElement === void 0) return;
|
|
1898
|
-
|
|
1899
|
-
let last;
|
|
2624
|
+
if (contentElement === void 0) return [];
|
|
2625
|
+
const ranges = [];
|
|
1900
2626
|
for (const child of contentElement.children) {
|
|
1901
2627
|
const el = child;
|
|
1902
2628
|
const lineType = el.dataset.lineType;
|
|
1903
2629
|
const lineNumber = getLineNumberAttr(el);
|
|
1904
2630
|
if (lineNumber === void 0 || lineType === void 0 || !isLineEditable(lineType)) continue;
|
|
1905
2631
|
const line = lineNumber - 1;
|
|
1906
|
-
|
|
1907
|
-
if (
|
|
2632
|
+
const current = ranges.at(-1);
|
|
2633
|
+
if (current !== void 0 && line <= current[1] + 1) current[1] = Math.max(current[1], line);
|
|
2634
|
+
else ranges.push([line, line]);
|
|
1908
2635
|
}
|
|
1909
|
-
return
|
|
1910
|
-
first,
|
|
1911
|
-
last
|
|
1912
|
-
};
|
|
2636
|
+
return ranges;
|
|
1913
2637
|
}
|
|
1914
2638
|
#getLineElement(line) {
|
|
1915
2639
|
let lineElement = this.#lineElementsCache.get(line);
|
|
1916
2640
|
if (lineElement !== void 0) return lineElement ?? void 0;
|
|
2641
|
+
const renderRange = this.#renderRange;
|
|
2642
|
+
if (renderRange !== void 0 && (line < renderRange.startingLine || line >= renderRange.startingLine + renderRange.totalLines)) return;
|
|
1917
2643
|
const contentElement = this.#contentElement;
|
|
1918
2644
|
if (contentElement === void 0) return;
|
|
1919
|
-
if (
|
|
1920
|
-
const { startingLine } =
|
|
2645
|
+
if (renderRange !== void 0) {
|
|
2646
|
+
const { startingLine } = renderRange;
|
|
1921
2647
|
const { children } = contentElement;
|
|
1922
2648
|
for (let i = line - startingLine; i <= children.length; i++) {
|
|
1923
2649
|
const child = children[i];
|
|
@@ -2008,6 +2734,7 @@ var Editor = class {
|
|
|
2008
2734
|
#wrapLineText(line) {
|
|
2009
2735
|
const cachedOffsets = this.#wrapLineOffsetsCache.get(line);
|
|
2010
2736
|
if (cachedOffsets !== void 0) return cachedOffsets;
|
|
2737
|
+
if (this.#wrapLineOffsetsCache.size >= MAX_WRAP_OFFSETS_CACHE_LINES) this.#wrapLineOffsetsCache.clear();
|
|
2011
2738
|
const lineText = this.#textDocument?.getLineText(line);
|
|
2012
2739
|
if (lineText === void 0 || lineText.length === 0) {
|
|
2013
2740
|
const offsets = new Uint32Array([0]);
|
|
@@ -2037,21 +2764,30 @@ var Editor = class {
|
|
|
2037
2764
|
try {
|
|
2038
2765
|
const unicodeOffsets = getUnicodeMeasurementOffsets(lineText);
|
|
2039
2766
|
const wrapLineStartLeft = div.getBoundingClientRect().left + this.#metrics.ch;
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
range.
|
|
2045
|
-
range.
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
|
|
2767
|
+
const graphemeCount = unicodeOffsets === void 0 ? lineText.length : unicodeOffsets.length - 1;
|
|
2768
|
+
const graphemeStart = (index) => unicodeOffsets === void 0 ? index : unicodeOffsets[index];
|
|
2769
|
+
const measureGrapheme = (index) => {
|
|
2770
|
+
range.setStart(textNode, graphemeStart(index));
|
|
2771
|
+
range.setEnd(textNode, graphemeStart(index + 1));
|
|
2772
|
+
return range.getBoundingClientRect();
|
|
2773
|
+
};
|
|
2774
|
+
starts.push(0);
|
|
2775
|
+
let lastTop = measureGrapheme(0).top;
|
|
2776
|
+
let searchStart = 1;
|
|
2777
|
+
while (searchStart < graphemeCount) {
|
|
2778
|
+
let low = searchStart;
|
|
2779
|
+
let high = graphemeCount;
|
|
2780
|
+
while (low < high) {
|
|
2781
|
+
const mid = low + high >> 1;
|
|
2782
|
+
if (measureGrapheme(mid).top > lastTop) high = mid;
|
|
2783
|
+
else low = mid + 1;
|
|
2051
2784
|
}
|
|
2052
|
-
|
|
2053
|
-
|
|
2054
|
-
|
|
2785
|
+
if (low >= graphemeCount) break;
|
|
2786
|
+
const { left, top } = measureGrapheme(low);
|
|
2787
|
+
const startsPastLineStart = isSafari() && left - wrapLineStartLeft > this.#metrics.ch / 2;
|
|
2788
|
+
starts.push(graphemeStart(startsPastLineStart ? low - 1 : low));
|
|
2789
|
+
lastTop = top;
|
|
2790
|
+
searchStart = low + 1;
|
|
2055
2791
|
}
|
|
2056
2792
|
const offsets = new Uint32Array(starts.length + 1);
|
|
2057
2793
|
for (let i = 0; i < starts.length; i++) offsets[i] = starts[i];
|