@pierre/diffs 1.3.6 → 1.4.1
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 +115 -68
- package/dist/components/CodeView.d.ts.map +1 -1
- package/dist/components/CodeView.js +189 -59
- package/dist/components/CodeView.js.map +1 -1
- package/dist/components/File.d.ts +79 -15
- package/dist/components/File.d.ts.map +1 -1
- package/dist/components/File.js +244 -66
- package/dist/components/File.js.map +1 -1
- package/dist/components/FileDiff.d.ts +101 -21
- package/dist/components/FileDiff.d.ts.map +1 -1
- package/dist/components/FileDiff.js +432 -102
- package/dist/components/FileDiff.js.map +1 -1
- package/dist/components/FileStream.js +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 +17 -7
- package/dist/components/VirtualizedFile.d.ts.map +1 -1
- package/dist/components/VirtualizedFile.js +142 -53
- package/dist/components/VirtualizedFile.js.map +1 -1
- package/dist/components/VirtualizedFileDiff.d.ts +15 -8
- package/dist/components/VirtualizedFileDiff.d.ts.map +1 -1
- package/dist/components/VirtualizedFileDiff.js +186 -96
- 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 +1108 -384
- 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/highlighter/shared_highlighter.d.ts +6 -2
- package/dist/highlighter/shared_highlighter.d.ts.map +1 -1
- package/dist/highlighter/shared_highlighter.js +7 -3
- package/dist/highlighter/shared_highlighter.js.map +1 -1
- package/dist/highlighter/themes/areThemesAttached.js +1 -1
- package/dist/index.d.ts +8 -6
- package/dist/index.js +22 -21
- 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 -109
- 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 +141 -67
- 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 +44 -6
- 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,168 @@ 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
|
+
fileInstance.__acceptEditorChange(event);
|
|
269
|
+
editor.#options.onChange?.(event);
|
|
270
|
+
fileInstance.emitEditChange(event);
|
|
271
|
+
};
|
|
272
|
+
if (this.#detach == null) this.#detach = fileInstance.__attachEditor(editor);
|
|
273
|
+
else fileInstance.__resumeEditor(editor);
|
|
274
|
+
} else if (fileInstance.type === "file-diff" && editor.type === "file-diff") {
|
|
275
|
+
editor.#applyDocumentChange = fileInstance.applyDocumentChange.bind(fileInstance);
|
|
276
|
+
editor.#publishChange = (changes, file, lineAnnotations) => {
|
|
277
|
+
const event = {
|
|
278
|
+
changes,
|
|
279
|
+
file,
|
|
280
|
+
editor,
|
|
281
|
+
lineAnnotations
|
|
282
|
+
};
|
|
283
|
+
fileInstance.__acceptEditorChange(event);
|
|
284
|
+
editor.#options.onChange?.(event);
|
|
285
|
+
fileInstance.emitEditChange(event);
|
|
286
|
+
};
|
|
287
|
+
if (this.#detach == null) this.#detach = fileInstance.__attachEditor(editor);
|
|
288
|
+
else fileInstance.__resumeEditor(editor);
|
|
289
|
+
} else throw new Error("Editor.edit: Impossible edit state");
|
|
290
|
+
} catch (error) {
|
|
291
|
+
this.cleanUp("recycle");
|
|
292
|
+
if (editSession.type === "file-diff" && editSession.diffSession == null) editSession.diffSession = previousDiffSession;
|
|
293
|
+
if (this.#detach == null && editStateKey != null) if (editor.type === "file") EditStateManager.releaseFile(editStateKey, editor);
|
|
294
|
+
else EditStateManager.releaseFileDiff(editStateKey, editor);
|
|
295
|
+
this.#editSession = previousSession;
|
|
296
|
+
if (this.#detach == null) {
|
|
297
|
+
this.#fileInstance = void 0;
|
|
298
|
+
this.#applyDocumentChange = void 0;
|
|
299
|
+
this.#publishChange = void 0;
|
|
300
|
+
}
|
|
301
|
+
if (initialState != null && initialEditorState != null) initialState.editor = initialEditorState;
|
|
302
|
+
this.#initialState = initialState;
|
|
303
|
+
throw error;
|
|
304
|
+
}
|
|
305
|
+
return () => {
|
|
306
|
+
this.cleanUp("complete");
|
|
307
|
+
};
|
|
165
308
|
}
|
|
166
309
|
/**
|
|
167
310
|
* Apply edits to current attached file. Every edit joins the undo timeline:
|
|
@@ -174,8 +317,8 @@ var Editor = class {
|
|
|
174
317
|
* are remapped during replay and the text edit still joins the undo timeline.
|
|
175
318
|
*/
|
|
176
319
|
applyEdits(edits, updateHistory = true) {
|
|
177
|
-
const textDocument = this.#
|
|
178
|
-
if (textDocument == null) throw new Error("Editor is not attached");
|
|
320
|
+
const textDocument = this.#editSession?.document;
|
|
321
|
+
if (textDocument == null) throw new Error("Editor.applyEdits: Editor is not attached");
|
|
179
322
|
const wasFocused = this.#contentHasFocus;
|
|
180
323
|
const selectionsBefore = this.#selections;
|
|
181
324
|
const selectionOffsetsBefore = selectionsBefore?.map((selection) => [textDocument.offsetAt(selection.start), textDocument.offsetAt(selection.end)]);
|
|
@@ -191,11 +334,11 @@ var Editor = class {
|
|
|
191
334
|
}
|
|
192
335
|
/** Whether there is an edit to undo. */
|
|
193
336
|
get canUndo() {
|
|
194
|
-
return this.#
|
|
337
|
+
return (this.#editSession ?? this.#initialState)?.document?.canUndo ?? false;
|
|
195
338
|
}
|
|
196
339
|
/** Whether there is an undone edit to redo. */
|
|
197
340
|
get canRedo() {
|
|
198
|
-
return this.#
|
|
341
|
+
return (this.#editSession ?? this.#initialState)?.document?.canRedo ?? false;
|
|
199
342
|
}
|
|
200
343
|
/** Undo the last edit. Does nothing when there is nothing to undo. */
|
|
201
344
|
undo() {
|
|
@@ -206,8 +349,9 @@ var Editor = class {
|
|
|
206
349
|
this.#runCommand("redo");
|
|
207
350
|
}
|
|
208
351
|
getFile() {
|
|
209
|
-
const
|
|
210
|
-
const
|
|
352
|
+
const editSession = this.#editSession ?? this.#initialState;
|
|
353
|
+
const fileInfo = editSession?.fileInfo;
|
|
354
|
+
const textDocument = editSession?.document;
|
|
211
355
|
if (fileInfo === void 0 || textDocument === void 0) return;
|
|
212
356
|
const file = { ...fileInfo };
|
|
213
357
|
Object.defineProperty(file, "contents", {
|
|
@@ -217,32 +361,56 @@ var Editor = class {
|
|
|
217
361
|
return file;
|
|
218
362
|
}
|
|
219
363
|
getText() {
|
|
220
|
-
return this.#
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
|
|
364
|
+
return (this.#editSession ?? this.#initialState)?.document?.getText() ?? "";
|
|
365
|
+
}
|
|
366
|
+
/** Return an isolated copy of selections and restorable view state. */
|
|
367
|
+
getViewState() {
|
|
368
|
+
const fileInstance = this.#isRendering ? this.#fileInstance : void 0;
|
|
369
|
+
if (!this.#isRendering && this.#editSession?.editor != null) return cloneEditorViewState(this.#editSession.editor);
|
|
370
|
+
const selections = this.#selections?.map((selection) => ({
|
|
371
|
+
...selection,
|
|
372
|
+
start: { ...selection.start },
|
|
373
|
+
end: { ...selection.end }
|
|
374
|
+
}));
|
|
375
|
+
if (fileInstance == null) return { selections };
|
|
376
|
+
const viewport = this.#getOwnedVerticalViewport();
|
|
377
|
+
const scrollLeft = fileInstance.getCodeScrollLeft();
|
|
378
|
+
if (viewport == null) return {
|
|
379
|
+
selections,
|
|
380
|
+
view: { scrollLeft }
|
|
381
|
+
};
|
|
224
382
|
return {
|
|
225
|
-
selections
|
|
226
|
-
view:
|
|
227
|
-
scrollLeft
|
|
228
|
-
scrollTop:
|
|
229
|
-
}
|
|
383
|
+
selections,
|
|
384
|
+
view: {
|
|
385
|
+
scrollLeft,
|
|
386
|
+
scrollTop: viewport.scrollTop
|
|
387
|
+
}
|
|
230
388
|
};
|
|
231
389
|
}
|
|
232
|
-
|
|
233
|
-
|
|
390
|
+
/**
|
|
391
|
+
* Return the objects that make up the active edit session, or undefined when
|
|
392
|
+
* no complete session exists.
|
|
393
|
+
*/
|
|
394
|
+
getEditState() {
|
|
395
|
+
const editSession = this.#editSession;
|
|
396
|
+
if (editSession == null) return;
|
|
397
|
+
if (this.#fileInstance == null) throw new Error(`Editor.getEditState: active ${this.type} session has no component`);
|
|
398
|
+
return toManagedEditState(editSession);
|
|
399
|
+
}
|
|
400
|
+
setViewState({ selections, view }) {
|
|
401
|
+
if (!this.#isRendering || this.#fileInstance === void 0 || this.#editSession?.document === void 0) throw new Error("Editor.setViewState: Editor is not attached");
|
|
234
402
|
this.#canMountSelectionAction = false;
|
|
235
403
|
this.#updateSelections(selections ?? []);
|
|
236
404
|
if (view != null) {
|
|
237
405
|
this.#fileInstance.setCodeScrollLeft(view.scrollLeft);
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
}
|
|
241
|
-
this.#
|
|
406
|
+
const viewport = this.#getOwnedVerticalViewport();
|
|
407
|
+
if (view.scrollTop !== void 0 && viewport != null) viewport.scrollTop = view.scrollTop;
|
|
408
|
+
} else if (this.#ownsVerticalViewport) this.#scrollToPrimaryCaret();
|
|
409
|
+
this.#checkpointEditSessionState();
|
|
242
410
|
}
|
|
243
411
|
setSelections(selections) {
|
|
244
|
-
const textDocument = this.#
|
|
245
|
-
if (textDocument === void 0) throw new Error("Text document is not initialized");
|
|
412
|
+
const textDocument = this.#editSession?.document;
|
|
413
|
+
if (textDocument === void 0) throw new Error("Editor.setSelections: Text document is not initialized");
|
|
246
414
|
const resolvedSelections = selections.map((selection) => {
|
|
247
415
|
let start = textDocument.normalizePosition(selection.start);
|
|
248
416
|
let end = textDocument.normalizePosition(selection.end);
|
|
@@ -264,8 +432,8 @@ var Editor = class {
|
|
|
264
432
|
this.#scrollToPrimaryCaret();
|
|
265
433
|
}
|
|
266
434
|
setMarkers(markers) {
|
|
267
|
-
const textDocument = this.#
|
|
268
|
-
if (textDocument === void 0) throw new Error("Text document is not initialized");
|
|
435
|
+
const textDocument = this.#editSession?.document;
|
|
436
|
+
if (textDocument === void 0) throw new Error("Editor.setMarkers: Text document is not initialized");
|
|
269
437
|
if (markers.length === 0) {
|
|
270
438
|
this.#markerRenderer?.cleanup();
|
|
271
439
|
this.#markerRenderer = void 0;
|
|
@@ -284,13 +452,14 @@ var Editor = class {
|
|
|
284
452
|
this.#markerRenderer.setMarkers(markers, textDocument);
|
|
285
453
|
if (this.#contentElement !== void 0) this.#markerRenderer.listenHover(this.#contentElement);
|
|
286
454
|
this.#updateSelections(this.#selections ?? []);
|
|
455
|
+
this.#renderCarets();
|
|
287
456
|
}
|
|
288
457
|
focus(options) {
|
|
289
458
|
const preventScroll = options?.preventScroll ?? false;
|
|
290
459
|
const lineNumber = options?.lineNumber;
|
|
291
460
|
if (lineNumber === "first-visible" || typeof lineNumber === "number") {
|
|
292
|
-
const textDocument = this.#
|
|
293
|
-
if (textDocument == null || this.#fileInstance == null) return;
|
|
461
|
+
const textDocument = this.#editSession?.document;
|
|
462
|
+
if (textDocument == null || !this.#isRendering || this.#fileInstance == null) return;
|
|
294
463
|
const targetLineNumber = lineNumber === "first-visible" ? this.#getFirstVisibleLineNumber(options?.offset) : lineNumber;
|
|
295
464
|
if (targetLineNumber == null) return;
|
|
296
465
|
const position = textDocument.normalizePosition({
|
|
@@ -312,27 +481,30 @@ var Editor = class {
|
|
|
312
481
|
this.#shouldIgnoreSelectionChange = false;
|
|
313
482
|
this.#contentElement?.blur();
|
|
314
483
|
}
|
|
315
|
-
cleanUp(
|
|
484
|
+
cleanUp(reason = "discard") {
|
|
485
|
+
const fileInstance = this.#fileInstance;
|
|
486
|
+
const recycle = reason === "recycle";
|
|
487
|
+
this.#cancelEditPrediction(true, false);
|
|
488
|
+
if (!recycle) this.#editPredictionHistory = [];
|
|
489
|
+
const editSession = this.#editSession;
|
|
490
|
+
if (fileInstance != null && editSession != null) {
|
|
491
|
+
const discardDiffState = !this.#checkpointEditSessionState();
|
|
492
|
+
if (!recycle) this.#releaseEditSession(discardDiffState);
|
|
493
|
+
}
|
|
316
494
|
this.#invalidateOnAttach();
|
|
317
495
|
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;
|
|
496
|
+
this.#isRendering = false;
|
|
323
497
|
dequeueRender(this.#handleCustomPasteEvent);
|
|
324
498
|
this.#tokenizer?.cleanUp();
|
|
325
499
|
this.#tokenizer = void 0;
|
|
326
|
-
if (!recycle) {
|
|
327
|
-
this.#textDocument = void 0;
|
|
328
|
-
this.#fileInfo = void 0;
|
|
329
|
-
}
|
|
330
500
|
this.#globalEventDisposes?.forEach((dispose) => dispose());
|
|
331
501
|
this.#globalEventDisposes = void 0;
|
|
332
502
|
this.#editorEventDisposes?.forEach((dispose) => dispose());
|
|
333
503
|
this.#editorEventDisposes = void 0;
|
|
334
|
-
|
|
335
|
-
|
|
504
|
+
if (!recycle) {
|
|
505
|
+
this.#detach?.();
|
|
506
|
+
this.#detach = void 0;
|
|
507
|
+
}
|
|
336
508
|
this.#gutterWidthCache = void 0;
|
|
337
509
|
this.#contentWidthCache = void 0;
|
|
338
510
|
this.#lineYCache.clear();
|
|
@@ -351,6 +523,7 @@ var Editor = class {
|
|
|
351
523
|
this.#popoverManager?.cleanUp();
|
|
352
524
|
this.#popoverManager = void 0;
|
|
353
525
|
this.#gutterElement = void 0;
|
|
526
|
+
this.#deletionsColumn = void 0;
|
|
354
527
|
this.#contentElement?.removeAttribute("contentEditable");
|
|
355
528
|
this.#contentElement = void 0;
|
|
356
529
|
this.#replacementFocusRequest = void 0;
|
|
@@ -364,25 +537,44 @@ var Editor = class {
|
|
|
364
537
|
cancelAnimationFrame(this.#themeSelectionRefreshFrame);
|
|
365
538
|
this.#themeSelectionRefreshFrame = void 0;
|
|
366
539
|
}
|
|
367
|
-
this.#resetState();
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
this.#
|
|
378
|
-
this.#
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
540
|
+
this.#resetState(recycle);
|
|
541
|
+
if (!recycle) try {
|
|
542
|
+
if (fileInstance != null && editSession != null) {
|
|
543
|
+
const editor = this.#getTypedEditor;
|
|
544
|
+
const mode = reason === "complete" ? "install" : "discard";
|
|
545
|
+
if (fileInstance.type === "file" && editor.type === "file") fileInstance.__completeEditSession(editor, mode);
|
|
546
|
+
else if (fileInstance.type === "file-diff" && editor.type === "file-diff") fileInstance.__completeEditSession(editor, mode);
|
|
547
|
+
else throw new Error("Editor.cleanUp: Impossible edit state");
|
|
548
|
+
}
|
|
549
|
+
} finally {
|
|
550
|
+
this.#editSession = void 0;
|
|
551
|
+
this.#fileInstance = void 0;
|
|
552
|
+
this.#applyDocumentChange = void 0;
|
|
553
|
+
this.#publishChange = void 0;
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
#checkpointEditSessionState() {
|
|
557
|
+
const fileInstance = this.#fileInstance;
|
|
558
|
+
const editSession = this.#editSession;
|
|
559
|
+
if (fileInstance == null || editSession == null) return false;
|
|
560
|
+
const editorState = this.#isRendering ? this.getViewState() : editSession.editor ?? {};
|
|
561
|
+
const { view } = editorState;
|
|
562
|
+
const hasNonDefaultView = view != null && (view.scrollLeft !== 0 || (view.scrollTop ?? 0) !== 0);
|
|
563
|
+
const hasEditorState = editorState.selections != null || hasNonDefaultView;
|
|
564
|
+
editSession.editor = cloneEditorViewState(editorState);
|
|
565
|
+
if (editSession.type === "file") return false;
|
|
566
|
+
const capturedDiffSession = fileInstance.__captureDocumentSessionState();
|
|
567
|
+
editSession.diffSession = capturedDiffSession?.diffSession;
|
|
568
|
+
if (capturedDiffSession == null) return false;
|
|
569
|
+
const document = editSession.document;
|
|
570
|
+
return capturedDiffSession.hasChanges || hasEditorState || document?.canUndo === true || document?.canRedo === true;
|
|
571
|
+
}
|
|
572
|
+
#releaseEditSession(discardDiffState = false) {
|
|
573
|
+
const editStateKey = this.#editStateKey;
|
|
574
|
+
if (editStateKey == null) return;
|
|
575
|
+
const editor = this.#getTypedEditor;
|
|
576
|
+
if (editor.type === "file") EditStateManager.releaseFile(editStateKey, editor);
|
|
577
|
+
else EditStateManager.releaseFileDiff(editStateKey, editor, discardDiffState);
|
|
386
578
|
}
|
|
387
579
|
/** @internal */
|
|
388
580
|
__postponeBgTokenizeToNextFrame() {
|
|
@@ -401,9 +593,39 @@ var Editor = class {
|
|
|
401
593
|
if (contentElement != null && (this.#contentHasFocus || shadowActiveElement === contentElement || shadowActiveElement != null && contentElement.contains(shadowActiveElement))) this.#replacementFocusRequest = {};
|
|
402
594
|
}
|
|
403
595
|
/** @internal */
|
|
404
|
-
|
|
596
|
+
__getDocumentContents(fallbackFile) {
|
|
597
|
+
const fileInfo = this.#editSession?.fileInfo;
|
|
598
|
+
const textDocument = this.#editSession?.document;
|
|
599
|
+
if (textDocument == null) return fileInfo == null || fallbackFile == null ? void 0 : {
|
|
600
|
+
...fileInfo,
|
|
601
|
+
contents: fallbackFile.contents
|
|
602
|
+
};
|
|
603
|
+
const resolvedFileInfo = fileInfo ?? fallbackFile;
|
|
604
|
+
if (resolvedFileInfo == null) return;
|
|
605
|
+
return {
|
|
606
|
+
name: resolvedFileInfo.name,
|
|
607
|
+
lang: resolvedFileInfo.lang,
|
|
608
|
+
contents: textDocument.getText()
|
|
609
|
+
};
|
|
610
|
+
}
|
|
611
|
+
/** @internal */
|
|
612
|
+
__getDocumentSessionState() {
|
|
613
|
+
const snapshot = this.#editSession?.diffSession;
|
|
614
|
+
return snapshot != null ? cloneRetainedDiffSessionSnapshot(snapshot) : void 0;
|
|
615
|
+
}
|
|
616
|
+
/** @internal */
|
|
617
|
+
__syncRenderView(props) {
|
|
618
|
+
const { highlighter, fileContainer, renderRange, externalDocument = false } = props;
|
|
619
|
+
const renderView = props;
|
|
620
|
+
let fileOrDiff;
|
|
621
|
+
if ("file" in renderView && this.type === "file") fileOrDiff = renderView.file;
|
|
622
|
+
else if ("fileDiff" in renderView && this.type === "file-diff") fileOrDiff = renderView.fileDiff;
|
|
623
|
+
else throw new Error("Editor.__syncRenderView: Impossible render state");
|
|
624
|
+
const lineAnnotations = renderView.lineAnnotations;
|
|
625
|
+
const editStateKey = this.#editStateKey;
|
|
405
626
|
const fileInstance = this.#fileInstance;
|
|
406
|
-
|
|
627
|
+
const editSession = this.#editSession;
|
|
628
|
+
if (!this.#isRendering || fileInstance == null || editSession == null) return;
|
|
407
629
|
const shadowRoot = fileContainer.shadowRoot;
|
|
408
630
|
if (shadowRoot == null) {
|
|
409
631
|
console.error("[editor] Could not find the shadow root.");
|
|
@@ -412,16 +634,26 @@ var Editor = class {
|
|
|
412
634
|
let codeElement;
|
|
413
635
|
let gutterEl;
|
|
414
636
|
let contentEl;
|
|
415
|
-
|
|
416
|
-
|
|
637
|
+
let deletionsGutterEl;
|
|
638
|
+
let deletionsContentEl;
|
|
639
|
+
for (const el of shadowRoot.querySelectorAll("[data-code]")) {
|
|
640
|
+
const isDeletions = el.dataset.deletions != null;
|
|
641
|
+
if (!isDeletions) codeElement = el;
|
|
417
642
|
for (const child of el.children) {
|
|
418
|
-
|
|
419
|
-
const { gutter, content } =
|
|
420
|
-
if (gutter
|
|
421
|
-
else
|
|
643
|
+
if (!(child instanceof HTMLElement)) continue;
|
|
644
|
+
const { gutter, content } = child.dataset;
|
|
645
|
+
if (gutter != null) if (isDeletions) deletionsGutterEl = child;
|
|
646
|
+
else gutterEl = child;
|
|
647
|
+
else if (content != null) if (isDeletions) deletionsContentEl = child;
|
|
648
|
+
else contentEl = child;
|
|
422
649
|
}
|
|
423
|
-
break;
|
|
424
650
|
}
|
|
651
|
+
if (deletionsContentEl == null) this.#deletionsColumn = void 0;
|
|
652
|
+
else if (deletionsGutterEl == null) throw new Error("Editor.__syncRenderView: the deletions column has no gutter");
|
|
653
|
+
else this.#deletionsColumn = {
|
|
654
|
+
content: deletionsContentEl,
|
|
655
|
+
gutter: deletionsGutterEl
|
|
656
|
+
};
|
|
425
657
|
if (codeElement === void 0 || contentEl === void 0) {
|
|
426
658
|
this.#replacementFocusRequest = void 0;
|
|
427
659
|
return;
|
|
@@ -434,45 +666,45 @@ var Editor = class {
|
|
|
434
666
|
if (this.#themeStyleElement !== void 0) shadowRoot.appendChild(this.#themeStyleElement);
|
|
435
667
|
if (this.#spriteElement !== void 0) shadowRoot.prepend(this.#spriteElement);
|
|
436
668
|
}
|
|
437
|
-
const
|
|
438
|
-
const
|
|
439
|
-
|
|
440
|
-
|
|
669
|
+
const languageId = fileOrDiff.lang ?? getFiletypeFromFileName(fileOrDiff.name);
|
|
670
|
+
const contents = "contents" in fileOrDiff ? fileOrDiff.contents : fileOrDiff.additionLines.join("");
|
|
671
|
+
const previousTextDocument = editSession.document;
|
|
672
|
+
const resetHistory = props.resetHistory ?? (previousTextDocument != null && editSession.fileInfo != null && (editSession.fileInfo.name !== fileOrDiff.name || previousTextDocument.languageId !== languageId));
|
|
673
|
+
const documentChanges = externalDocument && previousTextDocument !== void 0 && previousTextDocument.getText() !== contents ? [createFullDocumentChange(previousTextDocument.getText(), contents)] : void 0;
|
|
674
|
+
const resetForExternalDocument = externalDocument && resetHistory;
|
|
675
|
+
if (editSession.document == null || editSession.fileInfo == null || editStateKey == null && (editSession.fileInfo.name !== fileOrDiff.name || editSession.document.languageId !== languageId) || resetForExternalDocument) {
|
|
676
|
+
this.#cancelEditPrediction(true);
|
|
677
|
+
this.#editPredictionHistory = [];
|
|
441
678
|
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 = {
|
|
679
|
+
const { name, lang } = fileOrDiff;
|
|
680
|
+
let textDocument = resetForExternalDocument || editStateKey == null && editSession.fileInfo != null ? void 0 : editSession.document;
|
|
681
|
+
if (previousTextDocument != null && textDocument == null) editSession.editor = void 0;
|
|
682
|
+
if (textDocument == null) {
|
|
683
|
+
const editStack = new EditStack({ maxEntries: this.#options.historyMaxEntries });
|
|
684
|
+
textDocument = new TextDocument(fileOrDiff.name, contents, languageId, 0, editStack);
|
|
685
|
+
}
|
|
686
|
+
editSession.fileInfo = {
|
|
452
687
|
name,
|
|
453
|
-
lang
|
|
454
|
-
cacheKey
|
|
688
|
+
lang
|
|
455
689
|
};
|
|
456
|
-
|
|
457
|
-
if (
|
|
458
|
-
this.#textDocumentCache.set(persistedCacheKey, textDocument);
|
|
459
|
-
persistedStateTarget = {
|
|
460
|
-
cacheKey: persistedCacheKey,
|
|
461
|
-
textDocument
|
|
462
|
-
};
|
|
463
|
-
}
|
|
690
|
+
editSession.document = textDocument;
|
|
691
|
+
if (resetForExternalDocument) editSession.diffSession = void 0;
|
|
464
692
|
this.#tokenizer?.cleanUp();
|
|
465
693
|
this.#tokenizer = void 0;
|
|
466
694
|
this.#resetState();
|
|
467
695
|
this.#wrapLineOffsetsCache.clear();
|
|
468
696
|
this.#selections = this.#initSelections;
|
|
469
|
-
if (this.#options.__debug === true) console.log(
|
|
697
|
+
if (this.#options.__debug === true) console.log("[diffs/editor] text document initialized from", fileOrDiff.name);
|
|
470
698
|
}
|
|
471
|
-
if (
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
699
|
+
if (externalDocument && !resetForExternalDocument) {
|
|
700
|
+
this.#applyExternalDocumentReplacement(editSession, contents, lineAnnotations);
|
|
701
|
+
const { name, lang } = fileOrDiff;
|
|
702
|
+
editSession.fileInfo = {
|
|
703
|
+
name,
|
|
704
|
+
lang
|
|
705
|
+
};
|
|
706
|
+
}
|
|
707
|
+
const textDocument = editSession.document;
|
|
476
708
|
if (this.#tokenizer == null && textDocument != null) this.#tokenizer = new EditorTokenizer({
|
|
477
709
|
highlighter,
|
|
478
710
|
textDocument,
|
|
@@ -516,178 +748,87 @@ var Editor = class {
|
|
|
516
748
|
this.#renderRange = renderRange;
|
|
517
749
|
this.#viewportWindowLines = renderRange?.totalLines;
|
|
518
750
|
this.#tokenizer?.prebuildStateStack(renderRange);
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
if (this.#initSelections !== void 0 && this.#primaryCaretElement !== void 0) {
|
|
522
|
-
this.#initSelections = void 0;
|
|
523
|
-
this.#scrollToPrimaryCaret(false, "center");
|
|
524
|
-
} else if (this.#scrollingToLine !== void 0) this.#scrollToLine(this.#scrollingToLine, this.#scrollingToLineChar, this.#scrollingToLineNoFocus);
|
|
525
|
-
else if (this.#replacementFocusRequest !== void 0) this.#restoreReplacementFocus();
|
|
526
|
-
else if (this.#selections !== void 0 && this.#selections.length > 0 && this.#contentHasFocus && !this.#retainSearchPanelFocus) this.focus({ preventScroll: true });
|
|
527
|
-
if (this.#retainSearchPanelFocus) this.#searchPanel?.focus();
|
|
528
|
-
if (this.#options.__debug === true && renderRange !== void 0) {
|
|
529
|
-
const { startingLine, totalLines } = renderRange;
|
|
530
|
-
console.log("[diffs/editor] render file:", fileOrDiff.name, "RenderRange:", startingLine + "-" + (startingLine + totalLines), "of", this.#textDocument?.lineCount, "lines");
|
|
531
|
-
}
|
|
532
|
-
if (persistedStateTarget !== void 0) {
|
|
533
|
-
this.#restoreStateOnNextSync = false;
|
|
534
|
-
this.#restorePersistedState(persistedStateTarget.cacheKey, persistedStateTarget.textDocument);
|
|
535
|
-
}
|
|
536
|
-
this.#scheduleOnAttach(fileInstance);
|
|
537
|
-
};
|
|
538
|
-
#getCachedTextDocument(file, cacheKey) {
|
|
539
|
-
const textDocument = this.#textDocumentCache.get(cacheKey);
|
|
540
|
-
const languageId = file.lang ?? getFiletypeFromFileName(file.name);
|
|
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;
|
|
751
|
+
const retainedEditorState = editSession.editor;
|
|
752
|
+
const restoreEditorStateOnSync = this.#restoreEditorStateOnSync;
|
|
558
753
|
try {
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
this.#
|
|
567
|
-
if (
|
|
568
|
-
this.#
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
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;
|
|
600
|
-
const selections = this.#selections;
|
|
601
|
-
const view = this.getState().view;
|
|
602
|
-
let inputWatch;
|
|
603
|
-
const applyState = (state) => {
|
|
604
|
-
const currentView = this.getState().view;
|
|
605
|
-
if (generation !== this.#stateRestoreGeneration || this.#textDocument !== textDocument || textDocument.version !== documentVersion || this.#selections !== selections || currentView?.scrollLeft !== view?.scrollLeft || this.#fileInfo === void 0 || requirePersistedCacheKey(this.#fileInfo) !== cacheKey) return;
|
|
606
|
-
const userScrolled = inputWatch?.userScrolled() === true;
|
|
607
|
-
if (state === void 0) {
|
|
608
|
-
this.#fileInstance?.setCodeScrollLeft(0);
|
|
609
|
-
if (!userScrolled) this.#setViewportScrollTop(0);
|
|
610
|
-
return;
|
|
754
|
+
this.#markerRenderer?.removePopover();
|
|
755
|
+
if (this.#selections !== void 0 || this.#matches !== void 0 || this.#markerRenderer !== void 0) this.#updateSelections(this.#selections ?? []);
|
|
756
|
+
this.#renderCarets();
|
|
757
|
+
if (this.#retryEditPredictionOnRender) this.#scheduleEditPrediction();
|
|
758
|
+
if (this.#initSelections !== void 0 && this.#primaryCaretElement !== void 0) {
|
|
759
|
+
this.#initSelections = void 0;
|
|
760
|
+
this.#scrollToPrimaryCaret(false, "center");
|
|
761
|
+
} else if (this.#scrollingToLine !== void 0) this.#scrollToLine(this.#scrollingToLine, this.#scrollingToLineChar, this.#scrollingToLineNoFocus);
|
|
762
|
+
else if (this.#replacementFocusRequest !== void 0) this.#restoreReplacementFocus();
|
|
763
|
+
else if (this.#selections !== void 0 && this.#selections.length > 0 && this.#contentHasFocus && !this.#retainSearchPanelFocus) this.focus({ preventScroll: true });
|
|
764
|
+
if (this.#retainSearchPanelFocus) this.#searchPanel?.focus();
|
|
765
|
+
if (restoreEditorStateOnSync) {
|
|
766
|
+
this.#restoreEditorStateOnSync = false;
|
|
767
|
+
if (retainedEditorState !== void 0) this.setViewState(retainedEditorState);
|
|
611
768
|
}
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
};
|
|
616
|
-
const readState = () => {
|
|
617
|
-
let result;
|
|
618
|
-
try {
|
|
619
|
-
result = this.#getStateStorage().get(cacheKey);
|
|
620
|
-
} catch {
|
|
621
|
-
return;
|
|
769
|
+
if (this.#options.__debug === true && renderRange !== void 0) {
|
|
770
|
+
const { startingLine, totalLines } = renderRange;
|
|
771
|
+
console.log("[diffs/editor] render file:", fileOrDiff.name, "RenderRange:", startingLine + "-" + (startingLine + totalLines), "of", editSession.document?.lineCount, "lines");
|
|
622
772
|
}
|
|
623
|
-
if (
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
773
|
+
if (externalDocument) fileInstance.__acknowledgeDocumentUpdate();
|
|
774
|
+
this.#checkpointEditSessionState();
|
|
775
|
+
} catch (error) {
|
|
776
|
+
this.#restoreEditorStateOnSync = restoreEditorStateOnSync;
|
|
777
|
+
editSession.editor = retainedEditorState;
|
|
778
|
+
throw error;
|
|
779
|
+
}
|
|
780
|
+
if (documentChanges != null) this.#emitChange(documentChanges, lineAnnotations);
|
|
781
|
+
this.#scheduleOnAttach(fileInstance);
|
|
782
|
+
}
|
|
783
|
+
#applyExternalDocumentReplacement(editSession, contents, lineAnnotations) {
|
|
784
|
+
const textDocument = editSession.document;
|
|
785
|
+
if (textDocument == null || textDocument.getText() === contents) return;
|
|
786
|
+
const selections = this.#selections;
|
|
787
|
+
const selectionOffsets = selections?.map((selection) => [textDocument.offsetAt(selection.start), textDocument.offsetAt(selection.end)]);
|
|
788
|
+
const replacement = {
|
|
789
|
+
start: 0,
|
|
790
|
+
end: textDocument.getText().length,
|
|
791
|
+
text: contents
|
|
627
792
|
};
|
|
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
|
-
});
|
|
793
|
+
if (textDocument.applyResolvedEdits([replacement], true, selections, void 0, true) == null) return;
|
|
794
|
+
if (selections != null && selectionOffsets != null) {
|
|
795
|
+
const nextSelections = remapSelectionsAfterEdits(textDocument, selections, selectionOffsets, [replacement]);
|
|
796
|
+
textDocument.setLastUndoSelectionsAfter(nextSelections);
|
|
797
|
+
this.#selections = nextSelections;
|
|
645
798
|
}
|
|
799
|
+
if (this.#lineAnnotations != null || lineAnnotations != null) textDocument.setLastUndoLineAnnotations(this.#lineAnnotations ?? [], lineAnnotations ?? []);
|
|
800
|
+
this.#tokenizer?.cleanUp();
|
|
801
|
+
this.#tokenizer = void 0;
|
|
802
|
+
this.#resetCache();
|
|
803
|
+
this.#wrapLineOffsetsCache.clear();
|
|
804
|
+
this.#markerRenderer?.removePopover();
|
|
805
|
+
if (this.#searchPanel !== void 0 && this.#matches !== void 0) this.#searchPanel.updateMatches({ syncSelection: false });
|
|
646
806
|
}
|
|
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
|
-
};
|
|
807
|
+
get #fileDiffInstance() {
|
|
808
|
+
return this.#fileInstance?.type === "file-diff" ? this.#fileInstance : void 0;
|
|
809
|
+
}
|
|
810
|
+
get #virtualizedInstance() {
|
|
811
|
+
return isVirtualizedEditorComponent(this.#fileInstance) ? this.#fileInstance : void 0;
|
|
671
812
|
}
|
|
672
813
|
#isLineRenderable(line) {
|
|
673
|
-
return this.#
|
|
814
|
+
return this.#fileDiffInstance?.isLineRenderable?.(line + 1) ?? true;
|
|
674
815
|
}
|
|
675
816
|
get #resolveRenderableLine() {
|
|
676
|
-
const fileInstance = this.#
|
|
677
|
-
if (fileInstance
|
|
817
|
+
const fileInstance = this.#fileDiffInstance;
|
|
818
|
+
if (fileInstance == null) return;
|
|
678
819
|
return (line, direction) => {
|
|
679
820
|
const nearest = fileInstance.getNearestRenderableLine(line + 1, direction);
|
|
680
821
|
return nearest == null ? void 0 : nearest - 1;
|
|
681
822
|
};
|
|
682
823
|
}
|
|
683
824
|
#revealLineIfCollapsed(line) {
|
|
684
|
-
if (!this.#isLineRenderable(line)) this.#
|
|
825
|
+
if (!this.#isLineRenderable(line)) this.#fileDiffInstance?.revealLine?.(line + 1);
|
|
685
826
|
}
|
|
686
827
|
get #diffSyle() {
|
|
687
|
-
return this.#
|
|
828
|
+
return this.#fileDiffInstance?.options.diffStyle ?? "split";
|
|
688
829
|
}
|
|
689
830
|
get #isDiff() {
|
|
690
|
-
return this
|
|
831
|
+
return this.type === "file-diff";
|
|
691
832
|
}
|
|
692
833
|
get #isWrap() {
|
|
693
834
|
return this.#fileInstance?.options.overflow === "wrap";
|
|
@@ -706,7 +847,7 @@ var Editor = class {
|
|
|
706
847
|
this.#lineElementsCache.clear();
|
|
707
848
|
this.#lastAccessedCharX = void 0;
|
|
708
849
|
}
|
|
709
|
-
#resetState() {
|
|
850
|
+
#resetState(preserveCarets = false) {
|
|
710
851
|
this.#setEditorActiveLineSafe(null);
|
|
711
852
|
this.#gutterWidthCache = void 0;
|
|
712
853
|
this.#contentWidthCache = void 0;
|
|
@@ -714,6 +855,11 @@ var Editor = class {
|
|
|
714
855
|
this.#suppressNativeSelectionSync = false;
|
|
715
856
|
this.#overlayElements?.forEach((el) => el.remove());
|
|
716
857
|
this.#overlayElements = void 0;
|
|
858
|
+
this.#caretElements?.forEach((element) => element.remove());
|
|
859
|
+
this.#caretElements = void 0;
|
|
860
|
+
this.#caretHighlightElements?.forEach((element) => element.remove());
|
|
861
|
+
this.#caretHighlightElements = void 0;
|
|
862
|
+
if (!preserveCarets) this.#carets = void 0;
|
|
717
863
|
this.#selections = void 0;
|
|
718
864
|
this.#scrollingToLine = void 0;
|
|
719
865
|
this.#markerRenderer?.cleanup();
|
|
@@ -734,13 +880,13 @@ var Editor = class {
|
|
|
734
880
|
}
|
|
735
881
|
#scheduleOnAttach(fileInstance) {
|
|
736
882
|
const attachState = this.#attachState;
|
|
737
|
-
const textDocument = this.#
|
|
883
|
+
const textDocument = this.#editSession?.document;
|
|
738
884
|
if (attachState.delivered || attachState.callback != null || textDocument == null) return;
|
|
739
885
|
const { generation } = attachState;
|
|
740
886
|
const callback = () => {
|
|
741
887
|
if (attachState.callback !== callback) return;
|
|
742
888
|
attachState.callback = void 0;
|
|
743
|
-
if (generation !== attachState.generation || this.#fileInstance !== fileInstance || this.#
|
|
889
|
+
if (generation !== attachState.generation || this.#fileInstance !== fileInstance || this.#editSession?.document !== textDocument) return;
|
|
744
890
|
const contentElement = this.#contentElement;
|
|
745
891
|
const shadowRoot = this.#fileContainer?.shadowRoot;
|
|
746
892
|
if (contentElement == null || shadowRoot == null || !shadowRoot.contains(contentElement)) return;
|
|
@@ -751,21 +897,16 @@ var Editor = class {
|
|
|
751
897
|
queueRender(callback);
|
|
752
898
|
}
|
|
753
899
|
#getScrollViewport() {
|
|
754
|
-
const viewport = this.#
|
|
755
|
-
if (viewport
|
|
900
|
+
const viewport = this.#virtualizedInstance?.getEditorViewport?.();
|
|
901
|
+
if (viewport != null) return viewport;
|
|
756
902
|
const fileContainer = this.#fileContainer;
|
|
757
903
|
if (this.#fileInstance == null || fileContainer == null) return;
|
|
758
904
|
return lookupScrollContainer(fileContainer);
|
|
759
905
|
}
|
|
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 });
|
|
906
|
+
#getOwnedVerticalViewport() {
|
|
907
|
+
if (!this.#ownsVerticalViewport) return;
|
|
908
|
+
const viewport = this.#virtualizedInstance?.getEditorViewport?.();
|
|
909
|
+
if (viewport instanceof HTMLElement) return viewport;
|
|
769
910
|
}
|
|
770
911
|
#initialize() {
|
|
771
912
|
this.#globalStyleElement = h("style", {
|
|
@@ -817,7 +958,9 @@ var Editor = class {
|
|
|
817
958
|
if (this.#selections !== void 0 && this.#selections.length > 1 && !this.#isContentMouseDown) return;
|
|
818
959
|
const selectionRaw = document.getSelection();
|
|
819
960
|
if (selectionRaw == null) return;
|
|
820
|
-
|
|
961
|
+
let composedRange;
|
|
962
|
+
if (typeof selectionRaw.getComposedRanges === "function") composedRange = selectionRaw.getComposedRanges({ shadowRoots: [shadowRoot] })?.[0];
|
|
963
|
+
else composedRange = getShadowRootRange(shadowRoot);
|
|
821
964
|
if (composedRange === void 0 || !this.#rangeBelongsToEditor(composedRange)) return;
|
|
822
965
|
let selection = convertSelection(composedRange, 0);
|
|
823
966
|
if (selection === void 0) return;
|
|
@@ -844,6 +987,10 @@ var Editor = class {
|
|
|
844
987
|
addEventListener(document, "pointercancel", finishMouseSelection, { passive: true }),
|
|
845
988
|
addEventListener(document, "keydown", (e) => {
|
|
846
989
|
if (e.key === "Shift") this.#selectionStart = this.#selections?.at(-1);
|
|
990
|
+
else if (e.key === "Alt" && !e.repeat && this.#contentHasFocus && this.#options.editPrediction?.mode === "subtle") {
|
|
991
|
+
this.#editPredictionRevealed = !this.#editPredictionRevealed;
|
|
992
|
+
this.#updateSelections(this.#selections ?? []);
|
|
993
|
+
}
|
|
847
994
|
}, { passive: true }),
|
|
848
995
|
addEventListener(document, "keyup", (e) => {
|
|
849
996
|
if (e.key === "Shift") this.#selectionStart = void 0;
|
|
@@ -955,6 +1102,16 @@ var Editor = class {
|
|
|
955
1102
|
this.#canMountSelectionAction = true;
|
|
956
1103
|
this.#suppressNativeSelectionSync = false;
|
|
957
1104
|
if (e.isComposing || e.keyCode === 229) return;
|
|
1105
|
+
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) {
|
|
1106
|
+
this.#acceptEditPrediction();
|
|
1107
|
+
e.preventDefault();
|
|
1108
|
+
return;
|
|
1109
|
+
}
|
|
1110
|
+
if (e.key === "Escape" && this.#editPrediction !== void 0) {
|
|
1111
|
+
this.#cancelEditPrediction(true);
|
|
1112
|
+
e.preventDefault();
|
|
1113
|
+
return;
|
|
1114
|
+
}
|
|
958
1115
|
const command = resolveEditorCommandFromKeyboardEvent(e, this.#options.keymap);
|
|
959
1116
|
if (command !== void 0) {
|
|
960
1117
|
e.preventDefault();
|
|
@@ -969,7 +1126,7 @@ var Editor = class {
|
|
|
969
1126
|
return;
|
|
970
1127
|
}
|
|
971
1128
|
const mvShortcut = isMoveCursorShortcut(e);
|
|
972
|
-
const textDocument = this.#
|
|
1129
|
+
const textDocument = this.#editSession?.document;
|
|
973
1130
|
if (this.#selections !== void 0 && this.#selections.length > 0 && mvShortcut !== void 0 && textDocument !== void 0) {
|
|
974
1131
|
const cursorMoveOptions = {
|
|
975
1132
|
getSoftLineOffsets: this.#isWrap ? (line) => this.#wrapLineTextOrWholeLine(line) : void 0,
|
|
@@ -1020,7 +1177,7 @@ var Editor = class {
|
|
|
1020
1177
|
if (!targetIsContentElement(e)) return;
|
|
1021
1178
|
e.preventDefault();
|
|
1022
1179
|
const clipboardData = e.clipboardData;
|
|
1023
|
-
const textDocument = this.#
|
|
1180
|
+
const textDocument = this.#editSession?.document;
|
|
1024
1181
|
if (clipboardData === null || textDocument === void 0) return;
|
|
1025
1182
|
let text = clipboardData.getData("text");
|
|
1026
1183
|
const selectionCount = this.#selections?.length ?? 0;
|
|
@@ -1035,7 +1192,10 @@ var Editor = class {
|
|
|
1035
1192
|
}),
|
|
1036
1193
|
addEventListener(contentEl, "beforeinput", (e) => {
|
|
1037
1194
|
if (!targetIsContentElement(e)) return;
|
|
1038
|
-
if (e.inputType === "insertCompositionText")
|
|
1195
|
+
if (e.inputType === "insertCompositionText") {
|
|
1196
|
+
this.#cancelEditPrediction(true);
|
|
1197
|
+
return;
|
|
1198
|
+
}
|
|
1039
1199
|
e.preventDefault();
|
|
1040
1200
|
this.#handleInput(e.inputType, e.data);
|
|
1041
1201
|
}),
|
|
@@ -1045,6 +1205,7 @@ var Editor = class {
|
|
|
1045
1205
|
}),
|
|
1046
1206
|
addEventListener(contentEl, "compositionstart", (e) => {
|
|
1047
1207
|
if (!targetIsContentElement(e)) return;
|
|
1208
|
+
this.#cancelEditPrediction(true);
|
|
1048
1209
|
this.#isComposing = true;
|
|
1049
1210
|
this.#shouldIgnoreSelectionChange = true;
|
|
1050
1211
|
}, { passive: true }),
|
|
@@ -1106,7 +1267,7 @@ var Editor = class {
|
|
|
1106
1267
|
return;
|
|
1107
1268
|
}
|
|
1108
1269
|
if (e.pointerType !== "mouse") return;
|
|
1109
|
-
const textDocument = this.#
|
|
1270
|
+
const textDocument = this.#editSession?.document;
|
|
1110
1271
|
const lineIndex = resolveEditableLine(gutterRow);
|
|
1111
1272
|
if (lineIndex === void 0 || textDocument === void 0) return;
|
|
1112
1273
|
this.#canMountSelectionAction = true;
|
|
@@ -1119,7 +1280,7 @@ var Editor = class {
|
|
|
1119
1280
|
this.#focus();
|
|
1120
1281
|
this.#replaceSelectEventListeners([addEventListener(document, "mousemove", (e) => {
|
|
1121
1282
|
if (!this.#isGutterMouseDown) return;
|
|
1122
|
-
const textDocument = this.#
|
|
1283
|
+
const textDocument = this.#editSession?.document;
|
|
1123
1284
|
const lineIndex = resolveEditableLine(resolveGutterTarget(e.composedPath()[0], true));
|
|
1124
1285
|
if (lineIndex === void 0 || textDocument === void 0) return;
|
|
1125
1286
|
const anchorLine = this.#selectionStart?.start.line ?? lineIndex;
|
|
@@ -1149,14 +1310,14 @@ var Editor = class {
|
|
|
1149
1310
|
if (Array.isArray(selectionTexts) && selectionTexts.length === selectionCount) text = selectionTexts;
|
|
1150
1311
|
} catch {}
|
|
1151
1312
|
}
|
|
1152
|
-
const textDocument = this.#
|
|
1153
|
-
if (textDocument
|
|
1313
|
+
const textDocument = this.#editSession?.document;
|
|
1314
|
+
if (textDocument != null) this.#replaceSelectionText(Array.isArray(text) ? text.map((t) => textDocument.normalizeEol(t)) : textDocument.normalizeEol(text), void 0, true, "document");
|
|
1154
1315
|
}
|
|
1155
1316
|
};
|
|
1156
1317
|
#computeContentOffset(contentEl) {
|
|
1157
1318
|
if (this.#isDiff && this.#diffSyle === "split" && this.#isWrap) {
|
|
1158
1319
|
this.#contentOffset = {
|
|
1159
|
-
top: contentEl.offsetTop,
|
|
1320
|
+
top: contentEl.offsetTop - this.#metrics.paddingTop,
|
|
1160
1321
|
left: contentEl.offsetLeft - this.#getGutterWidth()
|
|
1161
1322
|
};
|
|
1162
1323
|
if (this.#options.__debug === true) console.log("[diffs/editor] content offset:", this.#contentOffset);
|
|
@@ -1166,8 +1327,8 @@ var Editor = class {
|
|
|
1166
1327
|
if (this.#isDiff && this.#diffSyle === "split" && this.#isWrap) return this.#contentOffset;
|
|
1167
1328
|
}
|
|
1168
1329
|
#runCommand(command) {
|
|
1169
|
-
const textDocument = this.#
|
|
1170
|
-
if (textDocument
|
|
1330
|
+
const textDocument = this.#editSession?.document;
|
|
1331
|
+
if (textDocument == null) return;
|
|
1171
1332
|
switch (command) {
|
|
1172
1333
|
case "openSearchPanel":
|
|
1173
1334
|
this.#openSearchPanel("find");
|
|
@@ -1367,8 +1528,8 @@ var Editor = class {
|
|
|
1367
1528
|
}
|
|
1368
1529
|
}
|
|
1369
1530
|
#applyHistoryChange(command) {
|
|
1370
|
-
const textDocument = this.#
|
|
1371
|
-
if (textDocument
|
|
1531
|
+
const textDocument = this.#editSession?.document;
|
|
1532
|
+
if (textDocument == null) return;
|
|
1372
1533
|
if (command === "undo" && !textDocument.canUndo || command === "redo" && !textDocument.canRedo) return;
|
|
1373
1534
|
const selections = this.#selections;
|
|
1374
1535
|
const selectionOffsets = selections?.map((selection) => [textDocument.offsetAt(selection.start), textDocument.offsetAt(selection.end)]);
|
|
@@ -1376,11 +1537,12 @@ var Editor = class {
|
|
|
1376
1537
|
if (result === void 0) return;
|
|
1377
1538
|
const [change, recordedSelections, lineAnnotations, selectionEdits] = result;
|
|
1378
1539
|
const nextSelections = recordedSelections ?? (selections !== void 0 && selectionOffsets !== void 0 && selectionEdits !== void 0 ? remapSelectionsAfterEdits(textDocument, selections, selectionOffsets, selectionEdits) : void 0);
|
|
1379
|
-
this.#
|
|
1540
|
+
const replayedLineAnnotations = lineAnnotations ?? (this.#lineAnnotations != null ? applyDocumentChangeToLineAnnotations(change, this.#lineAnnotations) : void 0);
|
|
1541
|
+
this.#applyChange(change, nextSelections, replayedLineAnnotations);
|
|
1380
1542
|
}
|
|
1381
1543
|
/** Applies one undoable command batch and records its resulting selections. */
|
|
1382
1544
|
#applyCommandEdits(edits, resolveNextSelections) {
|
|
1383
|
-
const textDocument = this.#
|
|
1545
|
+
const textDocument = this.#editSession?.document;
|
|
1384
1546
|
const selections = this.#selections;
|
|
1385
1547
|
if (textDocument === void 0 || selections === void 0) return;
|
|
1386
1548
|
const remapSelections = resolveNextSelections === void 0;
|
|
@@ -1405,7 +1567,7 @@ var Editor = class {
|
|
|
1405
1567
|
}
|
|
1406
1568
|
/** Copies selected line blocks and keeps the selection in the requested copy. */
|
|
1407
1569
|
#copySelectedLines(direction) {
|
|
1408
|
-
const textDocument = this.#
|
|
1570
|
+
const textDocument = this.#editSession?.document;
|
|
1409
1571
|
const selections = this.#selections;
|
|
1410
1572
|
if (textDocument === void 0 || selections === void 0) return;
|
|
1411
1573
|
const blocks = getSelectedLineBlocks(selections);
|
|
@@ -1498,7 +1660,7 @@ var Editor = class {
|
|
|
1498
1660
|
}
|
|
1499
1661
|
/** Inserts an indented blank line after each selection's final line. */
|
|
1500
1662
|
#insertBlankLine() {
|
|
1501
|
-
const textDocument = this.#
|
|
1663
|
+
const textDocument = this.#editSession?.document;
|
|
1502
1664
|
const selections = this.#selections;
|
|
1503
1665
|
if (textDocument === void 0 || selections === void 0) return;
|
|
1504
1666
|
const selectionLines = selections.map((selection) => getCaretPosition(selection).line);
|
|
@@ -1539,7 +1701,7 @@ var Editor = class {
|
|
|
1539
1701
|
this.#applyCommandEdits(edits, () => nextSelections);
|
|
1540
1702
|
}
|
|
1541
1703
|
#moveSelectedLines(direction) {
|
|
1542
|
-
const textDocument = this.#
|
|
1704
|
+
const textDocument = this.#editSession?.document;
|
|
1543
1705
|
const selections = this.#selections;
|
|
1544
1706
|
if (textDocument === void 0 || selections === void 0) return;
|
|
1545
1707
|
const blocks = getSelectedLineBlocks(selections);
|
|
@@ -1616,6 +1778,7 @@ var Editor = class {
|
|
|
1616
1778
|
}
|
|
1617
1779
|
this.#markerRenderer?.removePopover();
|
|
1618
1780
|
this.#computeContentOffset(this.#contentElement);
|
|
1781
|
+
this.#renderCarets();
|
|
1619
1782
|
};
|
|
1620
1783
|
#remeasureMetricsOnFontLoad() {
|
|
1621
1784
|
if (this.#fontRemeasureScheduled) return;
|
|
@@ -1629,19 +1792,21 @@ var Editor = class {
|
|
|
1629
1792
|
this.#resetCache();
|
|
1630
1793
|
this.#wrapLineOffsetsCache.clear();
|
|
1631
1794
|
if (this.#selections !== void 0 || this.#matches !== void 0 || this.#markerRenderer !== void 0) this.#updateSelections(this.#selections ?? []);
|
|
1795
|
+
this.#renderCarets();
|
|
1632
1796
|
this.#markerRenderer?.removePopover();
|
|
1633
1797
|
});
|
|
1634
1798
|
}
|
|
1635
1799
|
#rerender(change, newLineAnnotations, renderRange = this.#renderRange, shouldUpdateBuffer) {
|
|
1636
1800
|
const tokenizer = this.#tokenizer;
|
|
1637
1801
|
const fileInstance = this.#fileInstance;
|
|
1638
|
-
const
|
|
1802
|
+
const applyDocumentChange = this.#applyDocumentChange;
|
|
1803
|
+
const textDocument = this.#editSession?.document;
|
|
1639
1804
|
const gutterEl = this.#gutterElement;
|
|
1640
1805
|
const contentEl = this.#contentElement;
|
|
1641
|
-
if (tokenizer
|
|
1806
|
+
if (tokenizer == null || fileInstance == null || applyDocumentChange == null || textDocument == null || contentEl == null) return;
|
|
1642
1807
|
tokenizer.stopBackgroundTokenize();
|
|
1643
1808
|
const t = performance.now();
|
|
1644
|
-
const dirtyLines = tokenizer.tokenize(change, renderRange, !this.#isDiff &&
|
|
1809
|
+
const dirtyLines = tokenizer.tokenize(change, renderRange, !this.#isDiff && this.#virtualizedInstance != null);
|
|
1645
1810
|
const t2 = performance.now();
|
|
1646
1811
|
if (dirtyLines.size > 0) {
|
|
1647
1812
|
const children = contentEl.children;
|
|
@@ -1720,19 +1885,20 @@ var Editor = class {
|
|
|
1720
1885
|
shouldRefreshDiffsView: this.#isDiff && !didLineCountChange,
|
|
1721
1886
|
lineCountChangeInFlight: didLineCountChange
|
|
1722
1887
|
});
|
|
1723
|
-
if (didLineCountChange)
|
|
1888
|
+
if (didLineCountChange) applyDocumentChange(textDocument, newLineAnnotations, shouldUpdateBuffer);
|
|
1724
1889
|
if (didLineCountChange || this.#isDiff && this.#diffSyle === "unified") this.#resetCache();
|
|
1725
|
-
if (newLineAnnotations
|
|
1890
|
+
if (newLineAnnotations != null) {
|
|
1726
1891
|
this.#lineAnnotations = newLineAnnotations;
|
|
1727
|
-
renderLineAnnotations(newLineAnnotations, contentEl, gutterEl);
|
|
1892
|
+
if (!this.#isDiff || !didLineCountChange) renderLineAnnotations(newLineAnnotations, contentEl, gutterEl, fileInstance.getAnnotationSlotName);
|
|
1728
1893
|
}
|
|
1894
|
+
this.#renderCarets();
|
|
1729
1895
|
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
1896
|
}
|
|
1731
1897
|
#handleInput(inputType, data) {
|
|
1732
1898
|
switch (inputType) {
|
|
1733
1899
|
case "insertText": {
|
|
1734
1900
|
const text = data ?? "";
|
|
1735
|
-
const textDocument = this.#
|
|
1901
|
+
const textDocument = this.#editSession?.document;
|
|
1736
1902
|
const selections = this.#selections;
|
|
1737
1903
|
const autoSurroundTexts = textDocument !== void 0 && selections !== void 0 ? getAutoSurroundReplacementTexts(textDocument, selections, text, this.#options.autoSurround) : void 0;
|
|
1738
1904
|
this.#replaceSelectionText(autoSurroundTexts ?? text);
|
|
@@ -1741,7 +1907,7 @@ var Editor = class {
|
|
|
1741
1907
|
case "insertCompositionText": break;
|
|
1742
1908
|
case "insertLineBreak":
|
|
1743
1909
|
case "insertParagraph":
|
|
1744
|
-
this.#replaceSelectionText(this.#
|
|
1910
|
+
this.#replaceSelectionText(this.#editSession?.document?.eol ?? "\n");
|
|
1745
1911
|
break;
|
|
1746
1912
|
case "deleteContentBackward":
|
|
1747
1913
|
this.#deleteSelectionText();
|
|
@@ -1833,7 +1999,7 @@ var Editor = class {
|
|
|
1833
1999
|
#getFirstVisibleLineNumber(offset = 0) {
|
|
1834
2000
|
const contentElement = this.#contentElement;
|
|
1835
2001
|
const fileContainer = this.#fileContainer;
|
|
1836
|
-
if (this.#
|
|
2002
|
+
if (this.#editSession?.document == null || contentElement == null || fileContainer == null) return;
|
|
1837
2003
|
const viewport = this.#getScrollViewport();
|
|
1838
2004
|
if (viewport === void 0) return;
|
|
1839
2005
|
let viewportTop;
|
|
@@ -1950,7 +2116,7 @@ var Editor = class {
|
|
|
1950
2116
|
this.#scrollingToLineFixed = false;
|
|
1951
2117
|
this.#scrollingToLineNoFocus = false;
|
|
1952
2118
|
} else {
|
|
1953
|
-
const modelLinePosition = this.#
|
|
2119
|
+
const modelLinePosition = this.#virtualizedInstance?.getLinePosition?.(line + 1);
|
|
1954
2120
|
if (modelLinePosition !== void 0) {
|
|
1955
2121
|
virtualCaret.style.top = modelLinePosition.top + "px";
|
|
1956
2122
|
this.#fileContainer?.shadowRoot?.appendChild(virtualCaret);
|
|
@@ -2102,7 +2268,7 @@ var Editor = class {
|
|
|
2102
2268
|
#updateAltColumnSelections() {
|
|
2103
2269
|
const drag = this.#altColumnDrag;
|
|
2104
2270
|
const selectionStart = this.#selectionStart;
|
|
2105
|
-
const textDocument = this.#
|
|
2271
|
+
const textDocument = this.#editSession?.document;
|
|
2106
2272
|
if (drag === void 0 || drag.focusLine === void 0 || selectionStart === void 0 || textDocument === void 0) return false;
|
|
2107
2273
|
const anchor = selectionStart.direction === -1 ? selectionStart.end : selectionStart.start;
|
|
2108
2274
|
const scrollLeft = this.#contentElement?.parentElement?.scrollLeft ?? 0;
|
|
@@ -2141,8 +2307,451 @@ var Editor = class {
|
|
|
2141
2307
|
this.#updateSelections(selections);
|
|
2142
2308
|
return true;
|
|
2143
2309
|
}
|
|
2310
|
+
#removeRenderedEditPrediction() {
|
|
2311
|
+
for (const [key, element] of this.#overlayElements ?? []) if (key.startsWith("editPrediction")) {
|
|
2312
|
+
element.remove();
|
|
2313
|
+
this.#overlayElements?.delete(key);
|
|
2314
|
+
}
|
|
2315
|
+
}
|
|
2316
|
+
#composeEditPredictionGroup(textDocument, edits, startIndex) {
|
|
2317
|
+
const firstEdit = edits[startIndex];
|
|
2318
|
+
let endIndex = startIndex;
|
|
2319
|
+
let endLine = firstEdit.range.end.line;
|
|
2320
|
+
while (endIndex + 1 < edits.length && edits[endIndex + 1].range.start.line <= endLine) {
|
|
2321
|
+
endIndex++;
|
|
2322
|
+
endLine = Math.max(endLine, edits[endIndex].range.end.line);
|
|
2323
|
+
}
|
|
2324
|
+
if (endIndex === startIndex && (firstEdit.newText.length === 0 || comparePosition(firstEdit.range.start, firstEdit.range.end) === 0)) return {
|
|
2325
|
+
edit: firstEdit,
|
|
2326
|
+
endIndex
|
|
2327
|
+
};
|
|
2328
|
+
const start = firstEdit.range.start;
|
|
2329
|
+
const end = {
|
|
2330
|
+
line: endLine,
|
|
2331
|
+
character: textDocument.getLineLength(endLine)
|
|
2332
|
+
};
|
|
2333
|
+
const parts = [];
|
|
2334
|
+
let consumed = textDocument.offsetAt(start);
|
|
2335
|
+
for (let index = startIndex; index <= endIndex; index++) {
|
|
2336
|
+
const edit = edits[index];
|
|
2337
|
+
const editStart = textDocument.offsetAt(edit.range.start);
|
|
2338
|
+
const editEnd = textDocument.offsetAt(edit.range.end);
|
|
2339
|
+
parts.push(textDocument.getTextSlice(consumed, editStart), edit.newText);
|
|
2340
|
+
consumed = editEnd;
|
|
2341
|
+
}
|
|
2342
|
+
parts.push(textDocument.getTextSlice(consumed, textDocument.offsetAt(end)));
|
|
2343
|
+
return {
|
|
2344
|
+
edit: {
|
|
2345
|
+
range: {
|
|
2346
|
+
start,
|
|
2347
|
+
end
|
|
2348
|
+
},
|
|
2349
|
+
newText: parts.join("")
|
|
2350
|
+
},
|
|
2351
|
+
endIndex
|
|
2352
|
+
};
|
|
2353
|
+
}
|
|
2354
|
+
#getEditPredictionGroups() {
|
|
2355
|
+
const prediction = this.#editPrediction;
|
|
2356
|
+
const textDocument = this.#editSession?.document;
|
|
2357
|
+
if (prediction == null || textDocument == null || prediction.document !== textDocument || prediction.version !== textDocument.version || this.#options.editPrediction?.mode === "subtle" && !this.#editPredictionRevealed) return;
|
|
2358
|
+
const { edits } = prediction.response;
|
|
2359
|
+
const groups = [];
|
|
2360
|
+
let allVisible = edits.length > 0;
|
|
2361
|
+
for (let startIndex = 0; startIndex < edits.length;) {
|
|
2362
|
+
const { edit, endIndex } = this.#composeEditPredictionGroup(textDocument, edits, startIndex);
|
|
2363
|
+
for (let line = edit.range.start.line; allVisible && line <= edit.range.end.line; line++) allVisible = this.#isLineVisible(line);
|
|
2364
|
+
groups.push({
|
|
2365
|
+
edit,
|
|
2366
|
+
startIndex,
|
|
2367
|
+
endIndex
|
|
2368
|
+
});
|
|
2369
|
+
startIndex = endIndex + 1;
|
|
2370
|
+
}
|
|
2371
|
+
return {
|
|
2372
|
+
groups,
|
|
2373
|
+
allVisible
|
|
2374
|
+
};
|
|
2375
|
+
}
|
|
2376
|
+
#fillGhostTextElement(element, newText, anchorLeft, lineLeft, insertionSuffix) {
|
|
2377
|
+
if (this.#isWrap) {
|
|
2378
|
+
element.dataset.wrap = "";
|
|
2379
|
+
element.style.width = `calc(100cqw - ${lineLeft}px)`;
|
|
2380
|
+
} else {
|
|
2381
|
+
delete element.dataset.wrap;
|
|
2382
|
+
element.style.width = "max-content";
|
|
2383
|
+
}
|
|
2384
|
+
const lines = newText.split(/\r\n|\r|\n/);
|
|
2385
|
+
for (let lineIndex = 0; lineIndex < lines.length; lineIndex++) {
|
|
2386
|
+
const lineText = lines[lineIndex];
|
|
2387
|
+
const suffix = lineIndex === lines.length - 1 ? insertionSuffix : void 0;
|
|
2388
|
+
const isEmpty = lineText.length === 0 && suffix === void 0;
|
|
2389
|
+
const line = h("span", {
|
|
2390
|
+
dataset: isEmpty ? ["editPredictionLine", "empty"] : "editPredictionLine",
|
|
2391
|
+
textContent: isEmpty ? "" : lineText
|
|
2392
|
+
}, element);
|
|
2393
|
+
if (suffix !== void 0) h("span", { dataset: "editPredictionSuffix" }, line).append(suffix);
|
|
2394
|
+
if (lineIndex === 0 && anchorLeft !== lineLeft) line.style.textIndent = `${anchorLeft - lineLeft}px`;
|
|
2395
|
+
}
|
|
2396
|
+
}
|
|
2397
|
+
#cloneInsertionSuffix(group) {
|
|
2398
|
+
const prediction = this.#editPrediction;
|
|
2399
|
+
const textDocument = this.#editSession?.document;
|
|
2400
|
+
if (prediction == null || textDocument == null) return;
|
|
2401
|
+
const { edit, startIndex, endIndex } = group;
|
|
2402
|
+
const { start, end } = edit.range;
|
|
2403
|
+
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;
|
|
2404
|
+
const sourceLine = this.#getLineElement(start.line);
|
|
2405
|
+
if (sourceLine === void 0) return document.createTextNode(textDocument.getLineText(start.line).slice(start.character));
|
|
2406
|
+
const [suffixNode, suffixOffset] = getSelectionAnchor(sourceLine, start.character);
|
|
2407
|
+
const suffixRange = document.createRange();
|
|
2408
|
+
suffixRange.selectNodeContents(sourceLine);
|
|
2409
|
+
suffixRange.setStart(suffixNode, clampDomOffset(suffixNode, suffixOffset));
|
|
2410
|
+
const suffix = suffixRange.cloneContents();
|
|
2411
|
+
if (suffix.firstChild?.textContent === "") suffix.firstChild.remove();
|
|
2412
|
+
return suffix;
|
|
2413
|
+
}
|
|
2414
|
+
#measureGhostTextRows(group) {
|
|
2415
|
+
const { edit } = group;
|
|
2416
|
+
const { start } = edit.range;
|
|
2417
|
+
const [anchorLeft, anchorWrapLine] = this.#getCharX(start.line, start.character);
|
|
2418
|
+
let anchorVisualLines = 1;
|
|
2419
|
+
let ghostVisualLines = edit.newText.split(/\r\n|\r|\n/).length;
|
|
2420
|
+
const overlayElement = this.#overlayElement;
|
|
2421
|
+
if (this.#isWrap && overlayElement != null) {
|
|
2422
|
+
anchorVisualLines = Math.max(1, this.#wrapLineTextOrWholeLine(start.line).length - 1);
|
|
2423
|
+
const probe = h("span", {
|
|
2424
|
+
dataset: "editPrediction",
|
|
2425
|
+
style: { visibility: "hidden" }
|
|
2426
|
+
}, overlayElement);
|
|
2427
|
+
this.#fillGhostTextElement(probe, edit.newText, anchorLeft, this.#getCharX(start.line, 0)[0], this.#cloneInsertionSuffix(group));
|
|
2428
|
+
const { width, height } = probe.getBoundingClientRect();
|
|
2429
|
+
probe.remove();
|
|
2430
|
+
const { lineHeight } = this.#metrics;
|
|
2431
|
+
if (width > 0 && height > 0 && lineHeight > 0) ghostVisualLines = Math.round(height / lineHeight);
|
|
2432
|
+
}
|
|
2433
|
+
return Math.max(0, ghostVisualLines - (anchorVisualLines - anchorWrapLine));
|
|
2434
|
+
}
|
|
2435
|
+
#syncEditPredictionSpacers(notifyComponent = true) {
|
|
2436
|
+
const nextSpacers = /* @__PURE__ */ new Map();
|
|
2437
|
+
const ghostTextRows = /* @__PURE__ */ new Map();
|
|
2438
|
+
const previousRows = this.#ghostTextRows;
|
|
2439
|
+
let rowsChanged = false;
|
|
2440
|
+
const contentElement = this.#contentElement;
|
|
2441
|
+
const composed = this.#getEditPredictionGroups();
|
|
2442
|
+
if (contentElement != null && composed != null && composed.allVisible) {
|
|
2443
|
+
for (const group of composed.groups) {
|
|
2444
|
+
const { edit } = group;
|
|
2445
|
+
if (edit.newText.length === 0) continue;
|
|
2446
|
+
const count = this.#measureGhostTextRows(group);
|
|
2447
|
+
if (count > (ghostTextRows.get(edit.range.start.line) ?? 0)) ghostTextRows.set(edit.range.start.line, count);
|
|
2448
|
+
}
|
|
2449
|
+
if (ghostTextRows.size > 0) {
|
|
2450
|
+
let rowIndexes;
|
|
2451
|
+
const startingLine = this.#renderRange?.startingLine ?? 0;
|
|
2452
|
+
for (const [line, count] of ghostTextRows) {
|
|
2453
|
+
rowsChanged ||= previousRows.get(line) !== count;
|
|
2454
|
+
const lineElement = this.#getLineElement(line);
|
|
2455
|
+
if (lineElement === void 0) continue;
|
|
2456
|
+
let rowIndex = line - startingLine;
|
|
2457
|
+
if (contentElement.children[rowIndex] !== lineElement) {
|
|
2458
|
+
if (rowIndexes === void 0) {
|
|
2459
|
+
rowIndexes = /* @__PURE__ */ new Map();
|
|
2460
|
+
for (let index = 0; index < contentElement.children.length; index++) rowIndexes.set(contentElement.children[index], index);
|
|
2461
|
+
}
|
|
2462
|
+
rowIndex = rowIndexes.get(lineElement) ?? -1;
|
|
2463
|
+
}
|
|
2464
|
+
if (rowIndex < 0) continue;
|
|
2465
|
+
nextSpacers.set(lineElement, count);
|
|
2466
|
+
const gutterRow = this.#gutterElement?.children[rowIndex];
|
|
2467
|
+
if (gutterRow instanceof HTMLElement) nextSpacers.set(gutterRow, count);
|
|
2468
|
+
const partner = this.#deletionsColumnPartner(rowIndex);
|
|
2469
|
+
if (partner != null) {
|
|
2470
|
+
nextSpacers.set(partner.content, (nextSpacers.get(partner.content) ?? 0) + count);
|
|
2471
|
+
nextSpacers.set(partner.gutter, (nextSpacers.get(partner.gutter) ?? 0) + count);
|
|
2472
|
+
}
|
|
2473
|
+
}
|
|
2474
|
+
}
|
|
2475
|
+
}
|
|
2476
|
+
let changed = false;
|
|
2477
|
+
for (const [element, count] of this.#editPredictionSpacers) {
|
|
2478
|
+
if (nextSpacers.get(element) === count) continue;
|
|
2479
|
+
delete element.dataset.editPredictionSpacer;
|
|
2480
|
+
element.style.removeProperty("--diffs-edit-prediction-spacer-height");
|
|
2481
|
+
changed = true;
|
|
2482
|
+
}
|
|
2483
|
+
for (const [element, count] of nextSpacers) {
|
|
2484
|
+
if (this.#editPredictionSpacers.get(element) === count) continue;
|
|
2485
|
+
element.dataset.editPredictionSpacer = "";
|
|
2486
|
+
element.style.setProperty("--diffs-edit-prediction-spacer-height", `${count}lh`);
|
|
2487
|
+
changed = true;
|
|
2488
|
+
}
|
|
2489
|
+
this.#editPredictionSpacers = nextSpacers;
|
|
2490
|
+
if (rowsChanged || ghostTextRows.size !== previousRows.size) {
|
|
2491
|
+
this.#ghostTextRows = ghostTextRows;
|
|
2492
|
+
if (notifyComponent) this.#virtualizedInstance?.syncGhostTextRows();
|
|
2493
|
+
}
|
|
2494
|
+
if (changed) this.#resetCache();
|
|
2495
|
+
}
|
|
2496
|
+
#deletionsColumnPartner(rowIndex) {
|
|
2497
|
+
const deletionsColumn = this.#deletionsColumn;
|
|
2498
|
+
const contentElement = this.#contentElement;
|
|
2499
|
+
if (deletionsColumn == null || contentElement == null || !this.#isDiff || this.#diffSyle !== "split" || this.#isWrap) return;
|
|
2500
|
+
let track = 0;
|
|
2501
|
+
for (let index = 0; index < rowIndex; index++) track += gridTrackSpan(contentElement.children[index]);
|
|
2502
|
+
const { content, gutter } = deletionsColumn;
|
|
2503
|
+
let covered = 0;
|
|
2504
|
+
for (let index = 0; index < content.children.length; index++) {
|
|
2505
|
+
const child = content.children[index];
|
|
2506
|
+
covered += gridTrackSpan(child);
|
|
2507
|
+
if (covered > track) {
|
|
2508
|
+
const gutterChild = gutter.children[index];
|
|
2509
|
+
if (!(child instanceof HTMLElement) || !(gutterChild instanceof HTMLElement)) throw new Error("Editor: deletions column rows and gutter cells are out of step");
|
|
2510
|
+
return {
|
|
2511
|
+
content: child,
|
|
2512
|
+
gutter: gutterChild
|
|
2513
|
+
};
|
|
2514
|
+
}
|
|
2515
|
+
}
|
|
2516
|
+
}
|
|
2517
|
+
#cancelEditPrediction(removeRendered, notifyComponent = true) {
|
|
2518
|
+
if (this.#editPredictionTimer !== void 0) {
|
|
2519
|
+
clearTimeout(this.#editPredictionTimer);
|
|
2520
|
+
this.#editPredictionTimer = void 0;
|
|
2521
|
+
}
|
|
2522
|
+
this.#editPredictionAbortController?.abort();
|
|
2523
|
+
this.#editPredictionAbortController = void 0;
|
|
2524
|
+
this.#editPredictionGeneration++;
|
|
2525
|
+
this.#editPredictionRevealed = false;
|
|
2526
|
+
this.#retryEditPredictionOnRender = false;
|
|
2527
|
+
this.#editPrediction = void 0;
|
|
2528
|
+
this.#syncEditPredictionSpacers(notifyComponent);
|
|
2529
|
+
if (removeRendered) this.#removeRenderedEditPrediction();
|
|
2530
|
+
}
|
|
2531
|
+
#includesEditPredictionPath(path) {
|
|
2532
|
+
const options = this.#options.editPrediction;
|
|
2533
|
+
if (options === void 0) return false;
|
|
2534
|
+
const normalizedPath = path.replaceAll("\\", "/");
|
|
2535
|
+
return (options.include === void 0 || options.include.some((pattern) => matchesEditPredictionPattern(normalizedPath, pattern))) && options.exclude?.some((pattern) => matchesEditPredictionPattern(normalizedPath, pattern)) !== true;
|
|
2536
|
+
}
|
|
2537
|
+
#scheduleEditPrediction() {
|
|
2538
|
+
this.#cancelEditPrediction(true);
|
|
2539
|
+
const selection = this.#selections?.[0];
|
|
2540
|
+
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;
|
|
2541
|
+
const document = this.#editSession?.document;
|
|
2542
|
+
const cursorOffset = document.offsetAt(getCaretPosition(selection));
|
|
2543
|
+
this.#editPredictionTimer = setTimeout(() => {
|
|
2544
|
+
this.#editPredictionTimer = void 0;
|
|
2545
|
+
const options = this.#options.editPrediction;
|
|
2546
|
+
const currentSelection = this.#selections?.[0];
|
|
2547
|
+
const path = this.#editSession?.fileInfo?.name;
|
|
2548
|
+
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;
|
|
2549
|
+
if (!this.#includesEditPredictionPath(path)) return;
|
|
2550
|
+
const isLineEditable = (line) => this.#isLineInRenderRange(line) && this.#isLineRenderable(line);
|
|
2551
|
+
if (!isLineEditable(getCaretPosition(currentSelection).line)) {
|
|
2552
|
+
this.#retryEditPredictionOnRender = true;
|
|
2553
|
+
return;
|
|
2554
|
+
}
|
|
2555
|
+
const request = buildEditPredictionRequest(path, document, cursorOffset, this.#editPredictionHistory, isLineEditable);
|
|
2556
|
+
if (request === void 0) return;
|
|
2557
|
+
const excerptStartOffset = document.offsetAt({
|
|
2558
|
+
line: request.excerptStartLine,
|
|
2559
|
+
character: 0
|
|
2560
|
+
});
|
|
2561
|
+
const editableStart = excerptStartOffset + request.editableRange.start;
|
|
2562
|
+
const editableEnd = excerptStartOffset + request.editableRange.end;
|
|
2563
|
+
const controller = new AbortController();
|
|
2564
|
+
const generation = ++this.#editPredictionGeneration;
|
|
2565
|
+
this.#editPredictionAbortController = controller;
|
|
2566
|
+
let prediction;
|
|
2567
|
+
try {
|
|
2568
|
+
prediction = options.provider.predict(request, { signal: controller.signal });
|
|
2569
|
+
} catch {
|
|
2570
|
+
this.#editPredictionAbortController = void 0;
|
|
2571
|
+
return;
|
|
2572
|
+
}
|
|
2573
|
+
Promise.resolve(prediction).then((response) => {
|
|
2574
|
+
const selection = this.#selections?.[0];
|
|
2575
|
+
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;
|
|
2576
|
+
if (response == null || !Array.isArray(response.edits) || response.edits.length === 0 || response.edits.length > MAX_EDIT_PREDICTION_RESPONSE_EDITS || response.newCursor == null) return;
|
|
2577
|
+
const resolvedEdits = [];
|
|
2578
|
+
let responseBytes = 0;
|
|
2579
|
+
for (const edit of response.edits) {
|
|
2580
|
+
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;
|
|
2581
|
+
responseBytes += editPredictionTextEncoder.encode(edit.newText).byteLength;
|
|
2582
|
+
if (responseBytes > MAX_EDIT_PREDICTION_RESPONSE_BYTES) return;
|
|
2583
|
+
const start = document.offsetAt(edit.range.start);
|
|
2584
|
+
const end = document.offsetAt(edit.range.end);
|
|
2585
|
+
const resolvedEdit = document.resolveEdits([edit])[0];
|
|
2586
|
+
if (resolvedEdit.start !== start || resolvedEdit.end !== end) return;
|
|
2587
|
+
resolvedEdits.push(resolvedEdit);
|
|
2588
|
+
}
|
|
2589
|
+
resolvedEdits.sort((left, right) => {
|
|
2590
|
+
const startDelta = left.start - right.start;
|
|
2591
|
+
return startDelta === 0 ? left.end - right.end : startDelta;
|
|
2592
|
+
});
|
|
2593
|
+
for (let index = 0; index < resolvedEdits.length; index++) {
|
|
2594
|
+
const edit = resolvedEdits[index];
|
|
2595
|
+
if (edit.start < editableStart || edit.end > editableEnd || index > 0 && resolvedEdits[index - 1].end > edit.start) return;
|
|
2596
|
+
}
|
|
2597
|
+
const edits = resolvedEdits.filter((edit) => edit.text !== document.getTextSlice(edit.start, edit.end));
|
|
2598
|
+
if (edits.length === 0) return;
|
|
2599
|
+
const firstEditPosition = document.positionAt(edits[0].start);
|
|
2600
|
+
const lastEditPosition = document.positionAt(edits.at(-1).end);
|
|
2601
|
+
const affectedStart = document.offsetAt({
|
|
2602
|
+
line: firstEditPosition.line,
|
|
2603
|
+
character: 0
|
|
2604
|
+
});
|
|
2605
|
+
const affectedEnd = document.offsetAt({
|
|
2606
|
+
line: lastEditPosition.line,
|
|
2607
|
+
character: document.getLineLength(lastEditPosition.line)
|
|
2608
|
+
});
|
|
2609
|
+
const predictedParts = [];
|
|
2610
|
+
let consumed = affectedStart;
|
|
2611
|
+
for (const edit of edits) {
|
|
2612
|
+
predictedParts.push(document.getTextSlice(consumed, edit.start), edit.text);
|
|
2613
|
+
consumed = edit.end;
|
|
2614
|
+
}
|
|
2615
|
+
predictedParts.push(document.getTextSlice(consumed, affectedEnd));
|
|
2616
|
+
const predictedLines = predictedParts.join("").split(/\r\n|\r|\n/);
|
|
2617
|
+
const affectedEndLine = firstEditPosition.line + predictedLines.length - 1;
|
|
2618
|
+
const lineDelta = predictedLines.length - (lastEditPosition.line - firstEditPosition.line + 1);
|
|
2619
|
+
const newCursor = response.newCursor;
|
|
2620
|
+
if (!Number.isInteger(newCursor.line) || !Number.isInteger(newCursor.character) || newCursor.line < 0 || newCursor.character < 0) return;
|
|
2621
|
+
if (newCursor.line >= firstEditPosition.line && newCursor.line <= affectedEndLine) {
|
|
2622
|
+
const line = predictedLines[newCursor.line - firstEditPosition.line];
|
|
2623
|
+
if (newCursor.character > line.length || splitsSurrogatePair(line, newCursor.character)) return;
|
|
2624
|
+
} else {
|
|
2625
|
+
const originalLine = newCursor.line < firstEditPosition.line ? newCursor.line : newCursor.line - lineDelta;
|
|
2626
|
+
if (originalLine < 0 || originalLine >= document.lineCount || newCursor.character > document.getLineLength(originalLine)) return;
|
|
2627
|
+
const originalOffset = document.offsetAt({
|
|
2628
|
+
line: originalLine,
|
|
2629
|
+
character: newCursor.character
|
|
2630
|
+
});
|
|
2631
|
+
if (splitsSurrogatePair(document.charAt(originalOffset - 1) + document.charAt(originalOffset), 1)) return;
|
|
2632
|
+
}
|
|
2633
|
+
this.#editPrediction = {
|
|
2634
|
+
document,
|
|
2635
|
+
version: request.version,
|
|
2636
|
+
cursorOffset,
|
|
2637
|
+
rendered: false,
|
|
2638
|
+
response: {
|
|
2639
|
+
edits: edits.map((edit) => ({
|
|
2640
|
+
range: {
|
|
2641
|
+
start: document.positionAt(edit.start),
|
|
2642
|
+
end: document.positionAt(edit.end)
|
|
2643
|
+
},
|
|
2644
|
+
newText: edit.text
|
|
2645
|
+
})),
|
|
2646
|
+
newCursor: { ...newCursor }
|
|
2647
|
+
}
|
|
2648
|
+
};
|
|
2649
|
+
this.#updateSelections(this.#selections);
|
|
2650
|
+
}).catch(() => {}).finally(() => {
|
|
2651
|
+
if (this.#editPredictionAbortController === controller) this.#editPredictionAbortController = void 0;
|
|
2652
|
+
});
|
|
2653
|
+
}, EDIT_PREDICTION_DEBOUNCE_MS);
|
|
2654
|
+
}
|
|
2655
|
+
#recordEditPredictionHistory(change, source) {
|
|
2656
|
+
const textDocument = this.#editSession?.document;
|
|
2657
|
+
const path = this.#editSession?.fileInfo?.name;
|
|
2658
|
+
const transaction = getTextDocumentChangeTransaction(change);
|
|
2659
|
+
if (textDocument === void 0 || path === void 0 || transaction === void 0 || !this.#includesEditPredictionPath(path)) return;
|
|
2660
|
+
this.#editPredictionHistory = recordEditPrediction(this.#editPredictionHistory, path, textDocument, transaction, source);
|
|
2661
|
+
}
|
|
2662
|
+
#acceptEditPrediction() {
|
|
2663
|
+
const prediction = this.#editPrediction;
|
|
2664
|
+
const textDocument = this.#editSession?.document;
|
|
2665
|
+
const selection = this.#selections?.[0];
|
|
2666
|
+
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;
|
|
2667
|
+
const { edits, newCursor } = prediction.response;
|
|
2668
|
+
this.#cancelEditPrediction(true);
|
|
2669
|
+
const change = textDocument.applyEdits(edits.map((edit) => ({
|
|
2670
|
+
range: {
|
|
2671
|
+
start: { ...edit.range.start },
|
|
2672
|
+
end: { ...edit.range.end }
|
|
2673
|
+
},
|
|
2674
|
+
newText: edit.newText
|
|
2675
|
+
})), true, this.#selections, void 0, true);
|
|
2676
|
+
if (change === void 0) {
|
|
2677
|
+
this.#scheduleEditPrediction();
|
|
2678
|
+
return;
|
|
2679
|
+
}
|
|
2680
|
+
const cursor = textDocument.normalizePosition(newCursor);
|
|
2681
|
+
const nextSelections = [{
|
|
2682
|
+
start: cursor,
|
|
2683
|
+
end: cursor,
|
|
2684
|
+
direction: 0
|
|
2685
|
+
}];
|
|
2686
|
+
textDocument.setLastUndoSelectionsAfter(nextSelections);
|
|
2687
|
+
this.#applyChange(change, nextSelections, this.#applyChangeToLineAnnotations(change), { editSource: "prediction" });
|
|
2688
|
+
}
|
|
2689
|
+
#renderEditPrediction(renderCtx) {
|
|
2690
|
+
const prediction = this.#editPrediction;
|
|
2691
|
+
const textDocument = this.#editSession?.document;
|
|
2692
|
+
if (prediction !== void 0) prediction.rendered = false;
|
|
2693
|
+
const composed = this.#getEditPredictionGroups();
|
|
2694
|
+
if (prediction == null || textDocument == null || composed == null || !composed.allVisible) return;
|
|
2695
|
+
for (const group of composed.groups) {
|
|
2696
|
+
const { edit, endIndex } = group;
|
|
2697
|
+
const { start, end } = edit.range;
|
|
2698
|
+
const isDeletion = edit.newText.length === 0;
|
|
2699
|
+
const isReplacement = comparePosition(start, end) !== 0;
|
|
2700
|
+
const lineLength = textDocument.getLineLength(start.line);
|
|
2701
|
+
const isMidLineInsertion = !isReplacement && start.character < lineLength;
|
|
2702
|
+
if (isReplacement) this.#renderSelection(renderCtx, isDeletion ? "editPredictionDeletion" : "editPredictionReplacement", {
|
|
2703
|
+
start,
|
|
2704
|
+
end
|
|
2705
|
+
});
|
|
2706
|
+
else if (isMidLineInsertion) this.#renderSelection(renderCtx, "editPredictionInsertion", {
|
|
2707
|
+
start,
|
|
2708
|
+
end: {
|
|
2709
|
+
line: start.line,
|
|
2710
|
+
character: lineLength
|
|
2711
|
+
}
|
|
2712
|
+
});
|
|
2713
|
+
if (isDeletion) continue;
|
|
2714
|
+
const [anchorLeft, anchorWrapLine] = this.#getCharX(start.line, start.character);
|
|
2715
|
+
const lineLeft = this.#getCharX(start.line, 0)[0];
|
|
2716
|
+
const anchorTop = this.#getLineY(start.line) + anchorWrapLine * this.#metrics.lineHeight;
|
|
2717
|
+
const key = `editPrediction-${endIndex}`;
|
|
2718
|
+
let element = this.#overlayElements?.get(key);
|
|
2719
|
+
if (element !== void 0) {
|
|
2720
|
+
this.#overlayElements?.delete(key);
|
|
2721
|
+
element.replaceChildren();
|
|
2722
|
+
} else element = h("span", {
|
|
2723
|
+
ariaHidden: "true",
|
|
2724
|
+
contentEditable: "false",
|
|
2725
|
+
dataset: "editPrediction"
|
|
2726
|
+
}, renderCtx.fragment);
|
|
2727
|
+
if (isReplacement) {
|
|
2728
|
+
element.dataset.replacement = "";
|
|
2729
|
+
const lineElement = this.#getLineElement(start.line);
|
|
2730
|
+
if (lineElement !== void 0) element.style.setProperty("--diffs-edit-prediction-bg", getComputedStyle(lineElement).getPropertyValue("--diffs-line-bg"));
|
|
2731
|
+
} else {
|
|
2732
|
+
delete element.dataset.replacement;
|
|
2733
|
+
element.style.removeProperty("--diffs-edit-prediction-bg");
|
|
2734
|
+
}
|
|
2735
|
+
this.#fillGhostTextElement(element, edit.newText, anchorLeft, lineLeft, this.#cloneInsertionSuffix(group));
|
|
2736
|
+
element.style.transform = `translateX(${lineLeft}px) translateY(${anchorTop}px)`;
|
|
2737
|
+
renderCtx.elements.set(key, element);
|
|
2738
|
+
}
|
|
2739
|
+
prediction.rendered = true;
|
|
2740
|
+
}
|
|
2144
2741
|
#updateSelections(selections) {
|
|
2145
2742
|
this.__postponeBgTokenizeToNextFrame();
|
|
2743
|
+
const previousSelections = this.#selections;
|
|
2744
|
+
let selectionsChanged = previousSelections?.length !== selections.length;
|
|
2745
|
+
if (!selectionsChanged && previousSelections !== void 0) for (let i = 0; i < selections.length; i++) {
|
|
2746
|
+
const previous = previousSelections[i];
|
|
2747
|
+
const next = selections[i];
|
|
2748
|
+
if (previous.direction !== next.direction || comparePosition(previous.start, next.start) !== 0 || comparePosition(previous.end, next.end) !== 0) {
|
|
2749
|
+
selectionsChanged = true;
|
|
2750
|
+
break;
|
|
2751
|
+
}
|
|
2752
|
+
}
|
|
2753
|
+
if (selectionsChanged) this.#cancelEditPrediction(true);
|
|
2754
|
+
this.#syncEditPredictionSpacers();
|
|
2146
2755
|
this.#primaryCaretElement = void 0;
|
|
2147
2756
|
this.#setEditorActiveLineSafe(null);
|
|
2148
2757
|
if (selections.length === 0 && this.#matches === void 0 && this.#markerRenderer === void 0) {
|
|
@@ -2151,6 +2760,7 @@ var Editor = class {
|
|
|
2151
2760
|
this.#overlayElements?.clear();
|
|
2152
2761
|
this.#selectionAction?.cleanup();
|
|
2153
2762
|
this.#selectionAction = void 0;
|
|
2763
|
+
if (selectionsChanged) this.#scheduleEditPrediction();
|
|
2154
2764
|
return;
|
|
2155
2765
|
}
|
|
2156
2766
|
const fragment = document.createDocumentFragment();
|
|
@@ -2169,14 +2779,14 @@ var Editor = class {
|
|
|
2169
2779
|
if (!isCollapsedSelection(selection)) this.#renderSelection(renderCtx, "selection", selection);
|
|
2170
2780
|
this.#renderCaret(renderCtx, selection, selection === primarySelection);
|
|
2171
2781
|
}
|
|
2172
|
-
const bracketMatchRanges = this.#options.matchBrackets !== false && this.#
|
|
2782
|
+
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
2783
|
if (bracketMatchRanges !== void 0) for (const range of bracketMatchRanges) this.#renderSelection(renderCtx, "bracketMatch", range);
|
|
2174
2784
|
}
|
|
2175
|
-
const textDocument = this.#
|
|
2785
|
+
const textDocument = this.#editSession?.document;
|
|
2176
2786
|
if (this.#matches !== void 0 && textDocument !== void 0) {
|
|
2177
2787
|
const matches = this.#matches;
|
|
2178
2788
|
const renderRange = this.#renderRange;
|
|
2179
|
-
const renderedLineRanges = renderRange
|
|
2789
|
+
const renderedLineRanges = renderRange != null && Number.isFinite(renderRange.totalLines) || this.#isDiff && this.#fileDiffInstance?.options.expandUnchanged !== true ? this.#getRenderedEditableLineRanges() : void 0;
|
|
2180
2790
|
const primarySelection = this.#selections?.at(-1);
|
|
2181
2791
|
const primaryStartOffset = primarySelection !== void 0 ? textDocument.offsetAt(primarySelection.start) : -1;
|
|
2182
2792
|
const primaryEndOffset = primarySelection !== void 0 ? textDocument.offsetAt(primarySelection.end) : -1;
|
|
@@ -2221,14 +2831,70 @@ var Editor = class {
|
|
|
2221
2831
|
}
|
|
2222
2832
|
}
|
|
2223
2833
|
if (this.#markerRenderer !== void 0 && textDocument !== void 0) for (const marker of this.#markerRenderer.markers) this.#renderSelection(renderCtx, "marker", marker, markerSeverityDatasetKey(marker.severity));
|
|
2834
|
+
this.#renderEditPrediction(renderCtx);
|
|
2224
2835
|
this.#overlayElement?.appendChild(fragment);
|
|
2225
2836
|
this.#overlayElements?.forEach((el) => el.remove());
|
|
2226
2837
|
this.#overlayElements?.clear();
|
|
2227
2838
|
this.#overlayElements = renderCtx.elements;
|
|
2228
2839
|
this.#updateSelectionActionPopover();
|
|
2840
|
+
if (selectionsChanged) this.#scheduleEditPrediction();
|
|
2229
2841
|
}
|
|
2230
|
-
#
|
|
2231
|
-
|
|
2842
|
+
#renderCarets() {
|
|
2843
|
+
const carets = this.#carets;
|
|
2844
|
+
const renderCaret = this.#options.renderCaret;
|
|
2845
|
+
const overlayElement = this.#overlayElement;
|
|
2846
|
+
this.#caretHighlightElements?.forEach((element) => element.remove());
|
|
2847
|
+
this.#caretHighlightElements = void 0;
|
|
2848
|
+
if (carets === void 0 || renderCaret === void 0 || overlayElement === void 0) {
|
|
2849
|
+
this.#caretElements?.forEach((element) => element.remove());
|
|
2850
|
+
this.#caretElements = void 0;
|
|
2851
|
+
return;
|
|
2852
|
+
}
|
|
2853
|
+
const elements = this.#caretElements ??= /* @__PURE__ */ new Map();
|
|
2854
|
+
for (const [trackedCaret, element] of elements) if (!this.#isLineVisible(trackedCaret.caret.focus.line)) {
|
|
2855
|
+
element.remove();
|
|
2856
|
+
elements.delete(trackedCaret);
|
|
2857
|
+
}
|
|
2858
|
+
const fragment = document.createDocumentFragment();
|
|
2859
|
+
const highlightElements = [];
|
|
2860
|
+
for (const trackedCaret of carets) {
|
|
2861
|
+
const { caret } = trackedCaret;
|
|
2862
|
+
const { line, character } = caret.focus;
|
|
2863
|
+
if (trackedCaret.anchorOffset !== trackedCaret.focusOffset) {
|
|
2864
|
+
const highlightContext = {
|
|
2865
|
+
fragment,
|
|
2866
|
+
elements: /* @__PURE__ */ new Map()
|
|
2867
|
+
};
|
|
2868
|
+
this.#renderSelection(highlightContext, "caretHighlight", trackedCaret.anchorOffset < trackedCaret.focusOffset ? {
|
|
2869
|
+
start: caret.anchor,
|
|
2870
|
+
end: caret.focus
|
|
2871
|
+
} : {
|
|
2872
|
+
start: caret.focus,
|
|
2873
|
+
end: caret.anchor
|
|
2874
|
+
}, void 0, caret.focus);
|
|
2875
|
+
for (const highlightElement of highlightContext.elements.values()) {
|
|
2876
|
+
highlightElement.style.setProperty("--diffs-caret-highlight-bg", `color-mix(in srgb, ${caret.metadata.color} 32%, transparent)`);
|
|
2877
|
+
highlightElements.push(highlightElement);
|
|
2878
|
+
}
|
|
2879
|
+
}
|
|
2880
|
+
if (!this.#isLineVisible(line)) continue;
|
|
2881
|
+
let element = elements.get(trackedCaret);
|
|
2882
|
+
if (element === void 0) {
|
|
2883
|
+
element = h("div", {
|
|
2884
|
+
dataset: "remoteCaret",
|
|
2885
|
+
children: [renderCaret(caret)]
|
|
2886
|
+
}, fragment);
|
|
2887
|
+
elements.set(trackedCaret, element);
|
|
2888
|
+
}
|
|
2889
|
+
const [left, wrapLine] = this.#getCharX(line, character);
|
|
2890
|
+
const top = this.#getLineY(line) + wrapLine * this.#metrics.lineHeight;
|
|
2891
|
+
element.style.transform = `translateX(${left}px) translateY(${top}px)`;
|
|
2892
|
+
}
|
|
2893
|
+
this.#caretHighlightElements = highlightElements;
|
|
2894
|
+
overlayElement.appendChild(fragment);
|
|
2895
|
+
}
|
|
2896
|
+
#renderSelection(renderCtx, type, range, extraDataset, connectedCaret) {
|
|
2897
|
+
if (this.#editSession?.document == null) return;
|
|
2232
2898
|
const { start, end } = range;
|
|
2233
2899
|
let firstLine = start.line;
|
|
2234
2900
|
let endLine = end.line + 1;
|
|
@@ -2241,12 +2907,18 @@ var Editor = class {
|
|
|
2241
2907
|
if (!this.#isLineVisible(line)) continue;
|
|
2242
2908
|
const isLastLine = line === end.line;
|
|
2243
2909
|
const startChar = line === start.line ? start.character : 0;
|
|
2244
|
-
const endChar = isLastLine ? end.character : this.#
|
|
2910
|
+
const endChar = isLastLine ? end.character : this.#editSession?.document.getLineLength(line);
|
|
2911
|
+
if (startChar === endChar && (type === "editPredictionDeletion" || type === "editPredictionReplacement")) {
|
|
2912
|
+
if (isLastLine && line !== start.line) continue;
|
|
2913
|
+
const [left, wrapLine] = this.#getCharX(line, startChar);
|
|
2914
|
+
this.#renderSelectionBlock(renderCtx, type, line, wrapLine, left, this.#metrics.ch, extraDataset);
|
|
2915
|
+
continue;
|
|
2916
|
+
}
|
|
2245
2917
|
if (this.#isWrap) {
|
|
2246
2918
|
const contentWidth = this.#getContentWidth();
|
|
2247
|
-
const lineText = this.#
|
|
2919
|
+
const lineText = this.#editSession?.document.getLineText(line);
|
|
2248
2920
|
if (2 * this.#metrics.ch + this.#metrics.measureTextWidth(lineText) > contentWidth) {
|
|
2249
|
-
this.#renderWrappedSelection(renderCtx, line, lineText, startChar, endChar, isLastLine, type, extraDataset);
|
|
2921
|
+
this.#renderWrappedSelection(renderCtx, line, lineText, startChar, endChar, isLastLine, type, extraDataset, connectedCaret);
|
|
2250
2922
|
continue;
|
|
2251
2923
|
}
|
|
2252
2924
|
}
|
|
@@ -2258,10 +2930,13 @@ var Editor = class {
|
|
|
2258
2930
|
if (!isLastLine && type === "selection") paddingEnd = this.#metrics.ch;
|
|
2259
2931
|
if (startChar === endChar) width = paddingEnd;
|
|
2260
2932
|
else width = this.#getCharX(line, endChar)[0] - left + paddingEnd;
|
|
2261
|
-
this.#renderSelectionBlock(renderCtx, type, line, 0, left, width, extraDataset
|
|
2933
|
+
this.#renderSelectionBlock(renderCtx, type, line, 0, left, width, extraDataset, {
|
|
2934
|
+
start: connectedCaret?.line === start.line && connectedCaret.character === start.character && line === start.line,
|
|
2935
|
+
end: connectedCaret?.line === end.line && connectedCaret.character === end.character && line === end.line
|
|
2936
|
+
});
|
|
2262
2937
|
}
|
|
2263
2938
|
}
|
|
2264
|
-
#renderWrappedSelection(renderCtx, line, lineText, startChar, endChar, isLastLine, type, extraDataset) {
|
|
2939
|
+
#renderWrappedSelection(renderCtx, line, lineText, startChar, endChar, isLastLine, type, extraDataset, connectedCaret) {
|
|
2265
2940
|
const wrapOffsets = this.#wrapLineTextOrWholeLine(line);
|
|
2266
2941
|
const segmentCount = wrapOffsets.length - 1;
|
|
2267
2942
|
const offsetLeft = this.#getGutterWidth() + this.#metrics.ch + (this.#activeContentOffset?.left ?? 0);
|
|
@@ -2276,7 +2951,10 @@ var Editor = class {
|
|
|
2276
2951
|
let paddingEnd = 0;
|
|
2277
2952
|
if (!isLastLine && wrapLine === segmentCount - 1 && type === "selection") paddingEnd = this.#metrics.ch;
|
|
2278
2953
|
const segmentWidth = wrapStartChar === wrapEndChar ? paddingEnd : this.#segmentTextWidth(lineText, segmentStart, wrapEndChar) - segmentStartWidth + paddingEnd;
|
|
2279
|
-
this.#renderSelectionBlock(renderCtx, type, line, wrapLine, segmentLeft, segmentWidth, extraDataset
|
|
2954
|
+
this.#renderSelectionBlock(renderCtx, type, line, wrapLine, segmentLeft, segmentWidth, extraDataset, {
|
|
2955
|
+
start: connectedCaret?.line === line && connectedCaret.character === startChar && wrapStartChar === startChar,
|
|
2956
|
+
end: connectedCaret?.line === line && connectedCaret.character === endChar && wrapEndChar === endChar
|
|
2957
|
+
});
|
|
2280
2958
|
}
|
|
2281
2959
|
}
|
|
2282
2960
|
#segmentTextWidth(lineText, segmentStart, character) {
|
|
@@ -2285,13 +2963,13 @@ var Editor = class {
|
|
|
2285
2963
|
const asciiColumns = getExpandedAsciiTextColumns(segmentText, this.#metrics.tabSize);
|
|
2286
2964
|
return asciiColumns !== -1 ? asciiColumns * this.#metrics.ch : this.#metrics.measureTextWidth(segmentText);
|
|
2287
2965
|
}
|
|
2288
|
-
#renderSelectionBlock(renderCtx, type, line, wrapLine, left, width, extraDataset) {
|
|
2966
|
+
#renderSelectionBlock(renderCtx, type, line, wrapLine, left, width, extraDataset, connectedCaretEdge) {
|
|
2289
2967
|
if (width === 0) return;
|
|
2290
2968
|
const { ch, lineHeight } = this.#metrics;
|
|
2291
2969
|
const y = this.#getLineY(line) + wrapLine * lineHeight;
|
|
2292
2970
|
const cacheKey = `${type}-${line}/${wrapLine}-${left}-${width} ${extraDataset ?? ""}`;
|
|
2293
2971
|
const overlayEls = this.#overlayElements;
|
|
2294
|
-
const rounded = (this.#options.roundedSelection ?? true) && type === "selection";
|
|
2972
|
+
const rounded = (this.#options.roundedSelection ?? true) && (type === "selection" || type === "caretHighlight");
|
|
2295
2973
|
const addRoundedCorner = (line, wrapLine, left, radius) => {
|
|
2296
2974
|
const top = this.#getLineY(line) + wrapLine * lineHeight;
|
|
2297
2975
|
const lineElement = this.#getLineElement(line);
|
|
@@ -2321,7 +2999,7 @@ var Editor = class {
|
|
|
2321
2999
|
cornerEl.style.cssText = css;
|
|
2322
3000
|
overlayEls.delete(cacheKey);
|
|
2323
3001
|
} else cornerEl = h("div", {
|
|
2324
|
-
dataset: "selectionRange",
|
|
3002
|
+
dataset: type === "caretHighlight" ? "caretHighlightRange" : "selectionRange",
|
|
2325
3003
|
style: { cssText: css },
|
|
2326
3004
|
children: [h("div", { dataset })]
|
|
2327
3005
|
}, renderCtx.fragment);
|
|
@@ -2366,6 +3044,14 @@ var Editor = class {
|
|
|
2366
3044
|
dataset.rbl = "";
|
|
2367
3045
|
dataset.rbr = "";
|
|
2368
3046
|
}
|
|
3047
|
+
if (connectedCaretEdge?.start === true) {
|
|
3048
|
+
delete dataset.rtl;
|
|
3049
|
+
delete dataset.rbl;
|
|
3050
|
+
}
|
|
3051
|
+
if (connectedCaretEdge?.end === true) {
|
|
3052
|
+
delete dataset.rtr;
|
|
3053
|
+
delete dataset.rbr;
|
|
3054
|
+
}
|
|
2369
3055
|
};
|
|
2370
3056
|
let rangeEl = renderCtx.elements.get(cacheKey);
|
|
2371
3057
|
if (rangeEl !== void 0) {
|
|
@@ -2378,6 +3064,10 @@ var Editor = class {
|
|
|
2378
3064
|
} else rangeEl = h("div", { dataset: extraDataset ? [type + "Range", extraDataset] : type + "Range" }, renderCtx.fragment);
|
|
2379
3065
|
rangeEl.style.width = `${width}px`;
|
|
2380
3066
|
rangeEl.style.transform = `translateX(${left}px) translateY(${y}px)`;
|
|
3067
|
+
if (type === "editPredictionInsertion" || type === "editPredictionReplacement") {
|
|
3068
|
+
const lineElement = this.#getLineElement(line);
|
|
3069
|
+
if (lineElement !== void 0) rangeEl.style.setProperty("--diffs-edit-prediction-bg", getComputedStyle(lineElement).getPropertyValue("--diffs-line-bg"));
|
|
3070
|
+
} else rangeEl.style.removeProperty("--diffs-edit-prediction-bg");
|
|
2381
3071
|
if (rounded) addRadiusStyle(rangeEl);
|
|
2382
3072
|
renderCtx.elements.set(cacheKey, rangeEl);
|
|
2383
3073
|
}
|
|
@@ -2400,7 +3090,7 @@ var Editor = class {
|
|
|
2400
3090
|
#updateSelectionActionPopover() {
|
|
2401
3091
|
const primarySelection = this.#selections?.at(-1);
|
|
2402
3092
|
const overlayElement = this.#overlayElement;
|
|
2403
|
-
const textDocument = this.#
|
|
3093
|
+
const textDocument = this.#editSession?.document;
|
|
2404
3094
|
const renderSelectionAction = this.#options.renderSelectionAction;
|
|
2405
3095
|
const cleanup = () => {
|
|
2406
3096
|
this.#selectionAction?.cleanup();
|
|
@@ -2424,7 +3114,7 @@ var Editor = class {
|
|
|
2424
3114
|
return getActiveSelection();
|
|
2425
3115
|
},
|
|
2426
3116
|
applyEdits: (edits) => this.applyEdits(edits),
|
|
2427
|
-
getSelectionText: () => this.#
|
|
3117
|
+
getSelectionText: () => this.#editSession?.document?.getText(getActiveSelection()) ?? "",
|
|
2428
3118
|
replaceSelectionText: (text) => {
|
|
2429
3119
|
this.#replaceSelectionText(text, [getActiveSelection()]);
|
|
2430
3120
|
},
|
|
@@ -2494,7 +3184,7 @@ var Editor = class {
|
|
|
2494
3184
|
}
|
|
2495
3185
|
#renderSearchPanel(mode) {
|
|
2496
3186
|
this.#searchPanel?.cleanup();
|
|
2497
|
-
const textDocument = this.#
|
|
3187
|
+
const textDocument = this.#editSession?.document;
|
|
2498
3188
|
const preElement = this.#fileContainer?.shadowRoot?.querySelector("pre");
|
|
2499
3189
|
const selections = this.#selections;
|
|
2500
3190
|
if (textDocument === void 0 || preElement == null) return;
|
|
@@ -2577,13 +3267,13 @@ var Editor = class {
|
|
|
2577
3267
|
this.#retainSearchPanelFocus = false;
|
|
2578
3268
|
}
|
|
2579
3269
|
#getSelectionText() {
|
|
2580
|
-
const textDocument = this.#
|
|
3270
|
+
const textDocument = this.#editSession?.document;
|
|
2581
3271
|
const selections = this.#selections;
|
|
2582
3272
|
if (textDocument === void 0 || selections === void 0) return "";
|
|
2583
3273
|
return getSelectionText(textDocument, selections);
|
|
2584
3274
|
}
|
|
2585
3275
|
#getSelectionClipboardTexts() {
|
|
2586
|
-
const textDocument = this.#
|
|
3276
|
+
const textDocument = this.#editSession?.document;
|
|
2587
3277
|
const selections = this.#selections;
|
|
2588
3278
|
if (textDocument === void 0 || selections === void 0) return [];
|
|
2589
3279
|
return getSelectionClipboardTexts(textDocument, selections);
|
|
@@ -2595,7 +3285,7 @@ var Editor = class {
|
|
|
2595
3285
|
if (selectionTexts.length > 1) clipboardData.setData(MULTI_SELECTION_CLIPBOARD_TYPE, JSON.stringify(selectionTexts));
|
|
2596
3286
|
}
|
|
2597
3287
|
#cutSelectionText() {
|
|
2598
|
-
const textDocument = this.#
|
|
3288
|
+
const textDocument = this.#editSession?.document;
|
|
2599
3289
|
const selections = this.#selections;
|
|
2600
3290
|
if (textDocument === void 0 || selections === void 0 || selections.length === 0) return "";
|
|
2601
3291
|
if (selections.some((selection) => isCollapsedSelection(selection))) {
|
|
@@ -2608,7 +3298,7 @@ var Editor = class {
|
|
|
2608
3298
|
return text;
|
|
2609
3299
|
}
|
|
2610
3300
|
#applySelectionCutEdits(edits, nextSelectionOffsets) {
|
|
2611
|
-
const textDocument = this.#
|
|
3301
|
+
const textDocument = this.#editSession?.document;
|
|
2612
3302
|
const selections = this.#selections;
|
|
2613
3303
|
if (textDocument === void 0 || selections === void 0 || edits.length === 0) return;
|
|
2614
3304
|
const change = textDocument.applyResolvedEdits(edits, true, selections, void 0, true);
|
|
@@ -2626,7 +3316,7 @@ var Editor = class {
|
|
|
2626
3316
|
}
|
|
2627
3317
|
#replaceSelectionText(text, selections = this.#selections, undoBoundary = false, textOrder = "selection") {
|
|
2628
3318
|
if (selections === void 0) return;
|
|
2629
|
-
const textDocument = this.#
|
|
3319
|
+
const textDocument = this.#editSession?.document;
|
|
2630
3320
|
const primarySelection = selections.at(-1);
|
|
2631
3321
|
if (textDocument === void 0 || primarySelection === void 0) return;
|
|
2632
3322
|
const { nextSelections, change } = Array.isArray(text) && text.length === selections.length ? applyTextReplaceToSelections(textDocument, selections, text, this.#lineAnnotations, undoBoundary, textOrder) : applyTextChangeToSelections(textDocument, selections, {
|
|
@@ -2638,14 +3328,14 @@ var Editor = class {
|
|
|
2638
3328
|
}
|
|
2639
3329
|
#deleteSelectionText(forward = false) {
|
|
2640
3330
|
const selections = this.#selections;
|
|
2641
|
-
const textDocument = this.#
|
|
3331
|
+
const textDocument = this.#editSession?.document;
|
|
2642
3332
|
if (selections === void 0 || textDocument === void 0) return;
|
|
2643
3333
|
const { nextSelections, change } = applyDeleteCharacterToSelections(textDocument, selections, forward, this.#lineAnnotations, this.#metrics.tabSize);
|
|
2644
3334
|
if (change !== void 0) this.#applyChange(change, nextSelections, this.#applyChangeToLineAnnotations(change));
|
|
2645
3335
|
}
|
|
2646
3336
|
#deleteSoftLineBackward() {
|
|
2647
3337
|
const selections = this.#selections;
|
|
2648
|
-
const textDocument = this.#
|
|
3338
|
+
const textDocument = this.#editSession?.document;
|
|
2649
3339
|
if (selections === void 0 || textDocument === void 0) return;
|
|
2650
3340
|
const { nextSelections, change } = applyDeleteSoftLineBackwardToSelections(textDocument, selections, this.#isWrap ? (line, character) => {
|
|
2651
3341
|
const wrapOffsets = this.#wrapLineTextOrWholeLine(line);
|
|
@@ -2660,35 +3350,33 @@ var Editor = class {
|
|
|
2660
3350
|
}
|
|
2661
3351
|
#deleteWordBackward() {
|
|
2662
3352
|
const selections = this.#selections;
|
|
2663
|
-
const textDocument = this.#
|
|
3353
|
+
const textDocument = this.#editSession?.document;
|
|
2664
3354
|
if (selections === void 0 || textDocument === void 0) return;
|
|
2665
3355
|
const { nextSelections, change } = applyDeleteWordBackwardToSelections(textDocument, selections, this.#lineAnnotations);
|
|
2666
3356
|
if (change !== void 0) this.#applyChange(change, nextSelections, this.#applyChangeToLineAnnotations(change));
|
|
2667
3357
|
}
|
|
2668
3358
|
#deleteHardLineForward() {
|
|
2669
3359
|
const selections = this.#selections;
|
|
2670
|
-
const textDocument = this.#
|
|
3360
|
+
const textDocument = this.#editSession?.document;
|
|
2671
3361
|
if (selections === void 0 || textDocument === void 0) return;
|
|
2672
3362
|
const { nextSelections, change } = applyDeleteHardLineForwardToSelections(textDocument, selections, this.#lineAnnotations);
|
|
2673
3363
|
if (change !== void 0) this.#applyChange(change, nextSelections, this.#applyChangeToLineAnnotations(change));
|
|
2674
3364
|
}
|
|
2675
3365
|
#insertTranspose() {
|
|
2676
3366
|
const selections = this.#selections;
|
|
2677
|
-
const textDocument = this.#
|
|
3367
|
+
const textDocument = this.#editSession?.document;
|
|
2678
3368
|
if (selections === void 0 || textDocument === void 0) return;
|
|
2679
3369
|
const { nextSelections, change } = applyTransposeToSelections(textDocument, selections, this.#lineAnnotations);
|
|
2680
3370
|
if (change !== void 0) this.#applyChange(change, nextSelections, this.#applyChangeToLineAnnotations(change));
|
|
2681
3371
|
}
|
|
2682
3372
|
#applyChange(change, newSelections, newLineAnnotations, options) {
|
|
2683
|
-
|
|
2684
|
-
const
|
|
2685
|
-
if (
|
|
2686
|
-
|
|
2687
|
-
|
|
2688
|
-
|
|
2689
|
-
|
|
2690
|
-
lineAnnotations
|
|
2691
|
-
});
|
|
3373
|
+
if (this.#editPrediction != null) this.#cancelEditPrediction(true);
|
|
3374
|
+
const textDocument = this.#editSession?.document;
|
|
3375
|
+
if (textDocument !== void 0 && this.#carets !== void 0) for (const trackedCaret of this.#carets) {
|
|
3376
|
+
trackedCaret.anchorOffset = remapOffsetThroughEdits(trackedCaret.anchorOffset, change.changes);
|
|
3377
|
+
trackedCaret.focusOffset = remapOffsetThroughEdits(trackedCaret.focusOffset, change.changes);
|
|
3378
|
+
trackedCaret.caret.anchor = textDocument.positionAt(trackedCaret.anchorOffset);
|
|
3379
|
+
trackedCaret.caret.focus = textDocument.positionAt(trackedCaret.focusOffset);
|
|
2692
3380
|
}
|
|
2693
3381
|
if (change.lineDelta !== 0 || this.#isWrap) {
|
|
2694
3382
|
for (const line of this.#lineYCache.keys()) if (line >= change.startLine) this.#lineYCache.delete(line);
|
|
@@ -2717,9 +3405,14 @@ var Editor = class {
|
|
|
2717
3405
|
}
|
|
2718
3406
|
}
|
|
2719
3407
|
this.#rerender(change, newLineAnnotations, renderRange, shouldUpdateBuffer);
|
|
3408
|
+
if (newSelections != null) this.#updateSelections(newSelections);
|
|
3409
|
+
this.#fileInstance?.__acknowledgeDocumentUpdate();
|
|
3410
|
+
this.#checkpointEditSessionState();
|
|
3411
|
+
this.#recordEditPredictionHistory(change, options?.editSource ?? "user");
|
|
3412
|
+
this.#scheduleEditPrediction();
|
|
3413
|
+
this.#emitChange(change.changes, newLineAnnotations ?? this.#lineAnnotations);
|
|
2720
3414
|
if (options?.skipSearchRefresh !== true && this.#searchPanel !== void 0 && this.#matches !== void 0) this.#searchPanel.updateMatches({ syncSelection: false });
|
|
2721
|
-
if (newSelections
|
|
2722
|
-
this.#updateSelections(newSelections);
|
|
3415
|
+
if (newSelections != null) {
|
|
2723
3416
|
if (options?.skipFocus !== true) {
|
|
2724
3417
|
const revealTarget = newSelections.at(-1);
|
|
2725
3418
|
if (revealTarget !== void 0) this.#revealLineIfCollapsed(getCaretPosition(revealTarget).line);
|
|
@@ -2737,11 +3430,17 @@ var Editor = class {
|
|
|
2737
3430
|
}
|
|
2738
3431
|
}
|
|
2739
3432
|
}
|
|
3433
|
+
#emitChange(changes, lineAnnotations) {
|
|
3434
|
+
const file = this.getFile();
|
|
3435
|
+
const publishChange = this.#publishChange;
|
|
3436
|
+
if (file == null || publishChange == null) return;
|
|
3437
|
+
publishChange(changes, file, lineAnnotations);
|
|
3438
|
+
}
|
|
2740
3439
|
#applyChangeToLineAnnotations(change) {
|
|
2741
|
-
if (this.#lineAnnotations
|
|
3440
|
+
if (this.#lineAnnotations != null) {
|
|
2742
3441
|
const nextLineAnnotations = applyDocumentChangeToLineAnnotations(change, this.#lineAnnotations);
|
|
2743
|
-
if (nextLineAnnotations
|
|
2744
|
-
this.#
|
|
3442
|
+
if (nextLineAnnotations != null) {
|
|
3443
|
+
this.#editSession?.document?.setLastUndoLineAnnotations(this.#lineAnnotations, nextLineAnnotations);
|
|
2745
3444
|
return nextLineAnnotations;
|
|
2746
3445
|
}
|
|
2747
3446
|
}
|
|
@@ -2762,11 +3461,15 @@ var Editor = class {
|
|
|
2762
3461
|
}
|
|
2763
3462
|
return ranges;
|
|
2764
3463
|
}
|
|
3464
|
+
#isLineInRenderRange(line) {
|
|
3465
|
+
const renderRange = this.#renderRange;
|
|
3466
|
+
return renderRange == null || line >= renderRange.startingLine && line < renderRange.startingLine + renderRange.totalLines;
|
|
3467
|
+
}
|
|
2765
3468
|
#getLineElement(line) {
|
|
2766
3469
|
let lineElement = this.#lineElementsCache.get(line);
|
|
2767
3470
|
if (lineElement !== void 0) return lineElement ?? void 0;
|
|
2768
3471
|
const renderRange = this.#renderRange;
|
|
2769
|
-
if (
|
|
3472
|
+
if (!this.#isLineInRenderRange(line)) return;
|
|
2770
3473
|
const contentElement = this.#contentElement;
|
|
2771
3474
|
if (contentElement === void 0) return;
|
|
2772
3475
|
if (renderRange !== void 0) {
|
|
@@ -2817,7 +3520,7 @@ var Editor = class {
|
|
|
2817
3520
|
}
|
|
2818
3521
|
#getCharX(line, char) {
|
|
2819
3522
|
if (this.#lastAccessedCharX !== void 0 && this.#lastAccessedCharX[0] === line && this.#lastAccessedCharX[1] === char) return [this.#lastAccessedCharX[2], this.#lastAccessedCharX[3]];
|
|
2820
|
-
const lineText = this.#
|
|
3523
|
+
const lineText = this.#editSession?.document?.getLineText(line);
|
|
2821
3524
|
const offsetLeft = this.#getGutterWidth() + this.#metrics.ch;
|
|
2822
3525
|
if (lineText === void 0 || lineText.length === 0 || char <= 0) return [offsetLeft + (this.#activeContentOffset?.left ?? 0), 0];
|
|
2823
3526
|
const boundedCharacter = snapTextOffsetToUnicodeBoundary(lineText, Math.min(char, lineText.length));
|
|
@@ -2863,7 +3566,7 @@ var Editor = class {
|
|
|
2863
3566
|
const cachedOffsets = this.#wrapLineOffsetsCache.get(line);
|
|
2864
3567
|
if (cachedOffsets !== void 0) return cachedOffsets;
|
|
2865
3568
|
if (this.#wrapLineOffsetsCache.size >= MAX_WRAP_OFFSETS_CACHE_LINES) this.#wrapLineOffsetsCache.clear();
|
|
2866
|
-
const lineText = this.#
|
|
3569
|
+
const lineText = this.#editSession?.document?.getLineText(line);
|
|
2867
3570
|
if (lineText === void 0 || lineText.length === 0) {
|
|
2868
3571
|
const offsets = new Uint32Array([0]);
|
|
2869
3572
|
this.#wrapLineOffsetsCache.set(line, offsets);
|
|
@@ -2901,7 +3604,8 @@ var Editor = class {
|
|
|
2901
3604
|
const measureGrapheme = (index) => {
|
|
2902
3605
|
range.setStart(textNode, graphemeStart(index));
|
|
2903
3606
|
range.setEnd(textNode, graphemeStart(index + 1));
|
|
2904
|
-
|
|
3607
|
+
const clientRects = range.getClientRects();
|
|
3608
|
+
return clientRects.item(clientRects.length - 1) ?? range.getBoundingClientRect();
|
|
2905
3609
|
};
|
|
2906
3610
|
starts.push(0);
|
|
2907
3611
|
let lastTop = measureGrapheme(0).top;
|
|
@@ -2933,7 +3637,7 @@ var Editor = class {
|
|
|
2933
3637
|
#wrapLineTextOrWholeLine(line) {
|
|
2934
3638
|
const offsets = this.#wrapLineText(line);
|
|
2935
3639
|
if (offsets !== void 0) return offsets;
|
|
2936
|
-
const length = this.#
|
|
3640
|
+
const length = this.#editSession?.document?.getLineText(line)?.length ?? 0;
|
|
2937
3641
|
return Uint32Array.of(0, length);
|
|
2938
3642
|
}
|
|
2939
3643
|
#rangeBelongsToEditor({ startContainer, endContainer }) {
|
|
@@ -2942,11 +3646,31 @@ var Editor = class {
|
|
|
2942
3646
|
return contentEl.contains(startContainer) && contentEl.contains(endContainer);
|
|
2943
3647
|
}
|
|
2944
3648
|
#isLineVisible(line) {
|
|
2945
|
-
const lineCount = this.#
|
|
3649
|
+
const lineCount = this.#editSession?.document?.lineCount ?? 0;
|
|
2946
3650
|
if (line < 0 || line >= lineCount) return false;
|
|
2947
3651
|
return this.#getLineElement(line) !== void 0;
|
|
2948
3652
|
}
|
|
2949
3653
|
};
|
|
3654
|
+
function getEditSession({ type, editStateKey, owner, initialState, previousSession }) {
|
|
3655
|
+
if (initialState != null && initialState.type !== type) throw new TypeError(`Editor: initialState: a ${initialState.type} state cannot initialize a ${type} editor`);
|
|
3656
|
+
const initialSession = initialState;
|
|
3657
|
+
if (editStateKey != null) return EditStateManager.activate(type, editStateKey, owner, initialSession);
|
|
3658
|
+
if (initialSession != null) return initialSession;
|
|
3659
|
+
if (previousSession != null) return previousSession;
|
|
3660
|
+
return type === "file" ? { type: "file" } : { type: "file-diff" };
|
|
3661
|
+
}
|
|
3662
|
+
function gridTrackSpan(child) {
|
|
3663
|
+
if (!(child instanceof HTMLElement)) return 1;
|
|
3664
|
+
return Number(child.dataset.bufferSize ?? 1);
|
|
3665
|
+
}
|
|
3666
|
+
function isValidEditPredictionPosition(document, position) {
|
|
3667
|
+
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);
|
|
3668
|
+
}
|
|
3669
|
+
function splitsSurrogatePair(text, offset) {
|
|
3670
|
+
const previous = text.charCodeAt(offset - 1);
|
|
3671
|
+
const next = text.charCodeAt(offset);
|
|
3672
|
+
return offset > 0 && offset < text.length && previous >= 55296 && previous <= 56319 && next >= 56320 && next <= 57343;
|
|
3673
|
+
}
|
|
2950
3674
|
//#endregion
|
|
2951
3675
|
export { Editor };
|
|
2952
3676
|
|