@pierre/diffs 1.3.6 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/CodeView.d.ts +113 -68
- package/dist/components/CodeView.d.ts.map +1 -1
- package/dist/components/CodeView.js +153 -58
- package/dist/components/CodeView.js.map +1 -1
- package/dist/components/File.d.ts +75 -15
- package/dist/components/File.d.ts.map +1 -1
- package/dist/components/File.js +223 -62
- package/dist/components/File.js.map +1 -1
- package/dist/components/FileDiff.d.ts +97 -21
- package/dist/components/FileDiff.d.ts.map +1 -1
- package/dist/components/FileDiff.js +400 -100
- package/dist/components/FileDiff.js.map +1 -1
- package/dist/components/UnresolvedFile.d.ts +2 -2
- package/dist/components/UnresolvedFile.d.ts.map +1 -1
- package/dist/components/UnresolvedFile.js +2 -2
- package/dist/components/UnresolvedFile.js.map +1 -1
- package/dist/components/VirtualizedFile.d.ts +16 -7
- package/dist/components/VirtualizedFile.d.ts.map +1 -1
- package/dist/components/VirtualizedFile.js +140 -51
- package/dist/components/VirtualizedFile.js.map +1 -1
- package/dist/components/VirtualizedFileDiff.d.ts +14 -8
- package/dist/components/VirtualizedFileDiff.d.ts.map +1 -1
- package/dist/components/VirtualizedFileDiff.js +183 -93
- package/dist/components/VirtualizedFileDiff.js.map +1 -1
- package/dist/components/VirtulizerDevelopment.d.ts +1 -1
- package/dist/components/VirtulizerDevelopment.d.ts.map +1 -1
- package/dist/edit/index.d.ts +7 -4
- package/dist/edit/index.js +5 -1
- package/dist/editor/EditStateManager.d.ts +56 -0
- package/dist/editor/EditStateManager.d.ts.map +1 -0
- package/dist/editor/EditStateManager.js +135 -0
- package/dist/editor/EditStateManager.js.map +1 -0
- package/dist/editor/cloneRetainedDiffSessionSnapshot.d.ts +7 -0
- package/dist/editor/cloneRetainedDiffSessionSnapshot.d.ts.map +1 -0
- package/dist/editor/cloneRetainedDiffSessionSnapshot.js +16 -0
- package/dist/editor/cloneRetainedDiffSessionSnapshot.js.map +1 -0
- package/dist/editor/editPrediction.d.ts +76 -0
- package/dist/editor/editPrediction.d.ts.map +1 -0
- package/dist/editor/editPrediction.js +365 -0
- package/dist/editor/editPrediction.js.map +1 -0
- package/dist/editor/editStack.d.ts +19 -40
- package/dist/editor/editStack.d.ts.map +1 -1
- package/dist/editor/editStack.js +67 -4
- package/dist/editor/editStack.js.map +1 -1
- package/dist/editor/editor.d.ts +118 -29
- package/dist/editor/editor.d.ts.map +1 -1
- package/dist/editor/editor.js +1103 -383
- package/dist/editor/editor.js.map +1 -1
- package/dist/editor/editor2.js +1 -1
- package/dist/editor/languages.d.ts +3 -3
- package/dist/editor/languages.d.ts.map +1 -1
- package/dist/editor/languages.js.map +1 -1
- package/dist/editor/lineAnnotations.d.ts +3 -3
- package/dist/editor/lineAnnotations.d.ts.map +1 -1
- package/dist/editor/lineAnnotations.js +16 -7
- package/dist/editor/lineAnnotations.js.map +1 -1
- package/dist/editor/marker.d.ts +2 -2
- package/dist/editor/marker.d.ts.map +1 -1
- package/dist/editor/marker.js.map +1 -1
- package/dist/editor/matchBrackets.d.ts +2 -2
- package/dist/editor/matchBrackets.d.ts.map +1 -1
- package/dist/editor/matchBrackets.js.map +1 -1
- package/dist/editor/pieceTable.d.ts +1 -1
- package/dist/editor/pieceTable.js.map +1 -1
- package/dist/editor/searchPanel.d.ts +2 -2
- package/dist/editor/searchPanel.js +1 -1
- package/dist/editor/searchPanel.js.map +1 -1
- package/dist/editor/selection.d.ts +32 -23
- package/dist/editor/selection.d.ts.map +1 -1
- package/dist/editor/selection.js +3 -3
- package/dist/editor/selection.js.map +1 -1
- package/dist/editor/selectionAction.d.ts +3 -3
- package/dist/editor/selectionAction.d.ts.map +1 -1
- package/dist/editor/selectionAction.js.map +1 -1
- package/dist/editor/textDocument.d.ts +11 -8
- package/dist/editor/textDocument.d.ts.map +1 -1
- package/dist/editor/textDocument.js +28 -5
- package/dist/editor/textDocument.js.map +1 -1
- package/dist/editor/textDocumentChangeTransaction.d.ts +15 -0
- package/dist/editor/textDocumentChangeTransaction.d.ts.map +1 -0
- package/dist/editor/textDocumentChangeTransaction.js +12 -0
- package/dist/editor/textDocumentChangeTransaction.js.map +1 -0
- package/dist/editor/textMeasure.d.ts +5 -0
- package/dist/editor/textMeasure.d.ts.map +1 -1
- package/dist/editor/textMeasure.js +10 -0
- package/dist/editor/textMeasure.js.map +1 -1
- package/dist/editor/tokenizer.d.ts +1 -1
- package/dist/editor/tokenizer.js.map +1 -1
- package/dist/editor/types.d.ts +267 -0
- package/dist/editor/types.d.ts.map +1 -0
- package/dist/editor/types.js +0 -0
- package/dist/editor/utils.d.ts +2 -1
- package/dist/editor/utils.d.ts.map +1 -1
- package/dist/editor/utils.js +4 -1
- package/dist/editor/utils.js.map +1 -1
- package/dist/index.d.ts +8 -6
- package/dist/index.js +9 -8
- package/dist/managers/InteractionManager.d.ts.map +1 -1
- package/dist/managers/InteractionManager.js +7 -0
- package/dist/managers/InteractionManager.js.map +1 -1
- package/dist/react/CodeView.d.ts +36 -25
- package/dist/react/CodeView.d.ts.map +1 -1
- package/dist/react/CodeView.js +15 -14
- package/dist/react/CodeView.js.map +1 -1
- package/dist/react/EditContext.d.ts +8 -11
- package/dist/react/EditContext.d.ts.map +1 -1
- package/dist/react/EditContext.js +2 -9
- package/dist/react/EditContext.js.map +1 -1
- package/dist/react/File.d.ts +10 -6
- package/dist/react/File.d.ts.map +1 -1
- package/dist/react/File.js +8 -4
- package/dist/react/File.js.map +1 -1
- package/dist/react/FileDiff.d.ts +10 -5
- package/dist/react/FileDiff.d.ts.map +1 -1
- package/dist/react/FileDiff.js +8 -4
- package/dist/react/FileDiff.js.map +1 -1
- package/dist/react/MultiFileDiff.d.ts +8 -5
- package/dist/react/MultiFileDiff.d.ts.map +1 -1
- package/dist/react/MultiFileDiff.js +8 -12
- package/dist/react/MultiFileDiff.js.map +1 -1
- package/dist/react/PatchDiff.d.ts +7 -4
- package/dist/react/PatchDiff.d.ts.map +1 -1
- package/dist/react/PatchDiff.js +8 -4
- package/dist/react/PatchDiff.js.map +1 -1
- package/dist/react/UnresolvedFile.d.ts +3 -3
- package/dist/react/UnresolvedFile.d.ts.map +1 -1
- package/dist/react/UnresolvedFile.js.map +1 -1
- package/dist/react/index.d.ts +8 -5
- package/dist/react/types.d.ts +46 -9
- package/dist/react/types.d.ts.map +1 -1
- package/dist/react/utils/renderDiffChildren.d.ts +14 -12
- package/dist/react/utils/renderDiffChildren.d.ts.map +1 -1
- package/dist/react/utils/renderDiffChildren.js +2 -2
- package/dist/react/utils/renderDiffChildren.js.map +1 -1
- package/dist/react/utils/renderFileChildren.d.ts +14 -12
- package/dist/react/utils/renderFileChildren.d.ts.map +1 -1
- package/dist/react/utils/renderFileChildren.js +2 -2
- package/dist/react/utils/renderFileChildren.js.map +1 -1
- package/dist/react/utils/useFileDiffInstance.d.ts +22 -10
- package/dist/react/utils/useFileDiffInstance.d.ts.map +1 -1
- package/dist/react/utils/useFileDiffInstance.js +112 -22
- package/dist/react/utils/useFileDiffInstance.js.map +1 -1
- package/dist/react/utils/useFileInstance.d.ts +15 -9
- package/dist/react/utils/useFileInstance.d.ts.map +1 -1
- package/dist/react/utils/useFileInstance.js +84 -25
- package/dist/react/utils/useFileInstance.js.map +1 -1
- package/dist/renderers/DiffHunksRenderer.d.ts +30 -15
- package/dist/renderers/DiffHunksRenderer.d.ts.map +1 -1
- package/dist/renderers/DiffHunksRenderer.js +172 -108
- package/dist/renderers/DiffHunksRenderer.js.map +1 -1
- package/dist/renderers/FileRenderer.d.ts +27 -11
- package/dist/renderers/FileRenderer.d.ts.map +1 -1
- package/dist/renderers/FileRenderer.js +138 -64
- package/dist/renderers/FileRenderer.js.map +1 -1
- package/dist/renderers/UnresolvedFileHunksRenderer.d.ts +2 -2
- package/dist/renderers/UnresolvedFileHunksRenderer.d.ts.map +1 -1
- package/dist/renderers/UnresolvedFileHunksRenderer.js +2 -2
- package/dist/renderers/UnresolvedFileHunksRenderer.js.map +1 -1
- package/dist/shiki-stream/tokenizer.d.ts.map +1 -1
- package/dist/shiki-stream/tokenizer.js +2 -1
- package/dist/shiki-stream/tokenizer.js.map +1 -1
- package/dist/ssr/index.d.ts +2 -2
- package/dist/ssr/preloadDiffs.d.ts +21 -21
- package/dist/ssr/preloadDiffs.d.ts.map +1 -1
- package/dist/ssr/preloadDiffs.js +1 -1
- package/dist/ssr/preloadDiffs.js.map +1 -1
- package/dist/ssr/preloadFile.d.ts +6 -6
- package/dist/ssr/preloadFile.d.ts.map +1 -1
- package/dist/ssr/preloadFile.js.map +1 -1
- package/dist/ssr/preloadPatchFile.d.ts +4 -4
- package/dist/ssr/preloadPatchFile.d.ts.map +1 -1
- package/dist/ssr/preloadPatchFile.js.map +1 -1
- package/dist/style.js +1 -1
- package/dist/types.d.ts +13 -263
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/appendItems.d.ts +5 -0
- package/dist/utils/appendItems.d.ts.map +1 -0
- package/dist/utils/appendItems.js +8 -0
- package/dist/utils/appendItems.js.map +1 -0
- package/dist/utils/areDiffTargetsEqual.js +1 -1
- package/dist/utils/areDiffTargetsEqual.js.map +1 -1
- package/dist/utils/areFileTargetsEqual.d.ts +7 -0
- package/dist/utils/areFileTargetsEqual.d.ts.map +1 -0
- package/dist/utils/areFileTargetsEqual.js +8 -0
- package/dist/utils/areFileTargetsEqual.js.map +1 -0
- package/dist/utils/areManagedSnapshotsEqual.d.ts +1 -1
- package/dist/utils/areManagedSnapshotsEqual.d.ts.map +1 -1
- package/dist/utils/areManagedSnapshotsEqual.js.map +1 -1
- package/dist/utils/areOptionsEqual.d.ts +3 -3
- package/dist/utils/areOptionsEqual.d.ts.map +1 -1
- package/dist/utils/areOptionsEqual.js.map +1 -1
- package/dist/utils/cloneFileDiffMetadata.d.ts +3 -2
- package/dist/utils/cloneFileDiffMetadata.d.ts.map +1 -1
- package/dist/utils/cloneFileDiffMetadata.js +8 -5
- package/dist/utils/cloneFileDiffMetadata.js.map +1 -1
- package/dist/utils/composeCacheKey.d.ts +6 -0
- package/dist/utils/composeCacheKey.d.ts.map +1 -0
- package/dist/utils/composeCacheKey.js +10 -0
- package/dist/utils/composeCacheKey.js.map +1 -0
- package/dist/utils/editSessionAnnotations.d.ts +69 -0
- package/dist/utils/editSessionAnnotations.d.ts.map +1 -0
- package/dist/utils/editSessionAnnotations.js +64 -0
- package/dist/utils/editSessionAnnotations.js.map +1 -0
- package/dist/utils/editSessionHunks.d.ts +5 -3
- package/dist/utils/editSessionHunks.d.ts.map +1 -1
- package/dist/utils/editSessionHunks.js +7 -5
- package/dist/utils/editSessionHunks.js.map +1 -1
- package/dist/utils/getDiffHunksRendererOptions.d.ts +1 -1
- package/dist/utils/getDiffHunksRendererOptions.d.ts.map +1 -1
- package/dist/utils/getDiffHunksRendererOptions.js.map +1 -1
- package/dist/utils/getFileRendererOptions.d.ts +1 -1
- package/dist/utils/getFileRendererOptions.d.ts.map +1 -1
- package/dist/utils/getFileRendererOptions.js.map +1 -1
- package/dist/utils/hydratePartialDiff.d.ts.map +1 -1
- package/dist/utils/hydratePartialDiff.js +2 -1
- package/dist/utils/hydratePartialDiff.js.map +1 -1
- package/dist/utils/lineAnnotationIdentity.d.ts +16 -0
- package/dist/utils/lineAnnotationIdentity.d.ts.map +1 -0
- package/dist/utils/lineAnnotationIdentity.js +17 -0
- package/dist/utils/lineAnnotationIdentity.js.map +1 -0
- package/dist/utils/parseDiffFromFile.d.ts +2 -2
- package/dist/utils/parseDiffFromFile.d.ts.map +1 -1
- package/dist/utils/parseDiffFromFile.js +6 -6
- package/dist/utils/parseDiffFromFile.js.map +1 -1
- package/dist/utils/parsePatchFiles.d.ts +6 -3
- package/dist/utils/parsePatchFiles.d.ts.map +1 -1
- package/dist/utils/parsePatchFiles.js +34 -9
- package/dist/utils/parsePatchFiles.js.map +1 -1
- package/dist/utils/renderDiffWithHighlighter.d.ts.map +1 -1
- package/dist/utils/renderDiffWithHighlighter.js +6 -5
- package/dist/utils/renderDiffWithHighlighter.js.map +1 -1
- package/dist/utils/renderFileWithHighlighter.d.ts.map +1 -1
- package/dist/utils/renderFileWithHighlighter.js +7 -4
- package/dist/utils/renderFileWithHighlighter.js.map +1 -1
- package/dist/utils/trimPatchContext.d.ts.map +1 -1
- package/dist/utils/trimPatchContext.js +3 -2
- package/dist/utils/trimPatchContext.js.map +1 -1
- package/dist/utils/updateDiffHunks.js +1 -1
- package/dist/utils/virtualDiffLayout.js +1 -1
- package/dist/worker/WorkerPoolManager.d.ts +4 -3
- package/dist/worker/WorkerPoolManager.d.ts.map +1 -1
- package/dist/worker/WorkerPoolManager.js +33 -4
- package/dist/worker/WorkerPoolManager.js.map +1 -1
- package/dist/worker/types.d.ts +5 -0
- package/dist/worker/types.d.ts.map +1 -1
- package/dist/worker/worker-portable.js +14 -6
- package/dist/worker/worker-portable.js.map +1 -1
- package/dist/worker/worker.js +14 -6
- package/dist/worker/worker.js.map +1 -1
- package/package.json +9 -1
- package/dist/editor/stateStorage.d.ts +0 -15
- package/dist/editor/stateStorage.d.ts.map +0 -1
- package/dist/editor/stateStorage.js +0 -65
- package/dist/editor/stateStorage.js.map +0 -1
package/dist/editor/editor.js
CHANGED
|
@@ -1,23 +1,27 @@
|
|
|
1
1
|
import { dequeueRender, queueRender } from "../managers/UniversalRenderingManager.js";
|
|
2
2
|
import { isGutterUtilityPath } from "../utils/isGutterUtilityPath.js";
|
|
3
|
+
import { computeLineOffsets } from "../utils/computeFileOffsets.js";
|
|
3
4
|
import { getFiletypeFromFileName } from "../utils/getFiletypeFromFileName.js";
|
|
4
5
|
import { isSafari } from "../utils/platform.js";
|
|
6
|
+
import { EditStack } from "./editStack.js";
|
|
7
|
+
import { getTextDocumentChangeTransaction } from "./textDocumentChangeTransaction.js";
|
|
8
|
+
import { TextDocument } from "./textDocument.js";
|
|
9
|
+
import { EditStateManager, cloneEditorViewState, toManagedEditState } from "./EditStateManager.js";
|
|
5
10
|
import { isMoveCursorShortcut, isPrimaryModifier } from "./platform.js";
|
|
6
11
|
import { resolveEditorCommandFromKeyboardEvent, resolveFindAgainShortcut } from "./command.js";
|
|
12
|
+
import { cloneRetainedDiffSessionSnapshot } from "./cloneRetainedDiffSessionSnapshot.js";
|
|
7
13
|
import editor_default from "./editor2.js";
|
|
8
|
-
import {
|
|
14
|
+
import { buildEditPredictionRequest, matchesEditPredictionPattern, recordEditPrediction } from "./editPrediction.js";
|
|
9
15
|
import { resolveBlockCommentEdits, resolveCommentConfig, resolveLineCommentEdits } from "./languages.js";
|
|
10
16
|
import { addEventListener, clampDomOffset, extend, getLineNumberAttr, h, lookupScrollContainer, round } from "./utils.js";
|
|
11
17
|
import { applyDocumentChangeToLineAnnotations, renderLineAnnotations } from "./lineAnnotations.js";
|
|
12
18
|
import { PopoverManager } from "./popover.js";
|
|
13
|
-
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, snapCharacterToGraphemeBoundary } from "./selection.js";
|
|
19
|
+
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, remapOffsetThroughEdits, remapSelectionsAfterEdits, resolveIndentEdits, resolveSelectionCut, selectionIntersects, shiftSelectionLines, snapCharacterToGraphemeBoundary } from "./selection.js";
|
|
14
20
|
import { MarkerRenderer, markerSeverityDatasetKey } from "./marker.js";
|
|
15
21
|
import { findBracketMatchRanges } from "./matchBrackets.js";
|
|
16
22
|
import { createSpriteElement } from "./sprite.js";
|
|
17
23
|
import { SearchPanelWidget } from "./searchPanel.js";
|
|
18
24
|
import { SelectionActionWidget } from "./selectionAction.js";
|
|
19
|
-
import { cloneEditorState, createStateStorage } from "./stateStorage.js";
|
|
20
|
-
import { TextDocument } from "./textDocument.js";
|
|
21
25
|
import { Metrics, getExpandedAsciiTextColumns, getUnicodeMeasurementOffsets, snapTextOffsetToUnicodeBoundary } from "./textMeasure.js";
|
|
22
26
|
import { EditorTokenizer, renderLineTokens } from "./tokenizer.js";
|
|
23
27
|
//#region src/editor/editor.ts
|
|
@@ -33,29 +37,45 @@ function getShadowRootRange(shadowRoot) {
|
|
|
33
37
|
endOffset: range.endOffset
|
|
34
38
|
};
|
|
35
39
|
}
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
40
|
+
/** Describe replacing the complete document from its previous text. */
|
|
41
|
+
function createFullDocumentChange(previousContents, contents) {
|
|
42
|
+
const lineOffsets = computeLineOffsets(previousContents);
|
|
43
|
+
const lastLineOffset = lineOffsets[lineOffsets.length - 1] ?? 0;
|
|
44
|
+
return {
|
|
45
|
+
start: 0,
|
|
46
|
+
end: previousContents.length,
|
|
47
|
+
text: contents,
|
|
48
|
+
range: {
|
|
49
|
+
start: {
|
|
50
|
+
line: 0,
|
|
51
|
+
character: 0
|
|
52
|
+
},
|
|
53
|
+
end: {
|
|
54
|
+
line: lineOffsets.length - 1,
|
|
55
|
+
character: previousContents.length - lastLineOffset
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
};
|
|
39
59
|
}
|
|
40
|
-
function
|
|
41
|
-
return
|
|
60
|
+
function isVirtualizedEditorComponent(instance) {
|
|
61
|
+
return instance != null && "renderType" in instance && instance.renderType === "virtualized";
|
|
42
62
|
}
|
|
43
63
|
const MAX_EDIT_WIDEN_WINDOW_MULTIPLE = 2;
|
|
44
64
|
const MAX_WRAP_OFFSETS_CACHE_LINES = 1e4;
|
|
65
|
+
const EDIT_PREDICTION_DEBOUNCE_MS = 300;
|
|
66
|
+
const MAX_EDIT_PREDICTION_RESPONSE_EDITS = 256;
|
|
67
|
+
const MAX_EDIT_PREDICTION_RESPONSE_BYTES = 128 * 1024;
|
|
68
|
+
const editPredictionTextEncoder = new TextEncoder();
|
|
45
69
|
const SELECTION_ACTION_POPOVER_PLACEMENT_KEY = "selection-action";
|
|
46
70
|
const MULTI_SELECTION_CLIPBOARD_TYPE = "application/vnd.pierre.diffs-selections+json";
|
|
47
71
|
var Editor = class {
|
|
72
|
+
type;
|
|
48
73
|
#options;
|
|
74
|
+
#initialState;
|
|
75
|
+
#editSession;
|
|
49
76
|
#metrics = new Metrics();
|
|
50
77
|
#tokenizer;
|
|
51
78
|
#popoverManager;
|
|
52
|
-
#textDocumentCache = /* @__PURE__ */ new Map();
|
|
53
|
-
#stateStorage;
|
|
54
|
-
#stateStorageOption;
|
|
55
|
-
#pendingStateWrites = /* @__PURE__ */ new Map();
|
|
56
|
-
#pendingStateRestore;
|
|
57
|
-
#stateRestoreGeneration = 0;
|
|
58
|
-
#restoreStateOnNextSync = false;
|
|
59
79
|
#editorEventDisposes;
|
|
60
80
|
#globalEventDisposes;
|
|
61
81
|
#selectEventDisposes;
|
|
@@ -79,17 +99,25 @@ var Editor = class {
|
|
|
79
99
|
#fileContainer;
|
|
80
100
|
#gutterElement;
|
|
81
101
|
#contentElement;
|
|
102
|
+
#deletionsColumn;
|
|
82
103
|
#overlayElement;
|
|
83
104
|
#overlayElements;
|
|
105
|
+
#caretElements;
|
|
106
|
+
#caretHighlightElements;
|
|
84
107
|
#primaryCaretElement;
|
|
85
108
|
#resizeObserver;
|
|
86
109
|
#fileInstance;
|
|
87
|
-
#
|
|
110
|
+
#applyDocumentChange;
|
|
111
|
+
#publishChange;
|
|
112
|
+
#isRendering = false;
|
|
113
|
+
#restoreEditorStateOnSync = false;
|
|
88
114
|
#lineAnnotations;
|
|
89
|
-
#
|
|
115
|
+
#editStateKey;
|
|
116
|
+
#ownsVerticalViewport;
|
|
90
117
|
#renderRange;
|
|
91
118
|
#viewportWindowLines;
|
|
92
119
|
#markerRenderer;
|
|
120
|
+
#carets;
|
|
93
121
|
#searchPanel;
|
|
94
122
|
#selectionAction;
|
|
95
123
|
#canMountSelectionAction = true;
|
|
@@ -115,53 +143,166 @@ var Editor = class {
|
|
|
115
143
|
#retainSearchPanelFocus = false;
|
|
116
144
|
#fontRemeasureScheduled = false;
|
|
117
145
|
#themeSelectionRefreshFrame;
|
|
146
|
+
#editPredictionTimer;
|
|
147
|
+
#editPredictionAbortController;
|
|
148
|
+
#editPredictionGeneration = 0;
|
|
149
|
+
#editPredictionRevealed = false;
|
|
150
|
+
#retryEditPredictionOnRender = false;
|
|
151
|
+
#editPrediction;
|
|
152
|
+
#editPredictionHistory = [];
|
|
153
|
+
#editPredictionSpacers = /* @__PURE__ */ new Map();
|
|
154
|
+
#ghostTextRows = /* @__PURE__ */ new Map();
|
|
118
155
|
#onDeferTokenize = (lines, themeType) => {
|
|
156
|
+
if (!this.#isRendering) return;
|
|
119
157
|
this.#fileInstance?.updateRenderCache(lines, themeType);
|
|
120
158
|
if (this.#renderRange !== void 0 && this.#renderRange.totalLines !== Infinity) {
|
|
159
|
+
const predictionLines = this.#editPrediction === void 0 ? void 0 : new Set(this.#editPrediction.response.edits.map((edit) => edit.range.start.line));
|
|
160
|
+
let refreshPrediction = false;
|
|
121
161
|
const { startingLine, totalLines } = this.#renderRange;
|
|
122
|
-
const endLine = Math.min(startingLine + totalLines, this.#
|
|
162
|
+
const endLine = Math.min(startingLine + totalLines, (this.#editSession ?? this.#initialState)?.document?.lineCount ?? 0);
|
|
123
163
|
for (const [line, tokens] of lines) if (line >= startingLine && line < endLine) {
|
|
124
164
|
const lineElement = this.#getLineElement(line);
|
|
125
|
-
if (lineElement !== void 0)
|
|
165
|
+
if (lineElement !== void 0) {
|
|
166
|
+
lineElement.replaceChildren(...renderLineTokens(tokens));
|
|
167
|
+
refreshPrediction ||= predictionLines?.has(line) === true;
|
|
168
|
+
}
|
|
126
169
|
}
|
|
170
|
+
if (refreshPrediction && this.#selections !== void 0) this.#updateSelections(this.#selections);
|
|
127
171
|
}
|
|
128
172
|
};
|
|
129
|
-
|
|
173
|
+
/**
|
|
174
|
+
* @param type The component surface this editor can attach to.
|
|
175
|
+
* @param options Configure editor behavior and lifecycle callbacks.
|
|
176
|
+
* @param editStateKey Retain this editable draft and its undo/redo history
|
|
177
|
+
* in memory so a later editor using the same type and key can resume them.
|
|
178
|
+
*/
|
|
179
|
+
constructor(type, options = {}, editStateKey) {
|
|
180
|
+
this.type = type;
|
|
130
181
|
this.#options = options;
|
|
182
|
+
this.#ownsVerticalViewport = options.ownsVerticalViewport === true;
|
|
183
|
+
this.#initialState = options.initialState;
|
|
184
|
+
this.#editStateKey = editStateKey;
|
|
185
|
+
}
|
|
186
|
+
get #getTypedEditor() {
|
|
187
|
+
return this.type === "file" ? this : this;
|
|
131
188
|
}
|
|
132
189
|
setOptions(options) {
|
|
133
|
-
const
|
|
134
|
-
const
|
|
190
|
+
const previousRenderCaret = this.#options.renderCaret;
|
|
191
|
+
const previousEditPrediction = this.#options.editPrediction;
|
|
192
|
+
this.#options = {
|
|
135
193
|
...this.#options,
|
|
136
194
|
...options
|
|
137
195
|
};
|
|
138
|
-
if (
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
this.#options = nextOptions;
|
|
143
|
-
if (this.#options.persistState !== true) {
|
|
144
|
-
this.#textDocumentCache.clear();
|
|
145
|
-
this.#stateRestoreGeneration++;
|
|
146
|
-
this.#restoreStateOnNextSync = false;
|
|
196
|
+
if (previousRenderCaret !== this.#options.renderCaret) {
|
|
197
|
+
this.#caretElements?.forEach((element) => element.remove());
|
|
198
|
+
this.#caretElements = void 0;
|
|
199
|
+
this.#renderCarets();
|
|
147
200
|
}
|
|
148
|
-
if (
|
|
149
|
-
this.#
|
|
150
|
-
this.#
|
|
151
|
-
this.#
|
|
152
|
-
this.#pendingStateWrites.clear();
|
|
201
|
+
if (previousEditPrediction !== this.#options.editPrediction) {
|
|
202
|
+
this.#cancelEditPrediction(true);
|
|
203
|
+
this.#editPredictionHistory = [];
|
|
204
|
+
this.#scheduleEditPrediction();
|
|
153
205
|
}
|
|
154
206
|
}
|
|
207
|
+
__emitEditComplete(event) {
|
|
208
|
+
this.#options.onComplete?.(event);
|
|
209
|
+
}
|
|
210
|
+
/** @internal */
|
|
211
|
+
__getGhostTextRows() {
|
|
212
|
+
return this.#ghostTextRows;
|
|
213
|
+
}
|
|
214
|
+
setCarets(carets) {
|
|
215
|
+
const textDocument = this.#editSession?.document;
|
|
216
|
+
if (textDocument === void 0) return;
|
|
217
|
+
this.#caretElements?.forEach((element) => element.remove());
|
|
218
|
+
this.#caretElements = void 0;
|
|
219
|
+
this.#caretHighlightElements?.forEach((element) => element.remove());
|
|
220
|
+
this.#caretHighlightElements = void 0;
|
|
221
|
+
this.#carets = carets.length === 0 ? void 0 : carets.map((caret) => {
|
|
222
|
+
const anchor = textDocument.normalizePosition(caret.anchor);
|
|
223
|
+
const focus = textDocument.normalizePosition(caret.focus);
|
|
224
|
+
return {
|
|
225
|
+
caret: {
|
|
226
|
+
...caret,
|
|
227
|
+
anchor,
|
|
228
|
+
focus
|
|
229
|
+
},
|
|
230
|
+
anchorOffset: textDocument.offsetAt(anchor),
|
|
231
|
+
focusOffset: textDocument.offsetAt(focus)
|
|
232
|
+
};
|
|
233
|
+
});
|
|
234
|
+
this.#renderCarets();
|
|
235
|
+
}
|
|
155
236
|
edit(fileInstance) {
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
this.#
|
|
237
|
+
const editor = this.#getTypedEditor;
|
|
238
|
+
const previousSession = this.#editSession;
|
|
239
|
+
if (this.#isRendering) throw new Error("Editor.edit: the editor is already rendering its component");
|
|
240
|
+
if (this.#fileInstance != null && this.#fileInstance !== fileInstance) throw new Error("Editor.edit: a recycled edit session cannot attach to a different component");
|
|
241
|
+
const initialState = this.#initialState;
|
|
242
|
+
const initialEditorState = initialState?.editor;
|
|
243
|
+
const editStateKey = this.#editStateKey;
|
|
244
|
+
const editSession = getEditSession({
|
|
245
|
+
type: this.type,
|
|
246
|
+
editStateKey,
|
|
247
|
+
owner: this,
|
|
248
|
+
initialState,
|
|
249
|
+
previousSession
|
|
250
|
+
});
|
|
251
|
+
const previousDiffSession = editSession.diffSession;
|
|
252
|
+
this.#initialState = void 0;
|
|
253
|
+
this.#editSession = editSession;
|
|
161
254
|
this.#fileInstance = fileInstance;
|
|
162
|
-
this.#
|
|
163
|
-
this.#
|
|
164
|
-
|
|
255
|
+
this.#isRendering = true;
|
|
256
|
+
this.#restoreEditorStateOnSync = editSession.editor != null;
|
|
257
|
+
try {
|
|
258
|
+
this.#initialize();
|
|
259
|
+
if (fileInstance.type === "file" && editor.type === "file") {
|
|
260
|
+
editor.#applyDocumentChange = fileInstance.applyDocumentChange.bind(fileInstance);
|
|
261
|
+
editor.#publishChange = (changes, file, lineAnnotations) => {
|
|
262
|
+
const event = {
|
|
263
|
+
changes,
|
|
264
|
+
file,
|
|
265
|
+
editor,
|
|
266
|
+
lineAnnotations
|
|
267
|
+
};
|
|
268
|
+
editor.#options.onChange?.(event);
|
|
269
|
+
fileInstance.emitEditChange(event);
|
|
270
|
+
};
|
|
271
|
+
if (this.#detach == null) this.#detach = fileInstance.__attachEditor(editor);
|
|
272
|
+
else fileInstance.__resumeEditor(editor);
|
|
273
|
+
} else if (fileInstance.type === "file-diff" && editor.type === "file-diff") {
|
|
274
|
+
editor.#applyDocumentChange = fileInstance.applyDocumentChange.bind(fileInstance);
|
|
275
|
+
editor.#publishChange = (changes, file, lineAnnotations) => {
|
|
276
|
+
const event = {
|
|
277
|
+
changes,
|
|
278
|
+
file,
|
|
279
|
+
editor,
|
|
280
|
+
lineAnnotations
|
|
281
|
+
};
|
|
282
|
+
editor.#options.onChange?.(event);
|
|
283
|
+
fileInstance.emitEditChange(event);
|
|
284
|
+
};
|
|
285
|
+
if (this.#detach == null) this.#detach = fileInstance.__attachEditor(editor);
|
|
286
|
+
else fileInstance.__resumeEditor(editor);
|
|
287
|
+
} else throw new Error("Editor.edit: Impossible edit state");
|
|
288
|
+
} catch (error) {
|
|
289
|
+
this.cleanUp("recycle");
|
|
290
|
+
if (editSession.type === "file-diff" && editSession.diffSession == null) editSession.diffSession = previousDiffSession;
|
|
291
|
+
if (this.#detach == null && editStateKey != null) if (editor.type === "file") EditStateManager.releaseFile(editStateKey, editor);
|
|
292
|
+
else EditStateManager.releaseFileDiff(editStateKey, editor);
|
|
293
|
+
this.#editSession = previousSession;
|
|
294
|
+
if (this.#detach == null) {
|
|
295
|
+
this.#fileInstance = void 0;
|
|
296
|
+
this.#applyDocumentChange = void 0;
|
|
297
|
+
this.#publishChange = void 0;
|
|
298
|
+
}
|
|
299
|
+
if (initialState != null && initialEditorState != null) initialState.editor = initialEditorState;
|
|
300
|
+
this.#initialState = initialState;
|
|
301
|
+
throw error;
|
|
302
|
+
}
|
|
303
|
+
return () => {
|
|
304
|
+
this.cleanUp("complete");
|
|
305
|
+
};
|
|
165
306
|
}
|
|
166
307
|
/**
|
|
167
308
|
* Apply edits to current attached file. Every edit joins the undo timeline:
|
|
@@ -174,8 +315,8 @@ var Editor = class {
|
|
|
174
315
|
* are remapped during replay and the text edit still joins the undo timeline.
|
|
175
316
|
*/
|
|
176
317
|
applyEdits(edits, updateHistory = true) {
|
|
177
|
-
const textDocument = this.#
|
|
178
|
-
if (textDocument == null) throw new Error("Editor is not attached");
|
|
318
|
+
const textDocument = this.#editSession?.document;
|
|
319
|
+
if (textDocument == null) throw new Error("Editor.applyEdits: Editor is not attached");
|
|
179
320
|
const wasFocused = this.#contentHasFocus;
|
|
180
321
|
const selectionsBefore = this.#selections;
|
|
181
322
|
const selectionOffsetsBefore = selectionsBefore?.map((selection) => [textDocument.offsetAt(selection.start), textDocument.offsetAt(selection.end)]);
|
|
@@ -191,11 +332,11 @@ var Editor = class {
|
|
|
191
332
|
}
|
|
192
333
|
/** Whether there is an edit to undo. */
|
|
193
334
|
get canUndo() {
|
|
194
|
-
return this.#
|
|
335
|
+
return (this.#editSession ?? this.#initialState)?.document?.canUndo ?? false;
|
|
195
336
|
}
|
|
196
337
|
/** Whether there is an undone edit to redo. */
|
|
197
338
|
get canRedo() {
|
|
198
|
-
return this.#
|
|
339
|
+
return (this.#editSession ?? this.#initialState)?.document?.canRedo ?? false;
|
|
199
340
|
}
|
|
200
341
|
/** Undo the last edit. Does nothing when there is nothing to undo. */
|
|
201
342
|
undo() {
|
|
@@ -206,8 +347,9 @@ var Editor = class {
|
|
|
206
347
|
this.#runCommand("redo");
|
|
207
348
|
}
|
|
208
349
|
getFile() {
|
|
209
|
-
const
|
|
210
|
-
const
|
|
350
|
+
const editSession = this.#editSession ?? this.#initialState;
|
|
351
|
+
const fileInfo = editSession?.fileInfo;
|
|
352
|
+
const textDocument = editSession?.document;
|
|
211
353
|
if (fileInfo === void 0 || textDocument === void 0) return;
|
|
212
354
|
const file = { ...fileInfo };
|
|
213
355
|
Object.defineProperty(file, "contents", {
|
|
@@ -217,32 +359,56 @@ var Editor = class {
|
|
|
217
359
|
return file;
|
|
218
360
|
}
|
|
219
361
|
getText() {
|
|
220
|
-
return this.#
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
|
|
362
|
+
return (this.#editSession ?? this.#initialState)?.document?.getText() ?? "";
|
|
363
|
+
}
|
|
364
|
+
/** Return an isolated copy of selections and restorable view state. */
|
|
365
|
+
getViewState() {
|
|
366
|
+
const fileInstance = this.#isRendering ? this.#fileInstance : void 0;
|
|
367
|
+
if (!this.#isRendering && this.#editSession?.editor != null) return cloneEditorViewState(this.#editSession.editor);
|
|
368
|
+
const selections = this.#selections?.map((selection) => ({
|
|
369
|
+
...selection,
|
|
370
|
+
start: { ...selection.start },
|
|
371
|
+
end: { ...selection.end }
|
|
372
|
+
}));
|
|
373
|
+
if (fileInstance == null) return { selections };
|
|
374
|
+
const viewport = this.#getOwnedVerticalViewport();
|
|
375
|
+
const scrollLeft = fileInstance.getCodeScrollLeft();
|
|
376
|
+
if (viewport == null) return {
|
|
377
|
+
selections,
|
|
378
|
+
view: { scrollLeft }
|
|
379
|
+
};
|
|
224
380
|
return {
|
|
225
|
-
selections
|
|
226
|
-
view:
|
|
227
|
-
scrollLeft
|
|
228
|
-
scrollTop:
|
|
229
|
-
}
|
|
381
|
+
selections,
|
|
382
|
+
view: {
|
|
383
|
+
scrollLeft,
|
|
384
|
+
scrollTop: viewport.scrollTop
|
|
385
|
+
}
|
|
230
386
|
};
|
|
231
387
|
}
|
|
232
|
-
|
|
233
|
-
|
|
388
|
+
/**
|
|
389
|
+
* Return the objects that make up the active edit session, or undefined when
|
|
390
|
+
* no complete session exists.
|
|
391
|
+
*/
|
|
392
|
+
getEditState() {
|
|
393
|
+
const editSession = this.#editSession;
|
|
394
|
+
if (editSession == null) return;
|
|
395
|
+
if (this.#fileInstance == null) throw new Error(`Editor.getEditState: active ${this.type} session has no component`);
|
|
396
|
+
return toManagedEditState(editSession);
|
|
397
|
+
}
|
|
398
|
+
setViewState({ selections, view }) {
|
|
399
|
+
if (!this.#isRendering || this.#fileInstance === void 0 || this.#editSession?.document === void 0) throw new Error("Editor.setViewState: Editor is not attached");
|
|
234
400
|
this.#canMountSelectionAction = false;
|
|
235
401
|
this.#updateSelections(selections ?? []);
|
|
236
402
|
if (view != null) {
|
|
237
403
|
this.#fileInstance.setCodeScrollLeft(view.scrollLeft);
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
}
|
|
241
|
-
this.#
|
|
404
|
+
const viewport = this.#getOwnedVerticalViewport();
|
|
405
|
+
if (view.scrollTop !== void 0 && viewport != null) viewport.scrollTop = view.scrollTop;
|
|
406
|
+
} else if (this.#ownsVerticalViewport) this.#scrollToPrimaryCaret();
|
|
407
|
+
this.#checkpointEditSessionState();
|
|
242
408
|
}
|
|
243
409
|
setSelections(selections) {
|
|
244
|
-
const textDocument = this.#
|
|
245
|
-
if (textDocument === void 0) throw new Error("Text document is not initialized");
|
|
410
|
+
const textDocument = this.#editSession?.document;
|
|
411
|
+
if (textDocument === void 0) throw new Error("Editor.setSelections: Text document is not initialized");
|
|
246
412
|
const resolvedSelections = selections.map((selection) => {
|
|
247
413
|
let start = textDocument.normalizePosition(selection.start);
|
|
248
414
|
let end = textDocument.normalizePosition(selection.end);
|
|
@@ -264,8 +430,8 @@ var Editor = class {
|
|
|
264
430
|
this.#scrollToPrimaryCaret();
|
|
265
431
|
}
|
|
266
432
|
setMarkers(markers) {
|
|
267
|
-
const textDocument = this.#
|
|
268
|
-
if (textDocument === void 0) throw new Error("Text document is not initialized");
|
|
433
|
+
const textDocument = this.#editSession?.document;
|
|
434
|
+
if (textDocument === void 0) throw new Error("Editor.setMarkers: Text document is not initialized");
|
|
269
435
|
if (markers.length === 0) {
|
|
270
436
|
this.#markerRenderer?.cleanup();
|
|
271
437
|
this.#markerRenderer = void 0;
|
|
@@ -284,13 +450,14 @@ var Editor = class {
|
|
|
284
450
|
this.#markerRenderer.setMarkers(markers, textDocument);
|
|
285
451
|
if (this.#contentElement !== void 0) this.#markerRenderer.listenHover(this.#contentElement);
|
|
286
452
|
this.#updateSelections(this.#selections ?? []);
|
|
453
|
+
this.#renderCarets();
|
|
287
454
|
}
|
|
288
455
|
focus(options) {
|
|
289
456
|
const preventScroll = options?.preventScroll ?? false;
|
|
290
457
|
const lineNumber = options?.lineNumber;
|
|
291
458
|
if (lineNumber === "first-visible" || typeof lineNumber === "number") {
|
|
292
|
-
const textDocument = this.#
|
|
293
|
-
if (textDocument == null || this.#fileInstance == null) return;
|
|
459
|
+
const textDocument = this.#editSession?.document;
|
|
460
|
+
if (textDocument == null || !this.#isRendering || this.#fileInstance == null) return;
|
|
294
461
|
const targetLineNumber = lineNumber === "first-visible" ? this.#getFirstVisibleLineNumber(options?.offset) : lineNumber;
|
|
295
462
|
if (targetLineNumber == null) return;
|
|
296
463
|
const position = textDocument.normalizePosition({
|
|
@@ -312,27 +479,30 @@ var Editor = class {
|
|
|
312
479
|
this.#shouldIgnoreSelectionChange = false;
|
|
313
480
|
this.#contentElement?.blur();
|
|
314
481
|
}
|
|
315
|
-
cleanUp(
|
|
482
|
+
cleanUp(reason = "discard") {
|
|
483
|
+
const fileInstance = this.#fileInstance;
|
|
484
|
+
const recycle = reason === "recycle";
|
|
485
|
+
this.#cancelEditPrediction(true, false);
|
|
486
|
+
if (!recycle) this.#editPredictionHistory = [];
|
|
487
|
+
const editSession = this.#editSession;
|
|
488
|
+
if (fileInstance != null && editSession != null) {
|
|
489
|
+
const discardDiffState = !this.#checkpointEditSessionState();
|
|
490
|
+
if (!recycle) this.#releaseEditSession(discardDiffState);
|
|
491
|
+
}
|
|
316
492
|
this.#invalidateOnAttach();
|
|
317
493
|
if (!recycle) this.#attachState.delivered = false;
|
|
318
|
-
|
|
319
|
-
const shouldRestoreState = this.#options.persistState === true;
|
|
320
|
-
this.#stateRestoreGeneration++;
|
|
321
|
-
this.#persistCurrentState();
|
|
322
|
-
if (hadFileInstance) this.#restoreStateOnNextSync = shouldRestoreState;
|
|
494
|
+
this.#isRendering = false;
|
|
323
495
|
dequeueRender(this.#handleCustomPasteEvent);
|
|
324
496
|
this.#tokenizer?.cleanUp();
|
|
325
497
|
this.#tokenizer = void 0;
|
|
326
|
-
if (!recycle) {
|
|
327
|
-
this.#textDocument = void 0;
|
|
328
|
-
this.#fileInfo = void 0;
|
|
329
|
-
}
|
|
330
498
|
this.#globalEventDisposes?.forEach((dispose) => dispose());
|
|
331
499
|
this.#globalEventDisposes = void 0;
|
|
332
500
|
this.#editorEventDisposes?.forEach((dispose) => dispose());
|
|
333
501
|
this.#editorEventDisposes = void 0;
|
|
334
|
-
|
|
335
|
-
|
|
502
|
+
if (!recycle) {
|
|
503
|
+
this.#detach?.();
|
|
504
|
+
this.#detach = void 0;
|
|
505
|
+
}
|
|
336
506
|
this.#gutterWidthCache = void 0;
|
|
337
507
|
this.#contentWidthCache = void 0;
|
|
338
508
|
this.#lineYCache.clear();
|
|
@@ -351,6 +521,7 @@ var Editor = class {
|
|
|
351
521
|
this.#popoverManager?.cleanUp();
|
|
352
522
|
this.#popoverManager = void 0;
|
|
353
523
|
this.#gutterElement = void 0;
|
|
524
|
+
this.#deletionsColumn = void 0;
|
|
354
525
|
this.#contentElement?.removeAttribute("contentEditable");
|
|
355
526
|
this.#contentElement = void 0;
|
|
356
527
|
this.#replacementFocusRequest = void 0;
|
|
@@ -364,25 +535,44 @@ var Editor = class {
|
|
|
364
535
|
cancelAnimationFrame(this.#themeSelectionRefreshFrame);
|
|
365
536
|
this.#themeSelectionRefreshFrame = void 0;
|
|
366
537
|
}
|
|
367
|
-
this.#resetState();
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
this.#
|
|
378
|
-
this.#
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
538
|
+
this.#resetState(recycle);
|
|
539
|
+
if (!recycle) try {
|
|
540
|
+
if (fileInstance != null && editSession != null) {
|
|
541
|
+
const editor = this.#getTypedEditor;
|
|
542
|
+
const mode = reason === "complete" ? "install" : "discard";
|
|
543
|
+
if (fileInstance.type === "file" && editor.type === "file") fileInstance.__completeEditSession(editor, mode);
|
|
544
|
+
else if (fileInstance.type === "file-diff" && editor.type === "file-diff") fileInstance.__completeEditSession(editor, mode);
|
|
545
|
+
else throw new Error("Editor.cleanUp: Impossible edit state");
|
|
546
|
+
}
|
|
547
|
+
} finally {
|
|
548
|
+
this.#editSession = void 0;
|
|
549
|
+
this.#fileInstance = void 0;
|
|
550
|
+
this.#applyDocumentChange = void 0;
|
|
551
|
+
this.#publishChange = void 0;
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
#checkpointEditSessionState() {
|
|
555
|
+
const fileInstance = this.#fileInstance;
|
|
556
|
+
const editSession = this.#editSession;
|
|
557
|
+
if (fileInstance == null || editSession == null) return false;
|
|
558
|
+
const editorState = this.#isRendering ? this.getViewState() : editSession.editor ?? {};
|
|
559
|
+
const { view } = editorState;
|
|
560
|
+
const hasNonDefaultView = view != null && (view.scrollLeft !== 0 || (view.scrollTop ?? 0) !== 0);
|
|
561
|
+
const hasEditorState = editorState.selections != null || hasNonDefaultView;
|
|
562
|
+
editSession.editor = cloneEditorViewState(editorState);
|
|
563
|
+
if (editSession.type === "file") return false;
|
|
564
|
+
const capturedDiffSession = fileInstance.__captureDocumentSessionState();
|
|
565
|
+
editSession.diffSession = capturedDiffSession?.diffSession;
|
|
566
|
+
if (capturedDiffSession == null) return false;
|
|
567
|
+
const document = editSession.document;
|
|
568
|
+
return capturedDiffSession.hasChanges || hasEditorState || document?.canUndo === true || document?.canRedo === true;
|
|
569
|
+
}
|
|
570
|
+
#releaseEditSession(discardDiffState = false) {
|
|
571
|
+
const editStateKey = this.#editStateKey;
|
|
572
|
+
if (editStateKey == null) return;
|
|
573
|
+
const editor = this.#getTypedEditor;
|
|
574
|
+
if (editor.type === "file") EditStateManager.releaseFile(editStateKey, editor);
|
|
575
|
+
else EditStateManager.releaseFileDiff(editStateKey, editor, discardDiffState);
|
|
386
576
|
}
|
|
387
577
|
/** @internal */
|
|
388
578
|
__postponeBgTokenizeToNextFrame() {
|
|
@@ -401,9 +591,40 @@ var Editor = class {
|
|
|
401
591
|
if (contentElement != null && (this.#contentHasFocus || shadowActiveElement === contentElement || shadowActiveElement != null && contentElement.contains(shadowActiveElement))) this.#replacementFocusRequest = {};
|
|
402
592
|
}
|
|
403
593
|
/** @internal */
|
|
404
|
-
|
|
594
|
+
__getDocumentContents(fallbackFile) {
|
|
595
|
+
const fileInfo = this.#editSession?.fileInfo;
|
|
596
|
+
const textDocument = this.#editSession?.document;
|
|
597
|
+
if (textDocument == null) return fileInfo == null || fallbackFile == null ? void 0 : {
|
|
598
|
+
...fileInfo,
|
|
599
|
+
contents: fallbackFile.contents
|
|
600
|
+
};
|
|
601
|
+
const resolvedFileInfo = fileInfo ?? fallbackFile;
|
|
602
|
+
if (resolvedFileInfo == null) return;
|
|
603
|
+
return {
|
|
604
|
+
name: resolvedFileInfo.name,
|
|
605
|
+
lang: resolvedFileInfo.lang,
|
|
606
|
+
contents: textDocument.getText()
|
|
607
|
+
};
|
|
608
|
+
}
|
|
609
|
+
/** @internal */
|
|
610
|
+
__getDocumentSessionState() {
|
|
611
|
+
const snapshot = this.#editSession?.diffSession;
|
|
612
|
+
return snapshot != null ? cloneRetainedDiffSessionSnapshot(snapshot) : void 0;
|
|
613
|
+
}
|
|
614
|
+
/** @internal */
|
|
615
|
+
__syncRenderView = (props) => {
|
|
616
|
+
const { highlighter, fileContainer, renderRange, resetHistory = false } = props;
|
|
617
|
+
const renderView = props;
|
|
618
|
+
let fileOrDiff;
|
|
619
|
+
if ("file" in renderView && this.type === "file") fileOrDiff = renderView.file;
|
|
620
|
+
else if ("fileDiff" in renderView && this.type === "file-diff") fileOrDiff = renderView.fileDiff;
|
|
621
|
+
else throw new Error("Editor.__syncRenderView: Impossible render state");
|
|
622
|
+
const lineAnnotations = renderView.lineAnnotations;
|
|
623
|
+
const editStateKey = this.#editStateKey;
|
|
624
|
+
const externalDocument = renderView.externalDocument === true;
|
|
405
625
|
const fileInstance = this.#fileInstance;
|
|
406
|
-
|
|
626
|
+
const editSession = this.#editSession;
|
|
627
|
+
if (!this.#isRendering || fileInstance == null || editSession == null) return;
|
|
407
628
|
const shadowRoot = fileContainer.shadowRoot;
|
|
408
629
|
if (shadowRoot == null) {
|
|
409
630
|
console.error("[editor] Could not find the shadow root.");
|
|
@@ -412,16 +633,26 @@ var Editor = class {
|
|
|
412
633
|
let codeElement;
|
|
413
634
|
let gutterEl;
|
|
414
635
|
let contentEl;
|
|
415
|
-
|
|
416
|
-
|
|
636
|
+
let deletionsGutterEl;
|
|
637
|
+
let deletionsContentEl;
|
|
638
|
+
for (const el of shadowRoot.querySelectorAll("[data-code]")) {
|
|
639
|
+
const isDeletions = el.dataset.deletions != null;
|
|
640
|
+
if (!isDeletions) codeElement = el;
|
|
417
641
|
for (const child of el.children) {
|
|
418
|
-
|
|
419
|
-
const { gutter, content } =
|
|
420
|
-
if (gutter
|
|
421
|
-
else
|
|
642
|
+
if (!(child instanceof HTMLElement)) continue;
|
|
643
|
+
const { gutter, content } = child.dataset;
|
|
644
|
+
if (gutter != null) if (isDeletions) deletionsGutterEl = child;
|
|
645
|
+
else gutterEl = child;
|
|
646
|
+
else if (content != null) if (isDeletions) deletionsContentEl = child;
|
|
647
|
+
else contentEl = child;
|
|
422
648
|
}
|
|
423
|
-
break;
|
|
424
649
|
}
|
|
650
|
+
if (deletionsContentEl == null) this.#deletionsColumn = void 0;
|
|
651
|
+
else if (deletionsGutterEl == null) throw new Error("Editor.__syncRenderView: the deletions column has no gutter");
|
|
652
|
+
else this.#deletionsColumn = {
|
|
653
|
+
content: deletionsContentEl,
|
|
654
|
+
gutter: deletionsGutterEl
|
|
655
|
+
};
|
|
425
656
|
if (codeElement === void 0 || contentEl === void 0) {
|
|
426
657
|
this.#replacementFocusRequest = void 0;
|
|
427
658
|
return;
|
|
@@ -434,45 +665,44 @@ var Editor = class {
|
|
|
434
665
|
if (this.#themeStyleElement !== void 0) shadowRoot.appendChild(this.#themeStyleElement);
|
|
435
666
|
if (this.#spriteElement !== void 0) shadowRoot.prepend(this.#spriteElement);
|
|
436
667
|
}
|
|
437
|
-
const
|
|
438
|
-
const
|
|
439
|
-
|
|
440
|
-
|
|
668
|
+
const languageId = fileOrDiff.lang ?? getFiletypeFromFileName(fileOrDiff.name);
|
|
669
|
+
const contents = "contents" in fileOrDiff ? fileOrDiff.contents : fileOrDiff.additionLines.join("");
|
|
670
|
+
const previousTextDocument = editSession.document;
|
|
671
|
+
const documentChanges = externalDocument && previousTextDocument !== void 0 && previousTextDocument.getText() !== contents ? [createFullDocumentChange(previousTextDocument.getText(), contents)] : void 0;
|
|
672
|
+
const resetForExternalDocument = externalDocument && resetHistory;
|
|
673
|
+
if (editSession.document == null || editSession.fileInfo == null || editStateKey == null && (editSession.fileInfo.name !== fileOrDiff.name || editSession.document.languageId !== languageId) || resetForExternalDocument) {
|
|
674
|
+
this.#cancelEditPrediction(true);
|
|
675
|
+
this.#editPredictionHistory = [];
|
|
441
676
|
this.#invalidateOnAttach();
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
const textDocument = reusableTextDocument ?? new TextDocument(fileOrDiff.name, contents, languageId, 0, editStack);
|
|
451
|
-
this.#fileInfo = {
|
|
677
|
+
const { name, lang } = fileOrDiff;
|
|
678
|
+
let textDocument = resetForExternalDocument || editStateKey == null && editSession.fileInfo != null ? void 0 : editSession.document;
|
|
679
|
+
if (previousTextDocument != null && textDocument == null) editSession.editor = void 0;
|
|
680
|
+
if (textDocument == null) {
|
|
681
|
+
const editStack = new EditStack({ maxEntries: this.#options.historyMaxEntries });
|
|
682
|
+
textDocument = new TextDocument(fileOrDiff.name, contents, languageId, 0, editStack);
|
|
683
|
+
}
|
|
684
|
+
editSession.fileInfo = {
|
|
452
685
|
name,
|
|
453
|
-
lang
|
|
454
|
-
cacheKey
|
|
686
|
+
lang
|
|
455
687
|
};
|
|
456
|
-
|
|
457
|
-
if (
|
|
458
|
-
this.#textDocumentCache.set(persistedCacheKey, textDocument);
|
|
459
|
-
persistedStateTarget = {
|
|
460
|
-
cacheKey: persistedCacheKey,
|
|
461
|
-
textDocument
|
|
462
|
-
};
|
|
463
|
-
}
|
|
688
|
+
editSession.document = textDocument;
|
|
689
|
+
if (resetForExternalDocument) editSession.diffSession = void 0;
|
|
464
690
|
this.#tokenizer?.cleanUp();
|
|
465
691
|
this.#tokenizer = void 0;
|
|
466
692
|
this.#resetState();
|
|
467
693
|
this.#wrapLineOffsetsCache.clear();
|
|
468
694
|
this.#selections = this.#initSelections;
|
|
469
|
-
if (this.#options.__debug === true) console.log(
|
|
695
|
+
if (this.#options.__debug === true) console.log("[diffs/editor] text document initialized from", fileOrDiff.name);
|
|
470
696
|
}
|
|
471
|
-
if (
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
697
|
+
if (externalDocument && !resetForExternalDocument) {
|
|
698
|
+
this.#applyExternalDocumentReplacement(editSession, contents, lineAnnotations);
|
|
699
|
+
const { name, lang } = fileOrDiff;
|
|
700
|
+
editSession.fileInfo = {
|
|
701
|
+
name,
|
|
702
|
+
lang
|
|
703
|
+
};
|
|
704
|
+
}
|
|
705
|
+
const textDocument = editSession.document;
|
|
476
706
|
if (this.#tokenizer == null && textDocument != null) this.#tokenizer = new EditorTokenizer({
|
|
477
707
|
highlighter,
|
|
478
708
|
textDocument,
|
|
@@ -516,178 +746,86 @@ var Editor = class {
|
|
|
516
746
|
this.#renderRange = renderRange;
|
|
517
747
|
this.#viewportWindowLines = renderRange?.totalLines;
|
|
518
748
|
this.#tokenizer?.prebuildStateStack(renderRange);
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
this.#
|
|
523
|
-
this.#
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
749
|
+
const retainedEditorState = editSession.editor;
|
|
750
|
+
const restoreEditorStateOnSync = this.#restoreEditorStateOnSync;
|
|
751
|
+
try {
|
|
752
|
+
this.#markerRenderer?.removePopover();
|
|
753
|
+
if (this.#selections !== void 0 || this.#matches !== void 0 || this.#markerRenderer !== void 0) this.#updateSelections(this.#selections ?? []);
|
|
754
|
+
this.#renderCarets();
|
|
755
|
+
if (this.#retryEditPredictionOnRender) this.#scheduleEditPrediction();
|
|
756
|
+
if (this.#initSelections !== void 0 && this.#primaryCaretElement !== void 0) {
|
|
757
|
+
this.#initSelections = void 0;
|
|
758
|
+
this.#scrollToPrimaryCaret(false, "center");
|
|
759
|
+
} else if (this.#scrollingToLine !== void 0) this.#scrollToLine(this.#scrollingToLine, this.#scrollingToLineChar, this.#scrollingToLineNoFocus);
|
|
760
|
+
else if (this.#replacementFocusRequest !== void 0) this.#restoreReplacementFocus();
|
|
761
|
+
else if (this.#selections !== void 0 && this.#selections.length > 0 && this.#contentHasFocus && !this.#retainSearchPanelFocus) this.focus({ preventScroll: true });
|
|
762
|
+
if (this.#retainSearchPanelFocus) this.#searchPanel?.focus();
|
|
763
|
+
if (restoreEditorStateOnSync) {
|
|
764
|
+
this.#restoreEditorStateOnSync = false;
|
|
765
|
+
if (retainedEditorState !== void 0) this.setViewState(retainedEditorState);
|
|
766
|
+
}
|
|
767
|
+
if (this.#options.__debug === true && renderRange !== void 0) {
|
|
768
|
+
const { startingLine, totalLines } = renderRange;
|
|
769
|
+
console.log("[diffs/editor] render file:", fileOrDiff.name, "RenderRange:", startingLine + "-" + (startingLine + totalLines), "of", editSession.document?.lineCount, "lines");
|
|
770
|
+
}
|
|
771
|
+
this.#checkpointEditSessionState();
|
|
772
|
+
} catch (error) {
|
|
773
|
+
this.#restoreEditorStateOnSync = restoreEditorStateOnSync;
|
|
774
|
+
editSession.editor = retainedEditorState;
|
|
775
|
+
throw error;
|
|
535
776
|
}
|
|
777
|
+
if (documentChanges != null) this.#emitChange(documentChanges, lineAnnotations);
|
|
536
778
|
this.#scheduleOnAttach(fileInstance);
|
|
537
779
|
};
|
|
538
|
-
#
|
|
539
|
-
const textDocument =
|
|
540
|
-
|
|
541
|
-
return textDocument?.languageId === languageId ? textDocument : void 0;
|
|
542
|
-
}
|
|
543
|
-
#getStateStorage() {
|
|
544
|
-
const option = this.#options.persistStateStorage ?? "inMemory";
|
|
545
|
-
if (this.#stateStorage === void 0 || this.#stateStorageOption !== option) {
|
|
546
|
-
this.#stateStorage = createStateStorage(option);
|
|
547
|
-
this.#stateStorageOption = option;
|
|
548
|
-
}
|
|
549
|
-
return this.#stateStorage;
|
|
550
|
-
}
|
|
551
|
-
#persistCurrentState() {
|
|
552
|
-
const fileInfo = this.#fileInfo;
|
|
553
|
-
const textDocument = this.#textDocument;
|
|
554
|
-
if (this.#options.persistState !== true || this.#fileInstance === void 0 || fileInfo === void 0 || textDocument === void 0) return;
|
|
555
|
-
const cacheKey = requirePersistedCacheKey(fileInfo);
|
|
556
|
-
this.#textDocumentCache.set(cacheKey, textDocument);
|
|
557
|
-
let storage;
|
|
558
|
-
try {
|
|
559
|
-
storage = this.#getStateStorage();
|
|
560
|
-
} catch {
|
|
561
|
-
return;
|
|
562
|
-
}
|
|
563
|
-
const state = cloneEditorState(this.getState());
|
|
564
|
-
const pendingRestore = this.#pendingStateRestore;
|
|
565
|
-
if (pendingRestore?.cacheKey === cacheKey && pendingRestore.textDocument === textDocument) {
|
|
566
|
-
this.#pendingStateRestore = void 0;
|
|
567
|
-
if (textDocument.version === pendingRestore.documentVersion && this.#selections === pendingRestore.selections && state.view?.scrollLeft === pendingRestore.view?.scrollLeft && state.view?.scrollTop === pendingRestore.view?.scrollTop) return;
|
|
568
|
-
this.#writeState(storage, cacheKey, state, pendingRestore.completion);
|
|
569
|
-
return;
|
|
570
|
-
}
|
|
571
|
-
this.#writeState(storage, cacheKey, state);
|
|
572
|
-
}
|
|
573
|
-
#writeState(storage, cacheKey, state, waitFor) {
|
|
574
|
-
const previousWrite = this.#pendingStateWrites.get(cacheKey);
|
|
575
|
-
if (waitFor !== void 0 || previousWrite !== void 0) {
|
|
576
|
-
let pending = waitFor ?? Promise.resolve();
|
|
577
|
-
if (previousWrite !== void 0) pending = pending.then(() => previousWrite);
|
|
578
|
-
this.#trackStateWrite(cacheKey, pending.then(() => storage.set(cacheKey, state)));
|
|
579
|
-
return;
|
|
580
|
-
}
|
|
581
|
-
let result;
|
|
582
|
-
try {
|
|
583
|
-
result = storage.set(cacheKey, state);
|
|
584
|
-
} catch {
|
|
585
|
-
return;
|
|
586
|
-
}
|
|
587
|
-
if (!isPromise(result)) return;
|
|
588
|
-
this.#trackStateWrite(cacheKey, result);
|
|
589
|
-
}
|
|
590
|
-
#trackStateWrite(cacheKey, result) {
|
|
591
|
-
const pending = result.catch(() => {});
|
|
592
|
-
this.#pendingStateWrites.set(cacheKey, pending);
|
|
593
|
-
pending.finally(() => {
|
|
594
|
-
if (this.#pendingStateWrites.get(cacheKey) === pending) this.#pendingStateWrites.delete(cacheKey);
|
|
595
|
-
});
|
|
596
|
-
}
|
|
597
|
-
#restorePersistedState(cacheKey, textDocument) {
|
|
598
|
-
const generation = ++this.#stateRestoreGeneration;
|
|
599
|
-
const documentVersion = textDocument.version;
|
|
780
|
+
#applyExternalDocumentReplacement(editSession, contents, lineAnnotations) {
|
|
781
|
+
const textDocument = editSession.document;
|
|
782
|
+
if (textDocument == null || textDocument.getText() === contents) return;
|
|
600
783
|
const selections = this.#selections;
|
|
601
|
-
const
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
const userScrolled = inputWatch?.userScrolled() === true;
|
|
607
|
-
if (state === void 0) {
|
|
608
|
-
this.#fileInstance?.setCodeScrollLeft(0);
|
|
609
|
-
if (!userScrolled) this.#setViewportScrollTop(0);
|
|
610
|
-
return;
|
|
611
|
-
}
|
|
612
|
-
const restored = cloneEditorState(state);
|
|
613
|
-
if (userScrolled && restored.view !== void 0) restored.view = { scrollLeft: restored.view.scrollLeft };
|
|
614
|
-
this.setState(restored);
|
|
615
|
-
};
|
|
616
|
-
const readState = () => {
|
|
617
|
-
let result;
|
|
618
|
-
try {
|
|
619
|
-
result = this.#getStateStorage().get(cacheKey);
|
|
620
|
-
} catch {
|
|
621
|
-
return;
|
|
622
|
-
}
|
|
623
|
-
if (isPromise(result)) return result.then(applyState).catch(() => {});
|
|
624
|
-
else try {
|
|
625
|
-
applyState(result);
|
|
626
|
-
} catch {}
|
|
784
|
+
const selectionOffsets = selections?.map((selection) => [textDocument.offsetAt(selection.start), textDocument.offsetAt(selection.end)]);
|
|
785
|
+
const replacement = {
|
|
786
|
+
start: 0,
|
|
787
|
+
end: textDocument.getText().length,
|
|
788
|
+
text: contents
|
|
627
789
|
};
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
cacheKey,
|
|
634
|
-
textDocument,
|
|
635
|
-
documentVersion,
|
|
636
|
-
selections,
|
|
637
|
-
view,
|
|
638
|
-
completion: result.catch(() => {})
|
|
639
|
-
};
|
|
640
|
-
this.#pendingStateRestore = pendingRestore;
|
|
641
|
-
pendingRestore.completion.finally(() => {
|
|
642
|
-
inputWatch?.dispose();
|
|
643
|
-
if (this.#pendingStateRestore === pendingRestore) this.#pendingStateRestore = void 0;
|
|
644
|
-
});
|
|
790
|
+
if (textDocument.applyResolvedEdits([replacement], true, selections, void 0, true) == null) return;
|
|
791
|
+
if (selections != null && selectionOffsets != null) {
|
|
792
|
+
const nextSelections = remapSelectionsAfterEdits(textDocument, selections, selectionOffsets, [replacement]);
|
|
793
|
+
textDocument.setLastUndoSelectionsAfter(nextSelections);
|
|
794
|
+
this.#selections = nextSelections;
|
|
645
795
|
}
|
|
796
|
+
if (this.#lineAnnotations != null || lineAnnotations != null) textDocument.setLastUndoLineAnnotations(this.#lineAnnotations ?? [], lineAnnotations ?? []);
|
|
797
|
+
this.#tokenizer?.cleanUp();
|
|
798
|
+
this.#tokenizer = void 0;
|
|
799
|
+
this.#resetCache();
|
|
800
|
+
this.#wrapLineOffsetsCache.clear();
|
|
801
|
+
this.#markerRenderer?.removePopover();
|
|
802
|
+
if (this.#searchPanel !== void 0 && this.#matches !== void 0) this.#searchPanel.updateMatches({ syncSelection: false });
|
|
646
803
|
}
|
|
647
|
-
#
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
"wheel",
|
|
653
|
-
"touchstart",
|
|
654
|
-
"mousedown"
|
|
655
|
-
];
|
|
656
|
-
const dispose = () => {
|
|
657
|
-
for (const type of eventTypes) viewport.removeEventListener(type, onInput, { capture: true });
|
|
658
|
-
};
|
|
659
|
-
const onInput = () => {
|
|
660
|
-
scrolled = true;
|
|
661
|
-
dispose();
|
|
662
|
-
};
|
|
663
|
-
for (const type of eventTypes) viewport.addEventListener(type, onInput, {
|
|
664
|
-
capture: true,
|
|
665
|
-
passive: true
|
|
666
|
-
});
|
|
667
|
-
return {
|
|
668
|
-
userScrolled: () => scrolled,
|
|
669
|
-
dispose
|
|
670
|
-
};
|
|
804
|
+
get #fileDiffInstance() {
|
|
805
|
+
return this.#fileInstance?.type === "file-diff" ? this.#fileInstance : void 0;
|
|
806
|
+
}
|
|
807
|
+
get #virtualizedInstance() {
|
|
808
|
+
return isVirtualizedEditorComponent(this.#fileInstance) ? this.#fileInstance : void 0;
|
|
671
809
|
}
|
|
672
810
|
#isLineRenderable(line) {
|
|
673
|
-
return this.#
|
|
811
|
+
return this.#fileDiffInstance?.isLineRenderable?.(line + 1) ?? true;
|
|
674
812
|
}
|
|
675
813
|
get #resolveRenderableLine() {
|
|
676
|
-
const fileInstance = this.#
|
|
677
|
-
if (fileInstance
|
|
814
|
+
const fileInstance = this.#fileDiffInstance;
|
|
815
|
+
if (fileInstance == null) return;
|
|
678
816
|
return (line, direction) => {
|
|
679
817
|
const nearest = fileInstance.getNearestRenderableLine(line + 1, direction);
|
|
680
818
|
return nearest == null ? void 0 : nearest - 1;
|
|
681
819
|
};
|
|
682
820
|
}
|
|
683
821
|
#revealLineIfCollapsed(line) {
|
|
684
|
-
if (!this.#isLineRenderable(line)) this.#
|
|
822
|
+
if (!this.#isLineRenderable(line)) this.#fileDiffInstance?.revealLine?.(line + 1);
|
|
685
823
|
}
|
|
686
824
|
get #diffSyle() {
|
|
687
|
-
return this.#
|
|
825
|
+
return this.#fileDiffInstance?.options.diffStyle ?? "split";
|
|
688
826
|
}
|
|
689
827
|
get #isDiff() {
|
|
690
|
-
return this
|
|
828
|
+
return this.type === "file-diff";
|
|
691
829
|
}
|
|
692
830
|
get #isWrap() {
|
|
693
831
|
return this.#fileInstance?.options.overflow === "wrap";
|
|
@@ -706,7 +844,7 @@ var Editor = class {
|
|
|
706
844
|
this.#lineElementsCache.clear();
|
|
707
845
|
this.#lastAccessedCharX = void 0;
|
|
708
846
|
}
|
|
709
|
-
#resetState() {
|
|
847
|
+
#resetState(preserveCarets = false) {
|
|
710
848
|
this.#setEditorActiveLineSafe(null);
|
|
711
849
|
this.#gutterWidthCache = void 0;
|
|
712
850
|
this.#contentWidthCache = void 0;
|
|
@@ -714,6 +852,11 @@ var Editor = class {
|
|
|
714
852
|
this.#suppressNativeSelectionSync = false;
|
|
715
853
|
this.#overlayElements?.forEach((el) => el.remove());
|
|
716
854
|
this.#overlayElements = void 0;
|
|
855
|
+
this.#caretElements?.forEach((element) => element.remove());
|
|
856
|
+
this.#caretElements = void 0;
|
|
857
|
+
this.#caretHighlightElements?.forEach((element) => element.remove());
|
|
858
|
+
this.#caretHighlightElements = void 0;
|
|
859
|
+
if (!preserveCarets) this.#carets = void 0;
|
|
717
860
|
this.#selections = void 0;
|
|
718
861
|
this.#scrollingToLine = void 0;
|
|
719
862
|
this.#markerRenderer?.cleanup();
|
|
@@ -734,13 +877,13 @@ var Editor = class {
|
|
|
734
877
|
}
|
|
735
878
|
#scheduleOnAttach(fileInstance) {
|
|
736
879
|
const attachState = this.#attachState;
|
|
737
|
-
const textDocument = this.#
|
|
880
|
+
const textDocument = this.#editSession?.document;
|
|
738
881
|
if (attachState.delivered || attachState.callback != null || textDocument == null) return;
|
|
739
882
|
const { generation } = attachState;
|
|
740
883
|
const callback = () => {
|
|
741
884
|
if (attachState.callback !== callback) return;
|
|
742
885
|
attachState.callback = void 0;
|
|
743
|
-
if (generation !== attachState.generation || this.#fileInstance !== fileInstance || this.#
|
|
886
|
+
if (generation !== attachState.generation || this.#fileInstance !== fileInstance || this.#editSession?.document !== textDocument) return;
|
|
744
887
|
const contentElement = this.#contentElement;
|
|
745
888
|
const shadowRoot = this.#fileContainer?.shadowRoot;
|
|
746
889
|
if (contentElement == null || shadowRoot == null || !shadowRoot.contains(contentElement)) return;
|
|
@@ -751,21 +894,16 @@ var Editor = class {
|
|
|
751
894
|
queueRender(callback);
|
|
752
895
|
}
|
|
753
896
|
#getScrollViewport() {
|
|
754
|
-
const viewport = this.#
|
|
755
|
-
if (viewport
|
|
897
|
+
const viewport = this.#virtualizedInstance?.getEditorViewport?.();
|
|
898
|
+
if (viewport != null) return viewport;
|
|
756
899
|
const fileContainer = this.#fileContainer;
|
|
757
900
|
if (this.#fileInstance == null || fileContainer == null) return;
|
|
758
901
|
return lookupScrollContainer(fileContainer);
|
|
759
902
|
}
|
|
760
|
-
#
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
}
|
|
765
|
-
#setViewportScrollTop(scrollTop) {
|
|
766
|
-
const viewport = this.#getScrollViewport();
|
|
767
|
-
if (viewport instanceof HTMLElement) viewport.scrollTop = scrollTop;
|
|
768
|
-
else if (viewport instanceof Document) viewport.defaultView?.scrollTo({ top: scrollTop });
|
|
903
|
+
#getOwnedVerticalViewport() {
|
|
904
|
+
if (!this.#ownsVerticalViewport) return;
|
|
905
|
+
const viewport = this.#virtualizedInstance?.getEditorViewport?.();
|
|
906
|
+
if (viewport instanceof HTMLElement) return viewport;
|
|
769
907
|
}
|
|
770
908
|
#initialize() {
|
|
771
909
|
this.#globalStyleElement = h("style", {
|
|
@@ -817,7 +955,9 @@ var Editor = class {
|
|
|
817
955
|
if (this.#selections !== void 0 && this.#selections.length > 1 && !this.#isContentMouseDown) return;
|
|
818
956
|
const selectionRaw = document.getSelection();
|
|
819
957
|
if (selectionRaw == null) return;
|
|
820
|
-
|
|
958
|
+
let composedRange;
|
|
959
|
+
if (typeof selectionRaw.getComposedRanges === "function") composedRange = selectionRaw.getComposedRanges({ shadowRoots: [shadowRoot] })?.[0];
|
|
960
|
+
else composedRange = getShadowRootRange(shadowRoot);
|
|
821
961
|
if (composedRange === void 0 || !this.#rangeBelongsToEditor(composedRange)) return;
|
|
822
962
|
let selection = convertSelection(composedRange, 0);
|
|
823
963
|
if (selection === void 0) return;
|
|
@@ -844,6 +984,10 @@ var Editor = class {
|
|
|
844
984
|
addEventListener(document, "pointercancel", finishMouseSelection, { passive: true }),
|
|
845
985
|
addEventListener(document, "keydown", (e) => {
|
|
846
986
|
if (e.key === "Shift") this.#selectionStart = this.#selections?.at(-1);
|
|
987
|
+
else if (e.key === "Alt" && !e.repeat && this.#contentHasFocus && this.#options.editPrediction?.mode === "subtle") {
|
|
988
|
+
this.#editPredictionRevealed = !this.#editPredictionRevealed;
|
|
989
|
+
this.#updateSelections(this.#selections ?? []);
|
|
990
|
+
}
|
|
847
991
|
}, { passive: true }),
|
|
848
992
|
addEventListener(document, "keyup", (e) => {
|
|
849
993
|
if (e.key === "Shift") this.#selectionStart = void 0;
|
|
@@ -955,6 +1099,16 @@ var Editor = class {
|
|
|
955
1099
|
this.#canMountSelectionAction = true;
|
|
956
1100
|
this.#suppressNativeSelectionSync = false;
|
|
957
1101
|
if (e.isComposing || e.keyCode === 229) return;
|
|
1102
|
+
if (e.key === "Tab" && !e.shiftKey && !e.ctrlKey && !e.metaKey && !e.isComposing && !this.#isComposing && (!e.altKey || this.#options.editPrediction?.mode === "subtle") && this.#editPrediction?.rendered === true) {
|
|
1103
|
+
this.#acceptEditPrediction();
|
|
1104
|
+
e.preventDefault();
|
|
1105
|
+
return;
|
|
1106
|
+
}
|
|
1107
|
+
if (e.key === "Escape" && this.#editPrediction !== void 0) {
|
|
1108
|
+
this.#cancelEditPrediction(true);
|
|
1109
|
+
e.preventDefault();
|
|
1110
|
+
return;
|
|
1111
|
+
}
|
|
958
1112
|
const command = resolveEditorCommandFromKeyboardEvent(e, this.#options.keymap);
|
|
959
1113
|
if (command !== void 0) {
|
|
960
1114
|
e.preventDefault();
|
|
@@ -969,7 +1123,7 @@ var Editor = class {
|
|
|
969
1123
|
return;
|
|
970
1124
|
}
|
|
971
1125
|
const mvShortcut = isMoveCursorShortcut(e);
|
|
972
|
-
const textDocument = this.#
|
|
1126
|
+
const textDocument = this.#editSession?.document;
|
|
973
1127
|
if (this.#selections !== void 0 && this.#selections.length > 0 && mvShortcut !== void 0 && textDocument !== void 0) {
|
|
974
1128
|
const cursorMoveOptions = {
|
|
975
1129
|
getSoftLineOffsets: this.#isWrap ? (line) => this.#wrapLineTextOrWholeLine(line) : void 0,
|
|
@@ -1020,7 +1174,7 @@ var Editor = class {
|
|
|
1020
1174
|
if (!targetIsContentElement(e)) return;
|
|
1021
1175
|
e.preventDefault();
|
|
1022
1176
|
const clipboardData = e.clipboardData;
|
|
1023
|
-
const textDocument = this.#
|
|
1177
|
+
const textDocument = this.#editSession?.document;
|
|
1024
1178
|
if (clipboardData === null || textDocument === void 0) return;
|
|
1025
1179
|
let text = clipboardData.getData("text");
|
|
1026
1180
|
const selectionCount = this.#selections?.length ?? 0;
|
|
@@ -1035,7 +1189,10 @@ var Editor = class {
|
|
|
1035
1189
|
}),
|
|
1036
1190
|
addEventListener(contentEl, "beforeinput", (e) => {
|
|
1037
1191
|
if (!targetIsContentElement(e)) return;
|
|
1038
|
-
if (e.inputType === "insertCompositionText")
|
|
1192
|
+
if (e.inputType === "insertCompositionText") {
|
|
1193
|
+
this.#cancelEditPrediction(true);
|
|
1194
|
+
return;
|
|
1195
|
+
}
|
|
1039
1196
|
e.preventDefault();
|
|
1040
1197
|
this.#handleInput(e.inputType, e.data);
|
|
1041
1198
|
}),
|
|
@@ -1045,6 +1202,7 @@ var Editor = class {
|
|
|
1045
1202
|
}),
|
|
1046
1203
|
addEventListener(contentEl, "compositionstart", (e) => {
|
|
1047
1204
|
if (!targetIsContentElement(e)) return;
|
|
1205
|
+
this.#cancelEditPrediction(true);
|
|
1048
1206
|
this.#isComposing = true;
|
|
1049
1207
|
this.#shouldIgnoreSelectionChange = true;
|
|
1050
1208
|
}, { passive: true }),
|
|
@@ -1106,7 +1264,7 @@ var Editor = class {
|
|
|
1106
1264
|
return;
|
|
1107
1265
|
}
|
|
1108
1266
|
if (e.pointerType !== "mouse") return;
|
|
1109
|
-
const textDocument = this.#
|
|
1267
|
+
const textDocument = this.#editSession?.document;
|
|
1110
1268
|
const lineIndex = resolveEditableLine(gutterRow);
|
|
1111
1269
|
if (lineIndex === void 0 || textDocument === void 0) return;
|
|
1112
1270
|
this.#canMountSelectionAction = true;
|
|
@@ -1119,7 +1277,7 @@ var Editor = class {
|
|
|
1119
1277
|
this.#focus();
|
|
1120
1278
|
this.#replaceSelectEventListeners([addEventListener(document, "mousemove", (e) => {
|
|
1121
1279
|
if (!this.#isGutterMouseDown) return;
|
|
1122
|
-
const textDocument = this.#
|
|
1280
|
+
const textDocument = this.#editSession?.document;
|
|
1123
1281
|
const lineIndex = resolveEditableLine(resolveGutterTarget(e.composedPath()[0], true));
|
|
1124
1282
|
if (lineIndex === void 0 || textDocument === void 0) return;
|
|
1125
1283
|
const anchorLine = this.#selectionStart?.start.line ?? lineIndex;
|
|
@@ -1149,14 +1307,14 @@ var Editor = class {
|
|
|
1149
1307
|
if (Array.isArray(selectionTexts) && selectionTexts.length === selectionCount) text = selectionTexts;
|
|
1150
1308
|
} catch {}
|
|
1151
1309
|
}
|
|
1152
|
-
const textDocument = this.#
|
|
1153
|
-
if (textDocument
|
|
1310
|
+
const textDocument = this.#editSession?.document;
|
|
1311
|
+
if (textDocument != null) this.#replaceSelectionText(Array.isArray(text) ? text.map((t) => textDocument.normalizeEol(t)) : textDocument.normalizeEol(text), void 0, true, "document");
|
|
1154
1312
|
}
|
|
1155
1313
|
};
|
|
1156
1314
|
#computeContentOffset(contentEl) {
|
|
1157
1315
|
if (this.#isDiff && this.#diffSyle === "split" && this.#isWrap) {
|
|
1158
1316
|
this.#contentOffset = {
|
|
1159
|
-
top: contentEl.offsetTop,
|
|
1317
|
+
top: contentEl.offsetTop - this.#metrics.paddingTop,
|
|
1160
1318
|
left: contentEl.offsetLeft - this.#getGutterWidth()
|
|
1161
1319
|
};
|
|
1162
1320
|
if (this.#options.__debug === true) console.log("[diffs/editor] content offset:", this.#contentOffset);
|
|
@@ -1166,8 +1324,8 @@ var Editor = class {
|
|
|
1166
1324
|
if (this.#isDiff && this.#diffSyle === "split" && this.#isWrap) return this.#contentOffset;
|
|
1167
1325
|
}
|
|
1168
1326
|
#runCommand(command) {
|
|
1169
|
-
const textDocument = this.#
|
|
1170
|
-
if (textDocument
|
|
1327
|
+
const textDocument = this.#editSession?.document;
|
|
1328
|
+
if (textDocument == null) return;
|
|
1171
1329
|
switch (command) {
|
|
1172
1330
|
case "openSearchPanel":
|
|
1173
1331
|
this.#openSearchPanel("find");
|
|
@@ -1367,8 +1525,8 @@ var Editor = class {
|
|
|
1367
1525
|
}
|
|
1368
1526
|
}
|
|
1369
1527
|
#applyHistoryChange(command) {
|
|
1370
|
-
const textDocument = this.#
|
|
1371
|
-
if (textDocument
|
|
1528
|
+
const textDocument = this.#editSession?.document;
|
|
1529
|
+
if (textDocument == null) return;
|
|
1372
1530
|
if (command === "undo" && !textDocument.canUndo || command === "redo" && !textDocument.canRedo) return;
|
|
1373
1531
|
const selections = this.#selections;
|
|
1374
1532
|
const selectionOffsets = selections?.map((selection) => [textDocument.offsetAt(selection.start), textDocument.offsetAt(selection.end)]);
|
|
@@ -1376,11 +1534,12 @@ var Editor = class {
|
|
|
1376
1534
|
if (result === void 0) return;
|
|
1377
1535
|
const [change, recordedSelections, lineAnnotations, selectionEdits] = result;
|
|
1378
1536
|
const nextSelections = recordedSelections ?? (selections !== void 0 && selectionOffsets !== void 0 && selectionEdits !== void 0 ? remapSelectionsAfterEdits(textDocument, selections, selectionOffsets, selectionEdits) : void 0);
|
|
1379
|
-
this.#
|
|
1537
|
+
const replayedLineAnnotations = lineAnnotations ?? (this.#lineAnnotations != null ? applyDocumentChangeToLineAnnotations(change, this.#lineAnnotations) : void 0);
|
|
1538
|
+
this.#applyChange(change, nextSelections, replayedLineAnnotations);
|
|
1380
1539
|
}
|
|
1381
1540
|
/** Applies one undoable command batch and records its resulting selections. */
|
|
1382
1541
|
#applyCommandEdits(edits, resolveNextSelections) {
|
|
1383
|
-
const textDocument = this.#
|
|
1542
|
+
const textDocument = this.#editSession?.document;
|
|
1384
1543
|
const selections = this.#selections;
|
|
1385
1544
|
if (textDocument === void 0 || selections === void 0) return;
|
|
1386
1545
|
const remapSelections = resolveNextSelections === void 0;
|
|
@@ -1405,7 +1564,7 @@ var Editor = class {
|
|
|
1405
1564
|
}
|
|
1406
1565
|
/** Copies selected line blocks and keeps the selection in the requested copy. */
|
|
1407
1566
|
#copySelectedLines(direction) {
|
|
1408
|
-
const textDocument = this.#
|
|
1567
|
+
const textDocument = this.#editSession?.document;
|
|
1409
1568
|
const selections = this.#selections;
|
|
1410
1569
|
if (textDocument === void 0 || selections === void 0) return;
|
|
1411
1570
|
const blocks = getSelectedLineBlocks(selections);
|
|
@@ -1498,7 +1657,7 @@ var Editor = class {
|
|
|
1498
1657
|
}
|
|
1499
1658
|
/** Inserts an indented blank line after each selection's final line. */
|
|
1500
1659
|
#insertBlankLine() {
|
|
1501
|
-
const textDocument = this.#
|
|
1660
|
+
const textDocument = this.#editSession?.document;
|
|
1502
1661
|
const selections = this.#selections;
|
|
1503
1662
|
if (textDocument === void 0 || selections === void 0) return;
|
|
1504
1663
|
const selectionLines = selections.map((selection) => getCaretPosition(selection).line);
|
|
@@ -1539,7 +1698,7 @@ var Editor = class {
|
|
|
1539
1698
|
this.#applyCommandEdits(edits, () => nextSelections);
|
|
1540
1699
|
}
|
|
1541
1700
|
#moveSelectedLines(direction) {
|
|
1542
|
-
const textDocument = this.#
|
|
1701
|
+
const textDocument = this.#editSession?.document;
|
|
1543
1702
|
const selections = this.#selections;
|
|
1544
1703
|
if (textDocument === void 0 || selections === void 0) return;
|
|
1545
1704
|
const blocks = getSelectedLineBlocks(selections);
|
|
@@ -1616,6 +1775,7 @@ var Editor = class {
|
|
|
1616
1775
|
}
|
|
1617
1776
|
this.#markerRenderer?.removePopover();
|
|
1618
1777
|
this.#computeContentOffset(this.#contentElement);
|
|
1778
|
+
this.#renderCarets();
|
|
1619
1779
|
};
|
|
1620
1780
|
#remeasureMetricsOnFontLoad() {
|
|
1621
1781
|
if (this.#fontRemeasureScheduled) return;
|
|
@@ -1629,19 +1789,21 @@ var Editor = class {
|
|
|
1629
1789
|
this.#resetCache();
|
|
1630
1790
|
this.#wrapLineOffsetsCache.clear();
|
|
1631
1791
|
if (this.#selections !== void 0 || this.#matches !== void 0 || this.#markerRenderer !== void 0) this.#updateSelections(this.#selections ?? []);
|
|
1792
|
+
this.#renderCarets();
|
|
1632
1793
|
this.#markerRenderer?.removePopover();
|
|
1633
1794
|
});
|
|
1634
1795
|
}
|
|
1635
1796
|
#rerender(change, newLineAnnotations, renderRange = this.#renderRange, shouldUpdateBuffer) {
|
|
1636
1797
|
const tokenizer = this.#tokenizer;
|
|
1637
1798
|
const fileInstance = this.#fileInstance;
|
|
1638
|
-
const
|
|
1799
|
+
const applyDocumentChange = this.#applyDocumentChange;
|
|
1800
|
+
const textDocument = this.#editSession?.document;
|
|
1639
1801
|
const gutterEl = this.#gutterElement;
|
|
1640
1802
|
const contentEl = this.#contentElement;
|
|
1641
|
-
if (tokenizer
|
|
1803
|
+
if (tokenizer == null || fileInstance == null || applyDocumentChange == null || textDocument == null || contentEl == null) return;
|
|
1642
1804
|
tokenizer.stopBackgroundTokenize();
|
|
1643
1805
|
const t = performance.now();
|
|
1644
|
-
const dirtyLines = tokenizer.tokenize(change, renderRange, !this.#isDiff &&
|
|
1806
|
+
const dirtyLines = tokenizer.tokenize(change, renderRange, !this.#isDiff && this.#virtualizedInstance != null);
|
|
1645
1807
|
const t2 = performance.now();
|
|
1646
1808
|
if (dirtyLines.size > 0) {
|
|
1647
1809
|
const children = contentEl.children;
|
|
@@ -1720,19 +1882,20 @@ var Editor = class {
|
|
|
1720
1882
|
shouldRefreshDiffsView: this.#isDiff && !didLineCountChange,
|
|
1721
1883
|
lineCountChangeInFlight: didLineCountChange
|
|
1722
1884
|
});
|
|
1723
|
-
if (didLineCountChange)
|
|
1885
|
+
if (didLineCountChange) applyDocumentChange(textDocument, newLineAnnotations, shouldUpdateBuffer);
|
|
1724
1886
|
if (didLineCountChange || this.#isDiff && this.#diffSyle === "unified") this.#resetCache();
|
|
1725
|
-
if (newLineAnnotations
|
|
1887
|
+
if (newLineAnnotations != null) {
|
|
1726
1888
|
this.#lineAnnotations = newLineAnnotations;
|
|
1727
|
-
renderLineAnnotations(newLineAnnotations, contentEl, gutterEl);
|
|
1889
|
+
if (!this.#isDiff || !didLineCountChange) renderLineAnnotations(newLineAnnotations, contentEl, gutterEl, fileInstance.getAnnotationSlotName);
|
|
1728
1890
|
}
|
|
1891
|
+
this.#renderCarets();
|
|
1729
1892
|
if (this.#options.__debug === true) console.log(`[diffs/editor] re-render in: ${round(performance.now() - t2)}ms,`, `tokenize in: ${round(t2 - t)}ms (${dirtyLines.size} dirty lines)`);
|
|
1730
1893
|
}
|
|
1731
1894
|
#handleInput(inputType, data) {
|
|
1732
1895
|
switch (inputType) {
|
|
1733
1896
|
case "insertText": {
|
|
1734
1897
|
const text = data ?? "";
|
|
1735
|
-
const textDocument = this.#
|
|
1898
|
+
const textDocument = this.#editSession?.document;
|
|
1736
1899
|
const selections = this.#selections;
|
|
1737
1900
|
const autoSurroundTexts = textDocument !== void 0 && selections !== void 0 ? getAutoSurroundReplacementTexts(textDocument, selections, text, this.#options.autoSurround) : void 0;
|
|
1738
1901
|
this.#replaceSelectionText(autoSurroundTexts ?? text);
|
|
@@ -1741,7 +1904,7 @@ var Editor = class {
|
|
|
1741
1904
|
case "insertCompositionText": break;
|
|
1742
1905
|
case "insertLineBreak":
|
|
1743
1906
|
case "insertParagraph":
|
|
1744
|
-
this.#replaceSelectionText(this.#
|
|
1907
|
+
this.#replaceSelectionText(this.#editSession?.document?.eol ?? "\n");
|
|
1745
1908
|
break;
|
|
1746
1909
|
case "deleteContentBackward":
|
|
1747
1910
|
this.#deleteSelectionText();
|
|
@@ -1833,7 +1996,7 @@ var Editor = class {
|
|
|
1833
1996
|
#getFirstVisibleLineNumber(offset = 0) {
|
|
1834
1997
|
const contentElement = this.#contentElement;
|
|
1835
1998
|
const fileContainer = this.#fileContainer;
|
|
1836
|
-
if (this.#
|
|
1999
|
+
if (this.#editSession?.document == null || contentElement == null || fileContainer == null) return;
|
|
1837
2000
|
const viewport = this.#getScrollViewport();
|
|
1838
2001
|
if (viewport === void 0) return;
|
|
1839
2002
|
let viewportTop;
|
|
@@ -1950,7 +2113,7 @@ var Editor = class {
|
|
|
1950
2113
|
this.#scrollingToLineFixed = false;
|
|
1951
2114
|
this.#scrollingToLineNoFocus = false;
|
|
1952
2115
|
} else {
|
|
1953
|
-
const modelLinePosition = this.#
|
|
2116
|
+
const modelLinePosition = this.#virtualizedInstance?.getLinePosition?.(line + 1);
|
|
1954
2117
|
if (modelLinePosition !== void 0) {
|
|
1955
2118
|
virtualCaret.style.top = modelLinePosition.top + "px";
|
|
1956
2119
|
this.#fileContainer?.shadowRoot?.appendChild(virtualCaret);
|
|
@@ -2102,7 +2265,7 @@ var Editor = class {
|
|
|
2102
2265
|
#updateAltColumnSelections() {
|
|
2103
2266
|
const drag = this.#altColumnDrag;
|
|
2104
2267
|
const selectionStart = this.#selectionStart;
|
|
2105
|
-
const textDocument = this.#
|
|
2268
|
+
const textDocument = this.#editSession?.document;
|
|
2106
2269
|
if (drag === void 0 || drag.focusLine === void 0 || selectionStart === void 0 || textDocument === void 0) return false;
|
|
2107
2270
|
const anchor = selectionStart.direction === -1 ? selectionStart.end : selectionStart.start;
|
|
2108
2271
|
const scrollLeft = this.#contentElement?.parentElement?.scrollLeft ?? 0;
|
|
@@ -2141,8 +2304,451 @@ var Editor = class {
|
|
|
2141
2304
|
this.#updateSelections(selections);
|
|
2142
2305
|
return true;
|
|
2143
2306
|
}
|
|
2307
|
+
#removeRenderedEditPrediction() {
|
|
2308
|
+
for (const [key, element] of this.#overlayElements ?? []) if (key.startsWith("editPrediction")) {
|
|
2309
|
+
element.remove();
|
|
2310
|
+
this.#overlayElements?.delete(key);
|
|
2311
|
+
}
|
|
2312
|
+
}
|
|
2313
|
+
#composeEditPredictionGroup(textDocument, edits, startIndex) {
|
|
2314
|
+
const firstEdit = edits[startIndex];
|
|
2315
|
+
let endIndex = startIndex;
|
|
2316
|
+
let endLine = firstEdit.range.end.line;
|
|
2317
|
+
while (endIndex + 1 < edits.length && edits[endIndex + 1].range.start.line <= endLine) {
|
|
2318
|
+
endIndex++;
|
|
2319
|
+
endLine = Math.max(endLine, edits[endIndex].range.end.line);
|
|
2320
|
+
}
|
|
2321
|
+
if (endIndex === startIndex && (firstEdit.newText.length === 0 || comparePosition(firstEdit.range.start, firstEdit.range.end) === 0)) return {
|
|
2322
|
+
edit: firstEdit,
|
|
2323
|
+
endIndex
|
|
2324
|
+
};
|
|
2325
|
+
const start = firstEdit.range.start;
|
|
2326
|
+
const end = {
|
|
2327
|
+
line: endLine,
|
|
2328
|
+
character: textDocument.getLineLength(endLine)
|
|
2329
|
+
};
|
|
2330
|
+
const parts = [];
|
|
2331
|
+
let consumed = textDocument.offsetAt(start);
|
|
2332
|
+
for (let index = startIndex; index <= endIndex; index++) {
|
|
2333
|
+
const edit = edits[index];
|
|
2334
|
+
const editStart = textDocument.offsetAt(edit.range.start);
|
|
2335
|
+
const editEnd = textDocument.offsetAt(edit.range.end);
|
|
2336
|
+
parts.push(textDocument.getTextSlice(consumed, editStart), edit.newText);
|
|
2337
|
+
consumed = editEnd;
|
|
2338
|
+
}
|
|
2339
|
+
parts.push(textDocument.getTextSlice(consumed, textDocument.offsetAt(end)));
|
|
2340
|
+
return {
|
|
2341
|
+
edit: {
|
|
2342
|
+
range: {
|
|
2343
|
+
start,
|
|
2344
|
+
end
|
|
2345
|
+
},
|
|
2346
|
+
newText: parts.join("")
|
|
2347
|
+
},
|
|
2348
|
+
endIndex
|
|
2349
|
+
};
|
|
2350
|
+
}
|
|
2351
|
+
#getEditPredictionGroups() {
|
|
2352
|
+
const prediction = this.#editPrediction;
|
|
2353
|
+
const textDocument = this.#editSession?.document;
|
|
2354
|
+
if (prediction == null || textDocument == null || prediction.document !== textDocument || prediction.version !== textDocument.version || this.#options.editPrediction?.mode === "subtle" && !this.#editPredictionRevealed) return;
|
|
2355
|
+
const { edits } = prediction.response;
|
|
2356
|
+
const groups = [];
|
|
2357
|
+
let allVisible = edits.length > 0;
|
|
2358
|
+
for (let startIndex = 0; startIndex < edits.length;) {
|
|
2359
|
+
const { edit, endIndex } = this.#composeEditPredictionGroup(textDocument, edits, startIndex);
|
|
2360
|
+
for (let line = edit.range.start.line; allVisible && line <= edit.range.end.line; line++) allVisible = this.#isLineVisible(line);
|
|
2361
|
+
groups.push({
|
|
2362
|
+
edit,
|
|
2363
|
+
startIndex,
|
|
2364
|
+
endIndex
|
|
2365
|
+
});
|
|
2366
|
+
startIndex = endIndex + 1;
|
|
2367
|
+
}
|
|
2368
|
+
return {
|
|
2369
|
+
groups,
|
|
2370
|
+
allVisible
|
|
2371
|
+
};
|
|
2372
|
+
}
|
|
2373
|
+
#fillGhostTextElement(element, newText, anchorLeft, lineLeft, insertionSuffix) {
|
|
2374
|
+
if (this.#isWrap) {
|
|
2375
|
+
element.dataset.wrap = "";
|
|
2376
|
+
element.style.width = `calc(100cqw - ${lineLeft}px)`;
|
|
2377
|
+
} else {
|
|
2378
|
+
delete element.dataset.wrap;
|
|
2379
|
+
element.style.width = "max-content";
|
|
2380
|
+
}
|
|
2381
|
+
const lines = newText.split(/\r\n|\r|\n/);
|
|
2382
|
+
for (let lineIndex = 0; lineIndex < lines.length; lineIndex++) {
|
|
2383
|
+
const lineText = lines[lineIndex];
|
|
2384
|
+
const suffix = lineIndex === lines.length - 1 ? insertionSuffix : void 0;
|
|
2385
|
+
const isEmpty = lineText.length === 0 && suffix === void 0;
|
|
2386
|
+
const line = h("span", {
|
|
2387
|
+
dataset: isEmpty ? ["editPredictionLine", "empty"] : "editPredictionLine",
|
|
2388
|
+
textContent: isEmpty ? "" : lineText
|
|
2389
|
+
}, element);
|
|
2390
|
+
if (suffix !== void 0) h("span", { dataset: "editPredictionSuffix" }, line).append(suffix);
|
|
2391
|
+
if (lineIndex === 0 && anchorLeft !== lineLeft) line.style.textIndent = `${anchorLeft - lineLeft}px`;
|
|
2392
|
+
}
|
|
2393
|
+
}
|
|
2394
|
+
#cloneInsertionSuffix(group) {
|
|
2395
|
+
const prediction = this.#editPrediction;
|
|
2396
|
+
const textDocument = this.#editSession?.document;
|
|
2397
|
+
if (prediction == null || textDocument == null) return;
|
|
2398
|
+
const { edit, startIndex, endIndex } = group;
|
|
2399
|
+
const { start, end } = edit.range;
|
|
2400
|
+
if (!(comparePosition(start, end) === 0 && start.character < textDocument.getLineLength(start.line)) || prediction.response.edits[startIndex - 1]?.range.end.line === start.line || prediction.response.edits[endIndex + 1]?.range.start.line === start.line) return;
|
|
2401
|
+
const sourceLine = this.#getLineElement(start.line);
|
|
2402
|
+
if (sourceLine === void 0) return document.createTextNode(textDocument.getLineText(start.line).slice(start.character));
|
|
2403
|
+
const [suffixNode, suffixOffset] = getSelectionAnchor(sourceLine, start.character);
|
|
2404
|
+
const suffixRange = document.createRange();
|
|
2405
|
+
suffixRange.selectNodeContents(sourceLine);
|
|
2406
|
+
suffixRange.setStart(suffixNode, clampDomOffset(suffixNode, suffixOffset));
|
|
2407
|
+
const suffix = suffixRange.cloneContents();
|
|
2408
|
+
if (suffix.firstChild?.textContent === "") suffix.firstChild.remove();
|
|
2409
|
+
return suffix;
|
|
2410
|
+
}
|
|
2411
|
+
#measureGhostTextRows(group) {
|
|
2412
|
+
const { edit } = group;
|
|
2413
|
+
const { start } = edit.range;
|
|
2414
|
+
const [anchorLeft, anchorWrapLine] = this.#getCharX(start.line, start.character);
|
|
2415
|
+
let anchorVisualLines = 1;
|
|
2416
|
+
let ghostVisualLines = edit.newText.split(/\r\n|\r|\n/).length;
|
|
2417
|
+
const overlayElement = this.#overlayElement;
|
|
2418
|
+
if (this.#isWrap && overlayElement != null) {
|
|
2419
|
+
anchorVisualLines = Math.max(1, this.#wrapLineTextOrWholeLine(start.line).length - 1);
|
|
2420
|
+
const probe = h("span", {
|
|
2421
|
+
dataset: "editPrediction",
|
|
2422
|
+
style: { visibility: "hidden" }
|
|
2423
|
+
}, overlayElement);
|
|
2424
|
+
this.#fillGhostTextElement(probe, edit.newText, anchorLeft, this.#getCharX(start.line, 0)[0], this.#cloneInsertionSuffix(group));
|
|
2425
|
+
const { width, height } = probe.getBoundingClientRect();
|
|
2426
|
+
probe.remove();
|
|
2427
|
+
const { lineHeight } = this.#metrics;
|
|
2428
|
+
if (width > 0 && height > 0 && lineHeight > 0) ghostVisualLines = Math.round(height / lineHeight);
|
|
2429
|
+
}
|
|
2430
|
+
return Math.max(0, ghostVisualLines - (anchorVisualLines - anchorWrapLine));
|
|
2431
|
+
}
|
|
2432
|
+
#syncEditPredictionSpacers(notifyComponent = true) {
|
|
2433
|
+
const nextSpacers = /* @__PURE__ */ new Map();
|
|
2434
|
+
const ghostTextRows = /* @__PURE__ */ new Map();
|
|
2435
|
+
const previousRows = this.#ghostTextRows;
|
|
2436
|
+
let rowsChanged = false;
|
|
2437
|
+
const contentElement = this.#contentElement;
|
|
2438
|
+
const composed = this.#getEditPredictionGroups();
|
|
2439
|
+
if (contentElement != null && composed != null && composed.allVisible) {
|
|
2440
|
+
for (const group of composed.groups) {
|
|
2441
|
+
const { edit } = group;
|
|
2442
|
+
if (edit.newText.length === 0) continue;
|
|
2443
|
+
const count = this.#measureGhostTextRows(group);
|
|
2444
|
+
if (count > (ghostTextRows.get(edit.range.start.line) ?? 0)) ghostTextRows.set(edit.range.start.line, count);
|
|
2445
|
+
}
|
|
2446
|
+
if (ghostTextRows.size > 0) {
|
|
2447
|
+
let rowIndexes;
|
|
2448
|
+
const startingLine = this.#renderRange?.startingLine ?? 0;
|
|
2449
|
+
for (const [line, count] of ghostTextRows) {
|
|
2450
|
+
rowsChanged ||= previousRows.get(line) !== count;
|
|
2451
|
+
const lineElement = this.#getLineElement(line);
|
|
2452
|
+
if (lineElement === void 0) continue;
|
|
2453
|
+
let rowIndex = line - startingLine;
|
|
2454
|
+
if (contentElement.children[rowIndex] !== lineElement) {
|
|
2455
|
+
if (rowIndexes === void 0) {
|
|
2456
|
+
rowIndexes = /* @__PURE__ */ new Map();
|
|
2457
|
+
for (let index = 0; index < contentElement.children.length; index++) rowIndexes.set(contentElement.children[index], index);
|
|
2458
|
+
}
|
|
2459
|
+
rowIndex = rowIndexes.get(lineElement) ?? -1;
|
|
2460
|
+
}
|
|
2461
|
+
if (rowIndex < 0) continue;
|
|
2462
|
+
nextSpacers.set(lineElement, count);
|
|
2463
|
+
const gutterRow = this.#gutterElement?.children[rowIndex];
|
|
2464
|
+
if (gutterRow instanceof HTMLElement) nextSpacers.set(gutterRow, count);
|
|
2465
|
+
const partner = this.#deletionsColumnPartner(rowIndex);
|
|
2466
|
+
if (partner != null) {
|
|
2467
|
+
nextSpacers.set(partner.content, (nextSpacers.get(partner.content) ?? 0) + count);
|
|
2468
|
+
nextSpacers.set(partner.gutter, (nextSpacers.get(partner.gutter) ?? 0) + count);
|
|
2469
|
+
}
|
|
2470
|
+
}
|
|
2471
|
+
}
|
|
2472
|
+
}
|
|
2473
|
+
let changed = false;
|
|
2474
|
+
for (const [element, count] of this.#editPredictionSpacers) {
|
|
2475
|
+
if (nextSpacers.get(element) === count) continue;
|
|
2476
|
+
delete element.dataset.editPredictionSpacer;
|
|
2477
|
+
element.style.removeProperty("--diffs-edit-prediction-spacer-height");
|
|
2478
|
+
changed = true;
|
|
2479
|
+
}
|
|
2480
|
+
for (const [element, count] of nextSpacers) {
|
|
2481
|
+
if (this.#editPredictionSpacers.get(element) === count) continue;
|
|
2482
|
+
element.dataset.editPredictionSpacer = "";
|
|
2483
|
+
element.style.setProperty("--diffs-edit-prediction-spacer-height", `${count}lh`);
|
|
2484
|
+
changed = true;
|
|
2485
|
+
}
|
|
2486
|
+
this.#editPredictionSpacers = nextSpacers;
|
|
2487
|
+
if (rowsChanged || ghostTextRows.size !== previousRows.size) {
|
|
2488
|
+
this.#ghostTextRows = ghostTextRows;
|
|
2489
|
+
if (notifyComponent) this.#virtualizedInstance?.syncGhostTextRows();
|
|
2490
|
+
}
|
|
2491
|
+
if (changed) this.#resetCache();
|
|
2492
|
+
}
|
|
2493
|
+
#deletionsColumnPartner(rowIndex) {
|
|
2494
|
+
const deletionsColumn = this.#deletionsColumn;
|
|
2495
|
+
const contentElement = this.#contentElement;
|
|
2496
|
+
if (deletionsColumn == null || contentElement == null || !this.#isDiff || this.#diffSyle !== "split" || this.#isWrap) return;
|
|
2497
|
+
let track = 0;
|
|
2498
|
+
for (let index = 0; index < rowIndex; index++) track += gridTrackSpan(contentElement.children[index]);
|
|
2499
|
+
const { content, gutter } = deletionsColumn;
|
|
2500
|
+
let covered = 0;
|
|
2501
|
+
for (let index = 0; index < content.children.length; index++) {
|
|
2502
|
+
const child = content.children[index];
|
|
2503
|
+
covered += gridTrackSpan(child);
|
|
2504
|
+
if (covered > track) {
|
|
2505
|
+
const gutterChild = gutter.children[index];
|
|
2506
|
+
if (!(child instanceof HTMLElement) || !(gutterChild instanceof HTMLElement)) throw new Error("Editor: deletions column rows and gutter cells are out of step");
|
|
2507
|
+
return {
|
|
2508
|
+
content: child,
|
|
2509
|
+
gutter: gutterChild
|
|
2510
|
+
};
|
|
2511
|
+
}
|
|
2512
|
+
}
|
|
2513
|
+
}
|
|
2514
|
+
#cancelEditPrediction(removeRendered, notifyComponent = true) {
|
|
2515
|
+
if (this.#editPredictionTimer !== void 0) {
|
|
2516
|
+
clearTimeout(this.#editPredictionTimer);
|
|
2517
|
+
this.#editPredictionTimer = void 0;
|
|
2518
|
+
}
|
|
2519
|
+
this.#editPredictionAbortController?.abort();
|
|
2520
|
+
this.#editPredictionAbortController = void 0;
|
|
2521
|
+
this.#editPredictionGeneration++;
|
|
2522
|
+
this.#editPredictionRevealed = false;
|
|
2523
|
+
this.#retryEditPredictionOnRender = false;
|
|
2524
|
+
this.#editPrediction = void 0;
|
|
2525
|
+
this.#syncEditPredictionSpacers(notifyComponent);
|
|
2526
|
+
if (removeRendered) this.#removeRenderedEditPrediction();
|
|
2527
|
+
}
|
|
2528
|
+
#includesEditPredictionPath(path) {
|
|
2529
|
+
const options = this.#options.editPrediction;
|
|
2530
|
+
if (options === void 0) return false;
|
|
2531
|
+
const normalizedPath = path.replaceAll("\\", "/");
|
|
2532
|
+
return (options.include === void 0 || options.include.some((pattern) => matchesEditPredictionPattern(normalizedPath, pattern))) && options.exclude?.some((pattern) => matchesEditPredictionPattern(normalizedPath, pattern)) !== true;
|
|
2533
|
+
}
|
|
2534
|
+
#scheduleEditPrediction() {
|
|
2535
|
+
this.#cancelEditPrediction(true);
|
|
2536
|
+
const selection = this.#selections?.[0];
|
|
2537
|
+
if (this.#options.editPrediction === void 0 || this.#editSession?.document === void 0 || this.#editSession?.fileInfo === void 0 || this.#selections?.length !== 1 || selection === void 0 || !isCollapsedSelection(selection)) return;
|
|
2538
|
+
const document = this.#editSession?.document;
|
|
2539
|
+
const cursorOffset = document.offsetAt(getCaretPosition(selection));
|
|
2540
|
+
this.#editPredictionTimer = setTimeout(() => {
|
|
2541
|
+
this.#editPredictionTimer = void 0;
|
|
2542
|
+
const options = this.#options.editPrediction;
|
|
2543
|
+
const currentSelection = this.#selections?.[0];
|
|
2544
|
+
const path = this.#editSession?.fileInfo?.name;
|
|
2545
|
+
if (options === void 0 || path === void 0 || this.#editSession?.document !== document || this.#selections?.length !== 1 || currentSelection === void 0 || !isCollapsedSelection(currentSelection) || document.offsetAt(getCaretPosition(currentSelection)) !== cursorOffset) return;
|
|
2546
|
+
if (!this.#includesEditPredictionPath(path)) return;
|
|
2547
|
+
const isLineEditable = (line) => this.#isLineInRenderRange(line) && this.#isLineRenderable(line);
|
|
2548
|
+
if (!isLineEditable(getCaretPosition(currentSelection).line)) {
|
|
2549
|
+
this.#retryEditPredictionOnRender = true;
|
|
2550
|
+
return;
|
|
2551
|
+
}
|
|
2552
|
+
const request = buildEditPredictionRequest(path, document, cursorOffset, this.#editPredictionHistory, isLineEditable);
|
|
2553
|
+
if (request === void 0) return;
|
|
2554
|
+
const excerptStartOffset = document.offsetAt({
|
|
2555
|
+
line: request.excerptStartLine,
|
|
2556
|
+
character: 0
|
|
2557
|
+
});
|
|
2558
|
+
const editableStart = excerptStartOffset + request.editableRange.start;
|
|
2559
|
+
const editableEnd = excerptStartOffset + request.editableRange.end;
|
|
2560
|
+
const controller = new AbortController();
|
|
2561
|
+
const generation = ++this.#editPredictionGeneration;
|
|
2562
|
+
this.#editPredictionAbortController = controller;
|
|
2563
|
+
let prediction;
|
|
2564
|
+
try {
|
|
2565
|
+
prediction = options.provider.predict(request, { signal: controller.signal });
|
|
2566
|
+
} catch {
|
|
2567
|
+
this.#editPredictionAbortController = void 0;
|
|
2568
|
+
return;
|
|
2569
|
+
}
|
|
2570
|
+
Promise.resolve(prediction).then((response) => {
|
|
2571
|
+
const selection = this.#selections?.[0];
|
|
2572
|
+
if (controller.signal.aborted || generation !== this.#editPredictionGeneration || this.#editPredictionAbortController !== controller || this.#editSession?.document !== document || document.version !== request.version || this.#selections?.length !== 1 || selection === void 0 || !isCollapsedSelection(selection) || document.offsetAt(getCaretPosition(selection)) !== cursorOffset) return;
|
|
2573
|
+
if (response == null || !Array.isArray(response.edits) || response.edits.length === 0 || response.edits.length > MAX_EDIT_PREDICTION_RESPONSE_EDITS || response.newCursor == null) return;
|
|
2574
|
+
const resolvedEdits = [];
|
|
2575
|
+
let responseBytes = 0;
|
|
2576
|
+
for (const edit of response.edits) {
|
|
2577
|
+
if (edit == null || typeof edit.newText !== "string" || !isValidEditPredictionPosition(document, edit.range?.start) || !isValidEditPredictionPosition(document, edit.range?.end) || comparePosition(edit.range.start, edit.range.end) > 0) return;
|
|
2578
|
+
responseBytes += editPredictionTextEncoder.encode(edit.newText).byteLength;
|
|
2579
|
+
if (responseBytes > MAX_EDIT_PREDICTION_RESPONSE_BYTES) return;
|
|
2580
|
+
const start = document.offsetAt(edit.range.start);
|
|
2581
|
+
const end = document.offsetAt(edit.range.end);
|
|
2582
|
+
const resolvedEdit = document.resolveEdits([edit])[0];
|
|
2583
|
+
if (resolvedEdit.start !== start || resolvedEdit.end !== end) return;
|
|
2584
|
+
resolvedEdits.push(resolvedEdit);
|
|
2585
|
+
}
|
|
2586
|
+
resolvedEdits.sort((left, right) => {
|
|
2587
|
+
const startDelta = left.start - right.start;
|
|
2588
|
+
return startDelta === 0 ? left.end - right.end : startDelta;
|
|
2589
|
+
});
|
|
2590
|
+
for (let index = 0; index < resolvedEdits.length; index++) {
|
|
2591
|
+
const edit = resolvedEdits[index];
|
|
2592
|
+
if (edit.start < editableStart || edit.end > editableEnd || index > 0 && resolvedEdits[index - 1].end > edit.start) return;
|
|
2593
|
+
}
|
|
2594
|
+
const edits = resolvedEdits.filter((edit) => edit.text !== document.getTextSlice(edit.start, edit.end));
|
|
2595
|
+
if (edits.length === 0) return;
|
|
2596
|
+
const firstEditPosition = document.positionAt(edits[0].start);
|
|
2597
|
+
const lastEditPosition = document.positionAt(edits.at(-1).end);
|
|
2598
|
+
const affectedStart = document.offsetAt({
|
|
2599
|
+
line: firstEditPosition.line,
|
|
2600
|
+
character: 0
|
|
2601
|
+
});
|
|
2602
|
+
const affectedEnd = document.offsetAt({
|
|
2603
|
+
line: lastEditPosition.line,
|
|
2604
|
+
character: document.getLineLength(lastEditPosition.line)
|
|
2605
|
+
});
|
|
2606
|
+
const predictedParts = [];
|
|
2607
|
+
let consumed = affectedStart;
|
|
2608
|
+
for (const edit of edits) {
|
|
2609
|
+
predictedParts.push(document.getTextSlice(consumed, edit.start), edit.text);
|
|
2610
|
+
consumed = edit.end;
|
|
2611
|
+
}
|
|
2612
|
+
predictedParts.push(document.getTextSlice(consumed, affectedEnd));
|
|
2613
|
+
const predictedLines = predictedParts.join("").split(/\r\n|\r|\n/);
|
|
2614
|
+
const affectedEndLine = firstEditPosition.line + predictedLines.length - 1;
|
|
2615
|
+
const lineDelta = predictedLines.length - (lastEditPosition.line - firstEditPosition.line + 1);
|
|
2616
|
+
const newCursor = response.newCursor;
|
|
2617
|
+
if (!Number.isInteger(newCursor.line) || !Number.isInteger(newCursor.character) || newCursor.line < 0 || newCursor.character < 0) return;
|
|
2618
|
+
if (newCursor.line >= firstEditPosition.line && newCursor.line <= affectedEndLine) {
|
|
2619
|
+
const line = predictedLines[newCursor.line - firstEditPosition.line];
|
|
2620
|
+
if (newCursor.character > line.length || splitsSurrogatePair(line, newCursor.character)) return;
|
|
2621
|
+
} else {
|
|
2622
|
+
const originalLine = newCursor.line < firstEditPosition.line ? newCursor.line : newCursor.line - lineDelta;
|
|
2623
|
+
if (originalLine < 0 || originalLine >= document.lineCount || newCursor.character > document.getLineLength(originalLine)) return;
|
|
2624
|
+
const originalOffset = document.offsetAt({
|
|
2625
|
+
line: originalLine,
|
|
2626
|
+
character: newCursor.character
|
|
2627
|
+
});
|
|
2628
|
+
if (splitsSurrogatePair(document.charAt(originalOffset - 1) + document.charAt(originalOffset), 1)) return;
|
|
2629
|
+
}
|
|
2630
|
+
this.#editPrediction = {
|
|
2631
|
+
document,
|
|
2632
|
+
version: request.version,
|
|
2633
|
+
cursorOffset,
|
|
2634
|
+
rendered: false,
|
|
2635
|
+
response: {
|
|
2636
|
+
edits: edits.map((edit) => ({
|
|
2637
|
+
range: {
|
|
2638
|
+
start: document.positionAt(edit.start),
|
|
2639
|
+
end: document.positionAt(edit.end)
|
|
2640
|
+
},
|
|
2641
|
+
newText: edit.text
|
|
2642
|
+
})),
|
|
2643
|
+
newCursor: { ...newCursor }
|
|
2644
|
+
}
|
|
2645
|
+
};
|
|
2646
|
+
this.#updateSelections(this.#selections);
|
|
2647
|
+
}).catch(() => {}).finally(() => {
|
|
2648
|
+
if (this.#editPredictionAbortController === controller) this.#editPredictionAbortController = void 0;
|
|
2649
|
+
});
|
|
2650
|
+
}, EDIT_PREDICTION_DEBOUNCE_MS);
|
|
2651
|
+
}
|
|
2652
|
+
#recordEditPredictionHistory(change, source) {
|
|
2653
|
+
const textDocument = this.#editSession?.document;
|
|
2654
|
+
const path = this.#editSession?.fileInfo?.name;
|
|
2655
|
+
const transaction = getTextDocumentChangeTransaction(change);
|
|
2656
|
+
if (textDocument === void 0 || path === void 0 || transaction === void 0 || !this.#includesEditPredictionPath(path)) return;
|
|
2657
|
+
this.#editPredictionHistory = recordEditPrediction(this.#editPredictionHistory, path, textDocument, transaction, source);
|
|
2658
|
+
}
|
|
2659
|
+
#acceptEditPrediction() {
|
|
2660
|
+
const prediction = this.#editPrediction;
|
|
2661
|
+
const textDocument = this.#editSession?.document;
|
|
2662
|
+
const selection = this.#selections?.[0];
|
|
2663
|
+
if (prediction === void 0 || !prediction.rendered || textDocument === void 0 || prediction.document !== textDocument || prediction.version !== textDocument.version || this.#selections?.length !== 1 || selection === void 0 || !isCollapsedSelection(selection) || textDocument.offsetAt(getCaretPosition(selection)) !== prediction.cursorOffset) return;
|
|
2664
|
+
const { edits, newCursor } = prediction.response;
|
|
2665
|
+
this.#cancelEditPrediction(true);
|
|
2666
|
+
const change = textDocument.applyEdits(edits.map((edit) => ({
|
|
2667
|
+
range: {
|
|
2668
|
+
start: { ...edit.range.start },
|
|
2669
|
+
end: { ...edit.range.end }
|
|
2670
|
+
},
|
|
2671
|
+
newText: edit.newText
|
|
2672
|
+
})), true, this.#selections, void 0, true);
|
|
2673
|
+
if (change === void 0) {
|
|
2674
|
+
this.#scheduleEditPrediction();
|
|
2675
|
+
return;
|
|
2676
|
+
}
|
|
2677
|
+
const cursor = textDocument.normalizePosition(newCursor);
|
|
2678
|
+
const nextSelections = [{
|
|
2679
|
+
start: cursor,
|
|
2680
|
+
end: cursor,
|
|
2681
|
+
direction: 0
|
|
2682
|
+
}];
|
|
2683
|
+
textDocument.setLastUndoSelectionsAfter(nextSelections);
|
|
2684
|
+
this.#applyChange(change, nextSelections, this.#applyChangeToLineAnnotations(change), { editSource: "prediction" });
|
|
2685
|
+
}
|
|
2686
|
+
#renderEditPrediction(renderCtx) {
|
|
2687
|
+
const prediction = this.#editPrediction;
|
|
2688
|
+
const textDocument = this.#editSession?.document;
|
|
2689
|
+
if (prediction !== void 0) prediction.rendered = false;
|
|
2690
|
+
const composed = this.#getEditPredictionGroups();
|
|
2691
|
+
if (prediction == null || textDocument == null || composed == null || !composed.allVisible) return;
|
|
2692
|
+
for (const group of composed.groups) {
|
|
2693
|
+
const { edit, endIndex } = group;
|
|
2694
|
+
const { start, end } = edit.range;
|
|
2695
|
+
const isDeletion = edit.newText.length === 0;
|
|
2696
|
+
const isReplacement = comparePosition(start, end) !== 0;
|
|
2697
|
+
const lineLength = textDocument.getLineLength(start.line);
|
|
2698
|
+
const isMidLineInsertion = !isReplacement && start.character < lineLength;
|
|
2699
|
+
if (isReplacement) this.#renderSelection(renderCtx, isDeletion ? "editPredictionDeletion" : "editPredictionReplacement", {
|
|
2700
|
+
start,
|
|
2701
|
+
end
|
|
2702
|
+
});
|
|
2703
|
+
else if (isMidLineInsertion) this.#renderSelection(renderCtx, "editPredictionInsertion", {
|
|
2704
|
+
start,
|
|
2705
|
+
end: {
|
|
2706
|
+
line: start.line,
|
|
2707
|
+
character: lineLength
|
|
2708
|
+
}
|
|
2709
|
+
});
|
|
2710
|
+
if (isDeletion) continue;
|
|
2711
|
+
const [anchorLeft, anchorWrapLine] = this.#getCharX(start.line, start.character);
|
|
2712
|
+
const lineLeft = this.#getCharX(start.line, 0)[0];
|
|
2713
|
+
const anchorTop = this.#getLineY(start.line) + anchorWrapLine * this.#metrics.lineHeight;
|
|
2714
|
+
const key = `editPrediction-${endIndex}`;
|
|
2715
|
+
let element = this.#overlayElements?.get(key);
|
|
2716
|
+
if (element !== void 0) {
|
|
2717
|
+
this.#overlayElements?.delete(key);
|
|
2718
|
+
element.replaceChildren();
|
|
2719
|
+
} else element = h("span", {
|
|
2720
|
+
ariaHidden: "true",
|
|
2721
|
+
contentEditable: "false",
|
|
2722
|
+
dataset: "editPrediction"
|
|
2723
|
+
}, renderCtx.fragment);
|
|
2724
|
+
if (isReplacement) {
|
|
2725
|
+
element.dataset.replacement = "";
|
|
2726
|
+
const lineElement = this.#getLineElement(start.line);
|
|
2727
|
+
if (lineElement !== void 0) element.style.setProperty("--diffs-edit-prediction-bg", getComputedStyle(lineElement).getPropertyValue("--diffs-line-bg"));
|
|
2728
|
+
} else {
|
|
2729
|
+
delete element.dataset.replacement;
|
|
2730
|
+
element.style.removeProperty("--diffs-edit-prediction-bg");
|
|
2731
|
+
}
|
|
2732
|
+
this.#fillGhostTextElement(element, edit.newText, anchorLeft, lineLeft, this.#cloneInsertionSuffix(group));
|
|
2733
|
+
element.style.transform = `translateX(${lineLeft}px) translateY(${anchorTop}px)`;
|
|
2734
|
+
renderCtx.elements.set(key, element);
|
|
2735
|
+
}
|
|
2736
|
+
prediction.rendered = true;
|
|
2737
|
+
}
|
|
2144
2738
|
#updateSelections(selections) {
|
|
2145
2739
|
this.__postponeBgTokenizeToNextFrame();
|
|
2740
|
+
const previousSelections = this.#selections;
|
|
2741
|
+
let selectionsChanged = previousSelections?.length !== selections.length;
|
|
2742
|
+
if (!selectionsChanged && previousSelections !== void 0) for (let i = 0; i < selections.length; i++) {
|
|
2743
|
+
const previous = previousSelections[i];
|
|
2744
|
+
const next = selections[i];
|
|
2745
|
+
if (previous.direction !== next.direction || comparePosition(previous.start, next.start) !== 0 || comparePosition(previous.end, next.end) !== 0) {
|
|
2746
|
+
selectionsChanged = true;
|
|
2747
|
+
break;
|
|
2748
|
+
}
|
|
2749
|
+
}
|
|
2750
|
+
if (selectionsChanged) this.#cancelEditPrediction(true);
|
|
2751
|
+
this.#syncEditPredictionSpacers();
|
|
2146
2752
|
this.#primaryCaretElement = void 0;
|
|
2147
2753
|
this.#setEditorActiveLineSafe(null);
|
|
2148
2754
|
if (selections.length === 0 && this.#matches === void 0 && this.#markerRenderer === void 0) {
|
|
@@ -2151,6 +2757,7 @@ var Editor = class {
|
|
|
2151
2757
|
this.#overlayElements?.clear();
|
|
2152
2758
|
this.#selectionAction?.cleanup();
|
|
2153
2759
|
this.#selectionAction = void 0;
|
|
2760
|
+
if (selectionsChanged) this.#scheduleEditPrediction();
|
|
2154
2761
|
return;
|
|
2155
2762
|
}
|
|
2156
2763
|
const fragment = document.createDocumentFragment();
|
|
@@ -2169,14 +2776,14 @@ var Editor = class {
|
|
|
2169
2776
|
if (!isCollapsedSelection(selection)) this.#renderSelection(renderCtx, "selection", selection);
|
|
2170
2777
|
this.#renderCaret(renderCtx, selection, selection === primarySelection);
|
|
2171
2778
|
}
|
|
2172
|
-
const bracketMatchRanges = this.#options.matchBrackets !== false && this.#
|
|
2779
|
+
const bracketMatchRanges = this.#options.matchBrackets !== false && this.#editSession?.document != null && this.#tokenizer !== void 0 && isCollapsedSelection(primarySelection) ? findBracketMatchRanges(this.#editSession?.document, this.#tokenizer, primarySelection.start) : void 0;
|
|
2173
2780
|
if (bracketMatchRanges !== void 0) for (const range of bracketMatchRanges) this.#renderSelection(renderCtx, "bracketMatch", range);
|
|
2174
2781
|
}
|
|
2175
|
-
const textDocument = this.#
|
|
2782
|
+
const textDocument = this.#editSession?.document;
|
|
2176
2783
|
if (this.#matches !== void 0 && textDocument !== void 0) {
|
|
2177
2784
|
const matches = this.#matches;
|
|
2178
2785
|
const renderRange = this.#renderRange;
|
|
2179
|
-
const renderedLineRanges = renderRange
|
|
2786
|
+
const renderedLineRanges = renderRange != null && Number.isFinite(renderRange.totalLines) || this.#isDiff && this.#fileDiffInstance?.options.expandUnchanged !== true ? this.#getRenderedEditableLineRanges() : void 0;
|
|
2180
2787
|
const primarySelection = this.#selections?.at(-1);
|
|
2181
2788
|
const primaryStartOffset = primarySelection !== void 0 ? textDocument.offsetAt(primarySelection.start) : -1;
|
|
2182
2789
|
const primaryEndOffset = primarySelection !== void 0 ? textDocument.offsetAt(primarySelection.end) : -1;
|
|
@@ -2221,14 +2828,70 @@ var Editor = class {
|
|
|
2221
2828
|
}
|
|
2222
2829
|
}
|
|
2223
2830
|
if (this.#markerRenderer !== void 0 && textDocument !== void 0) for (const marker of this.#markerRenderer.markers) this.#renderSelection(renderCtx, "marker", marker, markerSeverityDatasetKey(marker.severity));
|
|
2831
|
+
this.#renderEditPrediction(renderCtx);
|
|
2224
2832
|
this.#overlayElement?.appendChild(fragment);
|
|
2225
2833
|
this.#overlayElements?.forEach((el) => el.remove());
|
|
2226
2834
|
this.#overlayElements?.clear();
|
|
2227
2835
|
this.#overlayElements = renderCtx.elements;
|
|
2228
2836
|
this.#updateSelectionActionPopover();
|
|
2837
|
+
if (selectionsChanged) this.#scheduleEditPrediction();
|
|
2229
2838
|
}
|
|
2230
|
-
#
|
|
2231
|
-
|
|
2839
|
+
#renderCarets() {
|
|
2840
|
+
const carets = this.#carets;
|
|
2841
|
+
const renderCaret = this.#options.renderCaret;
|
|
2842
|
+
const overlayElement = this.#overlayElement;
|
|
2843
|
+
this.#caretHighlightElements?.forEach((element) => element.remove());
|
|
2844
|
+
this.#caretHighlightElements = void 0;
|
|
2845
|
+
if (carets === void 0 || renderCaret === void 0 || overlayElement === void 0) {
|
|
2846
|
+
this.#caretElements?.forEach((element) => element.remove());
|
|
2847
|
+
this.#caretElements = void 0;
|
|
2848
|
+
return;
|
|
2849
|
+
}
|
|
2850
|
+
const elements = this.#caretElements ??= /* @__PURE__ */ new Map();
|
|
2851
|
+
for (const [trackedCaret, element] of elements) if (!this.#isLineVisible(trackedCaret.caret.focus.line)) {
|
|
2852
|
+
element.remove();
|
|
2853
|
+
elements.delete(trackedCaret);
|
|
2854
|
+
}
|
|
2855
|
+
const fragment = document.createDocumentFragment();
|
|
2856
|
+
const highlightElements = [];
|
|
2857
|
+
for (const trackedCaret of carets) {
|
|
2858
|
+
const { caret } = trackedCaret;
|
|
2859
|
+
const { line, character } = caret.focus;
|
|
2860
|
+
if (trackedCaret.anchorOffset !== trackedCaret.focusOffset) {
|
|
2861
|
+
const highlightContext = {
|
|
2862
|
+
fragment,
|
|
2863
|
+
elements: /* @__PURE__ */ new Map()
|
|
2864
|
+
};
|
|
2865
|
+
this.#renderSelection(highlightContext, "caretHighlight", trackedCaret.anchorOffset < trackedCaret.focusOffset ? {
|
|
2866
|
+
start: caret.anchor,
|
|
2867
|
+
end: caret.focus
|
|
2868
|
+
} : {
|
|
2869
|
+
start: caret.focus,
|
|
2870
|
+
end: caret.anchor
|
|
2871
|
+
}, void 0, caret.focus);
|
|
2872
|
+
for (const highlightElement of highlightContext.elements.values()) {
|
|
2873
|
+
highlightElement.style.setProperty("--diffs-caret-highlight-bg", `color-mix(in srgb, ${caret.metadata.color} 32%, transparent)`);
|
|
2874
|
+
highlightElements.push(highlightElement);
|
|
2875
|
+
}
|
|
2876
|
+
}
|
|
2877
|
+
if (!this.#isLineVisible(line)) continue;
|
|
2878
|
+
let element = elements.get(trackedCaret);
|
|
2879
|
+
if (element === void 0) {
|
|
2880
|
+
element = h("div", {
|
|
2881
|
+
dataset: "remoteCaret",
|
|
2882
|
+
children: [renderCaret(caret)]
|
|
2883
|
+
}, fragment);
|
|
2884
|
+
elements.set(trackedCaret, element);
|
|
2885
|
+
}
|
|
2886
|
+
const [left, wrapLine] = this.#getCharX(line, character);
|
|
2887
|
+
const top = this.#getLineY(line) + wrapLine * this.#metrics.lineHeight;
|
|
2888
|
+
element.style.transform = `translateX(${left}px) translateY(${top}px)`;
|
|
2889
|
+
}
|
|
2890
|
+
this.#caretHighlightElements = highlightElements;
|
|
2891
|
+
overlayElement.appendChild(fragment);
|
|
2892
|
+
}
|
|
2893
|
+
#renderSelection(renderCtx, type, range, extraDataset, connectedCaret) {
|
|
2894
|
+
if (this.#editSession?.document == null) return;
|
|
2232
2895
|
const { start, end } = range;
|
|
2233
2896
|
let firstLine = start.line;
|
|
2234
2897
|
let endLine = end.line + 1;
|
|
@@ -2241,12 +2904,18 @@ var Editor = class {
|
|
|
2241
2904
|
if (!this.#isLineVisible(line)) continue;
|
|
2242
2905
|
const isLastLine = line === end.line;
|
|
2243
2906
|
const startChar = line === start.line ? start.character : 0;
|
|
2244
|
-
const endChar = isLastLine ? end.character : this.#
|
|
2907
|
+
const endChar = isLastLine ? end.character : this.#editSession?.document.getLineLength(line);
|
|
2908
|
+
if (startChar === endChar && (type === "editPredictionDeletion" || type === "editPredictionReplacement")) {
|
|
2909
|
+
if (isLastLine && line !== start.line) continue;
|
|
2910
|
+
const [left, wrapLine] = this.#getCharX(line, startChar);
|
|
2911
|
+
this.#renderSelectionBlock(renderCtx, type, line, wrapLine, left, this.#metrics.ch, extraDataset);
|
|
2912
|
+
continue;
|
|
2913
|
+
}
|
|
2245
2914
|
if (this.#isWrap) {
|
|
2246
2915
|
const contentWidth = this.#getContentWidth();
|
|
2247
|
-
const lineText = this.#
|
|
2916
|
+
const lineText = this.#editSession?.document.getLineText(line);
|
|
2248
2917
|
if (2 * this.#metrics.ch + this.#metrics.measureTextWidth(lineText) > contentWidth) {
|
|
2249
|
-
this.#renderWrappedSelection(renderCtx, line, lineText, startChar, endChar, isLastLine, type, extraDataset);
|
|
2918
|
+
this.#renderWrappedSelection(renderCtx, line, lineText, startChar, endChar, isLastLine, type, extraDataset, connectedCaret);
|
|
2250
2919
|
continue;
|
|
2251
2920
|
}
|
|
2252
2921
|
}
|
|
@@ -2258,10 +2927,13 @@ var Editor = class {
|
|
|
2258
2927
|
if (!isLastLine && type === "selection") paddingEnd = this.#metrics.ch;
|
|
2259
2928
|
if (startChar === endChar) width = paddingEnd;
|
|
2260
2929
|
else width = this.#getCharX(line, endChar)[0] - left + paddingEnd;
|
|
2261
|
-
this.#renderSelectionBlock(renderCtx, type, line, 0, left, width, extraDataset
|
|
2930
|
+
this.#renderSelectionBlock(renderCtx, type, line, 0, left, width, extraDataset, {
|
|
2931
|
+
start: connectedCaret?.line === start.line && connectedCaret.character === start.character && line === start.line,
|
|
2932
|
+
end: connectedCaret?.line === end.line && connectedCaret.character === end.character && line === end.line
|
|
2933
|
+
});
|
|
2262
2934
|
}
|
|
2263
2935
|
}
|
|
2264
|
-
#renderWrappedSelection(renderCtx, line, lineText, startChar, endChar, isLastLine, type, extraDataset) {
|
|
2936
|
+
#renderWrappedSelection(renderCtx, line, lineText, startChar, endChar, isLastLine, type, extraDataset, connectedCaret) {
|
|
2265
2937
|
const wrapOffsets = this.#wrapLineTextOrWholeLine(line);
|
|
2266
2938
|
const segmentCount = wrapOffsets.length - 1;
|
|
2267
2939
|
const offsetLeft = this.#getGutterWidth() + this.#metrics.ch + (this.#activeContentOffset?.left ?? 0);
|
|
@@ -2276,7 +2948,10 @@ var Editor = class {
|
|
|
2276
2948
|
let paddingEnd = 0;
|
|
2277
2949
|
if (!isLastLine && wrapLine === segmentCount - 1 && type === "selection") paddingEnd = this.#metrics.ch;
|
|
2278
2950
|
const segmentWidth = wrapStartChar === wrapEndChar ? paddingEnd : this.#segmentTextWidth(lineText, segmentStart, wrapEndChar) - segmentStartWidth + paddingEnd;
|
|
2279
|
-
this.#renderSelectionBlock(renderCtx, type, line, wrapLine, segmentLeft, segmentWidth, extraDataset
|
|
2951
|
+
this.#renderSelectionBlock(renderCtx, type, line, wrapLine, segmentLeft, segmentWidth, extraDataset, {
|
|
2952
|
+
start: connectedCaret?.line === line && connectedCaret.character === startChar && wrapStartChar === startChar,
|
|
2953
|
+
end: connectedCaret?.line === line && connectedCaret.character === endChar && wrapEndChar === endChar
|
|
2954
|
+
});
|
|
2280
2955
|
}
|
|
2281
2956
|
}
|
|
2282
2957
|
#segmentTextWidth(lineText, segmentStart, character) {
|
|
@@ -2285,13 +2960,13 @@ var Editor = class {
|
|
|
2285
2960
|
const asciiColumns = getExpandedAsciiTextColumns(segmentText, this.#metrics.tabSize);
|
|
2286
2961
|
return asciiColumns !== -1 ? asciiColumns * this.#metrics.ch : this.#metrics.measureTextWidth(segmentText);
|
|
2287
2962
|
}
|
|
2288
|
-
#renderSelectionBlock(renderCtx, type, line, wrapLine, left, width, extraDataset) {
|
|
2963
|
+
#renderSelectionBlock(renderCtx, type, line, wrapLine, left, width, extraDataset, connectedCaretEdge) {
|
|
2289
2964
|
if (width === 0) return;
|
|
2290
2965
|
const { ch, lineHeight } = this.#metrics;
|
|
2291
2966
|
const y = this.#getLineY(line) + wrapLine * lineHeight;
|
|
2292
2967
|
const cacheKey = `${type}-${line}/${wrapLine}-${left}-${width} ${extraDataset ?? ""}`;
|
|
2293
2968
|
const overlayEls = this.#overlayElements;
|
|
2294
|
-
const rounded = (this.#options.roundedSelection ?? true) && type === "selection";
|
|
2969
|
+
const rounded = (this.#options.roundedSelection ?? true) && (type === "selection" || type === "caretHighlight");
|
|
2295
2970
|
const addRoundedCorner = (line, wrapLine, left, radius) => {
|
|
2296
2971
|
const top = this.#getLineY(line) + wrapLine * lineHeight;
|
|
2297
2972
|
const lineElement = this.#getLineElement(line);
|
|
@@ -2321,7 +2996,7 @@ var Editor = class {
|
|
|
2321
2996
|
cornerEl.style.cssText = css;
|
|
2322
2997
|
overlayEls.delete(cacheKey);
|
|
2323
2998
|
} else cornerEl = h("div", {
|
|
2324
|
-
dataset: "selectionRange",
|
|
2999
|
+
dataset: type === "caretHighlight" ? "caretHighlightRange" : "selectionRange",
|
|
2325
3000
|
style: { cssText: css },
|
|
2326
3001
|
children: [h("div", { dataset })]
|
|
2327
3002
|
}, renderCtx.fragment);
|
|
@@ -2366,6 +3041,14 @@ var Editor = class {
|
|
|
2366
3041
|
dataset.rbl = "";
|
|
2367
3042
|
dataset.rbr = "";
|
|
2368
3043
|
}
|
|
3044
|
+
if (connectedCaretEdge?.start === true) {
|
|
3045
|
+
delete dataset.rtl;
|
|
3046
|
+
delete dataset.rbl;
|
|
3047
|
+
}
|
|
3048
|
+
if (connectedCaretEdge?.end === true) {
|
|
3049
|
+
delete dataset.rtr;
|
|
3050
|
+
delete dataset.rbr;
|
|
3051
|
+
}
|
|
2369
3052
|
};
|
|
2370
3053
|
let rangeEl = renderCtx.elements.get(cacheKey);
|
|
2371
3054
|
if (rangeEl !== void 0) {
|
|
@@ -2378,6 +3061,10 @@ var Editor = class {
|
|
|
2378
3061
|
} else rangeEl = h("div", { dataset: extraDataset ? [type + "Range", extraDataset] : type + "Range" }, renderCtx.fragment);
|
|
2379
3062
|
rangeEl.style.width = `${width}px`;
|
|
2380
3063
|
rangeEl.style.transform = `translateX(${left}px) translateY(${y}px)`;
|
|
3064
|
+
if (type === "editPredictionInsertion" || type === "editPredictionReplacement") {
|
|
3065
|
+
const lineElement = this.#getLineElement(line);
|
|
3066
|
+
if (lineElement !== void 0) rangeEl.style.setProperty("--diffs-edit-prediction-bg", getComputedStyle(lineElement).getPropertyValue("--diffs-line-bg"));
|
|
3067
|
+
} else rangeEl.style.removeProperty("--diffs-edit-prediction-bg");
|
|
2381
3068
|
if (rounded) addRadiusStyle(rangeEl);
|
|
2382
3069
|
renderCtx.elements.set(cacheKey, rangeEl);
|
|
2383
3070
|
}
|
|
@@ -2400,7 +3087,7 @@ var Editor = class {
|
|
|
2400
3087
|
#updateSelectionActionPopover() {
|
|
2401
3088
|
const primarySelection = this.#selections?.at(-1);
|
|
2402
3089
|
const overlayElement = this.#overlayElement;
|
|
2403
|
-
const textDocument = this.#
|
|
3090
|
+
const textDocument = this.#editSession?.document;
|
|
2404
3091
|
const renderSelectionAction = this.#options.renderSelectionAction;
|
|
2405
3092
|
const cleanup = () => {
|
|
2406
3093
|
this.#selectionAction?.cleanup();
|
|
@@ -2424,7 +3111,7 @@ var Editor = class {
|
|
|
2424
3111
|
return getActiveSelection();
|
|
2425
3112
|
},
|
|
2426
3113
|
applyEdits: (edits) => this.applyEdits(edits),
|
|
2427
|
-
getSelectionText: () => this.#
|
|
3114
|
+
getSelectionText: () => this.#editSession?.document?.getText(getActiveSelection()) ?? "",
|
|
2428
3115
|
replaceSelectionText: (text) => {
|
|
2429
3116
|
this.#replaceSelectionText(text, [getActiveSelection()]);
|
|
2430
3117
|
},
|
|
@@ -2494,7 +3181,7 @@ var Editor = class {
|
|
|
2494
3181
|
}
|
|
2495
3182
|
#renderSearchPanel(mode) {
|
|
2496
3183
|
this.#searchPanel?.cleanup();
|
|
2497
|
-
const textDocument = this.#
|
|
3184
|
+
const textDocument = this.#editSession?.document;
|
|
2498
3185
|
const preElement = this.#fileContainer?.shadowRoot?.querySelector("pre");
|
|
2499
3186
|
const selections = this.#selections;
|
|
2500
3187
|
if (textDocument === void 0 || preElement == null) return;
|
|
@@ -2577,13 +3264,13 @@ var Editor = class {
|
|
|
2577
3264
|
this.#retainSearchPanelFocus = false;
|
|
2578
3265
|
}
|
|
2579
3266
|
#getSelectionText() {
|
|
2580
|
-
const textDocument = this.#
|
|
3267
|
+
const textDocument = this.#editSession?.document;
|
|
2581
3268
|
const selections = this.#selections;
|
|
2582
3269
|
if (textDocument === void 0 || selections === void 0) return "";
|
|
2583
3270
|
return getSelectionText(textDocument, selections);
|
|
2584
3271
|
}
|
|
2585
3272
|
#getSelectionClipboardTexts() {
|
|
2586
|
-
const textDocument = this.#
|
|
3273
|
+
const textDocument = this.#editSession?.document;
|
|
2587
3274
|
const selections = this.#selections;
|
|
2588
3275
|
if (textDocument === void 0 || selections === void 0) return [];
|
|
2589
3276
|
return getSelectionClipboardTexts(textDocument, selections);
|
|
@@ -2595,7 +3282,7 @@ var Editor = class {
|
|
|
2595
3282
|
if (selectionTexts.length > 1) clipboardData.setData(MULTI_SELECTION_CLIPBOARD_TYPE, JSON.stringify(selectionTexts));
|
|
2596
3283
|
}
|
|
2597
3284
|
#cutSelectionText() {
|
|
2598
|
-
const textDocument = this.#
|
|
3285
|
+
const textDocument = this.#editSession?.document;
|
|
2599
3286
|
const selections = this.#selections;
|
|
2600
3287
|
if (textDocument === void 0 || selections === void 0 || selections.length === 0) return "";
|
|
2601
3288
|
if (selections.some((selection) => isCollapsedSelection(selection))) {
|
|
@@ -2608,7 +3295,7 @@ var Editor = class {
|
|
|
2608
3295
|
return text;
|
|
2609
3296
|
}
|
|
2610
3297
|
#applySelectionCutEdits(edits, nextSelectionOffsets) {
|
|
2611
|
-
const textDocument = this.#
|
|
3298
|
+
const textDocument = this.#editSession?.document;
|
|
2612
3299
|
const selections = this.#selections;
|
|
2613
3300
|
if (textDocument === void 0 || selections === void 0 || edits.length === 0) return;
|
|
2614
3301
|
const change = textDocument.applyResolvedEdits(edits, true, selections, void 0, true);
|
|
@@ -2626,7 +3313,7 @@ var Editor = class {
|
|
|
2626
3313
|
}
|
|
2627
3314
|
#replaceSelectionText(text, selections = this.#selections, undoBoundary = false, textOrder = "selection") {
|
|
2628
3315
|
if (selections === void 0) return;
|
|
2629
|
-
const textDocument = this.#
|
|
3316
|
+
const textDocument = this.#editSession?.document;
|
|
2630
3317
|
const primarySelection = selections.at(-1);
|
|
2631
3318
|
if (textDocument === void 0 || primarySelection === void 0) return;
|
|
2632
3319
|
const { nextSelections, change } = Array.isArray(text) && text.length === selections.length ? applyTextReplaceToSelections(textDocument, selections, text, this.#lineAnnotations, undoBoundary, textOrder) : applyTextChangeToSelections(textDocument, selections, {
|
|
@@ -2638,14 +3325,14 @@ var Editor = class {
|
|
|
2638
3325
|
}
|
|
2639
3326
|
#deleteSelectionText(forward = false) {
|
|
2640
3327
|
const selections = this.#selections;
|
|
2641
|
-
const textDocument = this.#
|
|
3328
|
+
const textDocument = this.#editSession?.document;
|
|
2642
3329
|
if (selections === void 0 || textDocument === void 0) return;
|
|
2643
3330
|
const { nextSelections, change } = applyDeleteCharacterToSelections(textDocument, selections, forward, this.#lineAnnotations, this.#metrics.tabSize);
|
|
2644
3331
|
if (change !== void 0) this.#applyChange(change, nextSelections, this.#applyChangeToLineAnnotations(change));
|
|
2645
3332
|
}
|
|
2646
3333
|
#deleteSoftLineBackward() {
|
|
2647
3334
|
const selections = this.#selections;
|
|
2648
|
-
const textDocument = this.#
|
|
3335
|
+
const textDocument = this.#editSession?.document;
|
|
2649
3336
|
if (selections === void 0 || textDocument === void 0) return;
|
|
2650
3337
|
const { nextSelections, change } = applyDeleteSoftLineBackwardToSelections(textDocument, selections, this.#isWrap ? (line, character) => {
|
|
2651
3338
|
const wrapOffsets = this.#wrapLineTextOrWholeLine(line);
|
|
@@ -2660,35 +3347,33 @@ var Editor = class {
|
|
|
2660
3347
|
}
|
|
2661
3348
|
#deleteWordBackward() {
|
|
2662
3349
|
const selections = this.#selections;
|
|
2663
|
-
const textDocument = this.#
|
|
3350
|
+
const textDocument = this.#editSession?.document;
|
|
2664
3351
|
if (selections === void 0 || textDocument === void 0) return;
|
|
2665
3352
|
const { nextSelections, change } = applyDeleteWordBackwardToSelections(textDocument, selections, this.#lineAnnotations);
|
|
2666
3353
|
if (change !== void 0) this.#applyChange(change, nextSelections, this.#applyChangeToLineAnnotations(change));
|
|
2667
3354
|
}
|
|
2668
3355
|
#deleteHardLineForward() {
|
|
2669
3356
|
const selections = this.#selections;
|
|
2670
|
-
const textDocument = this.#
|
|
3357
|
+
const textDocument = this.#editSession?.document;
|
|
2671
3358
|
if (selections === void 0 || textDocument === void 0) return;
|
|
2672
3359
|
const { nextSelections, change } = applyDeleteHardLineForwardToSelections(textDocument, selections, this.#lineAnnotations);
|
|
2673
3360
|
if (change !== void 0) this.#applyChange(change, nextSelections, this.#applyChangeToLineAnnotations(change));
|
|
2674
3361
|
}
|
|
2675
3362
|
#insertTranspose() {
|
|
2676
3363
|
const selections = this.#selections;
|
|
2677
|
-
const textDocument = this.#
|
|
3364
|
+
const textDocument = this.#editSession?.document;
|
|
2678
3365
|
if (selections === void 0 || textDocument === void 0) return;
|
|
2679
3366
|
const { nextSelections, change } = applyTransposeToSelections(textDocument, selections, this.#lineAnnotations);
|
|
2680
3367
|
if (change !== void 0) this.#applyChange(change, nextSelections, this.#applyChangeToLineAnnotations(change));
|
|
2681
3368
|
}
|
|
2682
3369
|
#applyChange(change, newSelections, newLineAnnotations, options) {
|
|
2683
|
-
|
|
2684
|
-
const
|
|
2685
|
-
if (
|
|
2686
|
-
|
|
2687
|
-
|
|
2688
|
-
|
|
2689
|
-
|
|
2690
|
-
lineAnnotations
|
|
2691
|
-
});
|
|
3370
|
+
if (this.#editPrediction != null) this.#cancelEditPrediction(true);
|
|
3371
|
+
const textDocument = this.#editSession?.document;
|
|
3372
|
+
if (textDocument !== void 0 && this.#carets !== void 0) for (const trackedCaret of this.#carets) {
|
|
3373
|
+
trackedCaret.anchorOffset = remapOffsetThroughEdits(trackedCaret.anchorOffset, change.changes);
|
|
3374
|
+
trackedCaret.focusOffset = remapOffsetThroughEdits(trackedCaret.focusOffset, change.changes);
|
|
3375
|
+
trackedCaret.caret.anchor = textDocument.positionAt(trackedCaret.anchorOffset);
|
|
3376
|
+
trackedCaret.caret.focus = textDocument.positionAt(trackedCaret.focusOffset);
|
|
2692
3377
|
}
|
|
2693
3378
|
if (change.lineDelta !== 0 || this.#isWrap) {
|
|
2694
3379
|
for (const line of this.#lineYCache.keys()) if (line >= change.startLine) this.#lineYCache.delete(line);
|
|
@@ -2717,9 +3402,13 @@ var Editor = class {
|
|
|
2717
3402
|
}
|
|
2718
3403
|
}
|
|
2719
3404
|
this.#rerender(change, newLineAnnotations, renderRange, shouldUpdateBuffer);
|
|
3405
|
+
if (newSelections != null) this.#updateSelections(newSelections);
|
|
3406
|
+
this.#checkpointEditSessionState();
|
|
3407
|
+
this.#recordEditPredictionHistory(change, options?.editSource ?? "user");
|
|
3408
|
+
this.#scheduleEditPrediction();
|
|
3409
|
+
this.#emitChange(change.changes, newLineAnnotations ?? this.#lineAnnotations);
|
|
2720
3410
|
if (options?.skipSearchRefresh !== true && this.#searchPanel !== void 0 && this.#matches !== void 0) this.#searchPanel.updateMatches({ syncSelection: false });
|
|
2721
|
-
if (newSelections
|
|
2722
|
-
this.#updateSelections(newSelections);
|
|
3411
|
+
if (newSelections != null) {
|
|
2723
3412
|
if (options?.skipFocus !== true) {
|
|
2724
3413
|
const revealTarget = newSelections.at(-1);
|
|
2725
3414
|
if (revealTarget !== void 0) this.#revealLineIfCollapsed(getCaretPosition(revealTarget).line);
|
|
@@ -2737,11 +3426,17 @@ var Editor = class {
|
|
|
2737
3426
|
}
|
|
2738
3427
|
}
|
|
2739
3428
|
}
|
|
3429
|
+
#emitChange(changes, lineAnnotations) {
|
|
3430
|
+
const file = this.getFile();
|
|
3431
|
+
const publishChange = this.#publishChange;
|
|
3432
|
+
if (file == null || publishChange == null) return;
|
|
3433
|
+
publishChange(changes, file, lineAnnotations);
|
|
3434
|
+
}
|
|
2740
3435
|
#applyChangeToLineAnnotations(change) {
|
|
2741
|
-
if (this.#lineAnnotations
|
|
3436
|
+
if (this.#lineAnnotations != null) {
|
|
2742
3437
|
const nextLineAnnotations = applyDocumentChangeToLineAnnotations(change, this.#lineAnnotations);
|
|
2743
|
-
if (nextLineAnnotations
|
|
2744
|
-
this.#
|
|
3438
|
+
if (nextLineAnnotations != null) {
|
|
3439
|
+
this.#editSession?.document?.setLastUndoLineAnnotations(this.#lineAnnotations, nextLineAnnotations);
|
|
2745
3440
|
return nextLineAnnotations;
|
|
2746
3441
|
}
|
|
2747
3442
|
}
|
|
@@ -2762,11 +3457,15 @@ var Editor = class {
|
|
|
2762
3457
|
}
|
|
2763
3458
|
return ranges;
|
|
2764
3459
|
}
|
|
3460
|
+
#isLineInRenderRange(line) {
|
|
3461
|
+
const renderRange = this.#renderRange;
|
|
3462
|
+
return renderRange == null || line >= renderRange.startingLine && line < renderRange.startingLine + renderRange.totalLines;
|
|
3463
|
+
}
|
|
2765
3464
|
#getLineElement(line) {
|
|
2766
3465
|
let lineElement = this.#lineElementsCache.get(line);
|
|
2767
3466
|
if (lineElement !== void 0) return lineElement ?? void 0;
|
|
2768
3467
|
const renderRange = this.#renderRange;
|
|
2769
|
-
if (
|
|
3468
|
+
if (!this.#isLineInRenderRange(line)) return;
|
|
2770
3469
|
const contentElement = this.#contentElement;
|
|
2771
3470
|
if (contentElement === void 0) return;
|
|
2772
3471
|
if (renderRange !== void 0) {
|
|
@@ -2817,7 +3516,7 @@ var Editor = class {
|
|
|
2817
3516
|
}
|
|
2818
3517
|
#getCharX(line, char) {
|
|
2819
3518
|
if (this.#lastAccessedCharX !== void 0 && this.#lastAccessedCharX[0] === line && this.#lastAccessedCharX[1] === char) return [this.#lastAccessedCharX[2], this.#lastAccessedCharX[3]];
|
|
2820
|
-
const lineText = this.#
|
|
3519
|
+
const lineText = this.#editSession?.document?.getLineText(line);
|
|
2821
3520
|
const offsetLeft = this.#getGutterWidth() + this.#metrics.ch;
|
|
2822
3521
|
if (lineText === void 0 || lineText.length === 0 || char <= 0) return [offsetLeft + (this.#activeContentOffset?.left ?? 0), 0];
|
|
2823
3522
|
const boundedCharacter = snapTextOffsetToUnicodeBoundary(lineText, Math.min(char, lineText.length));
|
|
@@ -2863,7 +3562,7 @@ var Editor = class {
|
|
|
2863
3562
|
const cachedOffsets = this.#wrapLineOffsetsCache.get(line);
|
|
2864
3563
|
if (cachedOffsets !== void 0) return cachedOffsets;
|
|
2865
3564
|
if (this.#wrapLineOffsetsCache.size >= MAX_WRAP_OFFSETS_CACHE_LINES) this.#wrapLineOffsetsCache.clear();
|
|
2866
|
-
const lineText = this.#
|
|
3565
|
+
const lineText = this.#editSession?.document?.getLineText(line);
|
|
2867
3566
|
if (lineText === void 0 || lineText.length === 0) {
|
|
2868
3567
|
const offsets = new Uint32Array([0]);
|
|
2869
3568
|
this.#wrapLineOffsetsCache.set(line, offsets);
|
|
@@ -2901,7 +3600,8 @@ var Editor = class {
|
|
|
2901
3600
|
const measureGrapheme = (index) => {
|
|
2902
3601
|
range.setStart(textNode, graphemeStart(index));
|
|
2903
3602
|
range.setEnd(textNode, graphemeStart(index + 1));
|
|
2904
|
-
|
|
3603
|
+
const clientRects = range.getClientRects();
|
|
3604
|
+
return clientRects.item(clientRects.length - 1) ?? range.getBoundingClientRect();
|
|
2905
3605
|
};
|
|
2906
3606
|
starts.push(0);
|
|
2907
3607
|
let lastTop = measureGrapheme(0).top;
|
|
@@ -2933,7 +3633,7 @@ var Editor = class {
|
|
|
2933
3633
|
#wrapLineTextOrWholeLine(line) {
|
|
2934
3634
|
const offsets = this.#wrapLineText(line);
|
|
2935
3635
|
if (offsets !== void 0) return offsets;
|
|
2936
|
-
const length = this.#
|
|
3636
|
+
const length = this.#editSession?.document?.getLineText(line)?.length ?? 0;
|
|
2937
3637
|
return Uint32Array.of(0, length);
|
|
2938
3638
|
}
|
|
2939
3639
|
#rangeBelongsToEditor({ startContainer, endContainer }) {
|
|
@@ -2942,11 +3642,31 @@ var Editor = class {
|
|
|
2942
3642
|
return contentEl.contains(startContainer) && contentEl.contains(endContainer);
|
|
2943
3643
|
}
|
|
2944
3644
|
#isLineVisible(line) {
|
|
2945
|
-
const lineCount = this.#
|
|
3645
|
+
const lineCount = this.#editSession?.document?.lineCount ?? 0;
|
|
2946
3646
|
if (line < 0 || line >= lineCount) return false;
|
|
2947
3647
|
return this.#getLineElement(line) !== void 0;
|
|
2948
3648
|
}
|
|
2949
3649
|
};
|
|
3650
|
+
function getEditSession({ type, editStateKey, owner, initialState, previousSession }) {
|
|
3651
|
+
if (initialState != null && initialState.type !== type) throw new TypeError(`Editor: initialState: a ${initialState.type} state cannot initialize a ${type} editor`);
|
|
3652
|
+
const initialSession = initialState;
|
|
3653
|
+
if (editStateKey != null) return EditStateManager.activate(type, editStateKey, owner, initialSession);
|
|
3654
|
+
if (initialSession != null) return initialSession;
|
|
3655
|
+
if (previousSession != null) return previousSession;
|
|
3656
|
+
return type === "file" ? { type: "file" } : { type: "file-diff" };
|
|
3657
|
+
}
|
|
3658
|
+
function gridTrackSpan(child) {
|
|
3659
|
+
if (!(child instanceof HTMLElement)) return 1;
|
|
3660
|
+
return Number(child.dataset.bufferSize ?? 1);
|
|
3661
|
+
}
|
|
3662
|
+
function isValidEditPredictionPosition(document, position) {
|
|
3663
|
+
return position !== void 0 && Number.isInteger(position.line) && Number.isInteger(position.character) && position.line >= 0 && position.line < document.lineCount && position.character >= 0 && position.character <= document.getLineLength(position.line);
|
|
3664
|
+
}
|
|
3665
|
+
function splitsSurrogatePair(text, offset) {
|
|
3666
|
+
const previous = text.charCodeAt(offset - 1);
|
|
3667
|
+
const next = text.charCodeAt(offset);
|
|
3668
|
+
return offset > 0 && offset < text.length && previous >= 55296 && previous <= 56319 && next >= 56320 && next <= 57343;
|
|
3669
|
+
}
|
|
2950
3670
|
//#endregion
|
|
2951
3671
|
export { Editor };
|
|
2952
3672
|
|