@pierre/diffs 1.2.6 → 1.3.0-beta.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 +0 -1
- package/dist/components/CodeView.d.ts.map +1 -1
- package/dist/components/CodeView.js +0 -23
- package/dist/components/CodeView.js.map +1 -1
- package/dist/components/File.d.ts +7 -2
- package/dist/components/File.d.ts.map +1 -1
- package/dist/components/File.js +36 -2
- package/dist/components/File.js.map +1 -1
- package/dist/components/FileDiff.d.ts +8 -2
- package/dist/components/FileDiff.d.ts.map +1 -1
- package/dist/components/FileDiff.js +73 -1
- package/dist/components/FileDiff.js.map +1 -1
- package/dist/components/UnresolvedFile.d.ts.map +1 -1
- package/dist/components/UnresolvedFile.js +2 -2
- package/dist/components/VirtualizedFile.d.ts +2 -1
- package/dist/components/VirtualizedFile.d.ts.map +1 -1
- package/dist/components/VirtualizedFile.js +48 -48
- package/dist/components/VirtualizedFile.js.map +1 -1
- package/dist/components/VirtualizedFileDiff.js +42 -22
- package/dist/components/VirtualizedFileDiff.js.map +1 -1
- package/dist/components/Virtualizer.d.ts +1 -1
- package/dist/components/Virtualizer.d.ts.map +1 -1
- package/dist/components/Virtualizer.js +3 -5
- package/dist/components/Virtualizer.js.map +1 -1
- package/dist/constants.d.ts.map +1 -1
- package/dist/editor/command.d.ts +6 -0
- package/dist/editor/command.d.ts.map +1 -0
- package/dist/editor/command.js +31 -0
- package/dist/editor/command.js.map +1 -0
- package/dist/editor/css.d.ts +6 -0
- package/dist/editor/css.d.ts.map +1 -0
- package/dist/editor/css.js +218 -0
- package/dist/editor/css.js.map +1 -0
- package/dist/editor/editStack.d.ts +66 -0
- package/dist/editor/editStack.d.ts.map +1 -0
- package/dist/editor/editStack.js +218 -0
- package/dist/editor/editStack.js.map +1 -0
- package/dist/editor/editor.d.ts +22 -0
- package/dist/editor/editor.d.ts.map +1 -0
- package/dist/editor/editor.js +1323 -0
- package/dist/editor/editor.js.map +1 -0
- package/dist/editor/index.d.ts +3 -0
- package/dist/editor/index.js +4 -0
- package/dist/editor/lineAnnotations.d.ts +8 -0
- package/dist/editor/lineAnnotations.d.ts.map +1 -0
- package/dist/editor/lineAnnotations.js +32 -0
- package/dist/editor/lineAnnotations.js.map +1 -0
- package/dist/editor/pieceTable.d.ts +33 -0
- package/dist/editor/pieceTable.d.ts.map +1 -0
- package/dist/editor/pieceTable.js +590 -0
- package/dist/editor/pieceTable.js.map +1 -0
- package/dist/editor/platform.d.ts +12 -0
- package/dist/editor/platform.d.ts.map +1 -0
- package/dist/editor/platform.js +44 -0
- package/dist/editor/platform.js.map +1 -0
- package/dist/editor/quickEdit.d.ts +29 -0
- package/dist/editor/quickEdit.d.ts.map +1 -0
- package/dist/editor/quickEdit.js +81 -0
- package/dist/editor/quickEdit.js.map +1 -0
- package/dist/editor/searchPanel.d.ts +30 -0
- package/dist/editor/searchPanel.d.ts.map +1 -0
- package/dist/editor/searchPanel.js +219 -0
- package/dist/editor/searchPanel.js.map +1 -0
- package/dist/editor/selection.d.ts +126 -0
- package/dist/editor/selection.d.ts.map +1 -0
- package/dist/editor/selection.js +900 -0
- package/dist/editor/selection.js.map +1 -0
- package/dist/editor/textDocument.d.ts +139 -0
- package/dist/editor/textDocument.d.ts.map +1 -0
- package/dist/editor/textDocument.js +202 -0
- package/dist/editor/textDocument.js.map +1 -0
- package/dist/editor/textMeasure.d.ts +32 -0
- package/dist/editor/textMeasure.d.ts.map +1 -0
- package/dist/editor/textMeasure.js +108 -0
- package/dist/editor/textMeasure.js.map +1 -0
- package/dist/editor/tokenzier.d.ts +37 -0
- package/dist/editor/tokenzier.d.ts.map +1 -0
- package/dist/editor/tokenzier.js +348 -0
- package/dist/editor/tokenzier.js.map +1 -0
- package/dist/editor/utils.d.ts +16 -0
- package/dist/editor/utils.d.ts.map +1 -0
- package/dist/editor/utils.js +37 -0
- package/dist/editor/utils.js.map +1 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -2
- package/dist/react/EditorContext.d.ts +16 -0
- package/dist/react/EditorContext.d.ts.map +1 -0
- package/dist/react/EditorContext.js +26 -0
- package/dist/react/EditorContext.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 +3 -1
- 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 +3 -1
- 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 +3 -1
- 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/index.d.ts +3 -2
- package/dist/react/index.js +2 -1
- package/dist/react/jsx.d.ts +0 -1
- package/dist/react/jsx.d.ts.map +1 -1
- package/dist/react/types.d.ts +1 -0
- package/dist/react/types.d.ts.map +1 -1
- package/dist/react/types.js +0 -1
- package/dist/react/utils/useFileDiffInstance.d.ts +3 -1
- package/dist/react/utils/useFileDiffInstance.d.ts.map +1 -1
- package/dist/react/utils/useFileDiffInstance.js +31 -5
- package/dist/react/utils/useFileDiffInstance.js.map +1 -1
- package/dist/react/utils/useFileInstance.d.ts +4 -1
- package/dist/react/utils/useFileInstance.d.ts.map +1 -1
- package/dist/react/utils/useFileInstance.js +30 -5
- package/dist/react/utils/useFileInstance.js.map +1 -1
- package/dist/renderers/DiffHunksRenderer.d.ts +2 -2
- package/dist/renderers/DiffHunksRenderer.d.ts.map +1 -1
- package/dist/renderers/DiffHunksRenderer.js +9 -5
- package/dist/renderers/DiffHunksRenderer.js.map +1 -1
- package/dist/renderers/FileRenderer.d.ts +5 -1
- package/dist/renderers/FileRenderer.d.ts.map +1 -1
- package/dist/renderers/FileRenderer.js +108 -41
- package/dist/renderers/FileRenderer.js.map +1 -1
- package/dist/ssr/index.d.ts +2 -2
- package/dist/style.js +1 -1
- package/dist/style.js.map +1 -1
- package/dist/types.d.ts +45 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/cleanLastNewline.js +6 -1
- package/dist/utils/cleanLastNewline.js.map +1 -1
- package/dist/utils/computeEstimatedDiffHeights.js +20 -9
- package/dist/utils/computeEstimatedDiffHeights.js.map +1 -1
- package/dist/utils/computeFileOffsets.d.ts +13 -0
- package/dist/utils/computeFileOffsets.d.ts.map +1 -0
- package/dist/utils/computeFileOffsets.js +33 -0
- package/dist/utils/computeFileOffsets.js.map +1 -0
- package/dist/utils/createTransformerWithState.js +9 -0
- package/dist/utils/createTransformerWithState.js.map +1 -1
- package/dist/utils/iterateOverDiff.js +182 -147
- package/dist/utils/iterateOverDiff.js.map +1 -1
- package/dist/utils/renderDiffWithHighlighter.js +1 -1
- package/dist/utils/renderFileWithHighlighter.js +5 -14
- package/dist/utils/renderFileWithHighlighter.js.map +1 -1
- package/dist/utils/virtualDiffLayout.d.ts +2 -23
- package/dist/utils/virtualDiffLayout.d.ts.map +1 -1
- package/dist/utils/virtualDiffLayout.js +1 -41
- package/dist/utils/virtualDiffLayout.js.map +1 -1
- package/dist/worker/WorkerPoolManager.js +1 -1
- package/dist/worker/{wasm-BaDzIkIn.js → wasm-D4DU5jgR.js} +2 -2
- package/dist/worker/wasm-D4DU5jgR.js.map +1 -0
- package/dist/worker/worker-portable.js +349 -363
- package/dist/worker/worker-portable.js.map +1 -1
- package/dist/worker/worker.js +222 -243
- package/dist/worker/worker.js.map +1 -1
- package/package.json +9 -1
- package/dist/utils/iterateOverFile.d.ts +0 -50
- package/dist/utils/iterateOverFile.d.ts.map +0 -1
- package/dist/utils/iterateOverFile.js +0 -49
- package/dist/utils/iterateOverFile.js.map +0 -1
- package/dist/worker/wasm-BaDzIkIn.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"selection.js","names":["edits: TextEdit[]","newSelection: EditorSelection","selectionPositions: Position[]","ordered: Array<{\n index: number;\n start: number;\n end: number;\n }>","edits: ResolvedTextEdit[]","nextSelectionOffsets: Array<[number, number] | undefined>","mergedGroup:\n | {\n start: number;\n end: number;\n indices: number[];\n }\n | undefined","nextOffsets: [number, number]","ordered: Array<{\n index: number;\n start: number;\n end: number;\n text: string;\n }>","nextSelectionOffsets: number[]","nextOffsetPairs: Array<[number, number]>","edit: ResolvedTextEdit | undefined","deleteSelections: EditorSelection[]","accepted: {\n index: number;\n selection: EditorSelection;\n }[]","last: HTMLElement | null","lastTextNode: Text | null","normalizedOffsets: number[]","lineEl: HTMLElement | null","tokens: HTMLElement[]","stack: Array<{ container: Node; index: number }>","current: Node | null","offset","target: HTMLElement | null","current: HTMLElement | null","base"],"sources":["../../src/editor/selection.ts"],"sourcesContent":["import type { DiffLineAnnotation } from '../types';\nimport { applyDocumentChangeToLineAnnotations } from './lineAnnotations';\nimport type {\n Position,\n Range,\n ResolvedTextEdit,\n TextDocument,\n TextDocumentChange,\n TextEdit,\n} from './textDocument';\n\nexport const DirectionBackward = -1;\nexport const DirectionNone = 0;\nexport const DirectionForward = 1;\n\nexport type SelectionDirection =\n | typeof DirectionBackward\n | typeof DirectionNone\n | typeof DirectionForward;\n\nexport interface EditorSelection extends Range {\n direction: SelectionDirection;\n}\n\n/**\n * Converts a selection from a web selection to an editor selection.\n */\nexport function convertSelection(\n range: StaticRange,\n direction: SelectionDirection = DirectionNone\n): EditorSelection | undefined {\n const start = boundaryToPosition(range.startContainer, range.startOffset);\n const end = boundaryToPosition(range.endContainer, range.endOffset);\n if (start === null || end === null) {\n return undefined;\n }\n return {\n start,\n end,\n direction,\n };\n}\n\n/**\n * Resolves the indent edits for a selection.\n */\nexport function resolveIndentEdits(\n textDocument: TextDocument<unknown>,\n selection: EditorSelection,\n tabSize: number,\n outdent: boolean\n): [edits: TextEdit[], nextSelection: EditorSelection] {\n if (textDocument === undefined) {\n return [[], selection];\n }\n const { start, end } = selection;\n const edits: TextEdit[] = [];\n let newSelection: EditorSelection = { ...selection };\n let endLine = end.line;\n if (start.line < end.line && end.character === 0) {\n endLine--;\n }\n for (let line = start.line; line <= endLine; line++) {\n const lineText = textDocument.getLineText(line);\n if (lineText === undefined) {\n continue;\n }\n const indentUnit = lineText.startsWith('\\t') ? '\\t' : ' '.repeat(tabSize);\n let deleteLength = 0;\n let newText = indentUnit;\n if (outdent) {\n if (lineText.startsWith('\\t')) {\n deleteLength = 1;\n } else if (lineText.startsWith(' ')) {\n const leadingSpacesLength =\n lineText.length - lineText.trimStart().length;\n deleteLength = Math.min(indentUnit.length, leadingSpacesLength);\n }\n if (deleteLength === 0) {\n continue;\n }\n newText = '';\n }\n edits.push({\n range: {\n start: { line, character: 0 },\n end: { line, character: deleteLength },\n },\n newText,\n });\n const delta = newText.length - deleteLength;\n if (line === start.line) {\n newSelection = {\n ...newSelection,\n start: {\n ...start,\n character: Math.max(0, start.character + delta),\n },\n };\n }\n if (line === end.line) {\n newSelection = {\n ...newSelection,\n end: {\n ...end,\n character: Math.max(0, end.character + delta),\n },\n };\n }\n }\n return [edits, newSelection];\n}\n\n/**\n * Maps the cursor move to all selections.\n */\nexport function mapCursorMove(\n textDocument: TextDocument<unknown>,\n selections: EditorSelection[],\n shortcut: 'textStart' | 'start' | 'end' | 'up' | 'down' | 'left' | 'right'\n): EditorSelection[] {\n const lineCount = textDocument.lineCount;\n return selections.map((selection) => {\n let { line, character } =\n shortcut === 'up' || shortcut === 'left'\n ? selection.start\n : selection.end;\n if (\n shortcut === 'textStart' ||\n shortcut === 'start' ||\n shortcut === 'end'\n ) {\n if (shortcut === 'textStart') {\n const indent = getLeadingSpaces(textDocument.getLineText(line));\n character = character === indent ? 0 : indent;\n } else {\n character =\n shortcut === 'start' ? 0 : textDocument.getLineText(line).length;\n }\n if (selection.direction === DirectionBackward) {\n line = selection.start.line;\n } else {\n line = selection.end.line;\n }\n } else if (shortcut === 'up') {\n line = Math.max(0, line - 1);\n } else if (shortcut === 'down') {\n line = Math.min(Math.max(lineCount - 1, 0), line + 1);\n } else if (isCollapsedSelection(selection)) {\n if (shortcut === 'left') {\n character--;\n\n if (character < 0) {\n if (line === 0) {\n character = 0;\n } else {\n line = Math.max(0, line - 1);\n character = textDocument.getLineText(line).length;\n }\n }\n } else {\n character++;\n if (character > textDocument.getLineText(line).length) {\n if (line === lineCount - 1) {\n character--;\n } else {\n line = Math.min(Math.max(lineCount - 1, 0), line + 1);\n character = 0;\n }\n }\n }\n }\n const pos = { line, character };\n return {\n start: pos,\n end: pos,\n direction: DirectionNone,\n };\n });\n}\n\n/**\n * Same as mapCursorMove, but with shift key pressed.\n */\nexport function mapSelectionShift(\n textDocument: TextDocument<unknown>,\n selections: EditorSelection[],\n shortcut: 'textStart' | 'start' | 'end' | 'up' | 'down' | 'left' | 'right'\n): EditorSelection[] {\n return selections.map((selection) => {\n const [anchorOffset, focusOffset] = getSelectionAnchorAndFocusOffsets(\n textDocument,\n selection\n );\n const focusPosition = textDocument.positionAt(focusOffset);\n const [movedFocusSelection] = mapCursorMove(\n textDocument,\n [\n {\n start: focusPosition,\n end: focusPosition,\n direction: DirectionNone,\n },\n ],\n shortcut\n );\n const movedFocusOffset = textDocument.offsetAt(movedFocusSelection.start);\n return createSelectionFromAnchorAndFocusOffsets(\n textDocument,\n anchorOffset,\n movedFocusOffset\n );\n });\n}\n\n/**\n * Applies a text change to the given text document\n */\nexport function applyTextChangeToSelections<LAnnotation>(\n textDocument: TextDocument<LAnnotation>,\n selections: EditorSelection[],\n edit: ResolvedTextEdit,\n lineAnnotations?: DiffLineAnnotation<LAnnotation>[],\n tabSize = 2\n): {\n nextSelections: EditorSelection[];\n change?: TextDocumentChange;\n} {\n const primarySelection = selections[selections.length - 1];\n if (primarySelection === undefined) {\n return { nextSelections: [] };\n }\n const selectionPositions: Position[] = [];\n for (const selection of selections) {\n selectionPositions.push(selection.start, selection.end);\n }\n const selectionOffsets = textDocument.offsetsAt(selectionPositions);\n const primaryStartOffset = selectionOffsets[(selections.length - 1) * 2];\n const primaryEndOffset = selectionOffsets[(selections.length - 1) * 2 + 1];\n const ordered: Array<{\n index: number;\n start: number;\n end: number;\n }> = [];\n let isAlreadyOrdered = true;\n for (let index = 0; index < selections.length; index++) {\n const entry = {\n index,\n start: selectionOffsets[index * 2],\n end: selectionOffsets[index * 2 + 1],\n };\n const previous = ordered[ordered.length - 1];\n if (\n previous !== undefined &&\n (entry.start < previous.start ||\n (entry.start === previous.start && entry.end < previous.end))\n ) {\n isAlreadyOrdered = false;\n }\n ordered.push(entry);\n }\n if (!isAlreadyOrdered) {\n ordered.sort((a, b) => {\n const startOrder = a.start - b.start;\n if (startOrder !== 0) {\n return startOrder;\n }\n const endOrder = a.end - b.end;\n if (endOrder !== 0) {\n return endOrder;\n }\n return a.index - b.index;\n });\n }\n const adjustedChange = normalizeLeadingIndentForChange(\n textDocument,\n edit,\n tabSize\n );\n const edits: ResolvedTextEdit[] = [];\n const nextSelectionOffsets: Array<[number, number] | undefined> = Array.from({\n length: selections.length,\n });\n let offsetDelta = 0;\n let mergedGroup:\n | {\n start: number;\n end: number;\n indices: number[];\n }\n | undefined;\n const finalizeMergedGroup = () => {\n if (mergedGroup === undefined) {\n return;\n }\n const perGroupChange = normalizeLeadingIndentForChange(\n textDocument,\n {\n start: mergedGroup.start,\n end: mergedGroup.end,\n text: adjustedChange.text,\n },\n tabSize\n );\n const newText = expandSingleNewlineInsert(\n textDocument,\n perGroupChange.text,\n perGroupChange.start\n );\n edits.push({\n start: perGroupChange.start,\n end: perGroupChange.end,\n text: newText,\n });\n const nextOffsets: [number, number] = [\n mergedGroup.start + offsetDelta + newText.length,\n mergedGroup.start + offsetDelta + newText.length,\n ];\n for (const index of mergedGroup.indices) {\n nextSelectionOffsets[index] = nextOffsets;\n }\n offsetDelta += newText.length - (perGroupChange.end - perGroupChange.start);\n mergedGroup = undefined;\n };\n for (const entry of ordered) {\n const startOffset = Math.max(\n 0,\n entry.start + (adjustedChange.start - primaryStartOffset)\n );\n const endOffset = Math.max(\n startOffset,\n entry.end + (adjustedChange.end - primaryEndOffset)\n );\n if (mergedGroup !== undefined && startOffset < mergedGroup.end) {\n mergedGroup.end = Math.max(mergedGroup.end, endOffset);\n mergedGroup.indices.push(entry.index);\n continue;\n }\n finalizeMergedGroup();\n mergedGroup = {\n start: startOffset,\n end: endOffset,\n indices: [entry.index],\n };\n }\n finalizeMergedGroup();\n\n const change = textDocument.applyResolvedEdits(edits, true, selections);\n const nextSelections = createSelectionsFromOffsetPairs(\n textDocument,\n nextSelectionOffsets.map((offsets) => {\n if (offsets === undefined) {\n throw new Error('Missing next selection offsets');\n }\n return offsets;\n })\n );\n textDocument.setLastUndoSelectionsAfter(nextSelections);\n if (change !== undefined && lineAnnotations !== undefined) {\n const nextLineAnnotations =\n applyDocumentChangeToLineAnnotations<LAnnotation>(\n change,\n lineAnnotations\n );\n if (nextLineAnnotations !== undefined) {\n textDocument.setLastUndoLineAnnotations(\n lineAnnotations,\n nextLineAnnotations\n );\n }\n }\n return { nextSelections, change };\n}\n\n/**\n * Applies a text replace to multiple selections.\n */\nexport function applyTextReplaceToSelections<LAnnotation>(\n textDocument: TextDocument<LAnnotation>,\n selections: EditorSelection[],\n texts: string[],\n lineAnnotations?: DiffLineAnnotation<LAnnotation>[]\n): {\n nextSelections: EditorSelection[];\n change?: TextDocumentChange;\n} {\n if (selections.length !== texts.length) {\n throw new Error(\n 'Selection text replacements must match the selection count'\n );\n }\n const selectionPositions: Position[] = [];\n for (const selection of selections) {\n selectionPositions.push(selection.start, selection.end);\n }\n const selectionOffsets = textDocument.offsetsAt(selectionPositions);\n const ordered: Array<{\n index: number;\n start: number;\n end: number;\n text: string;\n }> = [];\n let isAlreadyOrdered = true;\n for (let index = 0; index < selections.length; index++) {\n const entry = {\n index,\n start: selectionOffsets[index * 2],\n end: selectionOffsets[index * 2 + 1],\n text: texts[index],\n };\n const previous = ordered[ordered.length - 1];\n if (\n previous !== undefined &&\n (entry.start < previous.start ||\n (entry.start === previous.start && entry.end < previous.end))\n ) {\n isAlreadyOrdered = false;\n }\n ordered.push(entry);\n }\n if (!isAlreadyOrdered) {\n ordered.sort((a, b) => {\n const startOrder = a.start - b.start;\n if (startOrder !== 0) {\n return startOrder;\n }\n const endOrder = a.end - b.end;\n if (endOrder !== 0) {\n return endOrder;\n }\n return a.index - b.index;\n });\n }\n const edits: ResolvedTextEdit[] = [];\n const nextSelectionOffsets: number[] = Array.from({\n length: selections.length,\n });\n let offsetDelta = 0;\n let previousEditEnd = -1;\n for (const entry of ordered) {\n if (entry.start < previousEditEnd) {\n throw new Error('Overlapping multi-selection edits are not supported');\n }\n previousEditEnd = entry.end;\n const newText = expandSingleNewlineInsert(\n textDocument,\n entry.text,\n entry.start\n );\n edits.push({\n start: entry.start,\n end: entry.end,\n text: newText,\n });\n nextSelectionOffsets[entry.index] =\n entry.start + offsetDelta + newText.length;\n offsetDelta += newText.length - (entry.end - entry.start);\n }\n\n const change = textDocument.applyResolvedEdits(edits, true, selections);\n const nextSelections = createSelectionsFromOffsetPairs(\n textDocument,\n nextSelectionOffsets.map((offset) => [offset, offset])\n );\n textDocument.setLastUndoSelectionsAfter(nextSelections);\n if (change !== undefined && lineAnnotations !== undefined) {\n const nextLineAnnotations =\n applyDocumentChangeToLineAnnotations<LAnnotation>(\n change,\n lineAnnotations\n );\n if (nextLineAnnotations !== undefined) {\n textDocument.setLastUndoLineAnnotations(\n lineAnnotations,\n nextLineAnnotations\n );\n }\n }\n return { nextSelections, change };\n}\n\n/**\n * Swaps the two characters adjacent to a collapsed selection, matching browser\n * insertTranspose (Ctrl+T) behavior.\n */\nexport function applyTransposeToSelections<LAnnotation>(\n textDocument: TextDocument<LAnnotation>,\n selections: EditorSelection[],\n lineAnnotations?: DiffLineAnnotation<LAnnotation>[]\n): {\n nextSelections: EditorSelection[];\n change?: TextDocumentChange;\n} {\n const text = textDocument.getText();\n const edits: ResolvedTextEdit[] = [];\n const nextOffsetPairs: Array<[number, number]> = [];\n\n for (const selection of selections) {\n const [anchor, focus] = getSelectionAnchorAndFocusOffsets(\n textDocument,\n selection\n );\n if (!isCollapsedSelection(selection)) {\n nextOffsetPairs.push([anchor, focus]);\n continue;\n }\n\n const { line, character } = selection.start;\n const offset = anchor;\n const lineLength = textDocument.getLineText(line).length;\n let edit: ResolvedTextEdit | undefined;\n\n if (character > 0 && character < lineLength) {\n edit = {\n start: offset - 1,\n end: offset + 1,\n text: text[offset] + text[offset - 1],\n };\n nextOffsetPairs.push([offset + 1, offset + 1]);\n } else if (character === lineLength && lineLength >= 2) {\n edit = {\n start: offset - 2,\n end: offset,\n text: text[offset - 1] + text[offset - 2],\n };\n nextOffsetPairs.push([offset, offset]);\n } else if (character === 0 && line > 0 && lineLength > 0) {\n const prevLine = line - 1;\n const prevLength = textDocument.getLineText(prevLine).length;\n const prevEnd = textDocument.offsetAt({\n line: prevLine,\n character: prevLength,\n });\n const prevStart = prevLength > 0 ? prevEnd - 1 : prevEnd;\n edit = {\n start: prevStart,\n end: offset + 1,\n text:\n text[offset] +\n text.slice(prevEnd, offset) +\n text.slice(prevStart, prevEnd),\n };\n nextOffsetPairs.push([offset + 1, offset + 1]);\n } else {\n nextOffsetPairs.push([anchor, focus]);\n continue;\n }\n\n edits.push(edit);\n }\n\n if (edits.length === 0) {\n return { nextSelections: selections };\n }\n\n edits.sort((a, b) => a.start - b.start);\n for (let index = 1; index < edits.length; index++) {\n if (edits[index].start < edits[index - 1].end) {\n throw new Error('Overlapping multi-selection edits are not supported');\n }\n }\n\n const change = textDocument.applyResolvedEdits(edits, true, selections);\n const nextSelections = createSelectionsFromOffsetPairs(\n textDocument,\n nextOffsetPairs\n );\n textDocument.setLastUndoSelectionsAfter(nextSelections);\n if (change !== undefined && lineAnnotations !== undefined) {\n const nextLineAnnotations =\n applyDocumentChangeToLineAnnotations<LAnnotation>(\n change,\n lineAnnotations\n );\n if (nextLineAnnotations !== undefined) {\n textDocument.setLastUndoLineAnnotations(\n lineAnnotations,\n nextLineAnnotations\n );\n }\n }\n return { nextSelections, change };\n}\n\n/**\n * Deletes from each selection to the end of its line, including the line break\n * when the caret is already at the end of a non-final line. Non-collapsed\n * selections delete their selected text instead.\n */\nexport function applyDeleteHardLineForwardToSelections<LAnnotation>(\n textDocument: TextDocument<LAnnotation>,\n selections: EditorSelection[],\n lineAnnotations?: DiffLineAnnotation<LAnnotation>[]\n): {\n nextSelections: EditorSelection[];\n change?: TextDocumentChange;\n} {\n const deleteSelections: EditorSelection[] = selections.map((selection) => {\n const range = resolveDeleteHardLineForwardRange(textDocument, selection);\n const deleteSelection: EditorSelection = {\n start: range.start,\n end: range.end,\n direction: DirectionNone,\n };\n return deleteSelection;\n });\n const hasEffect = deleteSelections.some(\n (selection) => comparePosition(selection.start, selection.end) !== 0\n );\n if (!hasEffect) {\n return { nextSelections: selections };\n }\n return applyTextReplaceToSelections(\n textDocument,\n deleteSelections,\n deleteSelections.map(() => ''),\n lineAnnotations\n );\n}\n\n/**\n * Checks if a selection is collapsed.\n */\nexport function isCollapsedSelection(selection: EditorSelection): boolean {\n return (\n selection.start.line === selection.end.line &&\n selection.start.character === selection.end.character\n );\n}\n\n/**\n * Returns the caret (focus) position for a selection.\n */\nexport function getCaretPosition(selection: EditorSelection): Position {\n const { start, end, direction } = selection;\n return direction === DirectionBackward ? start : end;\n}\n\n/**\n * Checks if a line is editable.\n */\nexport function isLineEditable(lineType: string): boolean {\n return (\n lineType === 'context' ||\n lineType === 'change-addition' ||\n lineType === 'context-expanded'\n );\n}\n\n/**\n * Checks whether selections `a` and `b` intersect.\n */\nexport function selectionIntersects(\n a: EditorSelection,\n b: EditorSelection\n): boolean {\n const aCollapsed = isCollapsedSelection(a);\n const bCollapsed = isCollapsedSelection(b);\n if (aCollapsed && bCollapsed) {\n return comparePosition(a.start, b.start) === 0;\n }\n if (aCollapsed) {\n return (\n comparePosition(b.start, a.start) <= 0 &&\n comparePosition(a.start, b.end) <= 0\n );\n }\n if (bCollapsed) {\n return (\n comparePosition(a.start, b.start) <= 0 &&\n comparePosition(b.start, a.end) <= 0\n );\n }\n return (\n comparePosition(a.start, b.end) < 0 && comparePosition(b.start, a.end) < 0\n );\n}\n\n/**\n * Compares two positions.\n */\nexport function comparePosition(a: Position, b: Position): number {\n if (a.line !== b.line) {\n return a.line - b.line;\n }\n return a.character - b.character;\n}\n\n/**\n * Creates a selection from anchor and focus offsets.\n */\nexport function createSelectionFromAnchorAndFocusOffsets(\n textDocument: TextDocument<unknown>,\n anchorOffset: number,\n focusOffset: number\n): EditorSelection {\n const direction =\n anchorOffset === focusOffset\n ? DirectionNone\n : anchorOffset < focusOffset\n ? DirectionForward\n : DirectionBackward;\n const start = Math.min(anchorOffset, focusOffset);\n const end = Math.max(anchorOffset, focusOffset);\n return {\n start: textDocument.positionAt(start),\n end: textDocument.positionAt(end),\n direction,\n };\n}\n\n/**\n * Creates a selection from a anchor and focus selection.\n */\nexport function createSelectionFrom(\n anchorSelection: EditorSelection,\n focusSelection: EditorSelection\n): EditorSelection {\n const anchor =\n anchorSelection.direction === DirectionBackward\n ? anchorSelection.end\n : anchorSelection.start;\n const currentStartOrder = comparePosition(anchor, focusSelection.start);\n const currentEndOrder = comparePosition(anchor, focusSelection.end);\n let focus = focusSelection.end;\n if (currentStartOrder <= 0) {\n focus = focusSelection.end;\n } else if (currentEndOrder >= 0) {\n focus = focusSelection.start;\n } else {\n // When the original anchor sits inside `current`, keep whichever edge\n // stayed at the anchor so drag direction remains stable.\n focus = currentStartOrder === 0 ? focusSelection.end : focusSelection.start;\n }\n const anchorVsFocus = comparePosition(anchor, focus);\n const direction: SelectionDirection =\n anchorVsFocus === 0\n ? DirectionNone\n : anchorVsFocus < 0\n ? DirectionForward\n : DirectionBackward;\n const selectionStart = anchorVsFocus <= 0 ? anchor : focus;\n const selectionEnd = anchorVsFocus <= 0 ? focus : anchor;\n return {\n start: selectionStart,\n end: selectionEnd,\n direction,\n };\n}\n\n/**\n * Extends or shrinks the selection `original` using the endpoints of `target`, \\\n * matching contenteditable shift + click extend behavior.\n */\nexport function extendSelection(\n original: EditorSelection,\n target: EditorSelection\n): EditorSelection {\n const leftExtended = comparePosition(target.start, original.start) < 0;\n const rightExtended = comparePosition(target.end, original.end) > 0;\n\n if (leftExtended && !rightExtended) {\n return {\n start: target.start,\n end: original.end,\n direction: DirectionBackward,\n };\n }\n\n if (rightExtended && !leftExtended) {\n return {\n start: original.start,\n end: target.end,\n direction: DirectionForward,\n };\n }\n\n if (original.direction === DirectionBackward) {\n return {\n start: target.start,\n end: original.end,\n direction:\n comparePosition(target.start, original.end) === 0\n ? DirectionNone\n : DirectionBackward,\n };\n }\n\n return {\n start: original.start,\n end: target.end,\n direction:\n comparePosition(original.start, target.end) === 0\n ? DirectionNone\n : DirectionForward,\n };\n}\n\n/**\n * Extends multiple selections.\n */\nexport function extendSelections(\n selections: EditorSelection[],\n target: EditorSelection\n): EditorSelection[] {\n const newSelections = selections.map((selection) => {\n return extendSelection(selection, target);\n });\n return mergeOverlappingSelections(newSelections);\n}\n\n/**\n * Merges overlapping selections.\n */\nexport function mergeOverlappingSelections(\n selections: EditorSelection[]\n): EditorSelection[] {\n if (selections.length <= 1) {\n return selections;\n }\n const selected = new Set<number>();\n const accepted: {\n index: number;\n selection: EditorSelection;\n }[] = [];\n for (let i = selections.length - 1; i >= 0; i--) {\n const selection = selections[i];\n if (selection === undefined) {\n continue;\n }\n let left = 0;\n let right = accepted.length;\n while (left < right) {\n const mid = Math.floor((left + right) / 2);\n const candidate = accepted[mid]?.selection;\n if (candidate === undefined) {\n break;\n }\n if (comparePosition(candidate.start, selection.start) < 0) {\n left = mid + 1;\n } else {\n right = mid;\n }\n }\n const previous = accepted[left - 1]?.selection;\n const next = accepted[left]?.selection;\n if (\n (previous !== undefined && selectionIntersects(previous, selection)) ||\n (next !== undefined && selectionIntersects(next, selection))\n ) {\n continue;\n }\n accepted.splice(left, 0, { index: i, selection });\n selected.add(i);\n }\n return selections.filter((_, index) => selected.has(index));\n}\n\n/**\n * Finds the next matching word and updates the selections.\n */\nexport function findNexMatch(\n textDocument: TextDocument<unknown>,\n selections: EditorSelection[]\n): EditorSelection[] | undefined {\n if (selections.length === 0) {\n return undefined;\n }\n\n const normalizedSelections = selections.map((selection) =>\n isCollapsedSelection(selection)\n ? expandCollapsedSelectionToWord(textDocument, selection)\n : selection\n );\n const texts = normalizedSelections.map((s) => textDocument.getText(s));\n const needle = texts[0];\n if (needle.length === 0 || texts.some((t) => t !== needle)) {\n return undefined;\n }\n\n const occupied = normalizedSelections.map(\n (s) =>\n [textDocument.offsetAt(s.start), textDocument.offsetAt(s.end)] as [\n number,\n number,\n ]\n );\n const nextOffset = textDocument.findNextNonOverlappingSubstring(\n needle,\n occupied\n );\n if (nextOffset === undefined) {\n return normalizedSelections.some((selection, index) => {\n const original = selections[index];\n return (\n comparePosition(selection.start, original.start) !== 0 ||\n comparePosition(selection.end, original.end) !== 0 ||\n selection.direction !== original.direction\n );\n })\n ? normalizedSelections\n : undefined;\n }\n const added = createSelectionFromAnchorAndFocusOffsets(\n textDocument,\n nextOffset,\n nextOffset + needle.length\n );\n return [...normalizedSelections, added];\n}\n\n/**\n * Get the full selection of the document.\n */\nexport function getDocumentFullSelection(\n textDocument: TextDocument<unknown>\n): EditorSelection {\n const lastLine = textDocument.lineCount - 1;\n const lastCharacter = textDocument.getLineText(lastLine)?.length ?? 0;\n return {\n start: { line: 0, character: 0 },\n end: { line: lastLine, character: lastCharacter },\n direction: DirectionForward,\n };\n}\n\n/**\n * Get the boundary selection of the document.\n */\nexport function getDocumentBoundarySelection(\n textDocument: TextDocument<unknown>,\n atEnd: boolean\n): EditorSelection {\n const line = atEnd ? textDocument.lineCount - 1 : 0;\n const character = atEnd ? (textDocument.getLineText(line)?.length ?? 0) : 0;\n const start = { line, character };\n return {\n start: start,\n end: start,\n direction: DirectionForward,\n };\n}\n\n/**\n * Get the text of the selections for the given text document.\n */\nexport function getSelectionText(\n textDocument: TextDocument<unknown>,\n selections: EditorSelection[]\n): string {\n return [...selections]\n .sort((a, b) => {\n const startOrder = comparePosition(a.start, b.start);\n if (startOrder !== 0) {\n return startOrder;\n }\n return comparePosition(a.end, b.end);\n })\n .map((selection) => {\n if (isCollapsedSelection(selection)) {\n return textDocument.getLineText(selection.start.line, false);\n }\n return textDocument.getText(selection);\n })\n .join('\\n');\n}\n\n/**\n * Get the anchor node and offset for a selection.\n */\nexport function getSelectionAnchor(\n lineElement: HTMLElement,\n character: number\n): [Node, number] {\n const ch = Math.max(0, character);\n const tokens = collectTokens(lineElement);\n\n let last: HTMLElement | null = null;\n for (const token of tokens) {\n last = token;\n const base = getCharacterIndex(token)!;\n const end = base + (token.textContent?.length ?? 0);\n if (ch <= end) {\n const anchor = textAt(token, ch < base ? 0 : ch - base);\n if (anchor !== null) {\n return anchor;\n }\n }\n }\n\n if (last !== null) {\n const anchor = textAt(last, last.textContent?.length ?? 0);\n if (anchor !== null) {\n return anchor;\n }\n return [last, 0];\n }\n\n let textOffset = 0;\n let lastTextNode: Text | null = null;\n for (const child of lineElement.childNodes) {\n if (child.nodeType === 1 && (child as HTMLElement).tagName === 'BR') {\n return [child, 0];\n }\n if (child.nodeType !== 3) {\n continue;\n }\n lastTextNode = child as Text;\n const len = getTextOffset(\n lastTextNode.textContent,\n lastTextNode.textContent?.length ?? 0\n );\n if (ch <= textOffset + len) {\n return [\n lastTextNode,\n getTextOffset(lastTextNode.textContent, ch - textOffset),\n ];\n }\n textOffset += len;\n }\n\n if (lastTextNode !== null) {\n return [\n lastTextNode,\n getTextOffset(\n lastTextNode.textContent,\n lastTextNode.textContent?.length ?? 0\n ),\n ];\n }\n return [lineElement, 0];\n}\n\n/**\n * Expands a zero-width selection to the word-like segment that contains the caret.\n */\nexport function expandCollapsedSelectionToWord(\n textDocument: TextDocument<unknown>,\n selection: EditorSelection\n): EditorSelection {\n const { line, character } = selection.start;\n const lineText = textDocument.getLineText(line);\n const ch = Math.max(0, Math.min(character, lineText.length));\n const span = expandCollapsedLineWord(lineText, ch);\n if (span === undefined) {\n return selection;\n }\n return {\n start: { line, character: span.start },\n end: { line, character: span.end },\n direction: DirectionForward,\n };\n}\n\nfunction expandCollapsedLineWord(\n lineText: string,\n character: number\n): { start: number; end: number } | undefined {\n const segmenter = new Intl.Segmenter(undefined, {\n granularity: 'word',\n });\n for (const seg of segmenter.segment(lineText)) {\n if (seg.isWordLike !== true) {\n continue;\n }\n const lo = seg.index;\n const hi = lo + seg.segment.length;\n // Match when the cursor is inside the word or immediately touching\n // one of its boundaries — not when separated by non-word characters.\n if (character >= lo && character <= hi) {\n return { start: lo, end: hi };\n }\n }\n return undefined;\n}\n\nfunction getSelectionAnchorAndFocusOffsets(\n textDocument: TextDocument<unknown>,\n selection: EditorSelection\n): [anchorOffset: number, focusOffset: number] {\n const isBackward = selection.direction === DirectionBackward;\n return [\n textDocument.offsetAt(isBackward ? selection.end : selection.start),\n textDocument.offsetAt(getCaretPosition(selection)),\n ];\n}\n\n// Resolves the range removed by deleteHardLineForward for one selection.\nfunction resolveDeleteHardLineForwardRange(\n textDocument: TextDocument<unknown>,\n selection: EditorSelection\n): Range {\n if (!isCollapsedSelection(selection)) {\n return { start: selection.start, end: selection.end };\n }\n const { line, character } = selection.start;\n const lineText = textDocument.getLineText(line);\n const lineLength = lineText.length;\n if (character < lineLength) {\n return {\n start: { line, character },\n end: { line, character: lineLength },\n };\n }\n if (line < textDocument.lineCount - 1) {\n return {\n start: { line, character },\n end: { line: line + 1, character: 0 },\n };\n }\n return {\n start: { line, character },\n end: { line, character },\n };\n}\n\n// When the user inserts a lone line break, copy the current line's indentation onto the new line.\nfunction expandSingleNewlineInsert(\n textDocument: TextDocument<unknown>,\n insertText: string,\n insertStartOffset: number\n): string {\n if (insertText !== '\\n' && insertText !== '\\r\\n') {\n return insertText;\n }\n const line = textDocument.positionAt(insertStartOffset).line;\n const lineText = textDocument.getLineText(line);\n const indentLen = getLeadingSpaces(lineText);\n if (indentLen === 0) {\n return insertText;\n }\n return insertText + lineText.slice(0, indentLen);\n}\n\nfunction getLeadingSpaces(text: string): number {\n let indent = 0;\n for (; indent < text.length; indent++) {\n const c = text.charCodeAt(indent);\n if (c !== /* space */ 32 && c !== /* tab */ 9) {\n break;\n }\n }\n return indent;\n}\n\nfunction createSelectionsFromOffsetPairs(\n textDocument: TextDocument<unknown>,\n offsetPairs: readonly [anchorOffset: number, focusOffset: number][]\n): EditorSelection[] {\n const normalizedOffsets: number[] = [];\n for (const [anchorOffset, focusOffset] of offsetPairs) {\n normalizedOffsets.push(\n Math.min(anchorOffset, focusOffset),\n Math.max(anchorOffset, focusOffset)\n );\n }\n const positions = textDocument.positionsAt(normalizedOffsets);\n return offsetPairs.map(([anchorOffset, focusOffset], index) => {\n const direction =\n anchorOffset === focusOffset\n ? DirectionNone\n : anchorOffset < focusOffset\n ? DirectionForward\n : DirectionBackward;\n return {\n start: positions[index * 2],\n end: positions[index * 2 + 1],\n direction,\n };\n });\n}\n\n// Expands a backspace over leading spaces into one soft-tab width so mixed hard/soft indentation\n// behaves like the explicit outdent command.\nfunction normalizeLeadingIndentForChange(\n textDocument: TextDocument<unknown>,\n change: ResolvedTextEdit,\n tabSize: number\n): ResolvedTextEdit {\n if (change.text !== '' || change.start !== change.end - 1) {\n return change;\n }\n const caretPosition = textDocument.positionAt(change.end);\n if (caretPosition.character === 0) {\n return change;\n }\n const lineText = textDocument.getLineText(caretPosition.line);\n const leadingText = lineText.slice(0, caretPosition.character);\n if (/[^ \\t]/.test(leadingText)) {\n return change;\n }\n if (lineText[caretPosition.character - 1] === '\\t') {\n return change;\n }\n const softTabStart = Math.max(0, caretPosition.character - tabSize);\n const softTabText = lineText.slice(softTabStart, caretPosition.character);\n if (softTabText.length === tabSize && /^ +$/.test(softTabText)) {\n return {\n ...change,\n start: change.end - softTabText.length,\n };\n }\n return change;\n}\n\nfunction boundaryToPosition(node: Node, offset: number): Position | null {\n const host = node.nodeType === 1 ? (node as HTMLElement) : node.parentElement;\n let lineEl: HTMLElement | null = host;\n while (lineEl !== null && getLineIndex(lineEl) === undefined) {\n lineEl = lineEl.parentElement;\n }\n if (lineEl === null) {\n return null;\n }\n const line = getLineIndex(lineEl);\n if (line === undefined) {\n return null;\n }\n\n if (node.nodeType === 3) {\n if (node.parentElement === null) {\n return null;\n }\n if (findTokenSpan(node.parentElement) !== null) {\n return { line, character: getLineChildEnd(node, offset) };\n }\n return {\n line,\n character:\n offsetBefore(lineEl, node) + getTextOffset(node.textContent, offset),\n };\n }\n\n if (node.nodeType === 1) {\n const el = node as HTMLElement;\n if (el.tagName === 'DIV') {\n let character = 0;\n for (let i = 0; i < offset; i++) {\n character = getLineChildEnd(el.childNodes[i]);\n }\n return { line, character };\n }\n if (el.tagName === 'BR') {\n return { line, character: 0 };\n }\n if (el.tagName === 'SPAN') {\n if (offset < el.childNodes.length) {\n const next = el.childNodes[offset];\n if (next?.nodeType === 1) {\n const nextBase = getCharacterIndex(next as HTMLElement);\n if (nextBase !== undefined) {\n return { line, character: nextBase };\n }\n const token = findTokenSpan(next as HTMLElement);\n const tokenBase =\n token === null ? undefined : getCharacterIndex(token);\n if (tokenBase !== undefined) {\n return { line, character: tokenBase };\n }\n }\n }\n return {\n line,\n character:\n offset > 0\n ? getLineChildEnd(el.childNodes[offset - 1])\n : offsetBefore(lineEl, el),\n };\n }\n return { line, character: offsetBefore(lineEl, el) };\n }\n return null;\n}\n\nfunction collectTokens(line: HTMLElement): HTMLElement[] {\n const tokens: HTMLElement[] = [];\n for (const child of line.childNodes) {\n if (child.nodeType !== 1) {\n continue;\n }\n const el = child as HTMLElement;\n if (el.tagName !== 'SPAN') {\n continue;\n }\n const base = getCharacterIndex(el);\n if (base !== undefined) {\n tokens.push(el);\n continue;\n }\n for (const nested of el.childNodes) {\n if (\n nested.nodeType === 1 &&\n getCharacterIndex(nested as HTMLElement) !== undefined\n ) {\n tokens.push(nested as HTMLElement);\n }\n }\n }\n return tokens;\n}\n\nfunction textAt(token: HTMLElement, offset: number): [Node, number] | null {\n let remaining = Math.max(0, offset);\n const stack: Array<{ container: Node; index: number }> = [\n { container: token, index: 0 },\n ];\n while (stack.length > 0) {\n const frame = stack[stack.length - 1];\n if (frame.index >= frame.container.childNodes.length) {\n stack.pop();\n continue;\n }\n const walkNode = frame.container.childNodes[frame.index];\n frame.index++;\n if (walkNode.nodeType === 3) {\n const len = getTextOffset(\n walkNode.textContent,\n walkNode.textContent?.length ?? 0\n );\n if (remaining <= len) {\n return [walkNode, remaining];\n }\n remaining -= len;\n } else if (walkNode.nodeType === 1) {\n stack.push({ container: walkNode, index: 0 });\n }\n }\n return null;\n}\n\nfunction textLengthBefore(root: Node, target: Node): number {\n let before = 0;\n const stack: Array<{ container: Node; index: number }> = [\n { container: root, index: 0 },\n ];\n while (stack.length > 0) {\n const frame = stack[stack.length - 1];\n if (frame.index >= frame.container.childNodes.length) {\n stack.pop();\n continue;\n }\n const walkNode = frame.container.childNodes[frame.index];\n if (walkNode === target) {\n return before;\n }\n frame.index++;\n if (walkNode.nodeType === 3) {\n before += getTextOffset(\n walkNode.textContent,\n walkNode.textContent?.length ?? 0\n );\n } else if (walkNode.nodeType === 1) {\n stack.push({ container: walkNode, index: 0 });\n }\n }\n return before;\n}\n\nfunction isInside(token: HTMLElement, node: Node): boolean {\n let current: Node | null = node;\n while (current !== null) {\n if (current === token) {\n return true;\n }\n current = current.parentElement;\n }\n return false;\n}\n\nfunction offsetBefore(line: HTMLElement, node: Node): number {\n if (node.parentElement === line) {\n let offset = 0;\n const index = Array.prototype.indexOf.call(line.childNodes, node);\n for (let i = 0; i < index; i++) {\n offset = getLineChildEnd(line.childNodes[i]);\n }\n return offset;\n }\n for (const token of collectTokens(line)) {\n if (isInside(token, node)) {\n const base = getCharacterIndex(token)!;\n return base + (node.nodeType === 3 ? textLengthBefore(token, node) : 0);\n }\n }\n let offset = 0;\n let target: HTMLElement | null =\n node.nodeType === 1 ? (node as HTMLElement) : node.parentElement;\n while (target !== null && target.parentElement !== null) {\n if (getLineIndex(target.parentElement) !== undefined) {\n break;\n }\n const parent = target.parentElement;\n const index = Array.prototype.indexOf.call(parent.childNodes, target);\n for (let i = 0; i < index; i++) {\n offset = getLineChildEnd(parent.childNodes[i]);\n }\n target = parent;\n }\n return offset;\n}\n\nfunction findTokenSpan(el: HTMLElement): HTMLElement | null {\n let current: HTMLElement | null = el;\n while (current !== null) {\n if (getLineIndex(current) !== undefined) {\n return null;\n }\n if (getCharacterIndex(current) !== undefined) {\n return current;\n }\n current = current.parentElement;\n }\n return null;\n}\n\nfunction getLineChildEnd(\n child: Node | undefined,\n textOffsetInChild?: number\n): number {\n if (child === undefined) {\n return 0;\n }\n if (child.nodeType === 3) {\n const parent = child.parentElement;\n if (parent === null) {\n return 0;\n }\n const token = findTokenSpan(parent);\n if (token === null) {\n return 0;\n }\n const base = getCharacterIndex(token);\n if (base === undefined) {\n return 0;\n }\n const length =\n textOffsetInChild === undefined\n ? getTextOffset(child.textContent, child.textContent?.length ?? 0)\n : getTextOffset(child.textContent, textOffsetInChild);\n return base + textLengthBefore(token, child) + length;\n }\n if (child.nodeType !== 1) {\n return 0;\n }\n const el = child as HTMLElement;\n if (el.tagName !== 'SPAN' && el.tagName !== 'BR') {\n return 0;\n }\n const base = getCharacterIndex(el);\n if (base !== undefined) {\n return base + (el.textContent?.length ?? 0);\n }\n let end = 0;\n for (const token of el.childNodes) {\n end = Math.max(end, getLineChildEnd(token));\n }\n return end;\n}\n\nfunction getLineIndex(el: HTMLElement): number | undefined {\n const { line } = el.dataset;\n if (line !== undefined) {\n return parseInt(line) - 1;\n }\n return undefined;\n}\n\nfunction getCharacterIndex(el: HTMLElement): number | undefined {\n const { char } = el.dataset;\n return char !== undefined ? parseInt(char) : undefined;\n}\n\nfunction getTextOffset(\n text: string | null | undefined,\n offset: number\n): number {\n const value = text ?? '';\n const lineBreakIndex = value.search(/[\\r\\n]/);\n return Math.min(\n offset,\n lineBreakIndex === -1 ? value.length : lineBreakIndex\n );\n}\n"],"mappings":";;;AAWA,MAAa,oBAAoB;AACjC,MAAa,gBAAgB;AAC7B,MAAa,mBAAmB;;;;AAchC,SAAgB,iBACd,OACA,YAAgC,eACH;CAC7B,MAAM,QAAQ,mBAAmB,MAAM,gBAAgB,MAAM,YAAY;CACzE,MAAM,MAAM,mBAAmB,MAAM,cAAc,MAAM,UAAU;AACnE,KAAI,UAAU,QAAQ,QAAQ,KAC5B;AAEF,QAAO;EACL;EACA;EACA;EACD;;;;;AAMH,SAAgB,mBACd,cACA,WACA,SACA,SACqD;AACrD,KAAI,iBAAiB,OACnB,QAAO,CAAC,EAAE,EAAE,UAAU;CAExB,MAAM,EAAE,OAAO,QAAQ;CACvB,MAAMA,QAAoB,EAAE;CAC5B,IAAIC,eAAgC,EAAE,GAAG,WAAW;CACpD,IAAI,UAAU,IAAI;AAClB,KAAI,MAAM,OAAO,IAAI,QAAQ,IAAI,cAAc,EAC7C;AAEF,MAAK,IAAI,OAAO,MAAM,MAAM,QAAQ,SAAS,QAAQ;EACnD,MAAM,WAAW,aAAa,YAAY,KAAK;AAC/C,MAAI,aAAa,OACf;EAEF,MAAM,aAAa,SAAS,WAAW,IAAK,GAAG,MAAO,IAAI,OAAO,QAAQ;EACzE,IAAI,eAAe;EACnB,IAAI,UAAU;AACd,MAAI,SAAS;AACX,OAAI,SAAS,WAAW,IAAK,CAC3B,gBAAe;YACN,SAAS,WAAW,IAAI,EAAE;IACnC,MAAM,sBACJ,SAAS,SAAS,SAAS,WAAW,CAAC;AACzC,mBAAe,KAAK,IAAI,WAAW,QAAQ,oBAAoB;;AAEjE,OAAI,iBAAiB,EACnB;AAEF,aAAU;;AAEZ,QAAM,KAAK;GACT,OAAO;IACL,OAAO;KAAE;KAAM,WAAW;KAAG;IAC7B,KAAK;KAAE;KAAM,WAAW;KAAc;IACvC;GACD;GACD,CAAC;EACF,MAAM,QAAQ,QAAQ,SAAS;AAC/B,MAAI,SAAS,MAAM,KACjB,gBAAe;GACb,GAAG;GACH,OAAO;IACL,GAAG;IACH,WAAW,KAAK,IAAI,GAAG,MAAM,YAAY,MAAM;IAChD;GACF;AAEH,MAAI,SAAS,IAAI,KACf,gBAAe;GACb,GAAG;GACH,KAAK;IACH,GAAG;IACH,WAAW,KAAK,IAAI,GAAG,IAAI,YAAY,MAAM;IAC9C;GACF;;AAGL,QAAO,CAAC,OAAO,aAAa;;;;;AAM9B,SAAgB,cACd,cACA,YACA,UACmB;CACnB,MAAM,YAAY,aAAa;AAC/B,QAAO,WAAW,KAAK,cAAc;EACnC,IAAI,EAAE,MAAM,cACV,aAAa,QAAQ,aAAa,SAC9B,UAAU,QACV,UAAU;AAChB,MACE,aAAa,eACb,aAAa,WACb,aAAa,OACb;AACA,OAAI,aAAa,aAAa;IAC5B,MAAM,SAAS,iBAAiB,aAAa,YAAY,KAAK,CAAC;AAC/D,gBAAY,cAAc,SAAS,IAAI;SAEvC,aACE,aAAa,UAAU,IAAI,aAAa,YAAY,KAAK,CAAC;AAE9D,OAAI,UAAU,cAAc,kBAC1B,QAAO,UAAU,MAAM;OAEvB,QAAO,UAAU,IAAI;aAEd,aAAa,KACtB,QAAO,KAAK,IAAI,GAAG,OAAO,EAAE;WACnB,aAAa,OACtB,QAAO,KAAK,IAAI,KAAK,IAAI,YAAY,GAAG,EAAE,EAAE,OAAO,EAAE;WAC5C,qBAAqB,UAAU,CACxC,KAAI,aAAa,QAAQ;AACvB;AAEA,OAAI,YAAY,EACd,KAAI,SAAS,EACX,aAAY;QACP;AACL,WAAO,KAAK,IAAI,GAAG,OAAO,EAAE;AAC5B,gBAAY,aAAa,YAAY,KAAK,CAAC;;SAG1C;AACL;AACA,OAAI,YAAY,aAAa,YAAY,KAAK,CAAC,OAC7C,KAAI,SAAS,YAAY,EACvB;QACK;AACL,WAAO,KAAK,IAAI,KAAK,IAAI,YAAY,GAAG,EAAE,EAAE,OAAO,EAAE;AACrD,gBAAY;;;EAKpB,MAAM,MAAM;GAAE;GAAM;GAAW;AAC/B,SAAO;GACL,OAAO;GACP,KAAK;GACL,WAAW;GACZ;GACD;;;;;AAMJ,SAAgB,kBACd,cACA,YACA,UACmB;AACnB,QAAO,WAAW,KAAK,cAAc;EACnC,MAAM,CAAC,cAAc,eAAe,kCAClC,cACA,UACD;EACD,MAAM,gBAAgB,aAAa,WAAW,YAAY;EAC1D,MAAM,CAAC,uBAAuB,cAC5B,cACA,CACE;GACE,OAAO;GACP,KAAK;GACL,WAAW;GACZ,CACF,EACD,SACD;AAED,SAAO,yCACL,cACA,cAHuB,aAAa,SAAS,oBAAoB,MAAM,CAKxE;GACD;;;;;AAMJ,SAAgB,4BACd,cACA,YACA,MACA,iBACA,UAAU,GAIV;AAEA,KADyB,WAAW,WAAW,SAAS,OAC/B,OACvB,QAAO,EAAE,gBAAgB,EAAE,EAAE;CAE/B,MAAMC,qBAAiC,EAAE;AACzC,MAAK,MAAM,aAAa,WACtB,oBAAmB,KAAK,UAAU,OAAO,UAAU,IAAI;CAEzD,MAAM,mBAAmB,aAAa,UAAU,mBAAmB;CACnE,MAAM,qBAAqB,kBAAkB,WAAW,SAAS,KAAK;CACtE,MAAM,mBAAmB,kBAAkB,WAAW,SAAS,KAAK,IAAI;CACxE,MAAMC,UAID,EAAE;CACP,IAAI,mBAAmB;AACvB,MAAK,IAAI,QAAQ,GAAG,QAAQ,WAAW,QAAQ,SAAS;EACtD,MAAM,QAAQ;GACZ;GACA,OAAO,iBAAiB,QAAQ;GAChC,KAAK,iBAAiB,QAAQ,IAAI;GACnC;EACD,MAAM,WAAW,QAAQ,QAAQ,SAAS;AAC1C,MACE,aAAa,WACZ,MAAM,QAAQ,SAAS,SACrB,MAAM,UAAU,SAAS,SAAS,MAAM,MAAM,SAAS,KAE1D,oBAAmB;AAErB,UAAQ,KAAK,MAAM;;AAErB,KAAI,CAAC,iBACH,SAAQ,MAAM,GAAG,MAAM;EACrB,MAAM,aAAa,EAAE,QAAQ,EAAE;AAC/B,MAAI,eAAe,EACjB,QAAO;EAET,MAAM,WAAW,EAAE,MAAM,EAAE;AAC3B,MAAI,aAAa,EACf,QAAO;AAET,SAAO,EAAE,QAAQ,EAAE;GACnB;CAEJ,MAAM,iBAAiB,gCACrB,cACA,MACA,QACD;CACD,MAAMC,QAA4B,EAAE;CACpC,MAAMC,uBAA4D,MAAM,KAAK,EAC3E,QAAQ,WAAW,QACpB,CAAC;CACF,IAAI,cAAc;CAClB,IAAIC;CAOJ,MAAM,4BAA4B;AAChC,MAAI,gBAAgB,OAClB;EAEF,MAAM,iBAAiB,gCACrB,cACA;GACE,OAAO,YAAY;GACnB,KAAK,YAAY;GACjB,MAAM,eAAe;GACtB,EACD,QACD;EACD,MAAM,UAAU,0BACd,cACA,eAAe,MACf,eAAe,MAChB;AACD,QAAM,KAAK;GACT,OAAO,eAAe;GACtB,KAAK,eAAe;GACpB,MAAM;GACP,CAAC;EACF,MAAMC,cAAgC,CACpC,YAAY,QAAQ,cAAc,QAAQ,QAC1C,YAAY,QAAQ,cAAc,QAAQ,OAC3C;AACD,OAAK,MAAM,SAAS,YAAY,QAC9B,sBAAqB,SAAS;AAEhC,iBAAe,QAAQ,UAAU,eAAe,MAAM,eAAe;AACrE,gBAAc;;AAEhB,MAAK,MAAM,SAAS,SAAS;EAC3B,MAAM,cAAc,KAAK,IACvB,GACA,MAAM,SAAS,eAAe,QAAQ,oBACvC;EACD,MAAM,YAAY,KAAK,IACrB,aACA,MAAM,OAAO,eAAe,MAAM,kBACnC;AACD,MAAI,gBAAgB,UAAa,cAAc,YAAY,KAAK;AAC9D,eAAY,MAAM,KAAK,IAAI,YAAY,KAAK,UAAU;AACtD,eAAY,QAAQ,KAAK,MAAM,MAAM;AACrC;;AAEF,uBAAqB;AACrB,gBAAc;GACZ,OAAO;GACP,KAAK;GACL,SAAS,CAAC,MAAM,MAAM;GACvB;;AAEH,sBAAqB;CAErB,MAAM,SAAS,aAAa,mBAAmB,OAAO,MAAM,WAAW;CACvE,MAAM,iBAAiB,gCACrB,cACA,qBAAqB,KAAK,YAAY;AACpC,MAAI,YAAY,OACd,OAAM,IAAI,MAAM,iCAAiC;AAEnD,SAAO;GACP,CACH;AACD,cAAa,2BAA2B,eAAe;AACvD,KAAI,WAAW,UAAa,oBAAoB,QAAW;EACzD,MAAM,sBACJ,qCACE,QACA,gBACD;AACH,MAAI,wBAAwB,OAC1B,cAAa,2BACX,iBACA,oBACD;;AAGL,QAAO;EAAE;EAAgB;EAAQ;;;;;AAMnC,SAAgB,6BACd,cACA,YACA,OACA,iBAIA;AACA,KAAI,WAAW,WAAW,MAAM,OAC9B,OAAM,IAAI,MACR,6DACD;CAEH,MAAML,qBAAiC,EAAE;AACzC,MAAK,MAAM,aAAa,WACtB,oBAAmB,KAAK,UAAU,OAAO,UAAU,IAAI;CAEzD,MAAM,mBAAmB,aAAa,UAAU,mBAAmB;CACnE,MAAMM,UAKD,EAAE;CACP,IAAI,mBAAmB;AACvB,MAAK,IAAI,QAAQ,GAAG,QAAQ,WAAW,QAAQ,SAAS;EACtD,MAAM,QAAQ;GACZ;GACA,OAAO,iBAAiB,QAAQ;GAChC,KAAK,iBAAiB,QAAQ,IAAI;GAClC,MAAM,MAAM;GACb;EACD,MAAM,WAAW,QAAQ,QAAQ,SAAS;AAC1C,MACE,aAAa,WACZ,MAAM,QAAQ,SAAS,SACrB,MAAM,UAAU,SAAS,SAAS,MAAM,MAAM,SAAS,KAE1D,oBAAmB;AAErB,UAAQ,KAAK,MAAM;;AAErB,KAAI,CAAC,iBACH,SAAQ,MAAM,GAAG,MAAM;EACrB,MAAM,aAAa,EAAE,QAAQ,EAAE;AAC/B,MAAI,eAAe,EACjB,QAAO;EAET,MAAM,WAAW,EAAE,MAAM,EAAE;AAC3B,MAAI,aAAa,EACf,QAAO;AAET,SAAO,EAAE,QAAQ,EAAE;GACnB;CAEJ,MAAMJ,QAA4B,EAAE;CACpC,MAAMK,uBAAiC,MAAM,KAAK,EAChD,QAAQ,WAAW,QACpB,CAAC;CACF,IAAI,cAAc;CAClB,IAAI,kBAAkB;AACtB,MAAK,MAAM,SAAS,SAAS;AAC3B,MAAI,MAAM,QAAQ,gBAChB,OAAM,IAAI,MAAM,sDAAsD;AAExE,oBAAkB,MAAM;EACxB,MAAM,UAAU,0BACd,cACA,MAAM,MACN,MAAM,MACP;AACD,QAAM,KAAK;GACT,OAAO,MAAM;GACb,KAAK,MAAM;GACX,MAAM;GACP,CAAC;AACF,uBAAqB,MAAM,SACzB,MAAM,QAAQ,cAAc,QAAQ;AACtC,iBAAe,QAAQ,UAAU,MAAM,MAAM,MAAM;;CAGrD,MAAM,SAAS,aAAa,mBAAmB,OAAO,MAAM,WAAW;CACvE,MAAM,iBAAiB,gCACrB,cACA,qBAAqB,KAAK,WAAW,CAAC,QAAQ,OAAO,CAAC,CACvD;AACD,cAAa,2BAA2B,eAAe;AACvD,KAAI,WAAW,UAAa,oBAAoB,QAAW;EACzD,MAAM,sBACJ,qCACE,QACA,gBACD;AACH,MAAI,wBAAwB,OAC1B,cAAa,2BACX,iBACA,oBACD;;AAGL,QAAO;EAAE;EAAgB;EAAQ;;;;;;AAOnC,SAAgB,2BACd,cACA,YACA,iBAIA;CACA,MAAM,OAAO,aAAa,SAAS;CACnC,MAAML,QAA4B,EAAE;CACpC,MAAMM,kBAA2C,EAAE;AAEnD,MAAK,MAAM,aAAa,YAAY;EAClC,MAAM,CAAC,QAAQ,SAAS,kCACtB,cACA,UACD;AACD,MAAI,CAAC,qBAAqB,UAAU,EAAE;AACpC,mBAAgB,KAAK,CAAC,QAAQ,MAAM,CAAC;AACrC;;EAGF,MAAM,EAAE,MAAM,cAAc,UAAU;EACtC,MAAM,SAAS;EACf,MAAM,aAAa,aAAa,YAAY,KAAK,CAAC;EAClD,IAAIC;AAEJ,MAAI,YAAY,KAAK,YAAY,YAAY;AAC3C,UAAO;IACL,OAAO,SAAS;IAChB,KAAK,SAAS;IACd,MAAM,KAAK,UAAU,KAAK,SAAS;IACpC;AACD,mBAAgB,KAAK,CAAC,SAAS,GAAG,SAAS,EAAE,CAAC;aACrC,cAAc,cAAc,cAAc,GAAG;AACtD,UAAO;IACL,OAAO,SAAS;IAChB,KAAK;IACL,MAAM,KAAK,SAAS,KAAK,KAAK,SAAS;IACxC;AACD,mBAAgB,KAAK,CAAC,QAAQ,OAAO,CAAC;aAC7B,cAAc,KAAK,OAAO,KAAK,aAAa,GAAG;GACxD,MAAM,WAAW,OAAO;GACxB,MAAM,aAAa,aAAa,YAAY,SAAS,CAAC;GACtD,MAAM,UAAU,aAAa,SAAS;IACpC,MAAM;IACN,WAAW;IACZ,CAAC;GACF,MAAM,YAAY,aAAa,IAAI,UAAU,IAAI;AACjD,UAAO;IACL,OAAO;IACP,KAAK,SAAS;IACd,MACE,KAAK,UACL,KAAK,MAAM,SAAS,OAAO,GAC3B,KAAK,MAAM,WAAW,QAAQ;IACjC;AACD,mBAAgB,KAAK,CAAC,SAAS,GAAG,SAAS,EAAE,CAAC;SACzC;AACL,mBAAgB,KAAK,CAAC,QAAQ,MAAM,CAAC;AACrC;;AAGF,QAAM,KAAK,KAAK;;AAGlB,KAAI,MAAM,WAAW,EACnB,QAAO,EAAE,gBAAgB,YAAY;AAGvC,OAAM,MAAM,GAAG,MAAM,EAAE,QAAQ,EAAE,MAAM;AACvC,MAAK,IAAI,QAAQ,GAAG,QAAQ,MAAM,QAAQ,QACxC,KAAI,MAAM,OAAO,QAAQ,MAAM,QAAQ,GAAG,IACxC,OAAM,IAAI,MAAM,sDAAsD;CAI1E,MAAM,SAAS,aAAa,mBAAmB,OAAO,MAAM,WAAW;CACvE,MAAM,iBAAiB,gCACrB,cACA,gBACD;AACD,cAAa,2BAA2B,eAAe;AACvD,KAAI,WAAW,UAAa,oBAAoB,QAAW;EACzD,MAAM,sBACJ,qCACE,QACA,gBACD;AACH,MAAI,wBAAwB,OAC1B,cAAa,2BACX,iBACA,oBACD;;AAGL,QAAO;EAAE;EAAgB;EAAQ;;;;;;;AAQnC,SAAgB,uCACd,cACA,YACA,iBAIA;CACA,MAAMC,mBAAsC,WAAW,KAAK,cAAc;EACxE,MAAM,QAAQ,kCAAkC,cAAc,UAAU;AAMxE,SALyC;GACvC,OAAO,MAAM;GACb,KAAK,MAAM;GACX,WAAW;GACZ;GAED;AAIF,KAAI,CAHc,iBAAiB,MAChC,cAAc,gBAAgB,UAAU,OAAO,UAAU,IAAI,KAAK,EACpE,CAEC,QAAO,EAAE,gBAAgB,YAAY;AAEvC,QAAO,6BACL,cACA,kBACA,iBAAiB,UAAU,GAAG,EAC9B,gBACD;;;;;AAMH,SAAgB,qBAAqB,WAAqC;AACxE,QACE,UAAU,MAAM,SAAS,UAAU,IAAI,QACvC,UAAU,MAAM,cAAc,UAAU,IAAI;;;;;AAOhD,SAAgB,iBAAiB,WAAsC;CACrE,MAAM,EAAE,OAAO,KAAK,cAAc;AAClC,QAAO,cAAc,oBAAoB,QAAQ;;;;;AAMnD,SAAgB,eAAe,UAA2B;AACxD,QACE,aAAa,aACb,aAAa,qBACb,aAAa;;;;;AAOjB,SAAgB,oBACd,GACA,GACS;CACT,MAAM,aAAa,qBAAqB,EAAE;CAC1C,MAAM,aAAa,qBAAqB,EAAE;AAC1C,KAAI,cAAc,WAChB,QAAO,gBAAgB,EAAE,OAAO,EAAE,MAAM,KAAK;AAE/C,KAAI,WACF,QACE,gBAAgB,EAAE,OAAO,EAAE,MAAM,IAAI,KACrC,gBAAgB,EAAE,OAAO,EAAE,IAAI,IAAI;AAGvC,KAAI,WACF,QACE,gBAAgB,EAAE,OAAO,EAAE,MAAM,IAAI,KACrC,gBAAgB,EAAE,OAAO,EAAE,IAAI,IAAI;AAGvC,QACE,gBAAgB,EAAE,OAAO,EAAE,IAAI,GAAG,KAAK,gBAAgB,EAAE,OAAO,EAAE,IAAI,GAAG;;;;;AAO7E,SAAgB,gBAAgB,GAAa,GAAqB;AAChE,KAAI,EAAE,SAAS,EAAE,KACf,QAAO,EAAE,OAAO,EAAE;AAEpB,QAAO,EAAE,YAAY,EAAE;;;;;AAMzB,SAAgB,yCACd,cACA,cACA,aACiB;CACjB,MAAM,YACJ,iBAAiB,cACb,gBACA,eAAe,cACb,mBACA;CACR,MAAM,QAAQ,KAAK,IAAI,cAAc,YAAY;CACjD,MAAM,MAAM,KAAK,IAAI,cAAc,YAAY;AAC/C,QAAO;EACL,OAAO,aAAa,WAAW,MAAM;EACrC,KAAK,aAAa,WAAW,IAAI;EACjC;EACD;;;;;AAMH,SAAgB,oBACd,iBACA,gBACiB;CACjB,MAAM,SACJ,gBAAgB,cAAc,oBAC1B,gBAAgB,MAChB,gBAAgB;CACtB,MAAM,oBAAoB,gBAAgB,QAAQ,eAAe,MAAM;CACvE,MAAM,kBAAkB,gBAAgB,QAAQ,eAAe,IAAI;CACnE,IAAI,QAAQ,eAAe;AAC3B,KAAI,qBAAqB,EACvB,SAAQ,eAAe;UACd,mBAAmB,EAC5B,SAAQ,eAAe;KAIvB,SAAQ,sBAAsB,IAAI,eAAe,MAAM,eAAe;CAExE,MAAM,gBAAgB,gBAAgB,QAAQ,MAAM;AASpD,QAAO;EACL,OAHqB,iBAAiB,IAAI,SAAS;EAInD,KAHmB,iBAAiB,IAAI,QAAQ;EAIhD,WAVA,kBAAkB,IACd,gBACA,gBAAgB,IACd,mBACA;EAOP;;;;;;AAOH,SAAgB,gBACd,UACA,QACiB;CACjB,MAAM,eAAe,gBAAgB,OAAO,OAAO,SAAS,MAAM,GAAG;CACrE,MAAM,gBAAgB,gBAAgB,OAAO,KAAK,SAAS,IAAI,GAAG;AAElE,KAAI,gBAAgB,CAAC,cACnB,QAAO;EACL,OAAO,OAAO;EACd,KAAK,SAAS;EACd,WAAW;EACZ;AAGH,KAAI,iBAAiB,CAAC,aACpB,QAAO;EACL,OAAO,SAAS;EAChB,KAAK,OAAO;EACZ,WAAW;EACZ;AAGH,KAAI,SAAS,cAAc,kBACzB,QAAO;EACL,OAAO,OAAO;EACd,KAAK,SAAS;EACd,WACE,gBAAgB,OAAO,OAAO,SAAS,IAAI,KAAK,IAC5C,gBACA;EACP;AAGH,QAAO;EACL,OAAO,SAAS;EAChB,KAAK,OAAO;EACZ,WACE,gBAAgB,SAAS,OAAO,OAAO,IAAI,KAAK,IAC5C,gBACA;EACP;;;;;AAMH,SAAgB,iBACd,YACA,QACmB;AAInB,QAAO,2BAHe,WAAW,KAAK,cAAc;AAClD,SAAO,gBAAgB,WAAW,OAAO;GACzC,CAC8C;;;;;AAMlD,SAAgB,2BACd,YACmB;AACnB,KAAI,WAAW,UAAU,EACvB,QAAO;CAET,MAAM,2BAAW,IAAI,KAAa;CAClC,MAAMC,WAGA,EAAE;AACR,MAAK,IAAI,IAAI,WAAW,SAAS,GAAG,KAAK,GAAG,KAAK;EAC/C,MAAM,YAAY,WAAW;AAC7B,MAAI,cAAc,OAChB;EAEF,IAAI,OAAO;EACX,IAAI,QAAQ,SAAS;AACrB,SAAO,OAAO,OAAO;GACnB,MAAM,MAAM,KAAK,OAAO,OAAO,SAAS,EAAE;GAC1C,MAAM,YAAY,SAAS,MAAM;AACjC,OAAI,cAAc,OAChB;AAEF,OAAI,gBAAgB,UAAU,OAAO,UAAU,MAAM,GAAG,EACtD,QAAO,MAAM;OAEb,SAAQ;;EAGZ,MAAM,WAAW,SAAS,OAAO,IAAI;EACrC,MAAM,OAAO,SAAS,OAAO;AAC7B,MACG,aAAa,UAAa,oBAAoB,UAAU,UAAU,IAClE,SAAS,UAAa,oBAAoB,MAAM,UAAU,CAE3D;AAEF,WAAS,OAAO,MAAM,GAAG;GAAE,OAAO;GAAG;GAAW,CAAC;AACjD,WAAS,IAAI,EAAE;;AAEjB,QAAO,WAAW,QAAQ,GAAG,UAAU,SAAS,IAAI,MAAM,CAAC;;;;;AAM7D,SAAgB,aACd,cACA,YAC+B;AAC/B,KAAI,WAAW,WAAW,EACxB;CAGF,MAAM,uBAAuB,WAAW,KAAK,cAC3C,qBAAqB,UAAU,GAC3B,+BAA+B,cAAc,UAAU,GACvD,UACL;CACD,MAAM,QAAQ,qBAAqB,KAAK,MAAM,aAAa,QAAQ,EAAE,CAAC;CACtE,MAAM,SAAS,MAAM;AACrB,KAAI,OAAO,WAAW,KAAK,MAAM,MAAM,MAAM,MAAM,OAAO,CACxD;CAGF,MAAM,WAAW,qBAAqB,KACnC,MACC,CAAC,aAAa,SAAS,EAAE,MAAM,EAAE,aAAa,SAAS,EAAE,IAAI,CAAC,CAIjE;CACD,MAAM,aAAa,aAAa,gCAC9B,QACA,SACD;AACD,KAAI,eAAe,OACjB,QAAO,qBAAqB,MAAM,WAAW,UAAU;EACrD,MAAM,WAAW,WAAW;AAC5B,SACE,gBAAgB,UAAU,OAAO,SAAS,MAAM,KAAK,KACrD,gBAAgB,UAAU,KAAK,SAAS,IAAI,KAAK,KACjD,UAAU,cAAc,SAAS;GAEnC,GACE,uBACA;CAEN,MAAM,QAAQ,yCACZ,cACA,YACA,aAAa,OAAO,OACrB;AACD,QAAO,CAAC,GAAG,sBAAsB,MAAM;;;;;AAMzC,SAAgB,yBACd,cACiB;CACjB,MAAM,WAAW,aAAa,YAAY;AAE1C,QAAO;EACL,OAAO;GAAE,MAAM;GAAG,WAAW;GAAG;EAChC,KAAK;GAAE,MAAM;GAAU,WAHH,aAAa,YAAY,SAAS,EAAE,UAAU;GAGjB;EACjD,WAAW;EACZ;;;;;AAMH,SAAgB,6BACd,cACA,OACiB;CACjB,MAAM,OAAO,QAAQ,aAAa,YAAY,IAAI;CAElD,MAAM,QAAQ;EAAE;EAAM,WADJ,QAAS,aAAa,YAAY,KAAK,EAAE,UAAU,IAAK;EACzC;AACjC,QAAO;EACE;EACP,KAAK;EACL,WAAW;EACZ;;;;;AAMH,SAAgB,iBACd,cACA,YACQ;AACR,QAAO,CAAC,GAAG,WAAW,CACnB,MAAM,GAAG,MAAM;EACd,MAAM,aAAa,gBAAgB,EAAE,OAAO,EAAE,MAAM;AACpD,MAAI,eAAe,EACjB,QAAO;AAET,SAAO,gBAAgB,EAAE,KAAK,EAAE,IAAI;GACpC,CACD,KAAK,cAAc;AAClB,MAAI,qBAAqB,UAAU,CACjC,QAAO,aAAa,YAAY,UAAU,MAAM,MAAM,MAAM;AAE9D,SAAO,aAAa,QAAQ,UAAU;GACtC,CACD,KAAK,KAAK;;;;;AAMf,SAAgB,mBACd,aACA,WACgB;CAChB,MAAM,KAAK,KAAK,IAAI,GAAG,UAAU;CACjC,MAAM,SAAS,cAAc,YAAY;CAEzC,IAAIC,OAA2B;AAC/B,MAAK,MAAM,SAAS,QAAQ;AAC1B,SAAO;EACP,MAAM,OAAO,kBAAkB,MAAM;AAErC,MAAI,MADQ,QAAQ,MAAM,aAAa,UAAU,IAClC;GACb,MAAM,SAAS,OAAO,OAAO,KAAK,OAAO,IAAI,KAAK,KAAK;AACvD,OAAI,WAAW,KACb,QAAO;;;AAKb,KAAI,SAAS,MAAM;EACjB,MAAM,SAAS,OAAO,MAAM,KAAK,aAAa,UAAU,EAAE;AAC1D,MAAI,WAAW,KACb,QAAO;AAET,SAAO,CAAC,MAAM,EAAE;;CAGlB,IAAI,aAAa;CACjB,IAAIC,eAA4B;AAChC,MAAK,MAAM,SAAS,YAAY,YAAY;AAC1C,MAAI,MAAM,aAAa,KAAM,MAAsB,YAAY,KAC7D,QAAO,CAAC,OAAO,EAAE;AAEnB,MAAI,MAAM,aAAa,EACrB;AAEF,iBAAe;EACf,MAAM,MAAM,cACV,aAAa,aACb,aAAa,aAAa,UAAU,EACrC;AACD,MAAI,MAAM,aAAa,IACrB,QAAO,CACL,cACA,cAAc,aAAa,aAAa,KAAK,WAAW,CACzD;AAEH,gBAAc;;AAGhB,KAAI,iBAAiB,KACnB,QAAO,CACL,cACA,cACE,aAAa,aACb,aAAa,aAAa,UAAU,EACrC,CACF;AAEH,QAAO,CAAC,aAAa,EAAE;;;;;AAMzB,SAAgB,+BACd,cACA,WACiB;CACjB,MAAM,EAAE,MAAM,cAAc,UAAU;CACtC,MAAM,WAAW,aAAa,YAAY,KAAK;CAE/C,MAAM,OAAO,wBAAwB,UAD1B,KAAK,IAAI,GAAG,KAAK,IAAI,WAAW,SAAS,OAAO,CAAC,CACV;AAClD,KAAI,SAAS,OACX,QAAO;AAET,QAAO;EACL,OAAO;GAAE;GAAM,WAAW,KAAK;GAAO;EACtC,KAAK;GAAE;GAAM,WAAW,KAAK;GAAK;EAClC,WAAW;EACZ;;AAGH,SAAS,wBACP,UACA,WAC4C;CAC5C,MAAM,YAAY,IAAI,KAAK,UAAU,QAAW,EAC9C,aAAa,QACd,CAAC;AACF,MAAK,MAAM,OAAO,UAAU,QAAQ,SAAS,EAAE;AAC7C,MAAI,IAAI,eAAe,KACrB;EAEF,MAAM,KAAK,IAAI;EACf,MAAM,KAAK,KAAK,IAAI,QAAQ;AAG5B,MAAI,aAAa,MAAM,aAAa,GAClC,QAAO;GAAE,OAAO;GAAI,KAAK;GAAI;;;AAMnC,SAAS,kCACP,cACA,WAC6C;CAC7C,MAAM,aAAa,UAAU,cAAc;AAC3C,QAAO,CACL,aAAa,SAAS,aAAa,UAAU,MAAM,UAAU,MAAM,EACnE,aAAa,SAAS,iBAAiB,UAAU,CAAC,CACnD;;AAIH,SAAS,kCACP,cACA,WACO;AACP,KAAI,CAAC,qBAAqB,UAAU,CAClC,QAAO;EAAE,OAAO,UAAU;EAAO,KAAK,UAAU;EAAK;CAEvD,MAAM,EAAE,MAAM,cAAc,UAAU;CAEtC,MAAM,aADW,aAAa,YAAY,KAAK,CACnB;AAC5B,KAAI,YAAY,WACd,QAAO;EACL,OAAO;GAAE;GAAM;GAAW;EAC1B,KAAK;GAAE;GAAM,WAAW;GAAY;EACrC;AAEH,KAAI,OAAO,aAAa,YAAY,EAClC,QAAO;EACL,OAAO;GAAE;GAAM;GAAW;EAC1B,KAAK;GAAE,MAAM,OAAO;GAAG,WAAW;GAAG;EACtC;AAEH,QAAO;EACL,OAAO;GAAE;GAAM;GAAW;EAC1B,KAAK;GAAE;GAAM;GAAW;EACzB;;AAIH,SAAS,0BACP,cACA,YACA,mBACQ;AACR,KAAI,eAAe,QAAQ,eAAe,OACxC,QAAO;CAET,MAAM,OAAO,aAAa,WAAW,kBAAkB,CAAC;CACxD,MAAM,WAAW,aAAa,YAAY,KAAK;CAC/C,MAAM,YAAY,iBAAiB,SAAS;AAC5C,KAAI,cAAc,EAChB,QAAO;AAET,QAAO,aAAa,SAAS,MAAM,GAAG,UAAU;;AAGlD,SAAS,iBAAiB,MAAsB;CAC9C,IAAI,SAAS;AACb,QAAO,SAAS,KAAK,QAAQ,UAAU;EACrC,MAAM,IAAI,KAAK,WAAW,OAAO;AACjC,MAAI,MAAkB,MAAM,MAAgB,EAC1C;;AAGJ,QAAO;;AAGT,SAAS,gCACP,cACA,aACmB;CACnB,MAAMC,oBAA8B,EAAE;AACtC,MAAK,MAAM,CAAC,cAAc,gBAAgB,YACxC,mBAAkB,KAChB,KAAK,IAAI,cAAc,YAAY,EACnC,KAAK,IAAI,cAAc,YAAY,CACpC;CAEH,MAAM,YAAY,aAAa,YAAY,kBAAkB;AAC7D,QAAO,YAAY,KAAK,CAAC,cAAc,cAAc,UAAU;EAC7D,MAAM,YACJ,iBAAiB,cACb,gBACA,eAAe,cACb,mBACA;AACR,SAAO;GACL,OAAO,UAAU,QAAQ;GACzB,KAAK,UAAU,QAAQ,IAAI;GAC3B;GACD;GACD;;AAKJ,SAAS,gCACP,cACA,QACA,SACkB;AAClB,KAAI,OAAO,SAAS,MAAM,OAAO,UAAU,OAAO,MAAM,EACtD,QAAO;CAET,MAAM,gBAAgB,aAAa,WAAW,OAAO,IAAI;AACzD,KAAI,cAAc,cAAc,EAC9B,QAAO;CAET,MAAM,WAAW,aAAa,YAAY,cAAc,KAAK;CAC7D,MAAM,cAAc,SAAS,MAAM,GAAG,cAAc,UAAU;AAC9D,KAAI,SAAS,KAAK,YAAY,CAC5B,QAAO;AAET,KAAI,SAAS,cAAc,YAAY,OAAO,IAC5C,QAAO;CAET,MAAM,eAAe,KAAK,IAAI,GAAG,cAAc,YAAY,QAAQ;CACnE,MAAM,cAAc,SAAS,MAAM,cAAc,cAAc,UAAU;AACzE,KAAI,YAAY,WAAW,WAAW,OAAO,KAAK,YAAY,CAC5D,QAAO;EACL,GAAG;EACH,OAAO,OAAO,MAAM,YAAY;EACjC;AAEH,QAAO;;AAGT,SAAS,mBAAmB,MAAY,QAAiC;CAEvE,IAAIC,SADS,KAAK,aAAa,IAAK,OAAuB,KAAK;AAEhE,QAAO,WAAW,QAAQ,aAAa,OAAO,KAAK,OACjD,UAAS,OAAO;AAElB,KAAI,WAAW,KACb,QAAO;CAET,MAAM,OAAO,aAAa,OAAO;AACjC,KAAI,SAAS,OACX,QAAO;AAGT,KAAI,KAAK,aAAa,GAAG;AACvB,MAAI,KAAK,kBAAkB,KACzB,QAAO;AAET,MAAI,cAAc,KAAK,cAAc,KAAK,KACxC,QAAO;GAAE;GAAM,WAAW,gBAAgB,MAAM,OAAO;GAAE;AAE3D,SAAO;GACL;GACA,WACE,aAAa,QAAQ,KAAK,GAAG,cAAc,KAAK,aAAa,OAAO;GACvE;;AAGH,KAAI,KAAK,aAAa,GAAG;EACvB,MAAM,KAAK;AACX,MAAI,GAAG,YAAY,OAAO;GACxB,IAAI,YAAY;AAChB,QAAK,IAAI,IAAI,GAAG,IAAI,QAAQ,IAC1B,aAAY,gBAAgB,GAAG,WAAW,GAAG;AAE/C,UAAO;IAAE;IAAM;IAAW;;AAE5B,MAAI,GAAG,YAAY,KACjB,QAAO;GAAE;GAAM,WAAW;GAAG;AAE/B,MAAI,GAAG,YAAY,QAAQ;AACzB,OAAI,SAAS,GAAG,WAAW,QAAQ;IACjC,MAAM,OAAO,GAAG,WAAW;AAC3B,QAAI,MAAM,aAAa,GAAG;KACxB,MAAM,WAAW,kBAAkB,KAAoB;AACvD,SAAI,aAAa,OACf,QAAO;MAAE;MAAM,WAAW;MAAU;KAEtC,MAAM,QAAQ,cAAc,KAAoB;KAChD,MAAM,YACJ,UAAU,OAAO,SAAY,kBAAkB,MAAM;AACvD,SAAI,cAAc,OAChB,QAAO;MAAE;MAAM,WAAW;MAAW;;;AAI3C,UAAO;IACL;IACA,WACE,SAAS,IACL,gBAAgB,GAAG,WAAW,SAAS,GAAG,GAC1C,aAAa,QAAQ,GAAG;IAC/B;;AAEH,SAAO;GAAE;GAAM,WAAW,aAAa,QAAQ,GAAG;GAAE;;AAEtD,QAAO;;AAGT,SAAS,cAAc,MAAkC;CACvD,MAAMC,SAAwB,EAAE;AAChC,MAAK,MAAM,SAAS,KAAK,YAAY;AACnC,MAAI,MAAM,aAAa,EACrB;EAEF,MAAM,KAAK;AACX,MAAI,GAAG,YAAY,OACjB;AAGF,MADa,kBAAkB,GAAG,KACrB,QAAW;AACtB,UAAO,KAAK,GAAG;AACf;;AAEF,OAAK,MAAM,UAAU,GAAG,WACtB,KACE,OAAO,aAAa,KACpB,kBAAkB,OAAsB,KAAK,OAE7C,QAAO,KAAK,OAAsB;;AAIxC,QAAO;;AAGT,SAAS,OAAO,OAAoB,QAAuC;CACzE,IAAI,YAAY,KAAK,IAAI,GAAG,OAAO;CACnC,MAAMC,QAAmD,CACvD;EAAE,WAAW;EAAO,OAAO;EAAG,CAC/B;AACD,QAAO,MAAM,SAAS,GAAG;EACvB,MAAM,QAAQ,MAAM,MAAM,SAAS;AACnC,MAAI,MAAM,SAAS,MAAM,UAAU,WAAW,QAAQ;AACpD,SAAM,KAAK;AACX;;EAEF,MAAM,WAAW,MAAM,UAAU,WAAW,MAAM;AAClD,QAAM;AACN,MAAI,SAAS,aAAa,GAAG;GAC3B,MAAM,MAAM,cACV,SAAS,aACT,SAAS,aAAa,UAAU,EACjC;AACD,OAAI,aAAa,IACf,QAAO,CAAC,UAAU,UAAU;AAE9B,gBAAa;aACJ,SAAS,aAAa,EAC/B,OAAM,KAAK;GAAE,WAAW;GAAU,OAAO;GAAG,CAAC;;AAGjD,QAAO;;AAGT,SAAS,iBAAiB,MAAY,QAAsB;CAC1D,IAAI,SAAS;CACb,MAAMA,QAAmD,CACvD;EAAE,WAAW;EAAM,OAAO;EAAG,CAC9B;AACD,QAAO,MAAM,SAAS,GAAG;EACvB,MAAM,QAAQ,MAAM,MAAM,SAAS;AACnC,MAAI,MAAM,SAAS,MAAM,UAAU,WAAW,QAAQ;AACpD,SAAM,KAAK;AACX;;EAEF,MAAM,WAAW,MAAM,UAAU,WAAW,MAAM;AAClD,MAAI,aAAa,OACf,QAAO;AAET,QAAM;AACN,MAAI,SAAS,aAAa,EACxB,WAAU,cACR,SAAS,aACT,SAAS,aAAa,UAAU,EACjC;WACQ,SAAS,aAAa,EAC/B,OAAM,KAAK;GAAE,WAAW;GAAU,OAAO;GAAG,CAAC;;AAGjD,QAAO;;AAGT,SAAS,SAAS,OAAoB,MAAqB;CACzD,IAAIC,UAAuB;AAC3B,QAAO,YAAY,MAAM;AACvB,MAAI,YAAY,MACd,QAAO;AAET,YAAU,QAAQ;;AAEpB,QAAO;;AAGT,SAAS,aAAa,MAAmB,MAAoB;AAC3D,KAAI,KAAK,kBAAkB,MAAM;EAC/B,IAAIC,WAAS;EACb,MAAM,QAAQ,MAAM,UAAU,QAAQ,KAAK,KAAK,YAAY,KAAK;AACjE,OAAK,IAAI,IAAI,GAAG,IAAI,OAAO,IACzB,YAAS,gBAAgB,KAAK,WAAW,GAAG;AAE9C,SAAOA;;AAET,MAAK,MAAM,SAAS,cAAc,KAAK,CACrC,KAAI,SAAS,OAAO,KAAK,CAEvB,QADa,kBAAkB,MAAM,IACtB,KAAK,aAAa,IAAI,iBAAiB,OAAO,KAAK,GAAG;CAGzE,IAAI,SAAS;CACb,IAAIC,SACF,KAAK,aAAa,IAAK,OAAuB,KAAK;AACrD,QAAO,WAAW,QAAQ,OAAO,kBAAkB,MAAM;AACvD,MAAI,aAAa,OAAO,cAAc,KAAK,OACzC;EAEF,MAAM,SAAS,OAAO;EACtB,MAAM,QAAQ,MAAM,UAAU,QAAQ,KAAK,OAAO,YAAY,OAAO;AACrE,OAAK,IAAI,IAAI,GAAG,IAAI,OAAO,IACzB,UAAS,gBAAgB,OAAO,WAAW,GAAG;AAEhD,WAAS;;AAEX,QAAO;;AAGT,SAAS,cAAc,IAAqC;CAC1D,IAAIC,UAA8B;AAClC,QAAO,YAAY,MAAM;AACvB,MAAI,aAAa,QAAQ,KAAK,OAC5B,QAAO;AAET,MAAI,kBAAkB,QAAQ,KAAK,OACjC,QAAO;AAET,YAAU,QAAQ;;AAEpB,QAAO;;AAGT,SAAS,gBACP,OACA,mBACQ;AACR,KAAI,UAAU,OACZ,QAAO;AAET,KAAI,MAAM,aAAa,GAAG;EACxB,MAAM,SAAS,MAAM;AACrB,MAAI,WAAW,KACb,QAAO;EAET,MAAM,QAAQ,cAAc,OAAO;AACnC,MAAI,UAAU,KACZ,QAAO;EAET,MAAMC,SAAO,kBAAkB,MAAM;AACrC,MAAIA,WAAS,OACX,QAAO;EAET,MAAM,SACJ,sBAAsB,SAClB,cAAc,MAAM,aAAa,MAAM,aAAa,UAAU,EAAE,GAChE,cAAc,MAAM,aAAa,kBAAkB;AACzD,SAAOA,SAAO,iBAAiB,OAAO,MAAM,GAAG;;AAEjD,KAAI,MAAM,aAAa,EACrB,QAAO;CAET,MAAM,KAAK;AACX,KAAI,GAAG,YAAY,UAAU,GAAG,YAAY,KAC1C,QAAO;CAET,MAAM,OAAO,kBAAkB,GAAG;AAClC,KAAI,SAAS,OACX,QAAO,QAAQ,GAAG,aAAa,UAAU;CAE3C,IAAI,MAAM;AACV,MAAK,MAAM,SAAS,GAAG,WACrB,OAAM,KAAK,IAAI,KAAK,gBAAgB,MAAM,CAAC;AAE7C,QAAO;;AAGT,SAAS,aAAa,IAAqC;CACzD,MAAM,EAAE,SAAS,GAAG;AACpB,KAAI,SAAS,OACX,QAAO,SAAS,KAAK,GAAG;;AAK5B,SAAS,kBAAkB,IAAqC;CAC9D,MAAM,EAAE,SAAS,GAAG;AACpB,QAAO,SAAS,SAAY,SAAS,KAAK,GAAG;;AAG/C,SAAS,cACP,MACA,QACQ;CACR,MAAM,QAAQ,QAAQ;CACtB,MAAM,iBAAiB,MAAM,OAAO,SAAS;AAC7C,QAAO,KAAK,IACV,QACA,mBAAmB,KAAK,MAAM,SAAS,eACxC"}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import { DiffLineAnnotation } from "../types.js";
|
|
2
|
+
import { EditStack } from "./editStack.js";
|
|
3
|
+
import { SearchParams } from "./searchPanel.js";
|
|
4
|
+
import { EditorSelection } from "./selection.js";
|
|
5
|
+
|
|
6
|
+
//#region src/editor/textDocument.d.ts
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Position in a text document expressed as zero-based line and character offset.
|
|
10
|
+
* The offsets are based on a UTF-16 string representation. So a string of the form
|
|
11
|
+
* `a𐐀b` the character offset of the character `a` is 0, the character offset of `𐐀`
|
|
12
|
+
* is 1 and the character offset of b is 3 since `𐐀` is represented using two code
|
|
13
|
+
* units in UTF-16.
|
|
14
|
+
*
|
|
15
|
+
* Positions are line end character agnostic. So you can not specify a position that
|
|
16
|
+
* denotes `\r|\n` or `\n|` where `|` represents the character offset.
|
|
17
|
+
*/
|
|
18
|
+
interface Position {
|
|
19
|
+
/**
|
|
20
|
+
* Line position in a document (zero-based).
|
|
21
|
+
*
|
|
22
|
+
* If a line number is greater than the number of lines in a document, it
|
|
23
|
+
* defaults back to the number of lines in the document.
|
|
24
|
+
* If a line number is negative, it defaults to 0.
|
|
25
|
+
*
|
|
26
|
+
* The above two properties are implementation specific.
|
|
27
|
+
*/
|
|
28
|
+
readonly line: number;
|
|
29
|
+
/**
|
|
30
|
+
* Character offset on a line in a document (zero-based).
|
|
31
|
+
*
|
|
32
|
+
* The meaning of this offset is determined by the negotiated
|
|
33
|
+
* `PositionEncodingKind`.
|
|
34
|
+
*
|
|
35
|
+
* If the character value is greater than the line length it defaults back
|
|
36
|
+
* to the line length. This property is implementation specific.
|
|
37
|
+
*/
|
|
38
|
+
readonly character: number;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* A range in a text document expressed as (zero-based) start and end positions.
|
|
42
|
+
*
|
|
43
|
+
* If you want to specify a range that contains a line including the line ending
|
|
44
|
+
* character(s) then use an end position denoting the start of the next line.
|
|
45
|
+
* For example:
|
|
46
|
+
* ```ts
|
|
47
|
+
* {
|
|
48
|
+
* start: { line: 5, character: 23 }
|
|
49
|
+
* end : { line 6, character : 0 }
|
|
50
|
+
* }
|
|
51
|
+
* ```
|
|
52
|
+
*/
|
|
53
|
+
interface Range {
|
|
54
|
+
/**
|
|
55
|
+
* The range's start position.
|
|
56
|
+
*/
|
|
57
|
+
readonly start: Position;
|
|
58
|
+
/**
|
|
59
|
+
* The range's end position.
|
|
60
|
+
*/
|
|
61
|
+
readonly end: Position;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* A text edit applicable to a text document.
|
|
65
|
+
*/
|
|
66
|
+
interface TextEdit {
|
|
67
|
+
/**
|
|
68
|
+
* The range of the text document to be manipulated. To insert
|
|
69
|
+
* text into a document create a range where start === end.
|
|
70
|
+
*/
|
|
71
|
+
readonly range: Range;
|
|
72
|
+
/**
|
|
73
|
+
* The string to be inserted. For delete operations use an
|
|
74
|
+
* empty string.
|
|
75
|
+
*/
|
|
76
|
+
readonly newText: string;
|
|
77
|
+
}
|
|
78
|
+
/** Different with `TextEdit`, the range has been resolved to offsets. */
|
|
79
|
+
interface ResolvedTextEdit {
|
|
80
|
+
/** The start offset of the text change. */
|
|
81
|
+
readonly start: number;
|
|
82
|
+
/** The end offset of the text change. */
|
|
83
|
+
readonly end: number;
|
|
84
|
+
/**
|
|
85
|
+
* The string to be inserted. For delete operations use an
|
|
86
|
+
* empty string.
|
|
87
|
+
*/
|
|
88
|
+
readonly text: string;
|
|
89
|
+
}
|
|
90
|
+
interface TextDocumentChange {
|
|
91
|
+
/** First line whose rendered content or tokenizer state may have changed. */
|
|
92
|
+
readonly startLine: number;
|
|
93
|
+
/** Character on the first changed line where the edit began. */
|
|
94
|
+
readonly startCharacter: number;
|
|
95
|
+
/** Last line whose rendered content may have changed after the edit. */
|
|
96
|
+
readonly endLine: number;
|
|
97
|
+
/** Line count before the edit was applied. */
|
|
98
|
+
readonly previousLineCount: number;
|
|
99
|
+
/** Line count after the edit was applied. */
|
|
100
|
+
readonly lineCount: number;
|
|
101
|
+
/** Difference between the old and new line counts. */
|
|
102
|
+
readonly lineDelta: number;
|
|
103
|
+
/** Exact rendered line ranges touched by each edit after the edit was applied. */
|
|
104
|
+
readonly changedLineRanges?: readonly [startLine: number, endLine: number][];
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* A vscode-languageserver-textdocument compatible text document.
|
|
108
|
+
*/
|
|
109
|
+
declare class TextDocument<LAnnotation> {
|
|
110
|
+
#private;
|
|
111
|
+
constructor(uri: string, text: string, languageId?: string, version?: number, editStack?: EditStack<LAnnotation>);
|
|
112
|
+
get uri(): string;
|
|
113
|
+
get languageId(): string;
|
|
114
|
+
get version(): number;
|
|
115
|
+
get lineCount(): number;
|
|
116
|
+
get canUndo(): boolean;
|
|
117
|
+
get canRedo(): boolean;
|
|
118
|
+
positionAt(offset: number): Position;
|
|
119
|
+
positionsAt(offsets: readonly number[]): Position[];
|
|
120
|
+
offsetAt(position: Position): number;
|
|
121
|
+
offsetsAt(positions: readonly Position[]): number[];
|
|
122
|
+
getText(range?: Range): string;
|
|
123
|
+
getLineText(line: number, trimEOF?: boolean): string;
|
|
124
|
+
charAt(offset: number): string;
|
|
125
|
+
charAt(position: Position): string;
|
|
126
|
+
getTextSlice(start: number, end: number): string;
|
|
127
|
+
findNextNonOverlappingSubstring(needle: string, occupied: readonly [start: number, end: number][]): number | undefined;
|
|
128
|
+
search(kind: 'findNext' | 'findPrevious' | 'findAll' | 'replace' | 'replaceAll', searchParams: SearchParams, selection?: Range): [start: number, end: number][];
|
|
129
|
+
applyEdits(edits: TextEdit[], updateHistory?: boolean, selectionsBefore?: EditorSelection[], selectionsAfter?: EditorSelection[]): TextDocumentChange | undefined;
|
|
130
|
+
applyResolvedEdits(edits: ResolvedTextEdit[], updateHistory?: boolean, selectionsBefore?: EditorSelection[], selectionsAfter?: EditorSelection[]): TextDocumentChange | undefined;
|
|
131
|
+
setLastUndoSelectionsAfter(selections: EditorSelection[]): void;
|
|
132
|
+
setLastUndoLineAnnotations(lineAnnotationsBefore: DiffLineAnnotation<LAnnotation>[], lineAnnotationsAfter: DiffLineAnnotation<LAnnotation>[]): void;
|
|
133
|
+
undo(): [change: TextDocumentChange, selections?: EditorSelection[], lineAnnotations?: DiffLineAnnotation<LAnnotation>[]] | undefined;
|
|
134
|
+
redo(): [change: TextDocumentChange, selections?: EditorSelection[], lineAnnotations?: DiffLineAnnotation<LAnnotation>[]] | undefined;
|
|
135
|
+
normalizePosition(position: Position): Position;
|
|
136
|
+
}
|
|
137
|
+
//#endregion
|
|
138
|
+
export { Position, Range, ResolvedTextEdit, TextDocument, TextDocumentChange, TextEdit };
|
|
139
|
+
//# sourceMappingURL=textDocument.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"textDocument.d.ts","names":["DiffLineAnnotation","EditStack","SearchParams","EditorSelection","Position","Range","TextEdit","ResolvedTextEdit","TextDocumentChange","TextDocument","LAnnotation"],"sources":["../../src/editor/textDocument.d.ts"],"sourcesContent":["import type { DiffLineAnnotation } from '../types';\nimport { EditStack } from './editStack';\nimport type { SearchParams } from './searchPanel';\nimport { type EditorSelection } from './selection';\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 * 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 * 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/** 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}\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}\n/**\n * A vscode-languageserver-textdocument compatible text document.\n */\nexport declare class TextDocument<LAnnotation> {\n #private;\n constructor(uri: string, text: string, languageId?: string, version?: number, editStack?: EditStack<LAnnotation>);\n get uri(): string;\n get languageId(): string;\n get version(): number;\n get lineCount(): number;\n get canUndo(): boolean;\n get canRedo(): boolean;\n positionAt(offset: number): Position;\n positionsAt(offsets: readonly number[]): Position[];\n offsetAt(position: Position): number;\n offsetsAt(positions: readonly Position[]): number[];\n getText(range?: Range): string;\n getLineText(line: number, trimEOF?: boolean): string;\n charAt(offset: number): string;\n charAt(position: Position): string;\n getTextSlice(start: number, end: number): string;\n findNextNonOverlappingSubstring(needle: string, occupied: readonly [start: number, end: number][]): number | undefined;\n search(kind: 'findNext' | 'findPrevious' | 'findAll' | 'replace' | 'replaceAll', searchParams: SearchParams, selection?: Range): [start: number, end: number][];\n applyEdits(edits: TextEdit[], updateHistory?: boolean, selectionsBefore?: EditorSelection[], selectionsAfter?: EditorSelection[]): TextDocumentChange | undefined;\n applyResolvedEdits(edits: ResolvedTextEdit[], updateHistory?: boolean, selectionsBefore?: EditorSelection[], selectionsAfter?: EditorSelection[]): TextDocumentChange | undefined;\n setLastUndoSelectionsAfter(selections: EditorSelection[]): void;\n setLastUndoLineAnnotations(lineAnnotationsBefore: DiffLineAnnotation<LAnnotation>[], lineAnnotationsAfter: DiffLineAnnotation<LAnnotation>[]): void;\n undo(): [\n change: TextDocumentChange,\n selections?: EditorSelection[],\n lineAnnotations?: DiffLineAnnotation<LAnnotation>[]\n ] | undefined;\n redo(): [\n change: TextDocumentChange,\n selections?: EditorSelection[],\n lineAnnotations?: DiffLineAnnotation<LAnnotation>[]\n ] | undefined;\n normalizePosition(position: Position): Position;\n}\n//# sourceMappingURL=textDocument.d.ts.map"],"mappings":";;;;;;;;;AAcA;AAmCA;AAaA;AAaA;AAWA;AAmBA;;;AASgCI,UApGfA,QAAAA,CAoGeA;EACaA;;;;;;;;;EAUsED,SAAAA,IAAAA,EAAAA,MAAAA;EAAoBK;;;;;;;;;EAGxBR,SAAAA,SAAAA,EAAAA,MAAAA;;;;;;;;;;;;;;;UA/E9FK,KAAAA;;;;kBAIGD;;;;gBAIFA;;;;;UAKDE,QAAAA;;;;;kBAKGD;;;;;;;;UAQHE,gBAAAA;;;;;;;;;;;UAWAC,kBAAAA;;;;;;;;;;;;;;;;;;;cAmBIC;;4FAEyER,UAAUS;;;;;;;8BAOxEN;2CACaA;qBACtBA;gCACWA;kBACdC;;;mBAGCD;;;iGAG8EF,0BAA0BG;oBACvGC,wDAAwDH,qCAAqCA,oBAAoBK;4BACzGD,gEAAgEJ,qCAAqCA,oBAAoBK;yCAC5GL;oDACWH,mBAAmBU,sCAAsCV,mBAAmBU;mBAElHF,iCACKL,qCACKH,mBAAmBU;mBAG7BF,iCACKL,qCACKH,mBAAmBU;8BAEbN,WAAWA"}
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
import { EditStack, coalesceEditStackEntries, createEditStackEntry, shouldCoalesceEditStackEntry } from "./editStack.js";
|
|
2
|
+
import { PieceTable } from "./pieceTable.js";
|
|
3
|
+
|
|
4
|
+
//#region src/editor/textDocument.ts
|
|
5
|
+
/**
|
|
6
|
+
* A vscode-languageserver-textdocument compatible text document.
|
|
7
|
+
*/
|
|
8
|
+
var TextDocument = class {
|
|
9
|
+
#uri;
|
|
10
|
+
#languageId;
|
|
11
|
+
#version;
|
|
12
|
+
#pieceTable;
|
|
13
|
+
#editStack;
|
|
14
|
+
constructor(uri, text, languageId = "plaintext", version = 0, editStack = new EditStack()) {
|
|
15
|
+
this.#uri = new URL(uri, "file://").toString();
|
|
16
|
+
this.#languageId = languageId;
|
|
17
|
+
this.#version = version;
|
|
18
|
+
this.#pieceTable = new PieceTable(text);
|
|
19
|
+
this.#editStack = editStack;
|
|
20
|
+
}
|
|
21
|
+
get uri() {
|
|
22
|
+
return this.#uri;
|
|
23
|
+
}
|
|
24
|
+
get languageId() {
|
|
25
|
+
return this.#languageId;
|
|
26
|
+
}
|
|
27
|
+
get version() {
|
|
28
|
+
return this.#version;
|
|
29
|
+
}
|
|
30
|
+
get lineCount() {
|
|
31
|
+
return this.#pieceTable.lineCount;
|
|
32
|
+
}
|
|
33
|
+
get canUndo() {
|
|
34
|
+
return this.#editStack.canUndo;
|
|
35
|
+
}
|
|
36
|
+
get canRedo() {
|
|
37
|
+
return this.#editStack.canRedo;
|
|
38
|
+
}
|
|
39
|
+
positionAt(offset) {
|
|
40
|
+
return this.#pieceTable.positionAt(offset);
|
|
41
|
+
}
|
|
42
|
+
positionsAt(offsets) {
|
|
43
|
+
return this.#pieceTable.positionsAt(offsets);
|
|
44
|
+
}
|
|
45
|
+
offsetAt(position) {
|
|
46
|
+
return this.#pieceTable.offsetAt(position);
|
|
47
|
+
}
|
|
48
|
+
offsetsAt(positions) {
|
|
49
|
+
return this.#pieceTable.offsetsAt(positions);
|
|
50
|
+
}
|
|
51
|
+
getText(range) {
|
|
52
|
+
return this.#pieceTable.getText(range);
|
|
53
|
+
}
|
|
54
|
+
getLineText(line, trimEOF = true) {
|
|
55
|
+
return this.#pieceTable.getLineText(line, trimEOF);
|
|
56
|
+
}
|
|
57
|
+
charAt(positionOrOffset) {
|
|
58
|
+
if (typeof positionOrOffset === "number") return this.#pieceTable.charAt(positionOrOffset);
|
|
59
|
+
return this.#pieceTable.charAt(this.offsetAt(positionOrOffset));
|
|
60
|
+
}
|
|
61
|
+
getTextSlice(start, end) {
|
|
62
|
+
return this.#pieceTable.getTextSlice(start, end);
|
|
63
|
+
}
|
|
64
|
+
findNextNonOverlappingSubstring(needle, occupied) {
|
|
65
|
+
return this.#pieceTable.findNextNonOverlappingSubstring(needle, occupied);
|
|
66
|
+
}
|
|
67
|
+
search(kind, searchParams, selection) {
|
|
68
|
+
return this.#pieceTable.search(kind, searchParams, selection);
|
|
69
|
+
}
|
|
70
|
+
applyEdits(edits, updateHistory = false, selectionsBefore, selectionsAfter) {
|
|
71
|
+
if (edits.length === 0) return;
|
|
72
|
+
return this.applyResolvedEdits(edits.map((edit) => this.#resolveEdit(edit)), updateHistory, selectionsBefore, selectionsAfter);
|
|
73
|
+
}
|
|
74
|
+
applyResolvedEdits(edits, updateHistory = false, selectionsBefore, selectionsAfter) {
|
|
75
|
+
if (edits.length === 0) return;
|
|
76
|
+
const resolvedEdits = this.#sortAndValidateResolvedEdits(edits);
|
|
77
|
+
if (updateHistory) {
|
|
78
|
+
const entry = createEditStackEntry(this, resolvedEdits, this.#version, this.#version + 1, selectionsBefore, selectionsAfter);
|
|
79
|
+
const previousEntry = this.#editStack.peekUndo();
|
|
80
|
+
const change$1 = this.#applyResolvedEditsToBuffer(resolvedEdits);
|
|
81
|
+
this.#version++;
|
|
82
|
+
if (change$1.lineDelta === 0 && shouldCoalesceEditStackEntry(previousEntry, entry)) this.#editStack.replaceLastUndo(coalesceEditStackEntries(previousEntry, entry));
|
|
83
|
+
else this.#editStack.push(entry);
|
|
84
|
+
return change$1;
|
|
85
|
+
}
|
|
86
|
+
const change = this.#applyResolvedEditsToBuffer(resolvedEdits);
|
|
87
|
+
this.#version++;
|
|
88
|
+
return change;
|
|
89
|
+
}
|
|
90
|
+
setLastUndoSelectionsAfter(selections) {
|
|
91
|
+
this.#editStack.setLastUndoSelectionsAfter(selections);
|
|
92
|
+
}
|
|
93
|
+
setLastUndoLineAnnotations(lineAnnotationsBefore, lineAnnotationsAfter) {
|
|
94
|
+
this.#editStack.setLastUndoLineAnnotations(lineAnnotationsBefore, lineAnnotationsAfter);
|
|
95
|
+
}
|
|
96
|
+
undo() {
|
|
97
|
+
const entry = this.#editStack.popUndoToRedo();
|
|
98
|
+
if (entry === void 0) return;
|
|
99
|
+
const change = this.#applyResolvedEditsToBuffer(entry.inverseEdits);
|
|
100
|
+
if (change === void 0) return;
|
|
101
|
+
this.#version = entry.versionBefore;
|
|
102
|
+
return [
|
|
103
|
+
change,
|
|
104
|
+
entry.selectionsBefore?.slice(),
|
|
105
|
+
entry.lineAnnotationsBefore?.slice()
|
|
106
|
+
];
|
|
107
|
+
}
|
|
108
|
+
redo() {
|
|
109
|
+
const entry = this.#editStack.popRedoToUndo();
|
|
110
|
+
if (entry === void 0) return;
|
|
111
|
+
const change = this.#applyResolvedEditsToBuffer(entry.forwardEdits);
|
|
112
|
+
if (change === void 0) return;
|
|
113
|
+
this.#version = entry.versionAfter;
|
|
114
|
+
return [
|
|
115
|
+
change,
|
|
116
|
+
entry.selectionsAfter?.slice(),
|
|
117
|
+
entry.lineAnnotationsAfter?.slice()
|
|
118
|
+
];
|
|
119
|
+
}
|
|
120
|
+
normalizePosition(position) {
|
|
121
|
+
const line = Math.max(0, Math.min(position.line, this.lineCount - 1));
|
|
122
|
+
return {
|
|
123
|
+
line,
|
|
124
|
+
character: Math.max(0, Math.min(position.character, this.getLineText(line).length))
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
#resolveEdit(edit) {
|
|
128
|
+
let start = this.offsetAt(edit.range.start);
|
|
129
|
+
let end = this.offsetAt(edit.range.end);
|
|
130
|
+
if (start > end) {
|
|
131
|
+
const t = start;
|
|
132
|
+
start = end;
|
|
133
|
+
end = t;
|
|
134
|
+
}
|
|
135
|
+
return {
|
|
136
|
+
start,
|
|
137
|
+
end,
|
|
138
|
+
text: edit.newText
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
#sortAndValidateResolvedEdits(edits) {
|
|
142
|
+
const sortedEdits = [...edits].sort((a, b) => a.start - b.start);
|
|
143
|
+
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");
|
|
144
|
+
return sortedEdits;
|
|
145
|
+
}
|
|
146
|
+
#applyResolvedEditsToBuffer(edits) {
|
|
147
|
+
const previousLineCount = this.#pieceTable.lineCount;
|
|
148
|
+
const editPositions = this.positionsAt(edits.flatMap((edit) => [edit.start, edit.end]));
|
|
149
|
+
const changedLineRange = this.#computeChangedLineRange(edits, editPositions);
|
|
150
|
+
const startPosition = editPositions[0];
|
|
151
|
+
this.#pieceTable.applyEdits(edits);
|
|
152
|
+
const lineCount = this.#pieceTable.lineCount;
|
|
153
|
+
return {
|
|
154
|
+
startLine: changedLineRange.startLine,
|
|
155
|
+
startCharacter: startPosition.character,
|
|
156
|
+
endLine: Math.min(changedLineRange.endLine, Math.max(0, lineCount - 1)),
|
|
157
|
+
previousLineCount,
|
|
158
|
+
lineCount,
|
|
159
|
+
lineDelta: lineCount - previousLineCount,
|
|
160
|
+
changedLineRanges: changedLineRange.ranges
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
#computeChangedLineRange(edits, editPositions) {
|
|
164
|
+
let startLine = Infinity;
|
|
165
|
+
let endLine = 0;
|
|
166
|
+
let lineDeltaBeforeEdit = 0;
|
|
167
|
+
const ranges = [];
|
|
168
|
+
for (let i = 0; i < edits.length; i++) {
|
|
169
|
+
const edit = edits[i];
|
|
170
|
+
const editStartLine = editPositions[i * 2].line;
|
|
171
|
+
const editEndLine = editPositions[i * 2 + 1].line;
|
|
172
|
+
const insertedLineSpan = lineFeedCount(edit.text);
|
|
173
|
+
const changedStartLine = editStartLine + lineDeltaBeforeEdit;
|
|
174
|
+
const changedEndLine = changedStartLine + insertedLineSpan;
|
|
175
|
+
startLine = Math.min(startLine, editStartLine);
|
|
176
|
+
endLine = Math.max(endLine, changedEndLine);
|
|
177
|
+
const lastRange = ranges[ranges.length - 1];
|
|
178
|
+
if (lastRange !== void 0 && changedStartLine <= lastRange[1] + 1) ranges[ranges.length - 1] = [lastRange[0], Math.max(lastRange[1], changedEndLine)];
|
|
179
|
+
else ranges.push([changedStartLine, changedEndLine]);
|
|
180
|
+
lineDeltaBeforeEdit += insertedLineSpan - (editEndLine - editStartLine);
|
|
181
|
+
}
|
|
182
|
+
if (startLine === Infinity) return {
|
|
183
|
+
startLine: 0,
|
|
184
|
+
endLine: 0,
|
|
185
|
+
ranges: [[0, 0]]
|
|
186
|
+
};
|
|
187
|
+
return {
|
|
188
|
+
startLine,
|
|
189
|
+
endLine,
|
|
190
|
+
ranges
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
};
|
|
194
|
+
function lineFeedCount(text) {
|
|
195
|
+
let count = 0;
|
|
196
|
+
for (let i = 0; i < text.length; i++) if (text.charCodeAt(i) === 10) count++;
|
|
197
|
+
return count;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
//#endregion
|
|
201
|
+
export { TextDocument };
|
|
202
|
+
//# sourceMappingURL=textDocument.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"textDocument.js","names":["#uri","#languageId","#version","#pieceTable","#editStack","#resolveEdit","#sortAndValidateResolvedEdits","change","#applyResolvedEditsToBuffer","#computeChangedLineRange","ranges: [number, number][]"],"sources":["../../src/editor/textDocument.ts"],"sourcesContent":["import type { DiffLineAnnotation } from '../types';\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}\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 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(position);\n }\n\n offsetsAt(positions: readonly Position[]): number[] {\n return this.#pieceTable.offsetsAt(positions);\n }\n\n getText(range?: Range): string {\n return this.#pieceTable.getText(range);\n }\n\n getLineText(line: number, trimEOF = true): string {\n return this.#pieceTable.getLineText(line, trimEOF);\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(\n kind: 'findNext' | 'findPrevious' | 'findAll' | 'replace' | 'replaceAll',\n searchParams: SearchParams,\n selection?: Range\n ): [start: number, end: number][] {\n return this.#pieceTable.search(kind, searchParams, selection);\n }\n\n applyEdits(\n edits: TextEdit[],\n updateHistory = false,\n selectionsBefore?: EditorSelection[],\n selectionsAfter?: EditorSelection[]\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 );\n }\n\n applyResolvedEdits(\n edits: ResolvedTextEdit[],\n updateHistory = false,\n selectionsBefore?: EditorSelection[],\n selectionsAfter?: EditorSelection[]\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 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.getLineText(line).length)\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 };\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 } {\n let startLine = Infinity;\n let endLine = 0;\n let lineDeltaBeforeEdit = 0;\n const ranges: [number, number][] = [];\n for (let i = 0; i < edits.length; i++) {\n const edit = edits[i];\n const editStartLine = editPositions[i * 2].line;\n const editEndLine = editPositions[i * 2 + 1].line;\n const insertedLineSpan = lineFeedCount(edit.text);\n const changedStartLine = editStartLine + lineDeltaBeforeEdit;\n const changedEndLine = changedStartLine + insertedLineSpan;\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 lineDeltaBeforeEdit += insertedLineSpan - (editEndLine - editStartLine);\n }\n if (startLine === Infinity) {\n return {\n startLine: 0,\n endLine: 0,\n ranges: [[0, 0]],\n };\n }\n return { startLine, endLine, ranges };\n }\n}\n\nfunction lineFeedCount(text: string): number {\n let count = 0;\n for (let i = 0; i < text.length; i++) {\n if (text.charCodeAt(i) === /* \\n */ 10) {\n count++;\n }\n }\n return count;\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
//#region src/editor/textMeasure.d.ts
|
|
2
|
+
declare class Metrics {
|
|
3
|
+
#private;
|
|
4
|
+
/** Width of the '0' character. */
|
|
5
|
+
ch: number;
|
|
6
|
+
/** Size of a tab(\t) character. */
|
|
7
|
+
tabSize: number;
|
|
8
|
+
/** Height of the code line. */
|
|
9
|
+
lineHeight: number;
|
|
10
|
+
/** initialize the metrics */
|
|
11
|
+
init(root: HTMLElement): void;
|
|
12
|
+
/** measure the width of the text */
|
|
13
|
+
measureTextWidth(text: string): number;
|
|
14
|
+
/** measure the width of the text using the canvas measureText API */
|
|
15
|
+
canvasMeasureTextWidth(text: string): number;
|
|
16
|
+
/**
|
|
17
|
+
* measure the width of the text using the DOM
|
|
18
|
+
* this is slow because it cause a reflow, use it for non-ascii text
|
|
19
|
+
*/
|
|
20
|
+
domMeasureTextWidth(text: string): number;
|
|
21
|
+
}
|
|
22
|
+
/** Check if the text needs DOM text measurement. */
|
|
23
|
+
declare function needsDomTextMeasurement(text: string): boolean;
|
|
24
|
+
/** snap the text offset to the Unicode boundary */
|
|
25
|
+
declare function snapTextOffsetToUnicodeBoundary(text: string, offset: number): number;
|
|
26
|
+
/** get the offsets of the Unicode grapheme clusters in the text */
|
|
27
|
+
declare function getUnicodeMeasurementOffsets(text: string): number[] | undefined;
|
|
28
|
+
/** get the number of columns of the ASCII text */
|
|
29
|
+
declare function getExpandedAsciiTextColumns(text: string, tabSize: number): number;
|
|
30
|
+
//#endregion
|
|
31
|
+
export { Metrics, getExpandedAsciiTextColumns, getUnicodeMeasurementOffsets, needsDomTextMeasurement, snapTextOffsetToUnicodeBoundary };
|
|
32
|
+
//# sourceMappingURL=textMeasure.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"textMeasure.d.ts","names":["Metrics","HTMLElement","needsDomTextMeasurement","snapTextOffsetToUnicodeBoundary","getUnicodeMeasurementOffsets","getExpandedAsciiTextColumns"],"sources":["../../src/editor/textMeasure.d.ts"],"sourcesContent":["export declare class Metrics {\n #private;\n /** Width of the '0' character. */\n ch: number;\n /** Size of a tab(\\t) character. */\n tabSize: number;\n /** Height of the code line. */\n lineHeight: number;\n /** initialize the metrics */\n init(root: HTMLElement): void;\n /** measure the width of the text */\n measureTextWidth(text: string): number;\n /** measure the width of the text using the canvas measureText API */\n canvasMeasureTextWidth(text: string): number;\n /**\n * measure the width of the text using the DOM\n * this is slow because it cause a reflow, use it for non-ascii text\n */\n domMeasureTextWidth(text: string): number;\n}\n/** Check if the text needs DOM text measurement. */\nexport declare function needsDomTextMeasurement(text: string): boolean;\n/** snap the text offset to the Unicode boundary */\nexport declare function snapTextOffsetToUnicodeBoundary(text: string, offset: number): number;\n/** get the offsets of the Unicode grapheme clusters in the text */\nexport declare function getUnicodeMeasurementOffsets(text: string): number[] | undefined;\n/** get the number of columns of the ASCII text */\nexport declare function getExpandedAsciiTextColumns(text: string, tabSize: number): number;\n//# sourceMappingURL=textMeasure.d.ts.map"],"mappings":";cAAqBA,OAAAA;EAAAA,CAAAA,OAAAA;EAqBGE;EAEAC,EAAAA,EAAAA,MAAAA;EAEAC;EAEAC,OAAAA,EAAAA,MAAAA;;;;aAlBTJ;;;;;;;;;;;;iBAYSC,uBAAAA;;iBAEAC,+BAAAA;;iBAEAC,4BAAAA;;iBAEAC,2BAAAA"}
|