@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
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EditStateManager.d.ts","names":[],"sources":["../../src/editor/EditStateManager.ts"],"mappings":";;;;;;UAcU,sBAAA,eACM,UAAA;EAGd,QAAA,GAAW,YAAA,CAAa,KAAA,EAAO,WAAA;EAC/B,QAAA,GAAW,IAAA,CAAK,YAAA;EAChB,MAAA,GAAS,eAAA;AAAA;AAAA,UAGM,sBAAA,gCAEP,sBAAsB,SAAS,WAAA;EACvC,IAAA;EACA,WAAA;AAAA;AAAA,UAGe,0BAAA,gCAEP,sBAAA,cAAoC,WAAA;EAC5C,IAAA;EACA,WAAA,GAAc,2BAAA;AAAA;AAAA,KAGJ,kBAAA,eACI,UAAA,GAAa,UAAA,2BAEzB,sBAAA,CAAuB,KAAA,EAAO,WAAA,KAC/B,KAAA,kBACG,IAAA,CAAK,sBAAA,4BACL,IAAA,CAAK,0BAAA;;cAuHL,qBAAA;EAAA;EAhJJ;EAqJA,QAAA,eAAuB,UAAA,sBACrB,IAAA,EAAM,KAAA,EACN,YAAA,UACA,KAAA,EAAO,MAAA,CAAO,KAAA,EAAO,WAAA,EAAa,KAAA,GAClC,YAAA,GAAe,kBAAA,CAAmB,KAAA,EAAO,WAAA,IACxC,kBAAA,CAAmB,KAAA,EAAO,WAAA;EA1JL;;;;EA8KxB,WAAA,qBACE,YAAA,UACA,KAAA,EAAO,MAAA,SAAe,WAAA,EAAa,KAAA,GACnC,OAAA;EA/KF;;;AAAwB;EAwLxB,eAAA,qBACE,YAAA,UACA,KAAA,EAAO,MAAA,cAAoB,WAAA,EAAa,KAAA,GACxC,OAAA;EAxLmC;EA8LrC,GAAA,eAAkB,UAAA,eAChB,IAAA,EAAM,KAAA,EACN,YAAA,WACC,SAAA,CAAU,KAAA,EAAO,WAAA;EA/LU;EAwM9B,KAAA,CACE,IAAA,EAAM,UAAA,EACN,YAAA,UACA,KAAA,GAAQ,qBAAA;EA3MF;EAmNR,QAAA;EAKA,WAAA,CAAY,QAAA;AAAA;AAAA,UAMG,qBAAA;EACf,QAAA;EACA,OAAA;EACA,MAAA;EACA,UAAA;EACA,IAAA;AAAA;AAAA,iBAGc,oBAAA,CAAqB,KAAA,EAAO,eAAA,GAAkB,eAAe;AAAA,iBAW7D,kBAAA,eAAiC,UAAA,eAC/C,OAAA,EAAS,kBAAA,CAAmB,KAAA,EAAO,WAAA,IAClC,SAAA,CAAU,KAAA,EAAO,WAAA;AAAA,cAmCP,gBAAA,EAAkB,qBACF"}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import LRUMapPkg from "lru_map";
|
|
2
|
+
//#region src/editor/EditStateManager.ts
|
|
3
|
+
const DEFAULT_EDIT_STATE_CAPACITY = 100;
|
|
4
|
+
/** Owns dormant edit state and active-key exclusion for one editor type. */
|
|
5
|
+
var EditStateManagerNamespace = class {
|
|
6
|
+
type;
|
|
7
|
+
#states = new LRUMapPkg.LRUMap(DEFAULT_EDIT_STATE_CAPACITY);
|
|
8
|
+
#sessions = /* @__PURE__ */ new Map();
|
|
9
|
+
constructor(type) {
|
|
10
|
+
this.type = type;
|
|
11
|
+
}
|
|
12
|
+
activate(editStateKey, owner, initialState) {
|
|
13
|
+
const activeSession = this.#sessions.get(editStateKey);
|
|
14
|
+
if (activeSession != null && activeSession.owner !== owner) throw new Error(`Editor: editStateKey "${editStateKey}" is already attached to another editor`);
|
|
15
|
+
if (activeSession != null) {
|
|
16
|
+
if (initialState != null) activeSession.session = initialState;
|
|
17
|
+
return activeSession.session;
|
|
18
|
+
}
|
|
19
|
+
const retainedState = this.#states.delete(editStateKey);
|
|
20
|
+
const emptyState = { type: this.type };
|
|
21
|
+
const state = initialState ?? retainedState ?? emptyState;
|
|
22
|
+
this.#sessions.set(editStateKey, {
|
|
23
|
+
owner,
|
|
24
|
+
session: state
|
|
25
|
+
});
|
|
26
|
+
return state;
|
|
27
|
+
}
|
|
28
|
+
release(editStateKey, owner, discard = false) {
|
|
29
|
+
const activeSession = this.#sessions.get(editStateKey);
|
|
30
|
+
if (activeSession?.owner !== owner) return;
|
|
31
|
+
this.#sessions.delete(editStateKey);
|
|
32
|
+
if (discard) return;
|
|
33
|
+
const retainedState = toManagedEditState(activeSession.session);
|
|
34
|
+
if (retainedState != null) this.#states.set(editStateKey, retainedState);
|
|
35
|
+
}
|
|
36
|
+
get(editStateKey) {
|
|
37
|
+
const activeSession = this.#sessions.get(editStateKey);
|
|
38
|
+
if (activeSession != null) {
|
|
39
|
+
const state = toManagedEditState(activeSession.session);
|
|
40
|
+
if (state == null) return;
|
|
41
|
+
return state;
|
|
42
|
+
}
|
|
43
|
+
return this.#states.find(editStateKey);
|
|
44
|
+
}
|
|
45
|
+
/** Clear dormant state for a key. Omit `parts` to clear everything. */
|
|
46
|
+
clear(editStateKey, parts) {
|
|
47
|
+
if (this.#sessions.has(editStateKey)) return false;
|
|
48
|
+
const state = this.#states.find(editStateKey);
|
|
49
|
+
if (state == null) return false;
|
|
50
|
+
if (parts == null || parts.document === true) this.#states.delete(editStateKey);
|
|
51
|
+
else applyClearEditStateOptions(state, parts);
|
|
52
|
+
return true;
|
|
53
|
+
}
|
|
54
|
+
clearAll() {
|
|
55
|
+
this.#states.clear();
|
|
56
|
+
}
|
|
57
|
+
setCapacity(capacity) {
|
|
58
|
+
if (!Number.isSafeInteger(capacity) || capacity < 1) throw new RangeError("EditStateManager: capacity must be a positive integer");
|
|
59
|
+
while (this.#states.size > capacity) this.#states.shift();
|
|
60
|
+
this.#states.limit = capacity;
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
/** Keeps file and diff edit state in independent persistence domains. */
|
|
64
|
+
var EditStateManagerClass = class {
|
|
65
|
+
#files = new EditStateManagerNamespace("file");
|
|
66
|
+
#diffs = new EditStateManagerNamespace("file-diff");
|
|
67
|
+
/** Mark a keyed session as active and return its initial or stored state. */
|
|
68
|
+
activate(type, editStateKey, owner, initialState) {
|
|
69
|
+
return type === "file" ? this.#files.activate(editStateKey, owner, initialState) : this.#diffs.activate(editStateKey, owner, initialState);
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Stop tracking this file session as active and store its current state,
|
|
73
|
+
* unless `discard` is true.
|
|
74
|
+
*/
|
|
75
|
+
releaseFile(editStateKey, owner, discard = false) {
|
|
76
|
+
this.#files.release(editStateKey, owner, discard);
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Stop tracking this diff session as active and store its current state,
|
|
80
|
+
* unless `discard` is true.
|
|
81
|
+
*/
|
|
82
|
+
releaseFileDiff(editStateKey, owner, discard = false) {
|
|
83
|
+
this.#diffs.release(editStateKey, owner, discard);
|
|
84
|
+
}
|
|
85
|
+
/** Return current state for an active or dormant editing session. */
|
|
86
|
+
get(type, editStateKey) {
|
|
87
|
+
return type === "file" ? this.#files.get(editStateKey) : this.#diffs.get(editStateKey);
|
|
88
|
+
}
|
|
89
|
+
/** Clear a dormant session, returning false when it is active or missing. */
|
|
90
|
+
clear(type, editStateKey, parts) {
|
|
91
|
+
return type === "file" ? this.#files.clear(editStateKey, parts) : this.#diffs.clear(editStateKey, parts);
|
|
92
|
+
}
|
|
93
|
+
/** Clear all dormant sessions without affecting active editors. */
|
|
94
|
+
clearAll() {
|
|
95
|
+
this.#files.clearAll();
|
|
96
|
+
this.#diffs.clearAll();
|
|
97
|
+
}
|
|
98
|
+
setCapacity(capacity) {
|
|
99
|
+
this.#files.setCapacity(capacity);
|
|
100
|
+
this.#diffs.setCapacity(capacity);
|
|
101
|
+
}
|
|
102
|
+
};
|
|
103
|
+
function cloneEditorViewState(state) {
|
|
104
|
+
return {
|
|
105
|
+
selections: state.selections?.map((selection) => ({
|
|
106
|
+
...selection,
|
|
107
|
+
start: { ...selection.start },
|
|
108
|
+
end: { ...selection.end }
|
|
109
|
+
})),
|
|
110
|
+
view: state.view == null ? void 0 : { ...state.view }
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
function toManagedEditState(session) {
|
|
114
|
+
if (session.document == null || session.fileInfo == null) return;
|
|
115
|
+
if (session.type === "file") {
|
|
116
|
+
session.editor ??= {};
|
|
117
|
+
return session;
|
|
118
|
+
}
|
|
119
|
+
if (session.diffSession == null) return;
|
|
120
|
+
session.editor ??= {};
|
|
121
|
+
return session;
|
|
122
|
+
}
|
|
123
|
+
function applyClearEditStateOptions(session, parts) {
|
|
124
|
+
if (session == null) return;
|
|
125
|
+
if (parts.history === true) session.document?.clearHistory();
|
|
126
|
+
if (session.editor != null) {
|
|
127
|
+
if (parts.editor === true || parts.selections === true) session.editor.selections = void 0;
|
|
128
|
+
if (parts.editor === true || parts.view === true) session.editor.view = void 0;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
const EditStateManager = new EditStateManagerClass();
|
|
132
|
+
//#endregion
|
|
133
|
+
export { EditStateManager, cloneEditorViewState, toManagedEditState };
|
|
134
|
+
|
|
135
|
+
//# sourceMappingURL=EditStateManager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EditStateManager.js","names":["#sessions","#states","#files","#diffs"],"sources":["../../src/editor/EditStateManager.ts"],"sourcesContent":["import LRUMapPkg from 'lru_map';\n\nimport type { FileContents } from '../types';\nimport type { Editor } from './editor';\nimport { TextDocument } from './textDocument';\nimport type {\n EditorType,\n EditorViewState,\n EditState,\n RetainedDiffSessionSnapshot,\n} from './types';\n\nconst DEFAULT_EDIT_STATE_CAPACITY = 100;\n\ninterface ManagedEditSessionBase<\n EType extends EditorType,\n LAnnotation = unknown,\n> {\n document?: TextDocument<EType, LAnnotation>;\n fileInfo?: Pick<FileContents, 'lang' | 'name'>;\n editor?: EditorViewState;\n}\n\nexport interface ManagedFileEditSession<\n LAnnotation = unknown,\n> extends ManagedEditSessionBase<'file', LAnnotation> {\n type: 'file';\n diffSession?: never;\n}\n\nexport interface ManagedFileDiffEditSession<\n LAnnotation = unknown,\n> extends ManagedEditSessionBase<'file-diff', LAnnotation> {\n type: 'file-diff';\n diffSession?: RetainedDiffSessionSnapshot;\n}\n\nexport type ManagedEditSession<\n EType extends EditorType = EditorType,\n LAnnotation = unknown,\n> = ManagedEditSessionBase<EType, LAnnotation> &\n (EType extends 'file'\n ? Pick<ManagedFileEditSession, 'type' | 'diffSession'>\n : Pick<ManagedFileDiffEditSession, 'type' | 'diffSession'>);\n\ninterface EditStateManagerSession<K extends EditorType> {\n owner: Editor<K, unknown>;\n session: ManagedEditSession<K>;\n}\n\n/** Owns dormant edit state and active-key exclusion for one editor type. */\nclass EditStateManagerNamespace<EType extends EditorType> {\n #states = new LRUMapPkg.LRUMap<string, EditState<EType>>(\n DEFAULT_EDIT_STATE_CAPACITY\n );\n #sessions = new Map<string, EditStateManagerSession<EType>>();\n\n constructor(readonly type: EType) {}\n\n activate<LAnnotation, Caret>(\n editStateKey: string,\n owner: Editor<EType, LAnnotation, Caret>,\n initialState?: ManagedEditSession<EType, LAnnotation>\n ): ManagedEditSession<EType, LAnnotation> {\n const activeSession = this.#sessions.get(editStateKey);\n if (activeSession != null && activeSession.owner !== owner) {\n throw new Error(\n `Editor: editStateKey \"${editStateKey}\" is already attached to another editor`\n );\n }\n if (activeSession != null) {\n if (initialState != null) {\n activeSession.session = initialState;\n }\n return activeSession.session as ManagedEditSession<EType, LAnnotation>;\n }\n const retainedState = this.#states.delete(editStateKey);\n const emptyState = {\n type: this.type,\n } as ManagedEditSession<EType>;\n const state = (initialState ??\n retainedState ??\n emptyState) as ManagedEditSession<EType, LAnnotation>;\n this.#sessions.set(editStateKey, {\n owner: owner as Editor<EType, unknown>,\n session: state as ManagedEditSession<EType>,\n });\n return state;\n }\n\n release<LAnnotation, Caret>(\n editStateKey: string,\n owner: Editor<EType, LAnnotation, Caret>,\n discard = false\n ): void {\n const activeSession = this.#sessions.get(editStateKey);\n if (activeSession?.owner !== owner) {\n return;\n }\n this.#sessions.delete(editStateKey);\n if (discard) {\n return;\n }\n const retainedState = toManagedEditState(activeSession.session);\n if (retainedState != null) {\n this.#states.set(editStateKey, retainedState as EditState<EType>);\n }\n }\n\n get<LAnnotation>(\n editStateKey: string\n ): EditState<EType, LAnnotation> | undefined {\n const activeSession = this.#sessions.get(editStateKey);\n if (activeSession != null) {\n const state = toManagedEditState(\n activeSession.session as ManagedEditSession<EType, LAnnotation>\n );\n if (state == null) {\n return undefined;\n }\n return state;\n }\n const state = this.#states.find(editStateKey);\n return state as EditState<EType, LAnnotation> | undefined;\n }\n\n /** Clear dormant state for a key. Omit `parts` to clear everything. */\n clear(editStateKey: string, parts?: ClearEditStateOptions): boolean {\n if (this.#sessions.has(editStateKey)) {\n return false;\n }\n\n const state = this.#states.find(editStateKey);\n if (state == null) {\n return false;\n }\n if (parts == null || parts.document === true) {\n this.#states.delete(editStateKey);\n } else {\n applyClearEditStateOptions(state, parts);\n }\n return true;\n }\n\n clearAll(): void {\n this.#states.clear();\n }\n\n setCapacity(capacity: number): void {\n if (!Number.isSafeInteger(capacity) || capacity < 1) {\n throw new RangeError(\n 'EditStateManager: capacity must be a positive integer'\n );\n }\n while (this.#states.size > capacity) {\n this.#states.shift();\n }\n this.#states.limit = capacity;\n }\n}\n\n/** Keeps file and diff edit state in independent persistence domains. */\nclass EditStateManagerClass {\n #files = new EditStateManagerNamespace('file');\n #diffs = new EditStateManagerNamespace('file-diff');\n\n /** Mark a keyed session as active and return its initial or stored state. */\n activate<EType extends EditorType, LAnnotation, Caret>(\n type: EType,\n editStateKey: string,\n owner: Editor<EType, LAnnotation, Caret>,\n initialState?: ManagedEditSession<EType, LAnnotation>\n ): ManagedEditSession<EType, LAnnotation> {\n return (\n type === 'file'\n ? this.#files.activate(\n editStateKey,\n owner as Editor<'file', LAnnotation, Caret>,\n initialState as ManagedFileEditSession<LAnnotation> | undefined\n )\n : this.#diffs.activate(\n editStateKey,\n owner as Editor<'file-diff', LAnnotation, Caret>,\n initialState as ManagedFileDiffEditSession<LAnnotation> | undefined\n )\n ) as ManagedEditSession<EType, LAnnotation>;\n }\n\n /**\n * Stop tracking this file session as active and store its current state,\n * unless `discard` is true.\n */\n releaseFile<LAnnotation, Caret>(\n editStateKey: string,\n owner: Editor<'file', LAnnotation, Caret>,\n discard = false\n ): void {\n this.#files.release(editStateKey, owner, discard);\n }\n\n /**\n * Stop tracking this diff session as active and store its current state,\n * unless `discard` is true.\n */\n releaseFileDiff<LAnnotation, Caret>(\n editStateKey: string,\n owner: Editor<'file-diff', LAnnotation, Caret>,\n discard = false\n ): void {\n this.#diffs.release(editStateKey, owner, discard);\n }\n\n /** Return current state for an active or dormant editing session. */\n get<EType extends EditorType, LAnnotation>(\n type: EType,\n editStateKey: string\n ): EditState<EType, LAnnotation> | undefined {\n return (\n type === 'file'\n ? this.#files.get<LAnnotation>(editStateKey)\n : this.#diffs.get<LAnnotation>(editStateKey)\n ) as EditState<EType, LAnnotation> | undefined;\n }\n\n /** Clear a dormant session, returning false when it is active or missing. */\n clear(\n type: EditorType,\n editStateKey: string,\n parts?: ClearEditStateOptions\n ): boolean {\n return type === 'file'\n ? this.#files.clear(editStateKey, parts)\n : this.#diffs.clear(editStateKey, parts);\n }\n\n /** Clear all dormant sessions without affecting active editors. */\n clearAll(): void {\n this.#files.clearAll();\n this.#diffs.clearAll();\n }\n\n setCapacity(capacity: number): void {\n this.#files.setCapacity(capacity);\n this.#diffs.setCapacity(capacity);\n }\n}\n\nexport interface ClearEditStateOptions {\n document?: boolean;\n history?: boolean;\n editor?: boolean;\n selections?: boolean;\n view?: boolean;\n}\n\nexport function cloneEditorViewState(state: EditorViewState): EditorViewState {\n return {\n selections: state.selections?.map((selection) => ({\n ...selection,\n start: { ...selection.start },\n end: { ...selection.end },\n })),\n view: state.view == null ? undefined : { ...state.view },\n };\n}\n\nexport function toManagedEditState<EType extends EditorType, LAnnotation>(\n session: ManagedEditSession<EType, LAnnotation>\n): EditState<EType, LAnnotation> | undefined {\n if (session.document == null || session.fileInfo == null) {\n return undefined;\n }\n if (session.type === 'file') {\n session.editor ??= {};\n return session as EditState<EType, LAnnotation>;\n }\n if (session.diffSession == null) {\n return undefined;\n }\n session.editor ??= {};\n return session as EditState<EType, LAnnotation>;\n}\n\nfunction applyClearEditStateOptions(\n session: ManagedEditSession | undefined,\n parts: ClearEditStateOptions\n): void {\n if (session == null) {\n return;\n }\n if (parts.history === true) {\n session.document?.clearHistory();\n }\n if (session.editor != null) {\n if (parts.editor === true || parts.selections === true) {\n session.editor.selections = undefined;\n }\n if (parts.editor === true || parts.view === true) {\n session.editor.view = undefined;\n }\n }\n}\n\nexport const EditStateManager: EditStateManagerClass =\n new EditStateManagerClass();\n"],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { RetainedDiffSessionSnapshot } from "./types.js";
|
|
2
|
+
|
|
3
|
+
//#region src/editor/cloneRetainedDiffSessionSnapshot.d.ts
|
|
4
|
+
declare function cloneRetainedDiffSessionSnapshot(snapshot: RetainedDiffSessionSnapshot): RetainedDiffSessionSnapshot;
|
|
5
|
+
//#endregion
|
|
6
|
+
export { cloneRetainedDiffSessionSnapshot };
|
|
7
|
+
//# sourceMappingURL=cloneRetainedDiffSessionSnapshot.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cloneRetainedDiffSessionSnapshot.d.ts","names":[],"sources":["../../src/editor/cloneRetainedDiffSessionSnapshot.ts"],"mappings":";;;iBAGgB,gCAAA,CACd,QAAA,EAAU,2BAAA,GACT,2BAA2B"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { cloneHunks } from "../utils/cloneFileDiffMetadata.js";
|
|
2
|
+
//#region src/editor/cloneRetainedDiffSessionSnapshot.ts
|
|
3
|
+
function cloneRetainedDiffSessionSnapshot(snapshot) {
|
|
4
|
+
return {
|
|
5
|
+
...snapshot,
|
|
6
|
+
oldFile: snapshot.oldFile != null ? {
|
|
7
|
+
...snapshot.oldFile,
|
|
8
|
+
lines: [...snapshot.oldFile.lines]
|
|
9
|
+
} : null,
|
|
10
|
+
hunks: cloneHunks(snapshot.hunks)
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
//#endregion
|
|
14
|
+
export { cloneRetainedDiffSessionSnapshot };
|
|
15
|
+
|
|
16
|
+
//# sourceMappingURL=cloneRetainedDiffSessionSnapshot.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cloneRetainedDiffSessionSnapshot.js","names":[],"sources":["../../src/editor/cloneRetainedDiffSessionSnapshot.ts"],"sourcesContent":["import { cloneHunks } from '../utils/cloneFileDiffMetadata';\nimport type { RetainedDiffSessionSnapshot } from './types';\n\nexport function cloneRetainedDiffSessionSnapshot(\n snapshot: RetainedDiffSessionSnapshot\n): RetainedDiffSessionSnapshot {\n return {\n ...snapshot,\n oldFile:\n snapshot.oldFile != null\n ? { ...snapshot.oldFile, lines: [...snapshot.oldFile.lines] }\n : null,\n hunks: cloneHunks(snapshot.hunks),\n };\n}\n"],"mappings":";;AAGA,SAAgB,iCACd,UAC6B;CAC7B,OAAO;EACL,GAAG;EACH,SACE,SAAS,WAAW,OAChB;GAAE,GAAG,SAAS;GAAS,OAAO,CAAC,GAAG,SAAS,QAAQ,KAAK;EAAE,IAC1D;EACN,OAAO,WAAW,SAAS,KAAK;CAClC;AACF"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { Position, TextEdit } from "./types.js";
|
|
2
|
+
import { TextDocumentChangeTransaction } from "./textDocumentChangeTransaction.js";
|
|
3
|
+
|
|
4
|
+
//#region src/editor/editPrediction.d.ts
|
|
5
|
+
interface EditPredictRequest {
|
|
6
|
+
/** Current file name/path as supplied to the File or FileDiff component. */
|
|
7
|
+
readonly path: string;
|
|
8
|
+
/** Document version. */
|
|
9
|
+
readonly version: number;
|
|
10
|
+
/** Document end-of-line sequence. */
|
|
11
|
+
readonly eol: '\n' | '\r\n' | '\r';
|
|
12
|
+
/** Bounded slice of the file around the cursor (not the whole file). */
|
|
13
|
+
readonly excerptText: string;
|
|
14
|
+
/** Zero-based document line where the excerpt starts. */
|
|
15
|
+
readonly excerptStartLine: number;
|
|
16
|
+
/** UTF-16 cursor offset relative to `excerptText`. */
|
|
17
|
+
readonly cursorOffsetInExcerpt: number;
|
|
18
|
+
/** Half-open UTF-16 range within `excerptText` that may be edited. */
|
|
19
|
+
readonly editableRange: {
|
|
20
|
+
readonly start: number;
|
|
21
|
+
readonly end: number;
|
|
22
|
+
};
|
|
23
|
+
/** Chronological, bounded edit history for this document. */
|
|
24
|
+
readonly editHistory: ReadonlyArray<{
|
|
25
|
+
/** Edit in unified-diff format. */readonly diff: string; /** Edit source. */
|
|
26
|
+
readonly source: 'user' | 'prediction';
|
|
27
|
+
}>;
|
|
28
|
+
}
|
|
29
|
+
interface EditPredictContext {
|
|
30
|
+
/** Aborted when the document or cursor changes. */
|
|
31
|
+
readonly signal: AbortSignal;
|
|
32
|
+
}
|
|
33
|
+
interface EditPredictResponse {
|
|
34
|
+
/** Non-overlapping edits using absolute document positions. */
|
|
35
|
+
readonly edits: readonly TextEdit[];
|
|
36
|
+
/** Absolute post-edit cursor position. */
|
|
37
|
+
readonly newCursor: Position;
|
|
38
|
+
}
|
|
39
|
+
interface EditPredictProvider {
|
|
40
|
+
/** Predicts the next edit for the given request. */
|
|
41
|
+
predict: (request: EditPredictRequest, context: EditPredictContext) => Promise<EditPredictResponse>;
|
|
42
|
+
}
|
|
43
|
+
interface EditPredictionHistoryRecord {
|
|
44
|
+
readonly path: string;
|
|
45
|
+
readonly hunk: string;
|
|
46
|
+
readonly start: number;
|
|
47
|
+
readonly end: number;
|
|
48
|
+
readonly at: number;
|
|
49
|
+
readonly source: 'user' | 'prediction';
|
|
50
|
+
readonly fragment?: EditPredictionHistoryFragment;
|
|
51
|
+
}
|
|
52
|
+
interface EditPredictionDocument {
|
|
53
|
+
readonly version: number;
|
|
54
|
+
readonly eol: '\n' | '\r\n' | '\r';
|
|
55
|
+
readonly lineCount: number;
|
|
56
|
+
positionAt(offset: number): Position;
|
|
57
|
+
positionsAt(offsets: readonly number[]): Position[];
|
|
58
|
+
offsetAt(position: Position): number;
|
|
59
|
+
getLineText(line: number): string;
|
|
60
|
+
getLineLength(line: number): number;
|
|
61
|
+
getTextSlice(start: number, end: number): string;
|
|
62
|
+
charAt(offset: number): string;
|
|
63
|
+
}
|
|
64
|
+
interface EditPredictionHistoryFragment {
|
|
65
|
+
readonly baseText: string;
|
|
66
|
+
readonly currentText: string;
|
|
67
|
+
readonly currentStart: number;
|
|
68
|
+
readonly currentEnd: number;
|
|
69
|
+
readonly startLine: number;
|
|
70
|
+
}
|
|
71
|
+
declare function recordEditPrediction(history: readonly EditPredictionHistoryRecord[], path: string, document: EditPredictionDocument, transaction: TextDocumentChangeTransaction, source: 'user' | 'prediction', at?: number): EditPredictionHistoryRecord[];
|
|
72
|
+
declare function buildEditPredictionRequest(path: string, document: EditPredictionDocument, cursorOffset: number, history: readonly EditPredictionHistoryRecord[], isLineEditable: (line: number) => boolean): EditPredictRequest | undefined;
|
|
73
|
+
declare function matchesEditPredictionPattern(path: string, pattern: string | RegExp): boolean;
|
|
74
|
+
//#endregion
|
|
75
|
+
export { EditPredictContext, EditPredictProvider, EditPredictRequest, EditPredictResponse, EditPredictionHistoryRecord, buildEditPredictionRequest, matchesEditPredictionPattern, recordEditPrediction };
|
|
76
|
+
//# sourceMappingURL=editPrediction.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"editPrediction.d.ts","names":[],"sources":["../../src/editor/editPrediction.ts"],"mappings":";;;;UAGiB,kBAAA;;WAEN,IAAA;EAFwB;EAAA,SAIxB,OAAA;EAY0B;EAAA,SAV1B,GAAA;EAFA;EAAA,SAIA,WAAA;EAAA;EAAA,SAEA,gBAAA;EAEA;EAAA,SAAA,qBAAA;EAE0B;EAAA,SAA1B,aAAA;IAAA,SAA0B,KAAA;IAAA,SAAwB,GAAA;EAAA;EAMhD;EAAA,SAJF,WAAA,EAAa,aAAa;IAIlB,4CAFN,IAAA,UAMsB;IAAA,SAJtB,MAAA;EAAA;AAAA;AAAA,UAII,kBAAA;EAKmB;EAAA,SAHzB,MAAA,EAAQ,WAAW;AAAA;AAAA,UAGb,mBAAA;EAEU;EAAA,SAAhB,KAAA,WAAgB,QAAA;EAEL;EAAA,SAAX,SAAA,EAAW,QAAQ;AAAA;AAAA,UAGb,mBAAA;EAAmB;EAElC,OAAA,GACE,OAAA,EAAS,kBAAA,EACT,OAAA,EAAS,kBAAA,KACN,OAAA,CAAQ,mBAAA;AAAA;AAAA,UAGE,2BAAA;EAAA,SACN,IAAA;EAAA,SACA,IAAA;EAAA,SACA,KAAA;EAAA,SACA,GAAA;EAAA,SACA,EAAA;EAAA,SACA,MAAA;EAAA,SACA,QAAA,GAAW,6BAA6B;AAAA;AAAA,UAGzC,sBAAA;EAAA,SACC,OAAA;EAAA,SACA,GAAA;EAAA,SACA,SAAA;EACT,UAAA,CAAW,MAAA,WAAiB,QAAA;EAC5B,WAAA,CAAY,OAAA,sBAA6B,QAAA;EACzC,QAAA,CAAS,QAAA,EAAU,QAAA;EACnB,WAAA,CAAY,IAAA;EACZ,aAAA,CAAc,IAAA;EACd,YAAA,CAAa,KAAA,UAAe,GAAA;EAC5B,MAAA,CAAO,MAAA;AAAA;AAAA,UAGC,6BAAA;EAAA,SACC,QAAA;EAAA,SACA,WAAA;EAAA,SACA,YAAA;EAAA,SACA,UAAA;EAAA,SACA,SAAA;AAAA;AAAA,iBAmTK,oBAAA,CACd,OAAA,WAAkB,2BAAA,IAClB,IAAA,UACA,QAAA,EAAU,sBAAA,EACV,WAAA,EAAa,6BAAA,EACb,MAAA,yBACA,EAAA,YACC,2BAAA;AAAA,iBAwLa,0BAAA,CACd,IAAA,UACA,QAAA,EAAU,sBAAA,EACV,YAAA,UACA,OAAA,WAAkB,2BAAA,IAClB,cAAA,GAAiB,IAAA,uBAChB,kBAAA;AAAA,iBAmKa,4BAAA,CACd,IAAA,UACA,OAAA,WAAkB,MAAM"}
|
|
@@ -0,0 +1,365 @@
|
|
|
1
|
+
//#region src/editor/editPrediction.ts
|
|
2
|
+
const EDITABLE_TOKENS = 350;
|
|
3
|
+
const CONTEXT_TOKENS = 150;
|
|
4
|
+
const MAX_EDITABLE_TOKENS = 512;
|
|
5
|
+
const MAX_CONTEXT_TOKENS = 662;
|
|
6
|
+
const MAX_REQUEST_BYTES = 128 * 1024;
|
|
7
|
+
const MAX_CAPTURE_BYTES = 6144;
|
|
8
|
+
const COALESCE_MS = 1e3;
|
|
9
|
+
const COALESCE_LINES = 8;
|
|
10
|
+
const DIFF_CONTEXT_LINES = 3;
|
|
11
|
+
const CAPTURE_CONTEXT_OPTIONS = [11, DIFF_CONTEXT_LINES];
|
|
12
|
+
const textEncoder = new TextEncoder();
|
|
13
|
+
function lineStarts(text) {
|
|
14
|
+
const starts = [0];
|
|
15
|
+
for (let index = 0; index < text.length; index++) {
|
|
16
|
+
if (text.charCodeAt(index) === 13 && text.charCodeAt(index + 1) === 10) index++;
|
|
17
|
+
if (text.charCodeAt(index) === 10 || text.charCodeAt(index) === 13) starts.push(index + 1);
|
|
18
|
+
}
|
|
19
|
+
return starts;
|
|
20
|
+
}
|
|
21
|
+
function diffLineCount(text, starts) {
|
|
22
|
+
if (text.length === 0) return 0;
|
|
23
|
+
return starts.at(-1) === text.length ? starts.length - 1 : starts.length;
|
|
24
|
+
}
|
|
25
|
+
function lineEnd(text, starts, line) {
|
|
26
|
+
const next = starts[line + 1];
|
|
27
|
+
return next === void 0 ? text.length : next - (text.charCodeAt(next - 1) === 10 && text.charCodeAt(next - 2) === 13 ? 2 : 1);
|
|
28
|
+
}
|
|
29
|
+
function linesEqual(left, leftStarts, leftLine, right, rightStarts, rightLine) {
|
|
30
|
+
const leftStart = leftStarts[leftLine];
|
|
31
|
+
const rightStart = rightStarts[rightLine];
|
|
32
|
+
const length = lineEnd(left, leftStarts, leftLine) - leftStart;
|
|
33
|
+
if (length !== lineEnd(right, rightStarts, rightLine) - rightStart) return false;
|
|
34
|
+
for (let index = 0; index < length; index++) if (left.charCodeAt(leftStart + index) !== right.charCodeAt(rightStart + index)) return false;
|
|
35
|
+
return true;
|
|
36
|
+
}
|
|
37
|
+
function lineDiffBounds(oldText, oldStarts, newText, newStarts) {
|
|
38
|
+
const oldLineCount = diffLineCount(oldText, oldStarts);
|
|
39
|
+
const newLineCount = diffLineCount(newText, newStarts);
|
|
40
|
+
let prefixLines = 0;
|
|
41
|
+
while (prefixLines < oldLineCount && prefixLines < newLineCount) {
|
|
42
|
+
if (!linesEqual(oldText, oldStarts, prefixLines, newText, newStarts, prefixLines)) break;
|
|
43
|
+
prefixLines++;
|
|
44
|
+
}
|
|
45
|
+
let suffixLines = 0;
|
|
46
|
+
while (suffixLines < oldLineCount - prefixLines && suffixLines < newLineCount - prefixLines) {
|
|
47
|
+
if (!linesEqual(oldText, oldStarts, oldLineCount - 1 - suffixLines, newText, newStarts, newLineCount - 1 - suffixLines)) break;
|
|
48
|
+
suffixLines++;
|
|
49
|
+
}
|
|
50
|
+
return {
|
|
51
|
+
oldLineCount,
|
|
52
|
+
newLineCount,
|
|
53
|
+
prefixLines,
|
|
54
|
+
suffixLines
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
function formatEditHunk(path, oldText, newText, lineOffset = 0) {
|
|
58
|
+
if (oldText === newText) return;
|
|
59
|
+
const oldStarts = lineStarts(oldText);
|
|
60
|
+
const newStarts = lineStarts(newText);
|
|
61
|
+
const bounds = lineDiffBounds(oldText, oldStarts, newText, newStarts);
|
|
62
|
+
if (bounds.prefixLines === bounds.oldLineCount && bounds.prefixLines === bounds.newLineCount) return;
|
|
63
|
+
const oldChangedEnd = bounds.oldLineCount - bounds.suffixLines;
|
|
64
|
+
const newChangedEnd = bounds.newLineCount - bounds.suffixLines;
|
|
65
|
+
const oldChanged = oldText.slice(oldStarts[bounds.prefixLines] ?? oldText.length, oldStarts[oldChangedEnd] ?? oldText.length);
|
|
66
|
+
const newChanged = newText.slice(newStarts[bounds.prefixLines] ?? newText.length, newStarts[newChangedEnd] ?? newText.length);
|
|
67
|
+
if (textEncoder.encode(oldChanged).byteLength > MAX_CAPTURE_BYTES || textEncoder.encode(newChanged).byteLength > MAX_CAPTURE_BYTES) return;
|
|
68
|
+
const start = Math.max(0, bounds.prefixLines - DIFF_CONTEXT_LINES);
|
|
69
|
+
const oldEnd = Math.min(bounds.oldLineCount, oldChangedEnd + DIFF_CONTEXT_LINES);
|
|
70
|
+
const newEnd = Math.min(bounds.newLineCount, newChangedEnd + DIFF_CONTEXT_LINES);
|
|
71
|
+
const oldCount = oldEnd - start;
|
|
72
|
+
const newCount = newEnd - start;
|
|
73
|
+
const line = start + lineOffset;
|
|
74
|
+
const output = [
|
|
75
|
+
`--- a/${path}`,
|
|
76
|
+
`+++ b/${path}`,
|
|
77
|
+
`@@ -${oldCount === 0 ? line : line + 1},${oldCount} +${newCount === 0 ? line : line + 1},${newCount} @@`
|
|
78
|
+
];
|
|
79
|
+
for (let line = start; line < bounds.prefixLines; line++) output.push(` ${oldText.slice(oldStarts[line], lineEnd(oldText, oldStarts, line))}`);
|
|
80
|
+
for (let line = bounds.prefixLines; line < oldChangedEnd; line++) output.push(`-${oldText.slice(oldStarts[line], lineEnd(oldText, oldStarts, line))}`);
|
|
81
|
+
for (let line = bounds.prefixLines; line < newChangedEnd; line++) output.push(`+${newText.slice(newStarts[line], lineEnd(newText, newStarts, line))}`);
|
|
82
|
+
for (let line = oldChangedEnd; line < oldEnd; line++) output.push(` ${oldText.slice(oldStarts[line], lineEnd(oldText, oldStarts, line))}`);
|
|
83
|
+
const hunk = output.join("\n");
|
|
84
|
+
return textEncoder.encode(hunk).byteLength <= MAX_CAPTURE_BYTES ? {
|
|
85
|
+
hunk,
|
|
86
|
+
bounds
|
|
87
|
+
} : void 0;
|
|
88
|
+
}
|
|
89
|
+
function applyEditsToSlice(text, sliceStart, edits) {
|
|
90
|
+
const chunks = [];
|
|
91
|
+
let offset = 0;
|
|
92
|
+
for (const edit of edits) {
|
|
93
|
+
const start = edit.start - sliceStart;
|
|
94
|
+
const end = edit.end - sliceStart;
|
|
95
|
+
if (start < offset || end < start || end > text.length) return;
|
|
96
|
+
chunks.push(text.slice(offset, start), edit.text);
|
|
97
|
+
offset = end;
|
|
98
|
+
}
|
|
99
|
+
chunks.push(text.slice(offset));
|
|
100
|
+
return chunks.join("");
|
|
101
|
+
}
|
|
102
|
+
function captureEditPredictionTransaction(document, transaction) {
|
|
103
|
+
const inverseEdits = transaction.inverseEdits;
|
|
104
|
+
if (inverseEdits.length === 0) return;
|
|
105
|
+
let changedStart = inverseEdits[0].start;
|
|
106
|
+
let changedEnd = inverseEdits[0].end;
|
|
107
|
+
for (let index = 1; index < inverseEdits.length; index++) {
|
|
108
|
+
changedStart = Math.min(changedStart, inverseEdits[index].start);
|
|
109
|
+
changedEnd = Math.max(changedEnd, inverseEdits[index].end);
|
|
110
|
+
}
|
|
111
|
+
const [startPosition, endPosition] = document.positionsAt([changedStart, changedEnd]);
|
|
112
|
+
for (const contextLines of CAPTURE_CONTEXT_OPTIONS) {
|
|
113
|
+
const startLine = Math.max(0, startPosition.line - contextLines);
|
|
114
|
+
const endLine = Math.min(document.lineCount - 1, endPosition.line + contextLines);
|
|
115
|
+
const afterStart = document.offsetAt({
|
|
116
|
+
line: startLine,
|
|
117
|
+
character: 0
|
|
118
|
+
});
|
|
119
|
+
const afterEnd = endLine + 1 < document.lineCount ? document.offsetAt({
|
|
120
|
+
line: endLine + 1,
|
|
121
|
+
character: 0
|
|
122
|
+
}) : document.offsetAt({
|
|
123
|
+
line: endLine,
|
|
124
|
+
character: document.getLineLength(endLine)
|
|
125
|
+
});
|
|
126
|
+
if (afterEnd - afterStart > MAX_CAPTURE_BYTES) continue;
|
|
127
|
+
const afterText = document.getTextSlice(afterStart, afterEnd);
|
|
128
|
+
if (textEncoder.encode(afterText).byteLength > MAX_CAPTURE_BYTES) continue;
|
|
129
|
+
const beforeText = applyEditsToSlice(afterText, afterStart, inverseEdits);
|
|
130
|
+
if (beforeText === void 0 || beforeText.length > MAX_CAPTURE_BYTES || textEncoder.encode(beforeText).byteLength > MAX_CAPTURE_BYTES) continue;
|
|
131
|
+
return {
|
|
132
|
+
beforeText,
|
|
133
|
+
afterText,
|
|
134
|
+
startOffset: afterStart,
|
|
135
|
+
startLine,
|
|
136
|
+
bounds: lineDiffBounds(beforeText, lineStarts(beforeText), afterText, lineStarts(afterText))
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
function recordEditPrediction(history, path, document, transaction, source, at = Date.now()) {
|
|
141
|
+
const kept = history.slice(-10);
|
|
142
|
+
const fragment = captureEditPredictionTransaction(document, transaction);
|
|
143
|
+
if (fragment === void 0) {
|
|
144
|
+
const previous = kept.at(-1);
|
|
145
|
+
if (previous?.fragment !== void 0) kept[kept.length - 1] = {
|
|
146
|
+
...previous,
|
|
147
|
+
fragment: void 0
|
|
148
|
+
};
|
|
149
|
+
return kept;
|
|
150
|
+
}
|
|
151
|
+
if (fragment.beforeText === fragment.afterText) return kept;
|
|
152
|
+
const changedStartLine = fragment.startLine + fragment.bounds.prefixLines;
|
|
153
|
+
const beforeChangedEndLine = fragment.startLine + fragment.bounds.oldLineCount - fragment.bounds.suffixLines;
|
|
154
|
+
const last = kept.at(-1);
|
|
155
|
+
const gap = last !== void 0 && changedStartLine > last.end ? changedStartLine - last.end : last !== void 0 && last.start > beforeChangedEndLine ? last.start - beforeChangedEndLine : 0;
|
|
156
|
+
if (last !== void 0 && last.fragment !== void 0 && last.path === path && last.source === source && at - last.at < COALESCE_MS && gap <= COALESCE_LINES) {
|
|
157
|
+
const previous = last.fragment;
|
|
158
|
+
const beforeEnd = fragment.startOffset + fragment.beforeText.length;
|
|
159
|
+
const overlapStart = Math.max(previous.currentStart, fragment.startOffset);
|
|
160
|
+
const overlapEnd = Math.min(previous.currentEnd, beforeEnd);
|
|
161
|
+
if (overlapStart <= overlapEnd && previous.currentText.slice(overlapStart - previous.currentStart, overlapEnd - previous.currentStart) === fragment.beforeText.slice(overlapStart - fragment.startOffset, overlapEnd - fragment.startOffset)) {
|
|
162
|
+
const unionStart = Math.min(previous.currentStart, fragment.startOffset);
|
|
163
|
+
const currentText = previous.currentStart <= fragment.startOffset ? previous.currentText + fragment.beforeText.slice(Math.max(0, previous.currentEnd - fragment.startOffset)) : fragment.beforeText + previous.currentText.slice(Math.max(0, beforeEnd - previous.currentStart));
|
|
164
|
+
const prefix = currentText.slice(0, previous.currentStart - unionStart);
|
|
165
|
+
const suffix = currentText.slice(previous.currentEnd - unionStart);
|
|
166
|
+
const baseText = prefix + previous.baseText + suffix;
|
|
167
|
+
const nextText = applyEditsToSlice(currentText, unionStart, transaction.appliedEdits);
|
|
168
|
+
const startLine = previous.currentStart <= fragment.startOffset ? previous.startLine : fragment.startLine;
|
|
169
|
+
if (nextText !== void 0 && baseText.length <= MAX_CAPTURE_BYTES && nextText.length <= MAX_CAPTURE_BYTES && textEncoder.encode(baseText).byteLength <= MAX_CAPTURE_BYTES && textEncoder.encode(nextText).byteLength <= MAX_CAPTURE_BYTES) {
|
|
170
|
+
if (baseText === nextText) {
|
|
171
|
+
kept.pop();
|
|
172
|
+
return kept;
|
|
173
|
+
}
|
|
174
|
+
const formatted = formatEditHunk(path, baseText, nextText, startLine);
|
|
175
|
+
if (formatted !== void 0) {
|
|
176
|
+
kept[kept.length - 1] = {
|
|
177
|
+
path,
|
|
178
|
+
hunk: formatted.hunk,
|
|
179
|
+
start: startLine + formatted.bounds.prefixLines,
|
|
180
|
+
end: startLine + formatted.bounds.newLineCount - formatted.bounds.suffixLines,
|
|
181
|
+
at,
|
|
182
|
+
source,
|
|
183
|
+
fragment: {
|
|
184
|
+
baseText,
|
|
185
|
+
currentText: nextText,
|
|
186
|
+
currentStart: unionStart,
|
|
187
|
+
currentEnd: unionStart + nextText.length,
|
|
188
|
+
startLine
|
|
189
|
+
}
|
|
190
|
+
};
|
|
191
|
+
return kept;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
const previous = kept.at(-1);
|
|
197
|
+
if (previous?.fragment !== void 0) kept[kept.length - 1] = {
|
|
198
|
+
...previous,
|
|
199
|
+
fragment: void 0
|
|
200
|
+
};
|
|
201
|
+
const formatted = formatEditHunk(path, fragment.beforeText, fragment.afterText, fragment.startLine);
|
|
202
|
+
if (formatted === void 0) return kept;
|
|
203
|
+
kept.push({
|
|
204
|
+
path,
|
|
205
|
+
hunk: formatted.hunk,
|
|
206
|
+
start: changedStartLine,
|
|
207
|
+
end: fragment.startLine + fragment.bounds.newLineCount - fragment.bounds.suffixLines,
|
|
208
|
+
at,
|
|
209
|
+
source,
|
|
210
|
+
fragment: {
|
|
211
|
+
baseText: fragment.beforeText,
|
|
212
|
+
currentText: fragment.afterText,
|
|
213
|
+
currentStart: fragment.startOffset,
|
|
214
|
+
currentEnd: fragment.startOffset + fragment.afterText.length,
|
|
215
|
+
startLine: fragment.startLine
|
|
216
|
+
}
|
|
217
|
+
});
|
|
218
|
+
return kept.slice(-10);
|
|
219
|
+
}
|
|
220
|
+
function expandLinewise(lineCount, costForLine, canExpandTo, first, last, remaining) {
|
|
221
|
+
while (remaining > 0 && (first > 0 || last < lineCount - 1)) {
|
|
222
|
+
let expanded = false;
|
|
223
|
+
if (first > 0 && canExpandTo(first - 1)) {
|
|
224
|
+
const cost = costForLine(first - 1);
|
|
225
|
+
if (cost <= remaining) {
|
|
226
|
+
first--;
|
|
227
|
+
remaining -= cost;
|
|
228
|
+
expanded = true;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
if (last < lineCount - 1 && canExpandTo(last + 1)) {
|
|
232
|
+
const cost = costForLine(last + 1);
|
|
233
|
+
if (cost <= remaining) {
|
|
234
|
+
last++;
|
|
235
|
+
remaining -= cost;
|
|
236
|
+
expanded = true;
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
if (!expanded) break;
|
|
240
|
+
}
|
|
241
|
+
return {
|
|
242
|
+
first,
|
|
243
|
+
last
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
function buildEditPredictionRequest(path, document, cursorOffset, history, isLineEditable) {
|
|
247
|
+
if (document.lineCount <= 0) return;
|
|
248
|
+
const lastLine = document.lineCount - 1;
|
|
249
|
+
const documentLength = document.offsetAt({
|
|
250
|
+
line: lastLine,
|
|
251
|
+
character: document.getLineLength(lastLine)
|
|
252
|
+
});
|
|
253
|
+
let cursor = Math.max(0, Math.min(Number.isFinite(cursorOffset) ? Math.trunc(cursorOffset) : 0, documentLength));
|
|
254
|
+
const previous = document.charAt(cursor - 1).charCodeAt(0);
|
|
255
|
+
const next = document.charAt(cursor).charCodeAt(0);
|
|
256
|
+
if (cursor > 0 && cursor < documentLength && (previous === 13 && next === 10 || previous >= 55296 && previous <= 56319 && next >= 56320 && next <= 57343)) cursor--;
|
|
257
|
+
const cursorLine = document.positionAt(cursor).line;
|
|
258
|
+
const editableLines = /* @__PURE__ */ new Map();
|
|
259
|
+
const canEdit = (line) => {
|
|
260
|
+
if (line < 0 || line >= document.lineCount) return false;
|
|
261
|
+
let editable = editableLines.get(line);
|
|
262
|
+
if (editable == null) {
|
|
263
|
+
editable = isLineEditable(line);
|
|
264
|
+
editableLines.set(line, editable);
|
|
265
|
+
}
|
|
266
|
+
return editable;
|
|
267
|
+
};
|
|
268
|
+
if (!canEdit(cursorLine)) return;
|
|
269
|
+
const tokenCosts = /* @__PURE__ */ new Map();
|
|
270
|
+
const costForLine = (line) => {
|
|
271
|
+
const cached = tokenCosts.get(line);
|
|
272
|
+
if (cached !== void 0) return cached;
|
|
273
|
+
const lineLength = document.getLineLength(line);
|
|
274
|
+
if (Math.floor(lineLength / 3) > MAX_CONTEXT_TOKENS) {
|
|
275
|
+
const cost = 663;
|
|
276
|
+
tokenCosts.set(line, cost);
|
|
277
|
+
return cost;
|
|
278
|
+
}
|
|
279
|
+
const cost = Math.max(1, Math.floor(textEncoder.encode(document.getLineText(line)).byteLength / 3));
|
|
280
|
+
tokenCosts.set(line, cost);
|
|
281
|
+
return cost;
|
|
282
|
+
};
|
|
283
|
+
let editableFirst = cursorLine;
|
|
284
|
+
let editableLast = cursorLine;
|
|
285
|
+
const initialBudget = Math.floor(EDITABLE_TOKENS * 3 / 4);
|
|
286
|
+
let remaining = Math.max(0, initialBudget - costForLine(cursorLine));
|
|
287
|
+
while (remaining > 0 && (canEdit(editableFirst - 1) || canEdit(editableLast + 1))) {
|
|
288
|
+
if (canEdit(editableLast + 1)) {
|
|
289
|
+
const cost = costForLine(editableLast + 1);
|
|
290
|
+
if (cost > remaining) break;
|
|
291
|
+
editableLast++;
|
|
292
|
+
remaining -= cost;
|
|
293
|
+
}
|
|
294
|
+
if (canEdit(editableFirst - 1) && remaining > 0) {
|
|
295
|
+
const cost = costForLine(editableFirst - 1);
|
|
296
|
+
if (cost > remaining) break;
|
|
297
|
+
editableFirst--;
|
|
298
|
+
remaining -= cost;
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
remaining += EDITABLE_TOKENS - initialBudget;
|
|
302
|
+
({first: editableFirst, last: editableLast} = expandLinewise(document.lineCount, costForLine, canEdit, editableFirst, editableLast, remaining));
|
|
303
|
+
let contextFirst = editableFirst;
|
|
304
|
+
let contextLast = editableLast;
|
|
305
|
+
({first: contextFirst, last: contextLast} = expandLinewise(document.lineCount, costForLine, () => true, contextFirst, contextLast, CONTEXT_TOKENS));
|
|
306
|
+
let editableTokens = 0;
|
|
307
|
+
for (let line = editableFirst; line <= editableLast; line++) editableTokens += costForLine(line);
|
|
308
|
+
let contextTokens = 0;
|
|
309
|
+
for (let line = contextFirst; line <= contextLast; line++) contextTokens += costForLine(line);
|
|
310
|
+
if (editableTokens > MAX_EDITABLE_TOKENS || contextTokens > MAX_CONTEXT_TOKENS) return;
|
|
311
|
+
const contextStart = document.offsetAt({
|
|
312
|
+
line: contextFirst,
|
|
313
|
+
character: 0
|
|
314
|
+
});
|
|
315
|
+
const contextEnd = document.offsetAt({
|
|
316
|
+
line: contextLast,
|
|
317
|
+
character: document.getLineLength(contextLast)
|
|
318
|
+
});
|
|
319
|
+
const excerptText = document.getTextSlice(contextStart, contextEnd);
|
|
320
|
+
const request = {
|
|
321
|
+
path,
|
|
322
|
+
version: document.version,
|
|
323
|
+
eol: document.eol,
|
|
324
|
+
excerptText,
|
|
325
|
+
excerptStartLine: contextFirst,
|
|
326
|
+
cursorOffsetInExcerpt: cursor - contextStart,
|
|
327
|
+
editableRange: {
|
|
328
|
+
start: document.offsetAt({
|
|
329
|
+
line: editableFirst,
|
|
330
|
+
character: 0
|
|
331
|
+
}) - contextStart,
|
|
332
|
+
end: document.offsetAt({
|
|
333
|
+
line: editableLast,
|
|
334
|
+
character: document.getLineLength(editableLast)
|
|
335
|
+
}) - contextStart
|
|
336
|
+
},
|
|
337
|
+
editHistory: history.slice(-10).map(({ hunk, source }) => ({
|
|
338
|
+
diff: hunk,
|
|
339
|
+
source
|
|
340
|
+
}))
|
|
341
|
+
};
|
|
342
|
+
return textEncoder.encode(JSON.stringify(request)).byteLength <= MAX_REQUEST_BYTES ? request : void 0;
|
|
343
|
+
}
|
|
344
|
+
function matchesEditPredictionPattern(path, pattern) {
|
|
345
|
+
if (typeof pattern !== "string") return new RegExp(pattern.source, pattern.flags).test(path);
|
|
346
|
+
pattern = pattern.replaceAll("\\", "/");
|
|
347
|
+
let source = "^";
|
|
348
|
+
for (let index = 0; index < pattern.length; index++) {
|
|
349
|
+
const character = pattern[index];
|
|
350
|
+
if (character === "*") if (pattern[index + 1] === "*") {
|
|
351
|
+
index++;
|
|
352
|
+
if (pattern[index + 1] === "/") {
|
|
353
|
+
index++;
|
|
354
|
+
source += "(?:.*/)?";
|
|
355
|
+
} else source += ".*";
|
|
356
|
+
} else source += "[^/]*";
|
|
357
|
+
else if (character === "?") source += "[^/]";
|
|
358
|
+
else source += /[\\^$.*+?()[\]{}|]/.test(character) ? `\\${character}` : character;
|
|
359
|
+
}
|
|
360
|
+
return new RegExp(`${source}$`).test(path);
|
|
361
|
+
}
|
|
362
|
+
//#endregion
|
|
363
|
+
export { buildEditPredictionRequest, matchesEditPredictionPattern, recordEditPrediction };
|
|
364
|
+
|
|
365
|
+
//# sourceMappingURL=editPrediction.js.map
|