@pierre/diffs 1.3.0-beta.9 → 1.3.0-rc.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -0
- package/dist/components/CodeView.d.ts +12 -13
- package/dist/components/CodeView.d.ts.map +1 -1
- package/dist/components/CodeView.js +50 -58
- package/dist/components/CodeView.js.map +1 -1
- package/dist/components/File.d.ts +10 -3
- package/dist/components/File.d.ts.map +1 -1
- package/dist/components/File.js +41 -10
- package/dist/components/File.js.map +1 -1
- package/dist/components/FileDiff.d.ts +37 -6
- package/dist/components/FileDiff.d.ts.map +1 -1
- package/dist/components/FileDiff.js +202 -19
- package/dist/components/FileDiff.js.map +1 -1
- package/dist/components/UnresolvedFile.d.ts.map +1 -1
- package/dist/components/UnresolvedFile.js +7 -2
- package/dist/components/UnresolvedFile.js.map +1 -1
- package/dist/components/VirtualizedFile.d.ts +2 -1
- package/dist/components/VirtualizedFile.d.ts.map +1 -1
- package/dist/components/VirtualizedFile.js +9 -5
- package/dist/components/VirtualizedFile.js.map +1 -1
- package/dist/components/VirtualizedFileDiff.d.ts +14 -0
- package/dist/components/VirtualizedFileDiff.d.ts.map +1 -1
- package/dist/components/VirtualizedFileDiff.js +61 -3
- package/dist/components/VirtualizedFileDiff.js.map +1 -1
- package/dist/components/Virtualizer.d.ts +14 -2
- package/dist/components/Virtualizer.d.ts.map +1 -1
- package/dist/components/Virtualizer.js +27 -2
- package/dist/components/Virtualizer.js.map +1 -1
- package/dist/edit/index.d.ts +5 -0
- package/dist/edit/index.js +3 -0
- package/dist/editor/command.d.ts +1 -1
- package/dist/editor/command.d.ts.map +1 -1
- package/dist/editor/command.js +11 -0
- package/dist/editor/command.js.map +1 -1
- package/dist/editor/editStack.d.ts +6 -2
- package/dist/editor/editStack.d.ts.map +1 -1
- package/dist/editor/editStack.js +53 -12
- package/dist/editor/editStack.js.map +1 -1
- package/dist/editor/editor.d.ts +51 -23
- package/dist/editor/editor.d.ts.map +1 -1
- package/dist/editor/editor.js +977 -241
- package/dist/editor/editor.js.map +1 -1
- package/dist/editor/editor2.js +1 -1
- package/dist/editor/languages.d.ts +26 -0
- package/dist/editor/languages.d.ts.map +1 -0
- package/dist/editor/languages.js +363 -0
- package/dist/editor/languages.js.map +1 -0
- package/dist/editor/lineAnnotations.d.ts.map +1 -1
- package/dist/editor/lineAnnotations.js +25 -26
- package/dist/editor/lineAnnotations.js.map +1 -1
- package/dist/editor/marker.d.ts +5 -3
- package/dist/editor/marker.d.ts.map +1 -1
- package/dist/editor/marker.js +111 -91
- package/dist/editor/marker.js.map +1 -1
- package/dist/editor/matchBrackets.d.ts +3 -2
- package/dist/editor/matchBrackets.d.ts.map +1 -1
- package/dist/editor/matchBrackets.js +2 -10
- package/dist/editor/matchBrackets.js.map +1 -1
- package/dist/editor/pieceTable.d.ts +2 -1
- package/dist/editor/pieceTable.d.ts.map +1 -1
- package/dist/editor/pieceTable.js +103 -39
- package/dist/editor/pieceTable.js.map +1 -1
- package/dist/editor/platform.js +2 -0
- package/dist/editor/platform.js.map +1 -1
- package/dist/editor/popover.d.ts +25 -5
- package/dist/editor/popover.d.ts.map +1 -1
- package/dist/editor/popover.js +60 -14
- package/dist/editor/popover.js.map +1 -1
- package/dist/editor/searchPanel.d.ts.map +1 -1
- package/dist/editor/searchPanel.js +9 -2
- package/dist/editor/searchPanel.js.map +1 -1
- package/dist/editor/selection.d.ts +31 -11
- package/dist/editor/selection.d.ts.map +1 -1
- package/dist/editor/selection.js +198 -70
- package/dist/editor/selection.js.map +1 -1
- package/dist/editor/selectionAction.d.ts +4 -3
- package/dist/editor/selectionAction.d.ts.map +1 -1
- package/dist/editor/selectionAction.js +9 -5
- package/dist/editor/selectionAction.js.map +1 -1
- package/dist/editor/stateStorage.d.ts +15 -0
- package/dist/editor/stateStorage.d.ts.map +1 -0
- package/dist/editor/stateStorage.js +65 -0
- package/dist/editor/stateStorage.js.map +1 -0
- package/dist/editor/textDocument.d.ts +12 -77
- package/dist/editor/textDocument.d.ts.map +1 -1
- package/dist/editor/textDocument.js +76 -34
- package/dist/editor/textDocument.js.map +1 -1
- package/dist/editor/textMeasure.d.ts +7 -12
- package/dist/editor/textMeasure.d.ts.map +1 -1
- package/dist/editor/textMeasure.js +40 -32
- package/dist/editor/textMeasure.js.map +1 -1
- package/dist/editor/{tokenzier.d.ts → tokenizer.d.ts} +3 -3
- package/dist/editor/tokenizer.d.ts.map +1 -0
- package/dist/editor/{tokenzier.js → tokenizer.js} +170 -50
- package/dist/editor/tokenizer.js.map +1 -0
- package/dist/editor/utils.js +1 -1
- package/dist/editor/utils.js.map +1 -1
- package/dist/index.d.ts +4 -3
- package/dist/index.js +6 -5
- package/dist/managers/InteractionManager.d.ts +18 -7
- package/dist/managers/InteractionManager.d.ts.map +1 -1
- package/dist/managers/InteractionManager.js +154 -99
- package/dist/managers/InteractionManager.js.map +1 -1
- package/dist/managers/UniversalRenderingManager.d.ts.map +1 -1
- package/dist/managers/UniversalRenderingManager.js +1 -2
- package/dist/managers/UniversalRenderingManager.js.map +1 -1
- package/dist/react/CodeView.d.ts +13 -13
- package/dist/react/CodeView.d.ts.map +1 -1
- package/dist/react/CodeView.js +37 -28
- package/dist/react/CodeView.js.map +1 -1
- package/dist/react/EditContext.d.ts +20 -0
- package/dist/react/EditContext.d.ts.map +1 -0
- package/dist/react/EditContext.js +20 -0
- package/dist/react/EditContext.js.map +1 -0
- package/dist/react/File.d.ts +2 -1
- package/dist/react/File.d.ts.map +1 -1
- package/dist/react/File.js +3 -2
- package/dist/react/File.js.map +1 -1
- package/dist/react/FileDiff.d.ts +2 -2
- package/dist/react/FileDiff.d.ts.map +1 -1
- package/dist/react/FileDiff.js +3 -2
- package/dist/react/FileDiff.js.map +1 -1
- package/dist/react/MultiFileDiff.d.ts +2 -2
- package/dist/react/MultiFileDiff.d.ts.map +1 -1
- package/dist/react/MultiFileDiff.js +3 -2
- package/dist/react/MultiFileDiff.js.map +1 -1
- package/dist/react/PatchDiff.d.ts +2 -2
- package/dist/react/PatchDiff.d.ts.map +1 -1
- package/dist/react/PatchDiff.js +3 -2
- package/dist/react/PatchDiff.js.map +1 -1
- package/dist/react/UnresolvedFile.d.ts +1 -1
- package/dist/react/UnresolvedFile.js.map +1 -1
- package/dist/react/index.d.ts +4 -4
- package/dist/react/index.js +3 -3
- package/dist/react/types.d.ts +9 -1
- package/dist/react/types.d.ts.map +1 -1
- package/dist/react/utils/useFileDiffInstance.d.ts +5 -3
- package/dist/react/utils/useFileDiffInstance.d.ts.map +1 -1
- package/dist/react/utils/useFileDiffInstance.js +24 -34
- package/dist/react/utils/useFileDiffInstance.js.map +1 -1
- package/dist/react/utils/useFileInstance.d.ts +5 -3
- package/dist/react/utils/useFileInstance.d.ts.map +1 -1
- package/dist/react/utils/useFileInstance.js +23 -33
- package/dist/react/utils/useFileInstance.js.map +1 -1
- package/dist/react/utils/useUnresolvedFileInstance.js +4 -4
- package/dist/react/utils/useUnresolvedFileInstance.js.map +1 -1
- package/dist/renderers/DiffHunksRenderer.d.ts +41 -1
- package/dist/renderers/DiffHunksRenderer.d.ts.map +1 -1
- package/dist/renderers/DiffHunksRenderer.js +167 -29
- package/dist/renderers/DiffHunksRenderer.js.map +1 -1
- package/dist/renderers/FileRenderer.d.ts +20 -1
- package/dist/renderers/FileRenderer.d.ts.map +1 -1
- package/dist/renderers/FileRenderer.js +119 -29
- package/dist/renderers/FileRenderer.js.map +1 -1
- package/dist/ssr/index.d.ts +2 -2
- package/dist/ssr/preloadDiffs.d.ts.map +1 -1
- package/dist/ssr/preloadDiffs.js +3 -1
- package/dist/ssr/preloadDiffs.js.map +1 -1
- package/dist/ssr/preloadFile.d.ts.map +1 -1
- package/dist/ssr/preloadFile.js +2 -0
- package/dist/ssr/preloadFile.js.map +1 -1
- package/dist/style.js +1 -1
- package/dist/types.d.ts +192 -42
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/annotationHelpers.d.ts +20 -0
- package/dist/utils/annotationHelpers.d.ts.map +1 -0
- package/dist/utils/annotationHelpers.js +29 -0
- package/dist/utils/annotationHelpers.js.map +1 -0
- package/dist/utils/computeFileOffsets.d.ts.map +1 -1
- package/dist/utils/computeFileOffsets.js +34 -5
- package/dist/utils/computeFileOffsets.js.map +1 -1
- package/dist/utils/editSessionHunks.d.ts +66 -0
- package/dist/utils/editSessionHunks.d.ts.map +1 -0
- package/dist/utils/editSessionHunks.js +437 -0
- package/dist/utils/editSessionHunks.js.map +1 -0
- package/dist/utils/getDiffHunksRendererOptions.d.ts.map +1 -1
- package/dist/utils/getDiffHunksRendererOptions.js +2 -1
- package/dist/utils/getDiffHunksRendererOptions.js.map +1 -1
- package/dist/utils/getFileRendererOptions.d.ts.map +1 -1
- package/dist/utils/getFileRendererOptions.js +2 -1
- package/dist/utils/getFileRendererOptions.js.map +1 -1
- package/dist/utils/getHunkSideBoundaries.d.ts +7 -0
- package/dist/utils/getHunkSideBoundaries.d.ts.map +1 -0
- package/dist/utils/getHunkSideBoundaries.js +12 -0
- package/dist/utils/getHunkSideBoundaries.js.map +1 -0
- package/dist/utils/getTotalLineCountFromHunks.d.ts.map +1 -1
- package/dist/utils/getTotalLineCountFromHunks.js +2 -1
- package/dist/utils/getTotalLineCountFromHunks.js.map +1 -1
- package/dist/utils/hydratePartialDiff.d.ts.map +1 -1
- package/dist/utils/hydratePartialDiff.js +4 -3
- package/dist/utils/hydratePartialDiff.js.map +1 -1
- package/dist/utils/isGutterUtilityPath.d.ts +5 -0
- package/dist/utils/isGutterUtilityPath.d.ts.map +1 -0
- package/dist/utils/isGutterUtilityPath.js +12 -0
- package/dist/utils/isGutterUtilityPath.js.map +1 -0
- package/dist/utils/iterateOverDiff.d.ts.map +1 -1
- package/dist/utils/iterateOverDiff.js +17 -12
- package/dist/utils/iterateOverDiff.js.map +1 -1
- package/dist/utils/parseMergeConflictDiffFromFile.d.ts.map +1 -1
- package/dist/utils/parseMergeConflictDiffFromFile.js +9 -6
- package/dist/utils/parseMergeConflictDiffFromFile.js.map +1 -1
- package/dist/utils/parsePatchFiles.d.ts.map +1 -1
- package/dist/utils/parsePatchFiles.js +6 -3
- package/dist/utils/parsePatchFiles.js.map +1 -1
- package/dist/utils/realignChangeContent.d.ts +33 -0
- package/dist/utils/realignChangeContent.d.ts.map +1 -0
- package/dist/utils/realignChangeContent.js +148 -0
- package/dist/utils/realignChangeContent.js.map +1 -0
- package/dist/utils/renderDiffWithHighlighter.js +1 -1
- package/dist/utils/resolveRegion.d.ts.map +1 -1
- package/dist/utils/resolveRegion.js +18 -2
- package/dist/utils/resolveRegion.js.map +1 -1
- package/dist/utils/shouldUseTokenTransformer.d.ts +7 -3
- package/dist/utils/shouldUseTokenTransformer.d.ts.map +1 -1
- package/dist/utils/shouldUseTokenTransformer.js +1 -1
- package/dist/utils/shouldUseTokenTransformer.js.map +1 -1
- package/dist/utils/updateDiffHunks.d.ts +8 -2
- package/dist/utils/updateDiffHunks.d.ts.map +1 -1
- package/dist/utils/updateDiffHunks.js +9 -7
- package/dist/utils/updateDiffHunks.js.map +1 -1
- package/dist/utils/virtualDiffLayout.d.ts +42 -2
- package/dist/utils/virtualDiffLayout.d.ts.map +1 -1
- package/dist/utils/virtualDiffLayout.js +101 -7
- package/dist/utils/virtualDiffLayout.js.map +1 -1
- package/dist/worker/WorkerPoolManager.d.ts +2 -1
- package/dist/worker/WorkerPoolManager.d.ts.map +1 -1
- package/dist/worker/WorkerPoolManager.js +3 -0
- package/dist/worker/WorkerPoolManager.js.map +1 -1
- package/dist/worker/worker-portable.js +60 -20
- package/dist/worker/worker-portable.js.map +1 -1
- package/dist/worker/worker.js +61 -19
- package/dist/worker/worker.js.map +1 -1
- package/package.json +10 -7
- package/dist/editor/index.d.ts +0 -3
- package/dist/editor/index.js +0 -3
- package/dist/editor/tokenzier.d.ts.map +0 -1
- package/dist/editor/tokenzier.js.map +0 -1
- package/dist/react/EditorContext.d.ts +0 -15
- package/dist/react/EditorContext.d.ts.map +0 -1
- package/dist/react/EditorContext.js +0 -23
- package/dist/react/EditorContext.js.map +0 -1
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { EditorState } from "../types.js";
|
|
2
|
+
|
|
3
|
+
//#region src/editor/stateStorage.d.ts
|
|
4
|
+
interface IStateStorage {
|
|
5
|
+
/** Read the editor state stored for a file cache key. */
|
|
6
|
+
get(cacheKey: string): EditorState | undefined | Promise<EditorState | undefined>;
|
|
7
|
+
/** Store the editor state for a file cache key. */
|
|
8
|
+
set(cacheKey: string, state: EditorState): void | Promise<void>;
|
|
9
|
+
}
|
|
10
|
+
type PersistStateStorage = 'inMemory' | 'indexedDB' | IStateStorage;
|
|
11
|
+
declare function cloneEditorState(state: EditorState): EditorState;
|
|
12
|
+
declare function createStateStorage(storage: PersistStateStorage): IStateStorage;
|
|
13
|
+
//#endregion
|
|
14
|
+
export { IStateStorage, PersistStateStorage, cloneEditorState, createStateStorage };
|
|
15
|
+
//# sourceMappingURL=stateStorage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stateStorage.d.ts","names":[],"sources":["../../src/editor/stateStorage.ts"],"mappings":";;;UAEiB,aAAA;;EAEf,GAAA,CACE,QAAA,WACC,WAAA,eAA0B,OAAA,CAAQ,WAAA;EAJT;EAM5B,GAAA,CAAI,QAAA,UAAkB,KAAA,EAAO,WAAA,UAAqB,OAAA;AAAA;AAAA,KAGxC,mBAAA,8BAAiD,aAAa;AAAA,iBAE1D,gBAAA,CAAiB,KAAA,EAAO,WAAA,GAAc,WAAW;AAAA,iBAWjD,kBAAA,CACd,OAAA,EAAS,mBAAA,GACR,aAAa"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
//#region src/editor/stateStorage.ts
|
|
2
|
+
function cloneEditorState(state) {
|
|
3
|
+
return {
|
|
4
|
+
selections: state.selections?.map((selection) => ({
|
|
5
|
+
start: { ...selection.start },
|
|
6
|
+
end: { ...selection.end },
|
|
7
|
+
direction: selection.direction
|
|
8
|
+
})),
|
|
9
|
+
view: state.view === void 0 ? void 0 : { ...state.view }
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
function createStateStorage(storage) {
|
|
13
|
+
return typeof storage === "object" ? storage : storage === "indexedDB" ? new IndexedDBStateStorage() : new InMemoryStateStorage();
|
|
14
|
+
}
|
|
15
|
+
var InMemoryStateStorage = class {
|
|
16
|
+
#states = /* @__PURE__ */ new Map();
|
|
17
|
+
get(cacheKey) {
|
|
18
|
+
const state = this.#states.get(cacheKey);
|
|
19
|
+
return state === void 0 ? void 0 : cloneEditorState(state);
|
|
20
|
+
}
|
|
21
|
+
set(cacheKey, state) {
|
|
22
|
+
this.#states.set(cacheKey, cloneEditorState(state));
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
const DATABASE_NAME = "pierre-diffs-editor-state";
|
|
26
|
+
const DATABASE_VERSION = 1;
|
|
27
|
+
const STORE_NAME = "states";
|
|
28
|
+
var IndexedDBStateStorage = class {
|
|
29
|
+
#database = openDatabase();
|
|
30
|
+
async get(cacheKey) {
|
|
31
|
+
const database = await this.#database;
|
|
32
|
+
if (database === void 0) return;
|
|
33
|
+
const state = await requestToPromise(database.transaction(STORE_NAME, "readonly").objectStore(STORE_NAME).get(cacheKey));
|
|
34
|
+
return state === void 0 ? void 0 : cloneEditorState(state);
|
|
35
|
+
}
|
|
36
|
+
async set(cacheKey, state) {
|
|
37
|
+
const database = await this.#database;
|
|
38
|
+
if (database === void 0) return;
|
|
39
|
+
await requestToPromise(database.transaction(STORE_NAME, "readwrite").objectStore(STORE_NAME).put(cloneEditorState(state), cacheKey));
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
function openDatabase() {
|
|
43
|
+
try {
|
|
44
|
+
const factory = globalThis.indexedDB;
|
|
45
|
+
if (factory === void 0) return Promise.resolve(void 0);
|
|
46
|
+
const request = factory.open(DATABASE_NAME, DATABASE_VERSION);
|
|
47
|
+
request.onupgradeneeded = () => {
|
|
48
|
+
const database = request.result;
|
|
49
|
+
if (!database.objectStoreNames.contains(STORE_NAME)) database.createObjectStore(STORE_NAME);
|
|
50
|
+
};
|
|
51
|
+
return requestToPromise(request);
|
|
52
|
+
} catch {
|
|
53
|
+
return Promise.resolve(void 0);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
function requestToPromise(request) {
|
|
57
|
+
return new Promise((resolve, reject) => {
|
|
58
|
+
request.onsuccess = () => resolve(request.result);
|
|
59
|
+
request.onerror = () => reject(request.error);
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
//#endregion
|
|
63
|
+
export { cloneEditorState, createStateStorage };
|
|
64
|
+
|
|
65
|
+
//# sourceMappingURL=stateStorage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stateStorage.js","names":["#states","#database"],"sources":["../../src/editor/stateStorage.ts"],"sourcesContent":["import type { EditorState } from '../types';\n\nexport interface IStateStorage {\n /** Read the editor state stored for a file cache key. */\n get(\n cacheKey: string\n ): EditorState | undefined | Promise<EditorState | undefined>;\n /** Store the editor state for a file cache key. */\n set(cacheKey: string, state: EditorState): void | Promise<void>;\n}\n\nexport type PersistStateStorage = 'inMemory' | 'indexedDB' | IStateStorage;\n\nexport function cloneEditorState(state: EditorState): EditorState {\n return {\n selections: state.selections?.map((selection) => ({\n start: { ...selection.start },\n end: { ...selection.end },\n direction: selection.direction,\n })),\n view: state.view === undefined ? undefined : { ...state.view },\n };\n}\n\nexport function createStateStorage(\n storage: PersistStateStorage\n): IStateStorage {\n return typeof storage === 'object'\n ? storage\n : storage === 'indexedDB'\n ? new IndexedDBStateStorage()\n : new InMemoryStateStorage();\n}\n\nclass InMemoryStateStorage implements IStateStorage {\n #states = new Map<string, EditorState>();\n\n get(cacheKey: string): EditorState | undefined {\n const state = this.#states.get(cacheKey);\n return state === undefined ? undefined : cloneEditorState(state);\n }\n\n set(cacheKey: string, state: EditorState): void {\n this.#states.set(cacheKey, cloneEditorState(state));\n }\n}\n\nconst DATABASE_NAME = 'pierre-diffs-editor-state';\nconst DATABASE_VERSION = 1;\nconst STORE_NAME = 'states';\n\nclass IndexedDBStateStorage implements IStateStorage {\n #database = openDatabase();\n\n async get(cacheKey: string): Promise<EditorState | undefined> {\n const database = await this.#database;\n if (database === undefined) {\n return undefined;\n }\n const state = await requestToPromise<EditorState | undefined>(\n database\n .transaction(STORE_NAME, 'readonly')\n .objectStore(STORE_NAME)\n .get(cacheKey)\n );\n return state === undefined ? undefined : cloneEditorState(state);\n }\n\n async set(cacheKey: string, state: EditorState): Promise<void> {\n const database = await this.#database;\n if (database === undefined) {\n return;\n }\n await requestToPromise(\n database\n .transaction(STORE_NAME, 'readwrite')\n .objectStore(STORE_NAME)\n .put(cloneEditorState(state), cacheKey)\n );\n }\n}\n\nfunction openDatabase(): Promise<IDBDatabase | undefined> {\n try {\n const factory = globalThis.indexedDB;\n if (factory === undefined) {\n return Promise.resolve(undefined);\n }\n\n const request = factory.open(DATABASE_NAME, DATABASE_VERSION);\n request.onupgradeneeded = () => {\n const database = request.result;\n if (!database.objectStoreNames.contains(STORE_NAME)) {\n database.createObjectStore(STORE_NAME);\n }\n };\n return requestToPromise(request);\n } catch {\n return Promise.resolve(undefined);\n }\n}\n\nfunction requestToPromise<T>(request: IDBRequest<T>): Promise<T> {\n return new Promise((resolve, reject) => {\n request.onsuccess = () => resolve(request.result);\n request.onerror = () => reject(request.error);\n });\n}\n"],"mappings":";AAaA,SAAgB,iBAAiB,OAAiC;CAChE,OAAO;EACL,YAAY,MAAM,YAAY,KAAK,eAAe;GAChD,OAAO,EAAE,GAAG,UAAU,MAAM;GAC5B,KAAK,EAAE,GAAG,UAAU,IAAI;GACxB,WAAW,UAAU;EACvB,EAAE;EACF,MAAM,MAAM,SAAS,KAAA,IAAY,KAAA,IAAY,EAAE,GAAG,MAAM,KAAK;CAC/D;AACF;AAEA,SAAgB,mBACd,SACe;CACf,OAAO,OAAO,YAAY,WACtB,UACA,YAAY,cACV,IAAI,sBAAsB,IAC1B,IAAI,qBAAqB;AACjC;AAEA,IAAM,uBAAN,MAAoD;CAClD,0BAAU,IAAI,IAAyB;CAEvC,IAAI,UAA2C;EAC7C,MAAM,QAAQ,KAAKA,QAAQ,IAAI,QAAQ;EACvC,OAAO,UAAU,KAAA,IAAY,KAAA,IAAY,iBAAiB,KAAK;CACjE;CAEA,IAAI,UAAkB,OAA0B;EAC9C,KAAKA,QAAQ,IAAI,UAAU,iBAAiB,KAAK,CAAC;CACpD;AACF;AAEA,MAAM,gBAAgB;AACtB,MAAM,mBAAmB;AACzB,MAAM,aAAa;AAEnB,IAAM,wBAAN,MAAqD;CACnD,YAAY,aAAa;CAEzB,MAAM,IAAI,UAAoD;EAC5D,MAAM,WAAW,MAAM,KAAKC;EAC5B,IAAI,aAAa,KAAA,GACf;EAEF,MAAM,QAAQ,MAAM,iBAClB,SACG,YAAY,YAAY,UAAU,CAAC,CACnC,YAAY,UAAU,CAAC,CACvB,IAAI,QAAQ,CACjB;EACA,OAAO,UAAU,KAAA,IAAY,KAAA,IAAY,iBAAiB,KAAK;CACjE;CAEA,MAAM,IAAI,UAAkB,OAAmC;EAC7D,MAAM,WAAW,MAAM,KAAKA;EAC5B,IAAI,aAAa,KAAA,GACf;EAEF,MAAM,iBACJ,SACG,YAAY,YAAY,WAAW,CAAC,CACpC,YAAY,UAAU,CAAC,CACvB,IAAI,iBAAiB,KAAK,GAAG,QAAQ,CAC1C;CACF;AACF;AAEA,SAAS,eAAiD;CACxD,IAAI;EACF,MAAM,UAAU,WAAW;EAC3B,IAAI,YAAY,KAAA,GACd,OAAO,QAAQ,QAAQ,KAAA,CAAS;EAGlC,MAAM,UAAU,QAAQ,KAAK,eAAe,gBAAgB;EAC5D,QAAQ,wBAAwB;GAC9B,MAAM,WAAW,QAAQ;GACzB,IAAI,CAAC,SAAS,iBAAiB,SAAS,UAAU,GAChD,SAAS,kBAAkB,UAAU;EAEzC;EACA,OAAO,iBAAiB,OAAO;CACjC,QAAQ;EACN,OAAO,QAAQ,QAAQ,KAAA,CAAS;CAClC;AACF;AAEA,SAAS,iBAAoB,SAAoC;CAC/D,OAAO,IAAI,SAAS,SAAS,WAAW;EACtC,QAAQ,kBAAkB,QAAQ,QAAQ,MAAM;EAChD,QAAQ,gBAAgB,OAAO,QAAQ,KAAK;CAC9C,CAAC;AACH"}
|
|
@@ -1,79 +1,8 @@
|
|
|
1
|
-
import { DiffLineAnnotation } from "../types.js";
|
|
2
|
-
import { SearchParams } from "./searchPanel.js";
|
|
3
|
-
import { EditorSelection } from "./selection.js";
|
|
1
|
+
import { DiffLineAnnotation, EditorSelection, Position, Range, TextEdit } from "../types.js";
|
|
4
2
|
import { EditStack } from "./editStack.js";
|
|
3
|
+
import { SearchParams } from "./searchPanel.js";
|
|
5
4
|
|
|
6
5
|
//#region src/editor/textDocument.d.ts
|
|
7
|
-
/**
|
|
8
|
-
* Position in a text document expressed as zero-based line and character offset.
|
|
9
|
-
* The offsets are based on a UTF-16 string representation. So a string of the form
|
|
10
|
-
* `a𐐀b` the character offset of the character `a` is 0, the character offset of `𐐀`
|
|
11
|
-
* is 1 and the character offset of b is 3 since `𐐀` is represented using two code
|
|
12
|
-
* units in UTF-16.
|
|
13
|
-
*
|
|
14
|
-
* Positions are line end character agnostic. So you can not specify a position that
|
|
15
|
-
* denotes `\r|\n` or `\n|` where `|` represents the character offset.
|
|
16
|
-
*/
|
|
17
|
-
interface Position {
|
|
18
|
-
/**
|
|
19
|
-
* Line position in a document (zero-based).
|
|
20
|
-
*
|
|
21
|
-
* If a line number is greater than the number of lines in a document, it
|
|
22
|
-
* defaults back to the number of lines in the document.
|
|
23
|
-
* If a line number is negative, it defaults to 0.
|
|
24
|
-
*
|
|
25
|
-
* The above two properties are implementation specific.
|
|
26
|
-
*/
|
|
27
|
-
readonly line: number;
|
|
28
|
-
/**
|
|
29
|
-
* Character offset on a line in a document (zero-based).
|
|
30
|
-
*
|
|
31
|
-
* The meaning of this offset is determined by the negotiated
|
|
32
|
-
* `PositionEncodingKind`.
|
|
33
|
-
*
|
|
34
|
-
* If the character value is greater than the line length it defaults back
|
|
35
|
-
* to the line length. This property is implementation specific.
|
|
36
|
-
*/
|
|
37
|
-
readonly character: number;
|
|
38
|
-
}
|
|
39
|
-
/**
|
|
40
|
-
* A range in a text document expressed as (zero-based) start and end positions.
|
|
41
|
-
*
|
|
42
|
-
* If you want to specify a range that contains a line including the line ending
|
|
43
|
-
* character(s) then use an end position denoting the start of the next line.
|
|
44
|
-
* For example:
|
|
45
|
-
* ```ts
|
|
46
|
-
* {
|
|
47
|
-
* start: { line: 5, character: 23 }
|
|
48
|
-
* end : { line 6, character : 0 }
|
|
49
|
-
* }
|
|
50
|
-
* ```
|
|
51
|
-
*/
|
|
52
|
-
interface Range {
|
|
53
|
-
/**
|
|
54
|
-
* The range's start position.
|
|
55
|
-
*/
|
|
56
|
-
readonly start: Position;
|
|
57
|
-
/**
|
|
58
|
-
* The range's end position.
|
|
59
|
-
*/
|
|
60
|
-
readonly end: Position;
|
|
61
|
-
}
|
|
62
|
-
/**
|
|
63
|
-
* A text edit applicable to a text document.
|
|
64
|
-
*/
|
|
65
|
-
interface TextEdit {
|
|
66
|
-
/**
|
|
67
|
-
* The range of the text document to be manipulated. To insert
|
|
68
|
-
* text into a document create a range where start === end.
|
|
69
|
-
*/
|
|
70
|
-
readonly range: Range;
|
|
71
|
-
/**
|
|
72
|
-
* The string to be inserted. For delete operations use an
|
|
73
|
-
* empty string.
|
|
74
|
-
*/
|
|
75
|
-
readonly newText: string;
|
|
76
|
-
}
|
|
77
6
|
/** Different with `TextEdit`, the range has been resolved to offsets. */
|
|
78
7
|
interface ResolvedTextEdit {
|
|
79
8
|
/** The start offset of the text change. */
|
|
@@ -91,8 +20,12 @@ interface TextDocumentChange {
|
|
|
91
20
|
readonly startLine: number;
|
|
92
21
|
/** Character on the first changed line where the edit began. */
|
|
93
22
|
readonly startCharacter: number;
|
|
23
|
+
/** Character on the original last changed line where the edit ended. */
|
|
24
|
+
readonly endCharacter: number;
|
|
94
25
|
/** Last line whose rendered content may have changed after the edit. */
|
|
95
26
|
readonly endLine: number;
|
|
27
|
+
/** Whether the original edit range ended at the previous document EOF. */
|
|
28
|
+
readonly endedAtDocumentEnd: boolean;
|
|
96
29
|
/** Line count before the edit was applied. */
|
|
97
30
|
readonly previousLineCount: number;
|
|
98
31
|
/** Line count after the edit was applied. */
|
|
@@ -102,8 +35,9 @@ interface TextDocumentChange {
|
|
|
102
35
|
/** Exact rendered line ranges touched by each edit after the edit was applied. */
|
|
103
36
|
readonly changedLineRanges: readonly [startLine: number, endLine: number][];
|
|
104
37
|
/** Per-edit rendered line ranges before adjacent ranges are coalesced. */
|
|
105
|
-
readonly changedLineChanges?: readonly [startLine: number, endLine: number, lineDelta: number][];
|
|
38
|
+
readonly changedLineChanges?: readonly [startLine: number, endLine: number, lineDelta: number, startCharacter?: number, endCharacter?: number, endedAtDocumentEnd?: boolean][];
|
|
106
39
|
}
|
|
40
|
+
type TextDocumentHistoryResult<LAnnotation> = [change: TextDocumentChange, selections?: EditorSelection[], lineAnnotations?: DiffLineAnnotation<LAnnotation>[], selectionEdits?: ResolvedTextEdit[]];
|
|
107
41
|
/**
|
|
108
42
|
* A vscode-languageserver-textdocument compatible text document.
|
|
109
43
|
*/
|
|
@@ -130,13 +64,14 @@ declare class TextDocument<LAnnotation> {
|
|
|
130
64
|
findNextNonOverlappingSubstring(needle: string, occupied: readonly [start: number, end: number][]): number | undefined;
|
|
131
65
|
search(searchParams: SearchParams): [start: number, end: number][];
|
|
132
66
|
applyEdits(edits: TextEdit[], updateHistory?: boolean, selectionsBefore?: EditorSelection[], selectionsAfter?: EditorSelection[], undoBoundary?: boolean): TextDocumentChange | undefined;
|
|
67
|
+
resolveEdits(edits: readonly TextEdit[]): ResolvedTextEdit[];
|
|
133
68
|
applyResolvedEdits(edits: ResolvedTextEdit[], updateHistory?: boolean, selectionsBefore?: EditorSelection[], selectionsAfter?: EditorSelection[], undoBoundary?: boolean): TextDocumentChange | undefined;
|
|
134
69
|
setLastUndoSelectionsAfter(selections: EditorSelection[]): void;
|
|
135
70
|
setLastUndoLineAnnotations(lineAnnotationsBefore: DiffLineAnnotation<LAnnotation>[], lineAnnotationsAfter: DiffLineAnnotation<LAnnotation>[]): void;
|
|
136
|
-
undo():
|
|
137
|
-
redo():
|
|
71
|
+
undo(): TextDocumentHistoryResult<LAnnotation> | undefined;
|
|
72
|
+
redo(): TextDocumentHistoryResult<LAnnotation> | undefined;
|
|
138
73
|
normalizePosition(position: Position): Position;
|
|
139
74
|
}
|
|
140
75
|
//#endregion
|
|
141
|
-
export { Position, Range, ResolvedTextEdit, TextDocument, TextDocumentChange, TextEdit };
|
|
76
|
+
export { type Position, type Range, ResolvedTextEdit, TextDocument, TextDocumentChange, type TextEdit };
|
|
142
77
|
//# sourceMappingURL=textDocument.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"textDocument.d.ts","names":[],"sources":["../../src/editor/textDocument.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"textDocument.d.ts","names":[],"sources":["../../src/editor/textDocument.ts"],"mappings":";;;;;;UAoBiB,gBAAA;EAAgB;EAAA,SAEtB,KAAA;EAFsB;EAAA,SAItB,GAAA;EAAA;;;AAKI;EALJ,SAKA,IAAA;AAAA;AAAA,UAGM,kBAAA;EAAkB;EAAA,SAExB,SAAA;EAEA;EAAA,SAAA,cAAA;EAIA;EAAA,SAFA,YAAA;EAMA;EAAA,SAJA,OAAA;EAQA;EAAA,SANA,kBAAA;EAQ6B;EAAA,SAN7B,iBAAA;EAQA;EAAA,SANA,SAAA;EAQP;EAAA,SANO,SAAA;EAQP;EAAA,SANO,iBAAA,YAA6B,SAAA,UAAmB,OAAA;EAQvD;EAAA,SANO,kBAAA,aACP,SAAA,UACA,OAAA,UACA,SAAA,UACA,cAAA,WACA,YAAA,WACA,kBAAA;AAAA;AAAA,KAMC,yBAAA,iBACH,MAAA,EAAQ,kBAAA,EACR,UAAA,GAAa,eAAA,IACb,eAAA,GAAkB,kBAAA,CAAmB,WAAA,KACrC,cAAA,GAAiB,gBAAA;;;;cAMN,YAAA;EAAA;EAQX,WAAA,CACE,GAAA,UACA,IAAA,UACA,UAAA,WACA,OAAA,WACA,SAAA,GAAW,SAAA,CAAU,WAAA;EAAA,IAsBnB,GAAA;EAAA,IAIA,UAAA;EAAA,IAIA,OAAA;EAAA,IAIA,SAAA;EAAA,IAIA,GAAA;EAAA,IAIA,OAAA;EAAA,IAIA,OAAA;EAIJ,UAAA,CAAW,MAAA,WAAiB,QAAA;EAI5B,WAAA,CAAY,OAAA,sBAA6B,QAAA;EAQzC,QAAA,CAAS,QAAA,EAAU,QAAA;EAInB,OAAA,CAAQ,KAAA,GAAQ,KAAA;EAgBhB,WAAA,CAAY,IAAA,UAAc,gBAAA;EAO1B,YAAA,CAAa,IAAA;EAIb,aAAA,CAAc,IAAA,UAAc,gBAAA;EAI5B,MAAA,CAAO,MAAA;EACP,MAAA,CAAO,QAAA,EAAU,QAAA;EAQjB,YAAA,CAAa,KAAA,UAAe,GAAA;EAI5B,+BAAA,CACE,MAAA,UACA,QAAA,YAAoB,KAAA,UAAe,GAAA;EAKrC,MAAA,CAAO,YAAA,EAAc,YAAA,IAAgB,KAAA,UAAe,GAAA;EAIpD,UAAA,CACE,KAAA,EAAO,QAAA,IACP,aAAA,YACA,gBAAA,GAAmB,eAAA,IACnB,eAAA,GAAkB,eAAA,IAClB,YAAA,aACC,kBAAA;EAgBH,YAAA,CAAa,KAAA,WAAgB,QAAA,KAAa,gBAAA;EAI1C,kBAAA,CACE,KAAA,EAAO,gBAAA,IACP,aAAA,YACA,gBAAA,GAAmB,eAAA,IACnB,eAAA,GAAkB,eAAA,IAClB,YAAA,aACC,kBAAA;EA2DH,0BAAA,CAA2B,UAAA,EAAY,eAAA;EAIvC,0BAAA,CACE,qBAAA,EAAuB,kBAAA,CAAmB,WAAA,KAC1C,oBAAA,EAAsB,kBAAA,CAAmB,WAAA;EAQ3C,IAAA,IAAQ,yBAAA,CAA0B,WAAA;EAqBlC,IAAA,IAAQ,yBAAA,CAA0B,WAAA;EAqBlC,iBAAA,CAAkB,QAAA,EAAU,QAAA,GAAW,QAAA;AAAA"}
|
|
@@ -5,18 +5,23 @@ import { PieceTable } from "./pieceTable.js";
|
|
|
5
5
|
/**
|
|
6
6
|
* A vscode-languageserver-textdocument compatible text document.
|
|
7
7
|
*/
|
|
8
|
-
var TextDocument = class {
|
|
8
|
+
var TextDocument = class TextDocument {
|
|
9
9
|
#uri;
|
|
10
10
|
#languageId;
|
|
11
11
|
#version;
|
|
12
12
|
#pieceTable;
|
|
13
13
|
#editStack;
|
|
14
|
-
|
|
14
|
+
#eol;
|
|
15
|
+
constructor(uri, text, languageId = "text", version = 0, editStack = new EditStack()) {
|
|
15
16
|
this.#uri = new URL(uri, "file://").toString();
|
|
16
17
|
this.#languageId = languageId;
|
|
17
18
|
this.#version = version;
|
|
18
19
|
this.#pieceTable = new PieceTable(text);
|
|
19
20
|
this.#editStack = editStack;
|
|
21
|
+
const firstLineBreak = this.#pieceTable.getLineText(0, true);
|
|
22
|
+
if (firstLineBreak.endsWith("\r\n")) this.#eol = "\r\n";
|
|
23
|
+
else if (firstLineBreak.endsWith("\r")) this.#eol = "\r";
|
|
24
|
+
else this.#eol = "\n";
|
|
20
25
|
}
|
|
21
26
|
get uri() {
|
|
22
27
|
return this.#uri;
|
|
@@ -31,12 +36,7 @@ var TextDocument = class {
|
|
|
31
36
|
return this.#pieceTable.lineCount;
|
|
32
37
|
}
|
|
33
38
|
get eol() {
|
|
34
|
-
|
|
35
|
-
const firstLineBreak = this.getLineText(0, true);
|
|
36
|
-
if (firstLineBreak.endsWith("\r\n")) return "\r\n";
|
|
37
|
-
if (firstLineBreak.endsWith("\r")) return "\r";
|
|
38
|
-
}
|
|
39
|
-
return "\n";
|
|
39
|
+
return this.#eol;
|
|
40
40
|
}
|
|
41
41
|
get canUndo() {
|
|
42
42
|
return this.#editStack.canUndo;
|
|
@@ -45,10 +45,12 @@ var TextDocument = class {
|
|
|
45
45
|
return this.#editStack.canRedo;
|
|
46
46
|
}
|
|
47
47
|
positionAt(offset) {
|
|
48
|
-
return this.#pieceTable.positionAt(offset);
|
|
48
|
+
return this.normalizePosition(this.#pieceTable.positionAt(offset));
|
|
49
49
|
}
|
|
50
50
|
positionsAt(offsets) {
|
|
51
|
-
|
|
51
|
+
const positions = this.#pieceTable.positionsAt(offsets);
|
|
52
|
+
for (let i = 0; i < positions.length; i++) positions[i] = this.normalizePosition(positions[i]);
|
|
53
|
+
return positions;
|
|
52
54
|
}
|
|
53
55
|
offsetAt(position) {
|
|
54
56
|
return this.#pieceTable.offsetAt(this.normalizePosition(position));
|
|
@@ -82,25 +84,25 @@ var TextDocument = class {
|
|
|
82
84
|
search(searchParams) {
|
|
83
85
|
return this.#pieceTable.search(searchParams);
|
|
84
86
|
}
|
|
85
|
-
applyEdits(edits, updateHistory =
|
|
87
|
+
applyEdits(edits, updateHistory = true, selectionsBefore, selectionsAfter, undoBoundary = false) {
|
|
86
88
|
if (edits.length === 0) return;
|
|
87
|
-
return this
|
|
89
|
+
return this.#applyResolvedEdits(this.#sortAndValidateResolvedEdits(this.resolveEdits(edits)), updateHistory, selectionsBefore, selectionsAfter, undoBoundary);
|
|
90
|
+
}
|
|
91
|
+
resolveEdits(edits) {
|
|
92
|
+
return edits.map((edit) => this.#resolveEdit(edit));
|
|
88
93
|
}
|
|
89
|
-
applyResolvedEdits(edits, updateHistory =
|
|
94
|
+
applyResolvedEdits(edits, updateHistory = true, selectionsBefore, selectionsAfter, undoBoundary = false) {
|
|
90
95
|
if (edits.length === 0) return;
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
this.#version++;
|
|
98
|
-
if (change.lineDelta === 0 && shouldCoalesceEditStackEntry(previousEntry, entry)) this.#editStack.replaceLastUndo(coalesceEditStackEntries(previousEntry, entry));
|
|
99
|
-
else this.#editStack.push(entry);
|
|
100
|
-
return change;
|
|
101
|
-
}
|
|
96
|
+
return this.#applyResolvedEdits(this.#sortAndValidateResolvedEdits(edits.map((edit) => this.#normalizeResolvedEdit(edit))), updateHistory, selectionsBefore, selectionsAfter, undoBoundary);
|
|
97
|
+
}
|
|
98
|
+
#applyResolvedEdits(resolvedEdits, updateHistory, selectionsBefore, selectionsAfter, undoBoundary) {
|
|
99
|
+
const entry = createEditStackEntry(this, resolvedEdits, this.#version, this.#version + 1, updateHistory ? selectionsBefore : void 0, updateHistory ? selectionsAfter : void 0);
|
|
100
|
+
if (updateHistory && undoBoundary) entry.undoBoundary = true;
|
|
101
|
+
const previousEntry = this.#editStack.peekUndoForCoalescing();
|
|
102
102
|
const change = this.#applyResolvedEditsToBuffer(resolvedEdits);
|
|
103
103
|
this.#version++;
|
|
104
|
+
if (change.lineDelta === 0 && shouldCoalesceEditStackEntry(previousEntry, entry)) this.#editStack.replaceLastUndo(coalesceEditStackEntries(previousEntry, entry));
|
|
105
|
+
else this.#editStack.push(entry);
|
|
104
106
|
return change;
|
|
105
107
|
}
|
|
106
108
|
setLastUndoSelectionsAfter(selections) {
|
|
@@ -115,10 +117,12 @@ var TextDocument = class {
|
|
|
115
117
|
const change = this.#applyResolvedEditsToBuffer(entry.inverseEdits);
|
|
116
118
|
if (change === void 0) return;
|
|
117
119
|
this.#version = entry.versionBefore;
|
|
120
|
+
const selections = entry.selectionsBefore?.slice();
|
|
118
121
|
return [
|
|
119
122
|
change,
|
|
120
|
-
|
|
121
|
-
entry.lineAnnotationsBefore?.slice()
|
|
123
|
+
selections,
|
|
124
|
+
entry.lineAnnotationsBefore?.slice(),
|
|
125
|
+
selections === void 0 ? entry.inverseEdits.map((edit) => ({ ...edit })) : void 0
|
|
122
126
|
];
|
|
123
127
|
}
|
|
124
128
|
redo() {
|
|
@@ -127,19 +131,25 @@ var TextDocument = class {
|
|
|
127
131
|
const change = this.#applyResolvedEditsToBuffer(entry.forwardEdits);
|
|
128
132
|
if (change === void 0) return;
|
|
129
133
|
this.#version = entry.versionAfter;
|
|
134
|
+
const selections = entry.selectionsAfter?.slice();
|
|
130
135
|
return [
|
|
131
136
|
change,
|
|
132
|
-
|
|
133
|
-
entry.lineAnnotationsAfter?.slice()
|
|
137
|
+
selections,
|
|
138
|
+
entry.lineAnnotationsAfter?.slice(),
|
|
139
|
+
selections === void 0 ? entry.forwardEdits.map((edit) => ({ ...edit })) : void 0
|
|
134
140
|
];
|
|
135
141
|
}
|
|
136
142
|
normalizePosition(position) {
|
|
137
|
-
const line =
|
|
143
|
+
const line = TextDocument.#clampIndex(position.line, this.lineCount - 1);
|
|
138
144
|
return {
|
|
139
145
|
line,
|
|
140
|
-
character:
|
|
146
|
+
character: TextDocument.#clampIndex(position.character, this.getLineLength(line))
|
|
141
147
|
};
|
|
142
148
|
}
|
|
149
|
+
static #clampIndex(value, max) {
|
|
150
|
+
if (Number.isNaN(value)) return 0;
|
|
151
|
+
return Math.max(0, Math.min(Math.floor(value), max));
|
|
152
|
+
}
|
|
143
153
|
#resolveEdit(edit) {
|
|
144
154
|
let start = this.offsetAt(edit.range.start);
|
|
145
155
|
let end = this.offsetAt(edit.range.end);
|
|
@@ -148,14 +158,34 @@ var TextDocument = class {
|
|
|
148
158
|
start = end;
|
|
149
159
|
end = t;
|
|
150
160
|
}
|
|
151
|
-
return {
|
|
161
|
+
return this.#normalizeResolvedEdit({
|
|
152
162
|
start,
|
|
153
163
|
end,
|
|
154
164
|
text: edit.newText
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
#normalizeResolvedEdit(edit) {
|
|
168
|
+
let { start, end } = edit;
|
|
169
|
+
const isInsertion = start === end;
|
|
170
|
+
if (this.#isInsideSurrogatePair(start)) start--;
|
|
171
|
+
if (isInsertion) end = start;
|
|
172
|
+
else if (this.#isInsideSurrogatePair(end)) end++;
|
|
173
|
+
return {
|
|
174
|
+
start,
|
|
175
|
+
end,
|
|
176
|
+
text: edit.text
|
|
155
177
|
};
|
|
156
178
|
}
|
|
179
|
+
#isInsideSurrogatePair(offset) {
|
|
180
|
+
const previous = this.#pieceTable.charAt(offset - 1).charCodeAt(0);
|
|
181
|
+
const next = this.#pieceTable.charAt(offset).charCodeAt(0);
|
|
182
|
+
return previous >= 55296 && previous <= 56319 && next >= 56320 && next <= 57343;
|
|
183
|
+
}
|
|
157
184
|
#sortAndValidateResolvedEdits(edits) {
|
|
158
|
-
const sortedEdits = [...edits].sort((a, b) =>
|
|
185
|
+
const sortedEdits = [...edits].sort((a, b) => {
|
|
186
|
+
const startDelta = a.start - b.start;
|
|
187
|
+
return startDelta === 0 ? a.end - b.end : startDelta;
|
|
188
|
+
});
|
|
159
189
|
for (let i = 0; i < sortedEdits.length - 1; i++) if (sortedEdits[i].end > sortedEdits[i + 1].start) throw new Error("Overlapping text edits are not supported");
|
|
160
190
|
return sortedEdits;
|
|
161
191
|
}
|
|
@@ -164,12 +194,16 @@ var TextDocument = class {
|
|
|
164
194
|
const editPositions = this.positionsAt(edits.flatMap((edit) => [edit.start, edit.end]));
|
|
165
195
|
const changedLineRange = this.#computeChangedLineRange(edits, editPositions);
|
|
166
196
|
const startPosition = editPositions[0];
|
|
197
|
+
const endPosition = editPositions[editPositions.length - 1];
|
|
198
|
+
const endedAtDocumentEnd = endPosition.line === previousLineCount - 1 && endPosition.character === this.#pieceTable.getLineLength(endPosition.line);
|
|
167
199
|
this.#pieceTable.applyEdits(edits);
|
|
168
200
|
const lineCount = this.#pieceTable.lineCount;
|
|
169
201
|
return {
|
|
170
202
|
startLine: changedLineRange.startLine,
|
|
171
203
|
startCharacter: startPosition.character,
|
|
204
|
+
endCharacter: endPosition.character,
|
|
172
205
|
endLine: Math.min(changedLineRange.endLine, Math.max(0, lineCount - 1)),
|
|
206
|
+
endedAtDocumentEnd,
|
|
173
207
|
previousLineCount,
|
|
174
208
|
lineCount,
|
|
175
209
|
lineDelta: lineCount - previousLineCount,
|
|
@@ -183,6 +217,8 @@ var TextDocument = class {
|
|
|
183
217
|
let lineDeltaBeforeEdit = 0;
|
|
184
218
|
const ranges = [];
|
|
185
219
|
const changes = [];
|
|
220
|
+
const previousLastLine = this.#pieceTable.lineCount - 1;
|
|
221
|
+
const previousLastLineLength = this.#pieceTable.getLineLength(previousLastLine);
|
|
186
222
|
for (let i = 0; i < edits.length; i++) {
|
|
187
223
|
const edit = edits[i];
|
|
188
224
|
const editStart = editPositions[i * 2];
|
|
@@ -201,7 +237,10 @@ var TextDocument = class {
|
|
|
201
237
|
changes.push([
|
|
202
238
|
changedStartLine,
|
|
203
239
|
changedEndLine,
|
|
204
|
-
lineDelta
|
|
240
|
+
lineDelta,
|
|
241
|
+
editStart.character,
|
|
242
|
+
editEnd.character,
|
|
243
|
+
editEndLine === previousLastLine && editEnd.character === previousLastLineLength
|
|
205
244
|
]);
|
|
206
245
|
lineDeltaBeforeEdit += lineDelta;
|
|
207
246
|
}
|
|
@@ -212,7 +251,10 @@ var TextDocument = class {
|
|
|
212
251
|
changes: [[
|
|
213
252
|
0,
|
|
214
253
|
0,
|
|
215
|
-
0
|
|
254
|
+
0,
|
|
255
|
+
0,
|
|
256
|
+
0,
|
|
257
|
+
false
|
|
216
258
|
]]
|
|
217
259
|
};
|
|
218
260
|
return {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"textDocument.js","names":["#uri","#languageId","#version","#pieceTable","#editStack","#resolveEdit","#sortAndValidateResolvedEdits","#applyResolvedEditsToBuffer","#computeChangedLineRange"],"sources":["../../src/editor/textDocument.ts"],"sourcesContent":["import type { DiffLineAnnotation } from '../types';\nimport { countLineBreaks } from '../utils/computeFileOffsets';\nimport {\n coalesceEditStackEntries,\n createEditStackEntry,\n EditStack,\n shouldCoalesceEditStackEntry,\n} from './editStack';\nimport { PieceTable } from './pieceTable';\nimport type { SearchParams } from './searchPanel';\nimport { type EditorSelection } from './selection';\n\n/**\n * Position in a text document expressed as zero-based line and character offset.\n * The offsets are based on a UTF-16 string representation. So a string of the form\n * `a𐐀b` the character offset of the character `a` is 0, the character offset of `𐐀`\n * is 1 and the character offset of b is 3 since `𐐀` is represented using two code\n * units in UTF-16.\n *\n * Positions are line end character agnostic. So you can not specify a position that\n * denotes `\\r|\\n` or `\\n|` where `|` represents the character offset.\n */\nexport interface Position {\n /**\n * Line position in a document (zero-based).\n *\n * If a line number is greater than the number of lines in a document, it\n * defaults back to the number of lines in the document.\n * If a line number is negative, it defaults to 0.\n *\n * The above two properties are implementation specific.\n */\n readonly line: number;\n /**\n * Character offset on a line in a document (zero-based).\n *\n * The meaning of this offset is determined by the negotiated\n * `PositionEncodingKind`.\n *\n * If the character value is greater than the line length it defaults back\n * to the line length. This property is implementation specific.\n */\n readonly character: number;\n}\n\n/**\n * A range in a text document expressed as (zero-based) start and end positions.\n *\n * If you want to specify a range that contains a line including the line ending\n * character(s) then use an end position denoting the start of the next line.\n * For example:\n * ```ts\n * {\n * start: { line: 5, character: 23 }\n * end : { line 6, character : 0 }\n * }\n * ```\n */\nexport interface Range {\n /**\n * The range's start position.\n */\n readonly start: Position;\n /**\n * The range's end position.\n */\n readonly end: Position;\n}\n\n/**\n * A text edit applicable to a text document.\n */\nexport interface TextEdit {\n /**\n * The range of the text document to be manipulated. To insert\n * text into a document create a range where start === end.\n */\n readonly range: Range;\n /**\n * The string to be inserted. For delete operations use an\n * empty string.\n */\n readonly newText: string;\n}\n\n/** Different with `TextEdit`, the range has been resolved to offsets. */\nexport interface ResolvedTextEdit {\n /** The start offset of the text change. */\n readonly start: number;\n /** The end offset of the text change. */\n readonly end: number;\n /**\n * The string to be inserted. For delete operations use an\n * empty string.\n */\n readonly text: string;\n}\n\nexport interface TextDocumentChange {\n /** First line whose rendered content or tokenizer state may have changed. */\n readonly startLine: number;\n /** Character on the first changed line where the edit began. */\n readonly startCharacter: number;\n /** Last line whose rendered content may have changed after the edit. */\n readonly endLine: number;\n /** Line count before the edit was applied. */\n readonly previousLineCount: number;\n /** Line count after the edit was applied. */\n readonly lineCount: number;\n /** Difference between the old and new line counts. */\n readonly lineDelta: number;\n /** Exact rendered line ranges touched by each edit after the edit was applied. */\n readonly changedLineRanges: readonly [startLine: number, endLine: number][];\n /** Per-edit rendered line ranges before adjacent ranges are coalesced. */\n readonly changedLineChanges?: readonly [\n startLine: number,\n endLine: number,\n lineDelta: number,\n ][];\n}\n\n/**\n * A vscode-languageserver-textdocument compatible text document.\n */\nexport class TextDocument<LAnnotation> {\n #uri: string;\n #languageId: string;\n #version: number;\n #pieceTable: PieceTable;\n #editStack: EditStack<LAnnotation>;\n\n constructor(\n uri: string,\n text: string,\n languageId = 'plaintext',\n version = 0,\n editStack: EditStack<LAnnotation> = new EditStack()\n ) {\n this.#uri = new URL(uri, 'file://').toString();\n this.#languageId = languageId;\n this.#version = version;\n this.#pieceTable = new PieceTable(text);\n this.#editStack = editStack;\n }\n\n get uri(): string {\n return this.#uri;\n }\n\n get languageId(): string {\n return this.#languageId;\n }\n\n get version(): number {\n return this.#version;\n }\n\n get lineCount(): number {\n return this.#pieceTable.lineCount;\n }\n\n // The line ending the document uses, detected from its first line. Lets\n // inserted or pasted text match the rest of the file instead of leaving\n // mixed endings behind. Recognizes Windows `\\r\\n` and classic-Mac lone `\\r`\n // breaks (both of which the piece table already splits on), defaulting to\n // Unix `\\n`.\n get eol(): string {\n if (this.lineCount > 1) {\n const firstLineBreak = this.getLineText(0, true);\n if (firstLineBreak.endsWith('\\r\\n')) {\n return '\\r\\n';\n }\n if (firstLineBreak.endsWith('\\r')) {\n return '\\r';\n }\n }\n return '\\n';\n }\n\n get canUndo(): boolean {\n return this.#editStack.canUndo;\n }\n\n get canRedo(): boolean {\n return this.#editStack.canRedo;\n }\n\n positionAt(offset: number): Position {\n return this.#pieceTable.positionAt(offset);\n }\n\n positionsAt(offsets: readonly number[]): Position[] {\n return this.#pieceTable.positionsAt(offsets);\n }\n\n offsetAt(position: Position): number {\n return this.#pieceTable.offsetAt(this.normalizePosition(position));\n }\n\n getText(range?: Range): string {\n if (range === undefined) {\n return this.#pieceTable.getText();\n }\n // Clamp the range to visible line content before extracting text. A\n // preserved vertical-move \"goal column\" can leave a selection focus whose\n // character overshoots a shorter line; without this, the piece table clamps\n // to the line's offset span (which includes the trailing line break) and\n // copy/cut would pull in that newline. Mirrors `offsetAt`, which normalizes\n // positions the same way.\n return this.#pieceTable.getText({\n start: this.normalizePosition(range.start),\n end: this.normalizePosition(range.end),\n });\n }\n\n getLineText(line: number, includeLineBreak?: boolean): string {\n return this.#pieceTable.getLineText(line, includeLineBreak);\n }\n\n // Rewrites every line break in `text` to the document's EOL. Clipboard text\n // can carry Windows (`\\r\\n`) or classic-Mac (`\\r`) breaks; inserting it\n // verbatim would leave mixed line endings in a file that uses one style.\n normalizeEol(text: string): string {\n return text.replace(/\\r\\n|\\r|\\n/g, this.eol);\n }\n\n getLineLength(line: number, includeLineBreak?: boolean): number {\n return this.#pieceTable.getLineLength(line, includeLineBreak);\n }\n\n charAt(offset: number): string;\n charAt(position: Position): string;\n charAt(positionOrOffset: Position | number): string {\n if (typeof positionOrOffset === 'number') {\n return this.#pieceTable.charAt(positionOrOffset);\n }\n return this.#pieceTable.charAt(this.offsetAt(positionOrOffset));\n }\n\n getTextSlice(start: number, end: number): string {\n return this.#pieceTable.getTextSlice(start, end);\n }\n\n findNextNonOverlappingSubstring(\n needle: string,\n occupied: readonly [start: number, end: number][]\n ): number | undefined {\n return this.#pieceTable.findNextNonOverlappingSubstring(needle, occupied);\n }\n\n search(searchParams: SearchParams): [start: number, end: number][] {\n return this.#pieceTable.search(searchParams);\n }\n\n applyEdits(\n edits: TextEdit[],\n updateHistory = false,\n selectionsBefore?: EditorSelection[],\n selectionsAfter?: EditorSelection[],\n undoBoundary = false\n ): TextDocumentChange | undefined {\n if (edits.length === 0) {\n return;\n }\n return this.applyResolvedEdits(\n edits.map((edit) => this.#resolveEdit(edit)),\n updateHistory,\n selectionsBefore,\n selectionsAfter,\n undoBoundary\n );\n }\n\n applyResolvedEdits(\n edits: ResolvedTextEdit[],\n updateHistory = false,\n selectionsBefore?: EditorSelection[],\n selectionsAfter?: EditorSelection[],\n undoBoundary = false\n ): TextDocumentChange | undefined {\n if (edits.length === 0) {\n return undefined;\n }\n const resolvedEdits = this.#sortAndValidateResolvedEdits(edits);\n if (updateHistory) {\n const entry = createEditStackEntry(\n this,\n resolvedEdits,\n this.#version,\n this.#version + 1,\n selectionsBefore,\n selectionsAfter\n );\n if (undoBoundary) {\n entry.undoBoundary = true;\n }\n const previousEntry = this.#editStack.peekUndo();\n const change = this.#applyResolvedEditsToBuffer(resolvedEdits);\n this.#version++;\n if (\n change.lineDelta === 0 &&\n shouldCoalesceEditStackEntry(previousEntry, entry)\n ) {\n this.#editStack.replaceLastUndo(\n coalesceEditStackEntries(previousEntry!, entry)\n );\n } else {\n this.#editStack.push(entry);\n }\n return change;\n }\n const change = this.#applyResolvedEditsToBuffer(resolvedEdits);\n this.#version++;\n return change;\n }\n\n setLastUndoSelectionsAfter(selections: EditorSelection[]): void {\n this.#editStack.setLastUndoSelectionsAfter(selections);\n }\n\n setLastUndoLineAnnotations(\n lineAnnotationsBefore: DiffLineAnnotation<LAnnotation>[],\n lineAnnotationsAfter: DiffLineAnnotation<LAnnotation>[]\n ): void {\n this.#editStack.setLastUndoLineAnnotations(\n lineAnnotationsBefore,\n lineAnnotationsAfter\n );\n }\n\n undo():\n | [\n change: TextDocumentChange,\n selections?: EditorSelection[],\n lineAnnotations?: DiffLineAnnotation<LAnnotation>[],\n ]\n | undefined {\n const entry = this.#editStack.popUndoToRedo();\n if (entry === undefined) {\n return undefined;\n }\n const change = this.#applyResolvedEditsToBuffer(entry.inverseEdits);\n if (change === undefined) {\n return undefined;\n }\n this.#version = entry.versionBefore;\n return [\n change,\n entry.selectionsBefore?.slice(),\n entry.lineAnnotationsBefore?.slice(),\n ];\n }\n\n redo():\n | [\n change: TextDocumentChange,\n selections?: EditorSelection[],\n lineAnnotations?: DiffLineAnnotation<LAnnotation>[],\n ]\n | undefined {\n const entry = this.#editStack.popRedoToUndo();\n if (entry === undefined) {\n return undefined;\n }\n const change = this.#applyResolvedEditsToBuffer(entry.forwardEdits);\n if (change === undefined) {\n return undefined;\n }\n this.#version = entry.versionAfter;\n return [\n change,\n entry.selectionsAfter?.slice(),\n entry.lineAnnotationsAfter?.slice(),\n ];\n }\n\n normalizePosition(position: Position): Position {\n const line = Math.max(0, Math.min(position.line, this.lineCount - 1));\n return {\n line,\n character: Math.max(\n 0,\n Math.min(position.character, this.getLineLength(line))\n ),\n };\n }\n\n #resolveEdit(edit: TextEdit): ResolvedTextEdit {\n let start = this.offsetAt(edit.range.start);\n let end = this.offsetAt(edit.range.end);\n if (start > end) {\n const t = start;\n start = end;\n end = t;\n }\n return { start, end, text: edit.newText };\n }\n\n #sortAndValidateResolvedEdits(edits: ResolvedTextEdit[]): ResolvedTextEdit[] {\n const sortedEdits = [...edits].sort((a, b) => a.start - b.start);\n for (let i = 0; i < sortedEdits.length - 1; i++) {\n if (sortedEdits[i].end > sortedEdits[i + 1].start) {\n throw new Error('Overlapping text edits are not supported');\n }\n }\n return sortedEdits;\n }\n\n #applyResolvedEditsToBuffer(edits: ResolvedTextEdit[]): TextDocumentChange {\n const previousLineCount = this.#pieceTable.lineCount;\n const editPositions = this.positionsAt(\n edits.flatMap((edit) => [edit.start, edit.end])\n );\n const changedLineRange = this.#computeChangedLineRange(\n edits,\n editPositions\n );\n const startPosition = editPositions[0];\n this.#pieceTable.applyEdits(edits);\n const lineCount = this.#pieceTable.lineCount;\n const change: TextDocumentChange = {\n startLine: changedLineRange.startLine,\n startCharacter: startPosition.character,\n endLine: Math.min(changedLineRange.endLine, Math.max(0, lineCount - 1)),\n previousLineCount,\n lineCount,\n lineDelta: lineCount - previousLineCount,\n changedLineRanges: changedLineRange.ranges,\n changedLineChanges: changedLineRange.changes,\n };\n return change;\n }\n\n #computeChangedLineRange(\n edits: ResolvedTextEdit[],\n editPositions: Position[]\n ): {\n startLine: number;\n endLine: number;\n ranges: [number, number][];\n changes: [startLine: number, endLine: number, lineDelta: number][];\n } {\n let startLine = Infinity;\n let endLine = 0;\n let lineDeltaBeforeEdit = 0;\n const ranges: [number, number][] = [];\n const changes: [startLine: number, endLine: number, lineDelta: number][] =\n [];\n for (let i = 0; i < edits.length; i++) {\n const edit = edits[i];\n const editStart = editPositions[i * 2];\n const editEnd = editPositions[i * 2 + 1];\n const editStartLine = editStart.line;\n const editEndLine = editEnd.line;\n const insertedLineSpan = countLineBreaks(edit.text);\n const changedStartLine = editStartLine + lineDeltaBeforeEdit;\n const changedEndLine = changedStartLine + insertedLineSpan;\n const lineDelta = insertedLineSpan - (editEndLine - editStartLine);\n startLine = Math.min(startLine, editStartLine);\n endLine = Math.max(endLine, changedEndLine);\n const lastRange = ranges[ranges.length - 1];\n if (lastRange !== undefined && changedStartLine <= lastRange[1] + 1) {\n ranges[ranges.length - 1] = [\n lastRange[0],\n Math.max(lastRange[1], changedEndLine),\n ];\n } else {\n ranges.push([changedStartLine, changedEndLine]);\n }\n changes.push([changedStartLine, changedEndLine, lineDelta]);\n lineDeltaBeforeEdit += lineDelta;\n }\n if (startLine === Infinity) {\n return {\n startLine: 0,\n endLine: 0,\n ranges: [[0, 0]],\n changes: [[0, 0, 0]],\n };\n }\n return { startLine, endLine, ranges, changes };\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"textDocument.js","names":["#uri","#languageId","#version","#pieceTable","#editStack","#eol","#applyResolvedEdits","#sortAndValidateResolvedEdits","#resolveEdit","#normalizeResolvedEdit","#applyResolvedEditsToBuffer","#clampIndex","#isInsideSurrogatePair","#computeChangedLineRange"],"sources":["../../src/editor/textDocument.ts"],"sourcesContent":["import type {\n DiffLineAnnotation,\n EditorSelection,\n Position,\n Range,\n TextEdit,\n} from '../types';\nimport { countLineBreaks } from '../utils/computeFileOffsets';\nimport {\n coalesceEditStackEntries,\n createEditStackEntry,\n EditStack,\n shouldCoalesceEditStackEntry,\n} from './editStack';\nimport { PieceTable } from './pieceTable';\nimport type { SearchParams } from './searchPanel';\n\nexport type { Position, Range, TextEdit } from '../types';\n\n/** Different with `TextEdit`, the range has been resolved to offsets. */\nexport interface ResolvedTextEdit {\n /** The start offset of the text change. */\n readonly start: number;\n /** The end offset of the text change. */\n readonly end: number;\n /**\n * The string to be inserted. For delete operations use an\n * empty string.\n */\n readonly text: string;\n}\n\nexport interface TextDocumentChange {\n /** First line whose rendered content or tokenizer state may have changed. */\n readonly startLine: number;\n /** Character on the first changed line where the edit began. */\n readonly startCharacter: number;\n /** Character on the original last changed line where the edit ended. */\n readonly endCharacter: number;\n /** Last line whose rendered content may have changed after the edit. */\n readonly endLine: number;\n /** Whether the original edit range ended at the previous document EOF. */\n readonly endedAtDocumentEnd: boolean;\n /** Line count before the edit was applied. */\n readonly previousLineCount: number;\n /** Line count after the edit was applied. */\n readonly lineCount: number;\n /** Difference between the old and new line counts. */\n readonly lineDelta: number;\n /** Exact rendered line ranges touched by each edit after the edit was applied. */\n readonly changedLineRanges: readonly [startLine: number, endLine: number][];\n /** Per-edit rendered line ranges before adjacent ranges are coalesced. */\n readonly changedLineChanges?: readonly [\n startLine: number,\n endLine: number,\n lineDelta: number,\n startCharacter?: number,\n endCharacter?: number,\n endedAtDocumentEnd?: boolean,\n ][];\n}\n\n// Metadata-less replay results include the resolved edits so Editor can remap\n// its live selections without storing a snapshot on the history entry.\ntype TextDocumentHistoryResult<LAnnotation> = [\n change: TextDocumentChange,\n selections?: EditorSelection[],\n lineAnnotations?: DiffLineAnnotation<LAnnotation>[],\n selectionEdits?: ResolvedTextEdit[],\n];\n\n/**\n * A vscode-languageserver-textdocument compatible text document.\n */\nexport class TextDocument<LAnnotation> {\n #uri: string;\n #languageId: string;\n #version: number;\n #pieceTable: PieceTable;\n #editStack: EditStack<LAnnotation>;\n #eol: string;\n\n constructor(\n uri: string,\n text: string,\n languageId = 'text',\n version = 0,\n editStack: EditStack<LAnnotation> = new EditStack()\n ) {\n this.#uri = new URL(uri, 'file://').toString();\n this.#languageId = languageId;\n this.#version = version;\n this.#pieceTable = new PieceTable(text);\n this.#editStack = editStack;\n\n // The line ending the document uses, detected once from its first line. Lets\n // inserted or pasted text match the rest of the file instead of leaving\n // mixed endings behind and keeps that convention stable as the file is\n // edited. Defaults to Unix `\\n` when the initial text has no line break.\n const firstLineBreak = this.#pieceTable.getLineText(0, true);\n if (firstLineBreak.endsWith('\\r\\n')) {\n this.#eol = '\\r\\n';\n } else if (firstLineBreak.endsWith('\\r')) {\n this.#eol = '\\r';\n } else {\n this.#eol = '\\n';\n }\n }\n\n get uri(): string {\n return this.#uri;\n }\n\n get languageId(): string {\n return this.#languageId;\n }\n\n get version(): number {\n return this.#version;\n }\n\n get lineCount(): number {\n return this.#pieceTable.lineCount;\n }\n\n get eol(): string {\n return this.#eol;\n }\n\n get canUndo(): boolean {\n return this.#editStack.canUndo;\n }\n\n get canRedo(): boolean {\n return this.#editStack.canRedo;\n }\n\n positionAt(offset: number): Position {\n return this.normalizePosition(this.#pieceTable.positionAt(offset));\n }\n\n positionsAt(offsets: readonly number[]): Position[] {\n const positions = this.#pieceTable.positionsAt(offsets);\n for (let i = 0; i < positions.length; i++) {\n positions[i] = this.normalizePosition(positions[i]);\n }\n return positions;\n }\n\n offsetAt(position: Position): number {\n return this.#pieceTable.offsetAt(this.normalizePosition(position));\n }\n\n getText(range?: Range): string {\n if (range === undefined) {\n return this.#pieceTable.getText();\n }\n // Clamp the range to visible line content before extracting text. A\n // preserved vertical-move \"goal column\" can leave a selection focus whose\n // character overshoots a shorter line; without this, the piece table clamps\n // to the line's offset span (which includes the trailing line break) and\n // copy/cut would pull in that newline. Mirrors `offsetAt`, which normalizes\n // positions the same way.\n return this.#pieceTable.getText({\n start: this.normalizePosition(range.start),\n end: this.normalizePosition(range.end),\n });\n }\n\n getLineText(line: number, includeLineBreak?: boolean): string {\n return this.#pieceTable.getLineText(line, includeLineBreak);\n }\n\n // Rewrites every line break in `text` to the document's EOL. Clipboard text\n // can carry Windows (`\\r\\n`) or classic-Mac (`\\r`) breaks; inserting it\n // verbatim would leave mixed line endings in a file that uses one style.\n normalizeEol(text: string): string {\n return text.replace(/\\r\\n|\\r|\\n/g, this.eol);\n }\n\n getLineLength(line: number, includeLineBreak?: boolean): number {\n return this.#pieceTable.getLineLength(line, includeLineBreak);\n }\n\n charAt(offset: number): string;\n charAt(position: Position): string;\n charAt(positionOrOffset: Position | number): string {\n if (typeof positionOrOffset === 'number') {\n return this.#pieceTable.charAt(positionOrOffset);\n }\n return this.#pieceTable.charAt(this.offsetAt(positionOrOffset));\n }\n\n getTextSlice(start: number, end: number): string {\n return this.#pieceTable.getTextSlice(start, end);\n }\n\n findNextNonOverlappingSubstring(\n needle: string,\n occupied: readonly [start: number, end: number][]\n ): number | undefined {\n return this.#pieceTable.findNextNonOverlappingSubstring(needle, occupied);\n }\n\n search(searchParams: SearchParams): [start: number, end: number][] {\n return this.#pieceTable.search(searchParams);\n }\n\n applyEdits(\n edits: TextEdit[],\n updateHistory = true,\n selectionsBefore?: EditorSelection[],\n selectionsAfter?: EditorSelection[],\n undoBoundary = false\n ): TextDocumentChange | undefined {\n if (edits.length === 0) {\n return;\n }\n return this.#applyResolvedEdits(\n this.#sortAndValidateResolvedEdits(this.resolveEdits(edits)),\n updateHistory,\n selectionsBefore,\n selectionsAfter,\n undoBoundary\n );\n }\n\n // Converts line/character ranges to the exact UTF-16 offsets applyEdits\n // uses, including widening invalid boundaries so they cannot split a valid\n // surrogate pair. Editor caret remapping uses the same resolved geometry.\n resolveEdits(edits: readonly TextEdit[]): ResolvedTextEdit[] {\n return edits.map((edit) => this.#resolveEdit(edit));\n }\n\n applyResolvedEdits(\n edits: ResolvedTextEdit[],\n updateHistory = true,\n selectionsBefore?: EditorSelection[],\n selectionsAfter?: EditorSelection[],\n undoBoundary = false\n ): TextDocumentChange | undefined {\n if (edits.length === 0) {\n return undefined;\n }\n return this.#applyResolvedEdits(\n this.#sortAndValidateResolvedEdits(\n edits.map((edit) => this.#normalizeResolvedEdit(edit))\n ),\n updateHistory,\n selectionsBefore,\n selectionsAfter,\n undoBoundary\n );\n }\n\n // Every edit joins the undo timeline: an edit applied with\n // `updateHistory=false` affects the edit stack exactly as the identical\n // call with `updateHistory=true` and no selections or undo boundary would.\n // The flag only controls whether the caller's interaction metadata is\n // recorded on the entry; the entry itself is always pushed (clearing any\n // pending redo) and coalesces by the normal geometry rules. This keeps a\n // mixed tracked/untracked sequence equivalent to the all-tracked sequence —\n // undo-to-exhaustion restores the original text, redo-to-exhaustion the\n // final text — instead of leaving frozen entries whose offsets go stale.\n // Only history replay (undo/redo) writes to the buffer without recording.\n #applyResolvedEdits(\n resolvedEdits: ResolvedTextEdit[],\n updateHistory: boolean,\n selectionsBefore: EditorSelection[] | undefined,\n selectionsAfter: EditorSelection[] | undefined,\n undoBoundary: boolean\n ): TextDocumentChange {\n const entry = createEditStackEntry(\n this,\n resolvedEdits,\n this.#version,\n this.#version + 1,\n updateHistory ? selectionsBefore : undefined,\n updateHistory ? selectionsAfter : undefined\n );\n if (updateHistory && undoBoundary) {\n entry.undoBoundary = true;\n }\n const previousEntry = this.#editStack.peekUndoForCoalescing();\n const change = this.#applyResolvedEditsToBuffer(resolvedEdits);\n this.#version++;\n if (\n change.lineDelta === 0 &&\n shouldCoalesceEditStackEntry(previousEntry, entry)\n ) {\n this.#editStack.replaceLastUndo(\n coalesceEditStackEntries(previousEntry!, entry)\n );\n } else {\n this.#editStack.push(entry);\n }\n return change;\n }\n\n setLastUndoSelectionsAfter(selections: EditorSelection[]): void {\n this.#editStack.setLastUndoSelectionsAfter(selections);\n }\n\n setLastUndoLineAnnotations(\n lineAnnotationsBefore: DiffLineAnnotation<LAnnotation>[],\n lineAnnotationsAfter: DiffLineAnnotation<LAnnotation>[]\n ): void {\n this.#editStack.setLastUndoLineAnnotations(\n lineAnnotationsBefore,\n lineAnnotationsAfter\n );\n }\n\n undo(): TextDocumentHistoryResult<LAnnotation> | undefined {\n const entry = this.#editStack.popUndoToRedo();\n if (entry === undefined) {\n return undefined;\n }\n const change = this.#applyResolvedEditsToBuffer(entry.inverseEdits);\n if (change === undefined) {\n return undefined;\n }\n this.#version = entry.versionBefore;\n const selections = entry.selectionsBefore?.slice();\n return [\n change,\n selections,\n entry.lineAnnotationsBefore?.slice(),\n selections === undefined\n ? entry.inverseEdits.map((edit) => ({ ...edit }))\n : undefined,\n ];\n }\n\n redo(): TextDocumentHistoryResult<LAnnotation> | undefined {\n const entry = this.#editStack.popRedoToUndo();\n if (entry === undefined) {\n return undefined;\n }\n const change = this.#applyResolvedEditsToBuffer(entry.forwardEdits);\n if (change === undefined) {\n return undefined;\n }\n this.#version = entry.versionAfter;\n const selections = entry.selectionsAfter?.slice();\n return [\n change,\n selections,\n entry.lineAnnotationsAfter?.slice(),\n selections === undefined\n ? entry.forwardEdits.map((edit) => ({ ...edit }))\n : undefined,\n ];\n }\n\n normalizePosition(position: Position): Position {\n const line = TextDocument.#clampIndex(position.line, this.lineCount - 1);\n return {\n line,\n character: TextDocument.#clampIndex(\n position.character,\n this.getLineLength(line)\n ),\n };\n }\n\n // Math.min/max pass NaN through, and a fractional index breaks the\n // integer-keyed line-offset lookup — either way the resolved offset becomes\n // NaN and a degenerate edit range can swallow the whole document. Malformed\n // components clamp like any other out-of-range value: NaN and -Infinity act\n // as 0, fractions floor, +Infinity clamps to the max.\n static #clampIndex(value: number, max: number): number {\n if (Number.isNaN(value)) {\n return 0;\n }\n return Math.max(0, Math.min(Math.floor(value), max));\n }\n\n #resolveEdit(edit: TextEdit): ResolvedTextEdit {\n let start = this.offsetAt(edit.range.start);\n let end = this.offsetAt(edit.range.end);\n if (start > end) {\n const t = start;\n start = end;\n end = t;\n }\n return this.#normalizeResolvedEdit({\n start,\n end,\n text: edit.newText,\n });\n }\n\n // Snaps an insertion before a pair and widens replacement boundaries\n // outward, so every edit addresses whole UTF-16 surrogate pairs.\n #normalizeResolvedEdit(edit: ResolvedTextEdit): ResolvedTextEdit {\n let { start, end } = edit;\n const isInsertion = start === end;\n if (this.#isInsideSurrogatePair(start)) {\n start--;\n }\n if (isInsertion) {\n end = start;\n } else if (this.#isInsideSurrogatePair(end)) {\n end++;\n }\n return { start, end, text: edit.text };\n }\n\n // A UTF-16 offset is invalid when it sits between the high and low units of\n // one well-formed surrogate pair. Lone surrogate units remain addressable.\n #isInsideSurrogatePair(offset: number): boolean {\n const previous = this.#pieceTable.charAt(offset - 1).charCodeAt(0);\n const next = this.#pieceTable.charAt(offset).charCodeAt(0);\n return (\n previous >= 0xd800 &&\n previous <= 0xdbff &&\n next >= 0xdc00 &&\n next <= 0xdfff\n );\n }\n\n #sortAndValidateResolvedEdits(edits: ResolvedTextEdit[]): ResolvedTextEdit[] {\n // Put zero-width edits before ranges at the same start so validation and\n // application do not depend on the caller's batch order.\n const sortedEdits = [...edits].sort((a, b) => {\n const startDelta = a.start - b.start;\n return startDelta === 0 ? a.end - b.end : startDelta;\n });\n for (let i = 0; i < sortedEdits.length - 1; i++) {\n if (sortedEdits[i].end > sortedEdits[i + 1].start) {\n throw new Error('Overlapping text edits are not supported');\n }\n }\n return sortedEdits;\n }\n\n #applyResolvedEditsToBuffer(edits: ResolvedTextEdit[]): TextDocumentChange {\n const previousLineCount = this.#pieceTable.lineCount;\n const editPositions = this.positionsAt(\n edits.flatMap((edit) => [edit.start, edit.end])\n );\n const changedLineRange = this.#computeChangedLineRange(\n edits,\n editPositions\n );\n const startPosition = editPositions[0];\n const endPosition = editPositions[editPositions.length - 1];\n const endedAtDocumentEnd =\n endPosition.line === previousLineCount - 1 &&\n endPosition.character ===\n this.#pieceTable.getLineLength(endPosition.line);\n this.#pieceTable.applyEdits(edits);\n const lineCount = this.#pieceTable.lineCount;\n const change: TextDocumentChange = {\n startLine: changedLineRange.startLine,\n startCharacter: startPosition.character,\n endCharacter: endPosition.character,\n endLine: Math.min(changedLineRange.endLine, Math.max(0, lineCount - 1)),\n endedAtDocumentEnd,\n previousLineCount,\n lineCount,\n lineDelta: lineCount - previousLineCount,\n changedLineRanges: changedLineRange.ranges,\n changedLineChanges: changedLineRange.changes,\n };\n return change;\n }\n\n #computeChangedLineRange(\n edits: ResolvedTextEdit[],\n editPositions: Position[]\n ): {\n startLine: number;\n endLine: number;\n ranges: [number, number][];\n changes: [\n startLine: number,\n endLine: number,\n lineDelta: number,\n startCharacter: number,\n endCharacter: number,\n endedAtDocumentEnd: boolean,\n ][];\n } {\n let startLine = Infinity;\n let endLine = 0;\n let lineDeltaBeforeEdit = 0;\n const ranges: [number, number][] = [];\n const changes: [\n startLine: number,\n endLine: number,\n lineDelta: number,\n startCharacter: number,\n endCharacter: number,\n endedAtDocumentEnd: boolean,\n ][] = [];\n const previousLastLine = this.#pieceTable.lineCount - 1;\n const previousLastLineLength =\n this.#pieceTable.getLineLength(previousLastLine);\n for (let i = 0; i < edits.length; i++) {\n const edit = edits[i];\n const editStart = editPositions[i * 2];\n const editEnd = editPositions[i * 2 + 1];\n const editStartLine = editStart.line;\n const editEndLine = editEnd.line;\n const insertedLineSpan = countLineBreaks(edit.text);\n const changedStartLine = editStartLine + lineDeltaBeforeEdit;\n const changedEndLine = changedStartLine + insertedLineSpan;\n const lineDelta = insertedLineSpan - (editEndLine - editStartLine);\n startLine = Math.min(startLine, editStartLine);\n endLine = Math.max(endLine, changedEndLine);\n const lastRange = ranges[ranges.length - 1];\n if (lastRange !== undefined && changedStartLine <= lastRange[1] + 1) {\n ranges[ranges.length - 1] = [\n lastRange[0],\n Math.max(lastRange[1], changedEndLine),\n ];\n } else {\n ranges.push([changedStartLine, changedEndLine]);\n }\n changes.push([\n changedStartLine,\n changedEndLine,\n lineDelta,\n editStart.character,\n editEnd.character,\n editEndLine === previousLastLine &&\n editEnd.character === previousLastLineLength,\n ]);\n lineDeltaBeforeEdit += lineDelta;\n }\n if (startLine === Infinity) {\n return {\n startLine: 0,\n endLine: 0,\n ranges: [[0, 0]],\n changes: [[0, 0, 0, 0, 0, false]],\n };\n }\n return { startLine, endLine, ranges, changes };\n }\n}\n"],"mappings":"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"}
|
|
@@ -13,15 +13,18 @@ declare class Metrics {
|
|
|
13
13
|
init(root: HTMLElement): void;
|
|
14
14
|
/**
|
|
15
15
|
* Re-measure the '0' character width against the font that is loaded right
|
|
16
|
-
* now, returning true when
|
|
16
|
+
* now, returning true when measurement-dependent UI should refresh.
|
|
17
17
|
*
|
|
18
18
|
* A custom web font can finish loading after the editor first renders.
|
|
19
19
|
* Until then canvas measureText reports the fallback font's width, and
|
|
20
20
|
* getComputedStyle returns the same font-family string before and after the
|
|
21
21
|
* file arrives, so init()'s font guard never re-measures on its own. Call
|
|
22
22
|
* this once fonts have settled (e.g. on document.fonts.ready) to replace a
|
|
23
|
-
* width measured against the fallback font with the real glyph width.
|
|
24
|
-
*
|
|
23
|
+
* width measured against the fallback font with the real glyph width. Font
|
|
24
|
+
* completion can also change DOM-measured emoji/ZWJ widths while leaving the
|
|
25
|
+
* ASCII width unchanged, and the computed font string stays the same in both
|
|
26
|
+
* cases. The boolean return lets the caller skip re-rendering when there is no
|
|
27
|
+
* measured state to refresh.
|
|
25
28
|
*/
|
|
26
29
|
remeasureCharacterWidth(): boolean;
|
|
27
30
|
/** measure the width of the text */
|
|
@@ -47,14 +50,6 @@ declare function needsDomTextMeasurement(text: string): boolean;
|
|
|
47
50
|
declare function snapTextOffsetToUnicodeBoundary(text: string, offset: number): number;
|
|
48
51
|
/** get the offsets of the Unicode grapheme clusters in the text */
|
|
49
52
|
declare function getUnicodeMeasurementOffsets(text: string): number[] | undefined;
|
|
50
|
-
/**
|
|
51
|
-
* Expand tab characters to spaces using fixed tab stops: each tab advances to
|
|
52
|
-
* the next multiple of tabSize from its running column, matching how the
|
|
53
|
-
* rendered text expands tabs via CSS `tab-size`. Expanding every tab to a flat
|
|
54
|
-
* tabSize would mis-measure tabs that follow other characters on the same line
|
|
55
|
-
* (e.g. an alignment tab in `foo\tbar`).
|
|
56
|
-
*/
|
|
57
|
-
declare function expandTabsToSpaces(text: string, tabSize: number): string;
|
|
58
53
|
/**
|
|
59
54
|
* Count the rendered columns of ASCII text, advancing each tab to the next
|
|
60
55
|
* fixed tab stop (a multiple of tabSize) to match CSS `tab-size`. Returns -1
|
|
@@ -62,5 +57,5 @@ declare function expandTabsToSpaces(text: string, tabSize: number): string;
|
|
|
62
57
|
*/
|
|
63
58
|
declare function getExpandedAsciiTextColumns(text: string, tabSize: number): number;
|
|
64
59
|
//#endregion
|
|
65
|
-
export { Metrics,
|
|
60
|
+
export { Metrics, getExpandedAsciiTextColumns, getUnicodeMeasurementOffsets, needsDomTextMeasurement, snapTextOffsetToUnicodeBoundary };
|
|
66
61
|
//# sourceMappingURL=textMeasure.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"textMeasure.d.ts","names":[],"sources":["../../src/editor/textMeasure.ts"],"mappings":";
|
|
1
|
+
{"version":3,"file":"textMeasure.d.ts","names":[],"sources":["../../src/editor/textMeasure.ts"],"mappings":";cAUa,OAAA;EAAA;EAAO;EASlB,EAAA;EASsB;EAPtB,OAAA;EAFA;EAIA,UAAA;EAAA;EAEA,UAAA;EAGA;EAAA,IAAA,CAAK,IAAA,EAAM,WAAW;EAAjB;;;;;;;;;;AAyLc;AAYrB;;;;EAtIE,uBAAA;EAuJc;EAxId,gBAAA,CAAiB,IAAA;;EA8CjB,sBAAA,CAAuB,IAAA;EA4FT;AA6ChB;;;;EA7HE,mBAAA,CAAoB,IAAA;EAyJN;;;;AAEC;EA1Gf,mBAAA;AAAA;;iBAYc,uBAAA,CAAwB,IAAY;;iBAiBpC,+BAAA,CACd,IAAA,UACA,MAAc;;iBA6CA,4BAAA,CACd,IAAY;;;;;;iBA2BE,2BAAA,CACd,IAAA,UACA,OAAe"}
|