@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.
Files changed (165) hide show
  1. package/dist/components/CodeView.d.ts +0 -1
  2. package/dist/components/CodeView.d.ts.map +1 -1
  3. package/dist/components/CodeView.js +0 -23
  4. package/dist/components/CodeView.js.map +1 -1
  5. package/dist/components/File.d.ts +7 -2
  6. package/dist/components/File.d.ts.map +1 -1
  7. package/dist/components/File.js +36 -2
  8. package/dist/components/File.js.map +1 -1
  9. package/dist/components/FileDiff.d.ts +8 -2
  10. package/dist/components/FileDiff.d.ts.map +1 -1
  11. package/dist/components/FileDiff.js +73 -1
  12. package/dist/components/FileDiff.js.map +1 -1
  13. package/dist/components/UnresolvedFile.d.ts.map +1 -1
  14. package/dist/components/UnresolvedFile.js +2 -2
  15. package/dist/components/VirtualizedFile.d.ts +2 -1
  16. package/dist/components/VirtualizedFile.d.ts.map +1 -1
  17. package/dist/components/VirtualizedFile.js +48 -48
  18. package/dist/components/VirtualizedFile.js.map +1 -1
  19. package/dist/components/VirtualizedFileDiff.js +42 -22
  20. package/dist/components/VirtualizedFileDiff.js.map +1 -1
  21. package/dist/components/Virtualizer.d.ts +1 -1
  22. package/dist/components/Virtualizer.d.ts.map +1 -1
  23. package/dist/components/Virtualizer.js +3 -5
  24. package/dist/components/Virtualizer.js.map +1 -1
  25. package/dist/constants.d.ts.map +1 -1
  26. package/dist/editor/command.d.ts +6 -0
  27. package/dist/editor/command.d.ts.map +1 -0
  28. package/dist/editor/command.js +31 -0
  29. package/dist/editor/command.js.map +1 -0
  30. package/dist/editor/css.d.ts +6 -0
  31. package/dist/editor/css.d.ts.map +1 -0
  32. package/dist/editor/css.js +218 -0
  33. package/dist/editor/css.js.map +1 -0
  34. package/dist/editor/editStack.d.ts +66 -0
  35. package/dist/editor/editStack.d.ts.map +1 -0
  36. package/dist/editor/editStack.js +218 -0
  37. package/dist/editor/editStack.js.map +1 -0
  38. package/dist/editor/editor.d.ts +22 -0
  39. package/dist/editor/editor.d.ts.map +1 -0
  40. package/dist/editor/editor.js +1323 -0
  41. package/dist/editor/editor.js.map +1 -0
  42. package/dist/editor/index.d.ts +3 -0
  43. package/dist/editor/index.js +4 -0
  44. package/dist/editor/lineAnnotations.d.ts +8 -0
  45. package/dist/editor/lineAnnotations.d.ts.map +1 -0
  46. package/dist/editor/lineAnnotations.js +32 -0
  47. package/dist/editor/lineAnnotations.js.map +1 -0
  48. package/dist/editor/pieceTable.d.ts +33 -0
  49. package/dist/editor/pieceTable.d.ts.map +1 -0
  50. package/dist/editor/pieceTable.js +590 -0
  51. package/dist/editor/pieceTable.js.map +1 -0
  52. package/dist/editor/platform.d.ts +12 -0
  53. package/dist/editor/platform.d.ts.map +1 -0
  54. package/dist/editor/platform.js +44 -0
  55. package/dist/editor/platform.js.map +1 -0
  56. package/dist/editor/quickEdit.d.ts +29 -0
  57. package/dist/editor/quickEdit.d.ts.map +1 -0
  58. package/dist/editor/quickEdit.js +81 -0
  59. package/dist/editor/quickEdit.js.map +1 -0
  60. package/dist/editor/searchPanel.d.ts +30 -0
  61. package/dist/editor/searchPanel.d.ts.map +1 -0
  62. package/dist/editor/searchPanel.js +219 -0
  63. package/dist/editor/searchPanel.js.map +1 -0
  64. package/dist/editor/selection.d.ts +126 -0
  65. package/dist/editor/selection.d.ts.map +1 -0
  66. package/dist/editor/selection.js +900 -0
  67. package/dist/editor/selection.js.map +1 -0
  68. package/dist/editor/textDocument.d.ts +139 -0
  69. package/dist/editor/textDocument.d.ts.map +1 -0
  70. package/dist/editor/textDocument.js +202 -0
  71. package/dist/editor/textDocument.js.map +1 -0
  72. package/dist/editor/textMeasure.d.ts +32 -0
  73. package/dist/editor/textMeasure.d.ts.map +1 -0
  74. package/dist/editor/textMeasure.js +108 -0
  75. package/dist/editor/textMeasure.js.map +1 -0
  76. package/dist/editor/tokenzier.d.ts +37 -0
  77. package/dist/editor/tokenzier.d.ts.map +1 -0
  78. package/dist/editor/tokenzier.js +348 -0
  79. package/dist/editor/tokenzier.js.map +1 -0
  80. package/dist/editor/utils.d.ts +16 -0
  81. package/dist/editor/utils.d.ts.map +1 -0
  82. package/dist/editor/utils.js +37 -0
  83. package/dist/editor/utils.js.map +1 -0
  84. package/dist/index.d.ts +2 -2
  85. package/dist/index.js +2 -2
  86. package/dist/react/EditorContext.d.ts +16 -0
  87. package/dist/react/EditorContext.d.ts.map +1 -0
  88. package/dist/react/EditorContext.js +26 -0
  89. package/dist/react/EditorContext.js.map +1 -0
  90. package/dist/react/File.d.ts +2 -1
  91. package/dist/react/File.d.ts.map +1 -1
  92. package/dist/react/File.js +3 -2
  93. package/dist/react/File.js.map +1 -1
  94. package/dist/react/FileDiff.d.ts +3 -1
  95. package/dist/react/FileDiff.d.ts.map +1 -1
  96. package/dist/react/FileDiff.js +3 -2
  97. package/dist/react/FileDiff.js.map +1 -1
  98. package/dist/react/MultiFileDiff.d.ts +3 -1
  99. package/dist/react/MultiFileDiff.d.ts.map +1 -1
  100. package/dist/react/MultiFileDiff.js +3 -2
  101. package/dist/react/MultiFileDiff.js.map +1 -1
  102. package/dist/react/PatchDiff.d.ts +3 -1
  103. package/dist/react/PatchDiff.d.ts.map +1 -1
  104. package/dist/react/PatchDiff.js +3 -2
  105. package/dist/react/PatchDiff.js.map +1 -1
  106. package/dist/react/index.d.ts +3 -2
  107. package/dist/react/index.js +2 -1
  108. package/dist/react/jsx.d.ts +0 -1
  109. package/dist/react/jsx.d.ts.map +1 -1
  110. package/dist/react/types.d.ts +1 -0
  111. package/dist/react/types.d.ts.map +1 -1
  112. package/dist/react/types.js +0 -1
  113. package/dist/react/utils/useFileDiffInstance.d.ts +3 -1
  114. package/dist/react/utils/useFileDiffInstance.d.ts.map +1 -1
  115. package/dist/react/utils/useFileDiffInstance.js +31 -5
  116. package/dist/react/utils/useFileDiffInstance.js.map +1 -1
  117. package/dist/react/utils/useFileInstance.d.ts +4 -1
  118. package/dist/react/utils/useFileInstance.d.ts.map +1 -1
  119. package/dist/react/utils/useFileInstance.js +30 -5
  120. package/dist/react/utils/useFileInstance.js.map +1 -1
  121. package/dist/renderers/DiffHunksRenderer.d.ts +2 -2
  122. package/dist/renderers/DiffHunksRenderer.d.ts.map +1 -1
  123. package/dist/renderers/DiffHunksRenderer.js +9 -5
  124. package/dist/renderers/DiffHunksRenderer.js.map +1 -1
  125. package/dist/renderers/FileRenderer.d.ts +5 -1
  126. package/dist/renderers/FileRenderer.d.ts.map +1 -1
  127. package/dist/renderers/FileRenderer.js +108 -41
  128. package/dist/renderers/FileRenderer.js.map +1 -1
  129. package/dist/ssr/index.d.ts +2 -2
  130. package/dist/style.js +1 -1
  131. package/dist/style.js.map +1 -1
  132. package/dist/types.d.ts +45 -1
  133. package/dist/types.d.ts.map +1 -1
  134. package/dist/utils/cleanLastNewline.js +6 -1
  135. package/dist/utils/cleanLastNewline.js.map +1 -1
  136. package/dist/utils/computeEstimatedDiffHeights.js +20 -9
  137. package/dist/utils/computeEstimatedDiffHeights.js.map +1 -1
  138. package/dist/utils/computeFileOffsets.d.ts +13 -0
  139. package/dist/utils/computeFileOffsets.d.ts.map +1 -0
  140. package/dist/utils/computeFileOffsets.js +33 -0
  141. package/dist/utils/computeFileOffsets.js.map +1 -0
  142. package/dist/utils/createTransformerWithState.js +9 -0
  143. package/dist/utils/createTransformerWithState.js.map +1 -1
  144. package/dist/utils/iterateOverDiff.js +182 -147
  145. package/dist/utils/iterateOverDiff.js.map +1 -1
  146. package/dist/utils/renderDiffWithHighlighter.js +1 -1
  147. package/dist/utils/renderFileWithHighlighter.js +5 -14
  148. package/dist/utils/renderFileWithHighlighter.js.map +1 -1
  149. package/dist/utils/virtualDiffLayout.d.ts +2 -23
  150. package/dist/utils/virtualDiffLayout.d.ts.map +1 -1
  151. package/dist/utils/virtualDiffLayout.js +1 -41
  152. package/dist/utils/virtualDiffLayout.js.map +1 -1
  153. package/dist/worker/WorkerPoolManager.js +1 -1
  154. package/dist/worker/{wasm-BaDzIkIn.js → wasm-D4DU5jgR.js} +2 -2
  155. package/dist/worker/wasm-D4DU5jgR.js.map +1 -0
  156. package/dist/worker/worker-portable.js +349 -363
  157. package/dist/worker/worker-portable.js.map +1 -1
  158. package/dist/worker/worker.js +222 -243
  159. package/dist/worker/worker.js.map +1 -1
  160. package/package.json +9 -1
  161. package/dist/utils/iterateOverFile.d.ts +0 -50
  162. package/dist/utils/iterateOverFile.d.ts.map +0 -1
  163. package/dist/utils/iterateOverFile.js +0 -49
  164. package/dist/utils/iterateOverFile.js.map +0 -1
  165. package/dist/worker/wasm-BaDzIkIn.js.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"editor.js","names":["#options","#component","#renderRange","#textDocument","#getLineElement","#initialize","#detach","#updateSelections","#scrollToPrimaryCaret","#initSelections","#selections","#focus","#tokenizer","#globalEventDisposes","#editorEventDisposes","#fileContents","#lineAnnotations","#gutterWidthCache","#contentWidthCache","#lineYCache","#wrapLineOffsetsCache","#lastCharX","#globalStyleElement","#editorStyleElement","#themeStyleElement","#componentContainer","#contentElement","#overlayElement","#primaryCaretElement","#selectionElements","#searchPanel","#quickEdit","#resizeObserver","#shouldIgnoreSelectionChange","#selectionStart","#reservedSelections","codeElement: HTMLElement | undefined","#editMode","#wrap","startingLine: number | undefined","endLine: number | undefined","startingLine","#codePaddingTop","#onDeferTokenize","#scrollingToLine","#metrics","#mouseUpDisposes","#isContentMouseDown","#updateWindowSelection","#shiftKeyPressed","#retainSearchPanelFocus","#runCommand","#getSelectionText","#replaceSelectionText","#handleInput","selection: EditorSelection","#isGutterMouseDown","target","e","lineNumber","lineType","lineIndex","selection","#handleLayoutResize","#scrollToLine","#scrollingToLineChar","#isLineVisible","#rangeBelongsToEditor","#renderSearchPanel","textDocument","expanded: EditorSelection[]","edits: TextEdit[]","nextSelections: EditorSelection[]","#applyChange","#getGutterWidth","#getContentWidth","#deleteSelectionText","#deleteHardLineForward","#insertTranspose","#renderSelection","#renderCaret","#renderQuickEditIcon","#getScrollMargin","#getCharX","#getLineY","#renderWrappedSelection","#renderSelectionRange","#wrapLineText","segmentLeft: number","segmentWidth: number","rangeEl: HTMLElement | undefined","line","initialMatch: [number, number] | undefined","#applyChangeToLineAnnotations","#applyResolvedTextEdit","contents: string | undefined","#emitChange","shouldUpdateBuffer: boolean | undefined","#rerender","starts: number[]"],"sources":["../../src/editor/editor.ts"],"sourcesContent":["import {\n type Position,\n type ResolvedTextEdit,\n TextDocument,\n type TextDocumentChange,\n type TextEdit,\n} from '../editor/textDocument';\nimport type {\n DiffLineAnnotation,\n DiffsEditableComponent,\n DiffsEditor,\n DiffsEditorSelection,\n DiffsHighlighter,\n FileContents,\n HighlightedToken,\n RenderRange,\n} from '../types';\nimport { getFiletypeFromFileName } from '../utils/getFiletypeFromFileName';\nimport {\n type EditorCommand,\n resolveEditorCommandFromKeyboardEvent,\n} from './command';\nimport { editorCSS, editorGlobalCSS } from './css';\nimport { applyDocumentChangeToLineAnnotations } from './lineAnnotations';\nimport { isMoveCursorShortcut, isPrimaryModifier, isSafari } from './platform';\nimport { type QuickEditContext, QuickEditWidget } from './quickEdit';\nimport { SearchPanelWidget } from './searchPanel';\nimport type { EditorSelection } from './selection';\nimport {\n applyDeleteHardLineForwardToSelections,\n applyTextChangeToSelections,\n applyTextReplaceToSelections,\n applyTransposeToSelections,\n comparePosition,\n convertSelection,\n createSelectionFrom,\n createSelectionFromAnchorAndFocusOffsets,\n DirectionBackward,\n DirectionForward,\n DirectionNone,\n expandCollapsedSelectionToWord,\n extendSelection,\n extendSelections,\n findNexMatch,\n getCaretPosition,\n getDocumentBoundarySelection,\n getDocumentFullSelection,\n getSelectionAnchor,\n getSelectionText,\n isCollapsedSelection,\n isLineEditable,\n mapCursorMove,\n mapSelectionShift,\n mergeOverlappingSelections,\n resolveIndentEdits,\n selectionIntersects,\n} from './selection';\nimport {\n getExpandedAsciiTextColumns,\n getUnicodeMeasurementOffsets,\n Metrics,\n snapTextOffsetToUnicodeBoundary,\n} from './textMeasure';\nimport { EditorTokenizer, renderLineTokens } from './tokenzier';\nimport { addEventListener, debounce, extend, h, round } from './utils';\n\nfunction clampDomOffset(node: Node, offset: number): number {\n if (node.nodeType === 3) {\n const length = (node as Text).textContent?.length ?? 0;\n return Math.max(0, Math.min(offset, length));\n }\n if (node.nodeType === 1) {\n return Math.max(0, Math.min(offset, node.childNodes.length));\n }\n return 0;\n}\n\nexport interface EditorOptions<LAnnotation> {\n enabledQuickEdit?: boolean;\n renderQuickEdit?: (context: QuickEditContext<LAnnotation>) => HTMLElement;\n onChange?: (\n file: FileContents,\n lineAnnotations?: DiffLineAnnotation<LAnnotation>[]\n ) => void;\n __debug?: boolean;\n}\n\nexport class Editor<LAnnotation> implements DiffsEditor<LAnnotation> {\n #options: EditorOptions<LAnnotation>;\n #editMode: 'simple' | 'advanced' = 'simple';\n #wrap = false;\n #metrics = new Metrics();\n #tokenizer?: EditorTokenizer;\n\n // event handlers\n #editorEventDisposes?: (() => void)[];\n #globalEventDisposes?: (() => void)[];\n #mouseUpDisposes?: (() => void)[];\n #detach?: () => void;\n\n // file\n #component?: DiffsEditableComponent<LAnnotation>;\n #fileContents?: FileContents;\n #lineAnnotations?: DiffLineAnnotation<LAnnotation>[];\n #textDocument?: TextDocument<LAnnotation>;\n #renderRange?: RenderRange;\n\n // cache\n #codePaddingTop = 0;\n #gutterWidthCache?: number;\n #contentWidthCache?: number;\n #lineYCache = new Map<number, number>();\n #wrapLineOffsetsCache = new Map<number, Uint32Array>();\n #lastCharX?: [line: number, character: number, x: number, wrapLine: number];\n\n // dom\n #globalStyleElement?: HTMLStyleElement;\n #editorStyleElement?: HTMLStyleElement;\n #themeStyleElement?: HTMLStyleElement;\n #componentContainer?: HTMLElement;\n #contentElement?: HTMLElement;\n #overlayElement?: HTMLElement;\n #primaryCaretElement?: HTMLElement;\n #selectionElements?: Map<string, HTMLElement>;\n #quickEdit?: QuickEditWidget;\n #searchPanel?: SearchPanelWidget;\n #resizeObserver?: ResizeObserver;\n\n // state\n #shouldIgnoreSelectionChange = false;\n #isGutterMouseDown = false;\n #isContentMouseDown = false;\n #shiftKeyPressed = false;\n #selectionStart: EditorSelection | undefined;\n #reservedSelections?: EditorSelection[];\n #selections?: EditorSelection[];\n #initSelections?: DiffsEditorSelection[];\n #scrollingToLine?: number;\n #scrollingToLineChar?: number;\n #retainSearchPanelFocus = false;\n\n #emitChange = debounce(\n (\n fileContents: FileContents,\n lineAnnotations?: DiffLineAnnotation<LAnnotation>[]\n ) => {\n this.#options.onChange?.(fileContents, lineAnnotations);\n },\n 500\n );\n\n #onDeferTokenize = (\n lines: Map<number, Array<HighlightedToken>>,\n themeType: 'light' | 'dark'\n ) => {\n this.#component?.applyLineChange?.(lines, themeType);\n // update the view if the render range is updated by scrolling\n // and the deferred tokenized lines inside the render range\n if (\n this.#renderRange !== undefined &&\n this.#renderRange.totalLines !== Infinity\n ) {\n const { startingLine, totalLines } = this.#renderRange;\n const endLine = Math.min(\n startingLine + totalLines,\n this.#textDocument?.lineCount ?? 0\n );\n for (const [line, tokens] of lines) {\n if (line >= startingLine && line < endLine) {\n const lineElement = this.#getLineElement(line);\n if (lineElement !== undefined) {\n lineElement.replaceChildren(...renderLineTokens(tokens, themeType));\n }\n }\n }\n }\n };\n\n constructor(options: EditorOptions<LAnnotation> = {}) {\n this.#options = options;\n }\n\n edit(component: DiffsEditableComponent<LAnnotation>): () => void {\n const {\n useTokenTransformer,\n enableGutterUtility,\n enableLineSelection,\n expandUnchanged,\n lineHoverHighlight,\n ...rest\n } = component.options;\n if (\n useTokenTransformer !== true ||\n enableGutterUtility === true ||\n enableLineSelection === true ||\n (expandUnchanged !== true && Object.hasOwn(component, 'fileDiff')) ||\n lineHoverHighlight !== 'disabled'\n ) {\n component.setOptions({\n ...rest,\n useTokenTransformer: true,\n enableGutterUtility: false,\n enableLineSelection: false,\n expandUnchanged: true,\n lineHoverHighlight: 'disabled',\n });\n component.rerender();\n }\n this.#component = component;\n this.#initialize();\n this.#detach = component.attachEditor(this);\n return () => this.cleanUp();\n }\n\n setSelections(selections: DiffsEditorSelection[]): void {\n const textDocument = this.#textDocument;\n if (textDocument !== undefined) {\n const resolvedSelections = selections.map<EditorSelection>(\n (selection) => {\n const start = textDocument.normalizePosition(selection.start);\n const end = textDocument.normalizePosition(selection.end);\n const direction =\n selection.direction === 'none'\n ? DirectionNone\n : selection.direction === 'backward'\n ? DirectionBackward\n : DirectionForward;\n return { direction, start, end };\n }\n );\n this.#updateSelections(resolvedSelections);\n this.#scrollToPrimaryCaret();\n } else {\n this.#initSelections = selections;\n }\n }\n\n focus(options?: FocusOptions): void {\n const preventScroll = options?.preventScroll ?? false;\n const primarySelection = this.#selections?.at(-1);\n if (primarySelection !== undefined) {\n const pos =\n primarySelection.direction === DirectionBackward\n ? primarySelection.end\n : primarySelection.start;\n this.#focus(pos, preventScroll);\n } else {\n this.#focus(undefined, preventScroll);\n }\n }\n\n cleanUp(): void {\n this.#tokenizer?.cleanUp();\n this.#tokenizer = undefined;\n\n this.#globalEventDisposes?.forEach((dispose) => dispose());\n this.#globalEventDisposes = undefined;\n this.#editorEventDisposes?.forEach((dispose) => dispose());\n this.#editorEventDisposes = undefined;\n\n this.#detach?.();\n this.#detach = undefined;\n this.#component?.setSelectedLines(null);\n this.#component = undefined;\n this.#fileContents = undefined;\n this.#lineAnnotations = undefined;\n this.#textDocument = undefined;\n this.#renderRange = undefined;\n\n this.#gutterWidthCache = undefined;\n this.#contentWidthCache = undefined;\n this.#lineYCache.clear();\n this.#wrapLineOffsetsCache.clear();\n this.#lastCharX = undefined;\n\n this.#globalStyleElement?.remove();\n this.#globalStyleElement = undefined;\n this.#editorStyleElement?.remove();\n this.#editorStyleElement = undefined;\n this.#themeStyleElement?.remove();\n this.#themeStyleElement = undefined;\n this.#componentContainer = undefined;\n this.#contentElement?.removeAttribute('contentEditable');\n this.#contentElement = undefined;\n this.#overlayElement?.remove();\n this.#overlayElement = undefined;\n this.#primaryCaretElement?.remove();\n this.#primaryCaretElement = undefined;\n this.#selectionElements?.forEach((el) => el.remove());\n this.#selectionElements?.clear();\n this.#selectionElements = undefined;\n this.#searchPanel?.cleanup();\n this.#searchPanel = undefined;\n this.#quickEdit?.cleanup();\n this.#quickEdit = undefined;\n this.#resizeObserver?.disconnect();\n this.#resizeObserver = undefined;\n\n this.#shouldIgnoreSelectionChange = false;\n this.#selectionStart = undefined;\n this.#selections = undefined;\n this.#reservedSelections = undefined;\n }\n\n syncWithRender(\n highlighter: DiffsHighlighter,\n fileContainer: HTMLElement,\n fileContents: FileContents,\n lineAnnotations: DiffLineAnnotation<LAnnotation>[] | undefined,\n renderRange: RenderRange | undefined,\n editMode?: 'simple' | 'advanced'\n ): void {\n const shadowRoot = fileContainer.shadowRoot;\n if (shadowRoot == null) {\n console.error('[editor] Could not find the shadow root.');\n return;\n }\n\n let codeElement: HTMLElement | undefined;\n for (const el of shadowRoot.querySelectorAll<HTMLElement>('[data-code]')) {\n if (el.dataset.deletions === undefined) {\n codeElement = el;\n break;\n }\n }\n if (codeElement === undefined) {\n return;\n }\n const contentEl = codeElement.children[1] as HTMLElement | undefined;\n if (contentEl === undefined) {\n return;\n }\n\n this.#editMode = editMode ?? 'simple';\n this.#wrap = this.#component?.options.overflow === 'wrap';\n\n if (editMode === 'advanced' || (lineAnnotations?.length ?? 0) > 0) {\n let startingLine: number | undefined;\n let endLine: number | undefined;\n for (const child of contentEl.children) {\n const el = child as HTMLElement;\n const line = el.dataset.line;\n const lineType = el.dataset.lineType;\n if (line !== undefined) {\n const lineIndex = Number(line) - 1;\n startingLine ??= lineIndex;\n endLine = lineIndex;\n }\n if (lineType === undefined || !isLineEditable(lineType)) {\n el.contentEditable = 'false';\n }\n }\n if (endLine !== undefined && renderRange !== undefined) {\n const { startingLine, totalLines } = renderRange;\n endLine = Math.max(endLine, startingLine + totalLines);\n }\n // normalize the render range\n if (startingLine !== undefined && endLine !== undefined) {\n renderRange = {\n startingLine: startingLine,\n totalLines: endLine - startingLine,\n bufferBefore: 0,\n bufferAfter: 0,\n };\n }\n }\n\n // inject editor css to the file container\n if (this.#componentContainer !== fileContainer) {\n this.#componentContainer = fileContainer;\n this.#codePaddingTop = Number(\n getComputedStyle(codeElement).paddingTop.slice(0, -2)\n );\n if (this.#globalStyleElement !== undefined) {\n fileContainer.appendChild(this.#globalStyleElement);\n }\n if (this.#editorStyleElement !== undefined) {\n shadowRoot.appendChild(this.#editorStyleElement);\n }\n if (this.#themeStyleElement !== undefined) {\n shadowRoot.appendChild(this.#themeStyleElement);\n }\n }\n\n if (\n this.#textDocument === undefined ||\n this.#fileContents === undefined ||\n this.#fileContents.name !== fileContents.name\n ) {\n const textDocument = new TextDocument<LAnnotation>(\n fileContents.name,\n fileContents.contents,\n fileContents.lang ?? getFiletypeFromFileName(fileContents.name)\n );\n this.#fileContents = fileContents;\n this.#textDocument = textDocument;\n this.#tokenizer?.cleanUp();\n this.#tokenizer = new EditorTokenizer({\n highlighter,\n textDocument,\n codeOptions: this.#component?.options ?? {},\n onDeferTokenize: this.#onDeferTokenize,\n setStyle: (css) => {\n this.#themeStyleElement!.textContent = css;\n },\n });\n this.#shouldIgnoreSelectionChange = false;\n this.#selectionElements?.forEach((el) => el.remove());\n this.#selectionElements?.clear();\n this.#component?.setSelectedLines(null);\n this.#selectionElements = undefined;\n this.#selections = undefined;\n this.#scrollingToLine = undefined;\n this.#reservedSelections = undefined;\n this.#searchPanel?.cleanup();\n this.#searchPanel = undefined;\n this.#quickEdit?.cleanup();\n this.#quickEdit = undefined;\n }\n\n if (this.#contentElement !== contentEl) {\n const guttterEl = contentEl.previousElementSibling as HTMLElement | null;\n const targetIsContentElement = (e: Event) => {\n const target = e.composedPath()[0] as HTMLElement;\n return target === contentEl || contentEl.contains(target);\n };\n\n this.#metrics.init(contentEl);\n this.#contentElement = extend(contentEl, {\n contentEditable: 'true',\n role: 'textbox',\n ariaMultiLine: 'true',\n autocapitalize: 'off',\n writingSuggestions: 'off',\n autocorrect: false,\n spellcheck: false,\n translate: false,\n });\n if (this.#overlayElement !== undefined) {\n contentEl.after(this.#overlayElement);\n }\n this.#editorEventDisposes?.forEach((dispose) => dispose());\n this.#editorEventDisposes = [\n addEventListener(\n contentEl,\n 'pointerdown',\n (e) => {\n if (e.pointerType !== 'mouse') {\n return;\n }\n\n // this is a workaround for the selection rendering glitch\n // happens when selecting content in shadow DOM on Safari\n if (\n isSafari() &&\n this.#lineAnnotations !== undefined &&\n this.#lineAnnotations.length > 0\n ) {\n this.#mouseUpDisposes = [\n ...contentEl.querySelectorAll<HTMLElement>(\n '[data-line-annotation]'\n ),\n ]\n .map((el) => [\n addEventListener(el, 'mouseenter', () => {\n this.#shouldIgnoreSelectionChange = true;\n }),\n addEventListener(el, 'mouseleave', () => {\n this.#shouldIgnoreSelectionChange = false;\n }),\n ])\n .flat();\n }\n\n this.#isContentMouseDown = true;\n this.#selectionStart = undefined;\n if (e.button === 0 && isPrimaryModifier(e)) {\n this.#reservedSelections = this.#selections?.map((selection) => ({\n ...selection,\n }));\n }\n if (e.shiftKey) {\n const primarySelection = this.#selections?.at(-1);\n if (primarySelection !== undefined) {\n const pos =\n primarySelection.direction === DirectionBackward\n ? primarySelection.end\n : primarySelection.start;\n // fix the window selection for shift mode\n this.#updateWindowSelection({\n start: pos,\n end: pos,\n direction: DirectionNone,\n });\n }\n this.#shiftKeyPressed = true;\n }\n },\n { passive: true }\n ),\n\n addEventListener(contentEl, 'keydown', (e) => {\n if (e.key === 'Escape') {\n e.preventDefault();\n this.#searchPanel?.cleanup();\n this.#searchPanel = undefined;\n this.#retainSearchPanelFocus = false;\n this.#quickEdit?.cleanup();\n this.#quickEdit = undefined;\n if (this.#selections !== undefined && this.#selections.length > 0) {\n const primarySelection = this.#selections.at(-1)!;\n if (\n !isCollapsedSelection(primarySelection) ||\n this.#selections.length > 1\n ) {\n const pos = getCaretPosition(primarySelection);\n this.#updateSelections([\n {\n start: pos,\n end: pos,\n direction: DirectionNone,\n },\n ]);\n this.#focus(pos);\n }\n }\n return;\n }\n if (!targetIsContentElement(e)) {\n return;\n }\n\n // handle the cursor move events manually for multiple selections and virtual viewport\n const mvShortcut = isMoveCursorShortcut(e);\n const textDocument = this.#textDocument;\n if (\n this.#selections !== undefined &&\n this.#selections.length > 0 &&\n mvShortcut !== undefined &&\n textDocument !== undefined\n ) {\n if (e.shiftKey) {\n this.#updateSelections(\n mapSelectionShift(textDocument, this.#selections, mvShortcut)\n );\n } else {\n this.#updateSelections(\n mapCursorMove(textDocument, this.#selections, mvShortcut)\n );\n }\n this.#scrollToPrimaryCaret();\n e.preventDefault();\n return;\n }\n\n const command = resolveEditorCommandFromKeyboardEvent(e);\n if (command !== undefined) {\n e.preventDefault();\n this.#runCommand(command);\n }\n }),\n\n addEventListener(contentEl, 'copy', (e) => {\n if (!targetIsContentElement(e)) {\n return;\n }\n e.preventDefault();\n e.clipboardData?.setData('text', this.#getSelectionText());\n }),\n\n addEventListener(contentEl, 'cut', (e) => {\n if (!targetIsContentElement(e)) {\n return;\n }\n e.preventDefault();\n e.clipboardData?.setData('text', this.#getSelectionText());\n this.#replaceSelectionText('');\n }),\n\n addEventListener(contentEl, 'paste', (e) => {\n if (!targetIsContentElement(e)) {\n return;\n }\n e.preventDefault();\n const text = e.clipboardData?.getData('text');\n if (text !== undefined) {\n // TODO(@ije): Add support of multiple selections copy&paste\n // TODO(@ije): normalize the pasted text with textDocument.EOF\n this.#replaceSelectionText(text);\n }\n }),\n\n addEventListener(contentEl, 'beforeinput', (e) => {\n if (!targetIsContentElement(e)) {\n return;\n }\n e.preventDefault();\n this.#handleInput(e.inputType, e.data);\n }),\n\n addEventListener(\n contentEl,\n 'compositionstart',\n (e) => {\n if (!targetIsContentElement(e)) {\n return;\n }\n this.#shouldIgnoreSelectionChange = true;\n },\n { passive: true }\n ),\n\n addEventListener(\n contentEl,\n 'compositionend',\n (e) => {\n if (!targetIsContentElement(e)) {\n return;\n }\n this.#shouldIgnoreSelectionChange = false;\n this.#handleInput('insertText', e.data);\n },\n { passive: true }\n ),\n ];\n if (guttterEl !== null && guttterEl.dataset.gutter !== undefined) {\n this.#editorEventDisposes.push(\n addEventListener(\n guttterEl,\n 'pointerdown',\n (e) => {\n let target = e.composedPath()[0] as HTMLElement | undefined;\n if (target?.dataset.lineNumberContent !== undefined) {\n target =\n target.parentElement ??\n (undefined as HTMLElement | undefined);\n }\n const textDocument = this.#textDocument;\n if (target === undefined || textDocument === undefined) {\n return;\n }\n const lineNumber = target.dataset.columnNumber;\n const lineType = target.dataset.lineType;\n if (\n lineNumber === undefined ||\n lineType === undefined ||\n !isLineEditable(lineType)\n ) {\n return;\n }\n const lineIndex = Number(lineNumber) - 1;\n const selection: EditorSelection = {\n start: { line: lineIndex, character: 0 },\n end: {\n line: lineIndex,\n character: textDocument.getLineText(lineIndex).length,\n },\n direction: DirectionForward,\n };\n this.#isGutterMouseDown = true;\n this.#selectionStart = selection;\n this.#updateSelections([selection]);\n this.#focus(selection.end);\n this.#mouseUpDisposes = [\n addEventListener(\n document,\n 'mousemove',\n (e) => {\n let target = e.composedPath()[0] as HTMLElement | undefined;\n if (target?.dataset.lineNumberContent !== undefined) {\n target = target?.parentElement ?? undefined;\n } else if (target?.tagName === 'SPAN') {\n target = target?.closest('[data-line]') as\n | HTMLElement\n | undefined;\n }\n if (target === undefined) {\n return;\n }\n const lineNumber =\n target.dataset.columnNumber ?? target.dataset.line;\n const lineType = target.dataset.lineType;\n if (\n this.#isGutterMouseDown &&\n this.#textDocument !== undefined &&\n lineNumber !== undefined &&\n lineType !== undefined &&\n isLineEditable(lineType)\n ) {\n const lineIndex = Number(lineNumber) - 1;\n let selection: EditorSelection = {\n start: { line: lineIndex, character: 0 },\n end: {\n line: lineIndex,\n character:\n this.#textDocument.getLineText(lineIndex).length,\n },\n direction: DirectionForward,\n };\n if (this.#selectionStart !== undefined) {\n selection = createSelectionFrom(\n this.#selectionStart,\n selection\n );\n } else {\n this.#selectionStart = selection;\n }\n this.#updateSelections([selection]);\n this.#focus(selection.end);\n }\n },\n { passive: true }\n ),\n ];\n },\n { passive: true }\n )\n );\n }\n this.#resizeObserver?.disconnect();\n this.#resizeObserver = new ResizeObserver(() => {\n requestAnimationFrame(() => {\n this.#handleLayoutResize();\n });\n });\n this.#resizeObserver.observe(contentEl);\n this.#resizeObserver.observe(contentEl.parentElement!);\n }\n\n this.#lineYCache.clear();\n this.#wrapLineOffsetsCache.clear();\n this.#lastCharX = undefined;\n\n this.#lineAnnotations = lineAnnotations;\n this.#renderRange = renderRange;\n this.#tokenizer?.prebuildStateStackMap(renderRange);\n\n if (this.#initSelections !== undefined) {\n this.setSelections(this.#initSelections);\n this.#scrollToPrimaryCaret();\n this.#initSelections = undefined;\n } else if (this.#selections !== undefined && this.#selections.length > 0) {\n // when re-rendering triggered by virtual viewport scroll,\n // re-render the existing selections\n this.#updateSelections(this.#selections);\n }\n\n if (this.#options.__debug === true && renderRange !== undefined) {\n const { startingLine, totalLines } = renderRange;\n console.log(\n '[diffs/editor] render file:',\n fileContents.name,\n 'RenderRange:',\n startingLine + '-' + (startingLine + totalLines),\n 'of',\n this.#textDocument.lineCount,\n 'lines'\n );\n }\n\n if (this.#scrollingToLine !== undefined) {\n this.#scrollToLine(this.#scrollingToLine, this.#scrollingToLineChar);\n this.#scrollingToLine = undefined;\n this.#scrollingToLineChar = undefined;\n } else if (this.#selections !== undefined && this.#selections.length > 0) {\n this.focus({ preventScroll: true });\n }\n\n if (this.#retainSearchPanelFocus) {\n this.#retainSearchPanelFocus = false;\n requestAnimationFrame(() => {\n this.#searchPanel?.focus();\n });\n }\n\n if (\n this.#quickEdit !== undefined &&\n this.#isLineVisible(this.#quickEdit.line) &&\n this.#contentElement !== undefined\n ) {\n this.#quickEdit.render(this.#contentElement);\n }\n }\n\n #initialize(): void {\n this.#editorStyleElement = h('style', {\n dataset: 'editorCss',\n textContent: editorCSS,\n });\n\n this.#themeStyleElement = h('style', {\n dataset: 'editorThemeCss',\n });\n\n this.#globalStyleElement = h('style', {\n dataset: 'editorGlobalCss',\n textContent: editorGlobalCSS,\n });\n\n this.#overlayElement = h('div', {\n dataset: 'editorOverlay',\n });\n\n this.#globalEventDisposes = [\n addEventListener(\n document,\n 'selectionchange',\n () => {\n const shadowRoot = this.#componentContainer?.shadowRoot;\n if (this.#shouldIgnoreSelectionChange || shadowRoot == null) {\n return;\n }\n\n const selectionRaw = document.getSelection();\n const composedRange = selectionRaw?.getComposedRanges({\n shadowRoots: [shadowRoot],\n })?.[0];\n if (\n composedRange === undefined ||\n !this.#rangeBelongsToEditor(composedRange)\n ) {\n return;\n }\n\n let selection = convertSelection(composedRange, DirectionNone);\n if (selection === undefined) {\n return;\n }\n\n // extend selection by shift + click\n if (\n this.#isContentMouseDown &&\n this.#shiftKeyPressed &&\n this.#selections !== undefined &&\n this.#selections.length > 0\n ) {\n const primarySelection = this.#selections.at(-1)!;\n this.#updateSelections([\n extendSelection(primarySelection, selection),\n ]);\n return;\n }\n\n if (this.#isContentMouseDown) {\n if (this.#selectionStart !== undefined) {\n selection = createSelectionFrom(this.#selectionStart, selection);\n } else {\n this.#selectionStart = selection;\n }\n } else if (this.#selectionStart !== undefined) {\n selection.direction = createSelectionFrom(\n this.#selectionStart,\n selection\n ).direction;\n }\n\n if (this.#reservedSelections !== undefined) {\n this.#updateSelections([\n ...this.#reservedSelections.filter(\n (reservedSelection) =>\n !selectionIntersects(reservedSelection, selection)\n ),\n selection,\n ]);\n } else {\n this.#updateSelections([selection]);\n }\n },\n { passive: true }\n ),\n\n addEventListener(\n document,\n 'pointerup',\n (e) => {\n if (e.pointerType !== 'mouse') {\n return;\n }\n\n this.#mouseUpDisposes?.forEach((dispose) => dispose());\n this.#mouseUpDisposes = undefined;\n\n if (this.#isGutterMouseDown) {\n this.#isGutterMouseDown = false;\n this.#focus();\n }\n this.#shouldIgnoreSelectionChange = false;\n this.#isContentMouseDown = false;\n this.#shiftKeyPressed = false;\n this.#selectionStart = undefined;\n this.#reservedSelections = undefined;\n this.#selectionElements?.forEach((el, key) => {\n if (key.startsWith('quickEditIcon-')) {\n el.dataset.visible = 'true';\n }\n });\n },\n { passive: true }\n ),\n\n addEventListener(\n document,\n 'keydown',\n (e) => {\n if (e.key === 'Shift') {\n this.#selectionStart = this.#selections?.at(-1);\n }\n },\n { passive: true }\n ),\n\n addEventListener(\n document,\n 'keyup',\n (e) => {\n if (e.key === 'Shift') {\n this.#selectionStart = undefined;\n }\n },\n { passive: true }\n ),\n ];\n }\n\n // TODO(@ije): add command registry\n #runCommand(command: EditorCommand) {\n const textDocument = this.#textDocument;\n if (textDocument === undefined) {\n return;\n }\n\n switch (command) {\n case 'openSearchPanel':\n this.#renderSearchPanel();\n break;\n\n case 'findNextMatch': {\n const selections = this.#selections;\n const textDocument = this.#textDocument;\n if (selections === undefined || textDocument === undefined) {\n break;\n }\n const hasCollapsed = selections.some(isCollapsedSelection);\n if (hasCollapsed) {\n const expanded: EditorSelection[] = selections.map((sel) => {\n if (isCollapsedSelection(sel)) {\n return expandCollapsedSelectionToWord(textDocument, sel);\n }\n return sel;\n });\n this.#updateSelections(expanded);\n this.focus();\n } else {\n const nextMatch = findNexMatch(textDocument, selections);\n if (nextMatch !== undefined) {\n this.#updateSelections(nextMatch);\n this.#scrollToPrimaryCaret();\n }\n }\n break;\n }\n\n case 'indent':\n case 'outdent':\n if (this.#selections !== undefined) {\n const edits: TextEdit[] = [];\n const nextSelections: EditorSelection[] = [];\n for (const selection of this.#selections) {\n const startLine = selection.start.line;\n const outdent = command === 'outdent';\n if (startLine !== selection.end.line || outdent) {\n const ret = resolveIndentEdits(\n textDocument,\n selection,\n this.#metrics.tabSize,\n outdent\n );\n edits.push(...ret[0]);\n nextSelections.push(ret[1]);\n } else {\n const lineChar0 = textDocument.charAt({\n line: startLine,\n character: 0,\n });\n this.#replaceSelectionText(\n lineChar0 === '\\t' ? '\\t' : ' '.repeat(this.#metrics.tabSize)\n );\n }\n }\n const change = textDocument.applyEdits(\n edits,\n true,\n this.#selections,\n nextSelections\n );\n if (change !== undefined) {\n this.#applyChange(change, nextSelections);\n }\n }\n break;\n\n case 'selectAll':\n this.#updateSelections([getDocumentFullSelection(textDocument)]);\n this.focus();\n break;\n\n case 'moveCursorToDocStart':\n case 'moveCursorToDocEnd':\n {\n const atEnd = command === 'moveCursorToDocEnd';\n this.#updateSelections([\n getDocumentBoundarySelection(textDocument, atEnd),\n ]);\n this.#scrollToPrimaryCaret();\n }\n break;\n\n case 'expandSelectionDocStart':\n case 'expandSelectionDocEnd':\n {\n const atEnd = command === 'expandSelectionDocEnd';\n const selections = this.#selections;\n if (selections !== undefined) {\n this.#updateSelections(\n extendSelections(\n selections,\n getDocumentBoundarySelection(textDocument, atEnd)\n )\n );\n this.#scrollToPrimaryCaret();\n }\n }\n break;\n\n case 'undo':\n if (this.#textDocument?.canUndo === true) {\n const undoResult = this.#textDocument.undo();\n if (undoResult !== undefined) {\n this.#applyChange(...undoResult);\n }\n }\n break;\n\n case 'redo':\n if (this.#textDocument?.canRedo === true) {\n const redoResult = this.#textDocument.redo();\n if (redoResult !== undefined) {\n this.#applyChange(...redoResult);\n }\n }\n break;\n }\n }\n\n #handleLayoutResize() {\n const lineAnnotations = this.#lineAnnotations?.length ?? 0;\n const prevGutterWidth = this.#gutterWidthCache;\n const prevContentWidth = this.#contentWidthCache;\n this.#gutterWidthCache = undefined;\n this.#contentWidthCache = undefined;\n const gutterWidthChanged = this.#getGutterWidth() !== prevGutterWidth;\n const contentWidthChanged = this.#getContentWidth() !== prevContentWidth;\n if (!gutterWidthChanged && !contentWidthChanged) {\n return;\n }\n\n this.#lastCharX = undefined;\n if (contentWidthChanged && (this.#wrap || lineAnnotations > 0)) {\n this.#lineYCache.clear();\n this.#wrapLineOffsetsCache.clear();\n }\n if (this.#selections !== undefined) {\n this.#updateSelections(this.#selections);\n this.focus();\n }\n }\n\n #rerender(\n change: TextDocumentChange,\n newLineAnnotations?: DiffLineAnnotation<LAnnotation>[],\n renderRange = this.#renderRange,\n shouldUpdateBuffer?: boolean\n ) {\n const tokenizer = this.#tokenizer;\n const component = this.#component;\n const fileContents = this.#fileContents;\n const textDocument = this.#textDocument;\n const contentEl = this.#contentElement;\n const gutterEl = this.#contentElement?.previousElementSibling ?? undefined;\n if (\n tokenizer === undefined ||\n component === undefined ||\n fileContents === undefined ||\n textDocument === undefined ||\n contentEl === undefined ||\n gutterEl === undefined ||\n !(gutterEl instanceof HTMLElement) ||\n gutterEl.dataset.gutter === undefined\n ) {\n return;\n }\n\n // cancel existing background tokenzier task\n tokenizer.stopBackgroundTokenize();\n\n const t = performance.now();\n const isAdvancedMode = this.#editMode === 'advanced';\n const dirtyLines = tokenizer.tokenize(change, renderRange);\n const t2 = performance.now();\n\n if (dirtyLines.size > 0) {\n const children = contentEl.children;\n const dirtyLineIndexes = new Set<number>(dirtyLines.keys());\n\n // update line elements that have been changed in the document\n if (isAdvancedMode) {\n for (const child of children) {\n const el = child as HTMLElement;\n const line = el.dataset.line;\n if (line !== undefined) {\n const lineIndex = Number(el.dataset.line) - 1;\n const tokens = dirtyLines.get(lineIndex);\n if (tokens !== undefined) {\n el.replaceChildren(\n ...renderLineTokens(tokens, tokenizer.themeType)\n );\n dirtyLineIndexes.delete(lineIndex);\n if (dirtyLineIndexes.size === 0) {\n break;\n }\n }\n }\n }\n } else {\n const startingLine = renderRange?.startingLine ?? 0;\n for (\n let i = change.startLine - startingLine;\n i < children.length;\n i++\n ) {\n const child = children[i] as HTMLElement | undefined;\n if (child?.dataset.line !== undefined) {\n const lineIndex = Number(child.dataset.line) - 1;\n if (dirtyLines.has(lineIndex)) {\n const tokens = dirtyLines.get(lineIndex)!;\n child.replaceChildren(\n ...renderLineTokens(tokens, tokenizer.themeType)\n );\n dirtyLineIndexes.delete(lineIndex);\n if (dirtyLineIndexes.size === 0) {\n break;\n }\n }\n }\n }\n }\n\n // create new line elements for new lines\n if (dirtyLineIndexes.size > 0) {\n for (const lineIndex of dirtyLineIndexes) {\n const tokens = dirtyLines.get(lineIndex)!;\n const lineNumber = String(lineIndex + 1);\n h(\n 'div',\n {\n dataset: {\n line: lineNumber,\n lineType: 'context',\n lineIndex: lineIndex.toString(),\n },\n // oxlint-disable-next-line react/no-children-prop\n children: renderLineTokens(tokens, tokenizer.themeType),\n },\n contentEl\n );\n h(\n 'div',\n {\n dataset: {\n lineType: 'context',\n columnNumber: lineNumber,\n lineIndex: lineIndex.toString(),\n },\n // oxlint-disable-next-line react/no-children-prop\n children: [\n h('span', {\n dataset: {\n lineNumberContent: '',\n },\n textContent: lineNumber,\n }),\n ],\n },\n gutterEl\n );\n }\n }\n }\n\n // remove line elements that have been deleted in the document\n if (change.lineDelta < 0) {\n for (const parent of [contentEl, gutterEl]) {\n const children = parent.children;\n for (let i = children.length - 1; i >= 0; i--) {\n const child = children[i] as HTMLElement;\n const { lineIndex, lineAnnotation } = child.dataset;\n if (lineIndex !== undefined || lineAnnotation !== undefined) {\n const lineIndexNum = Number(\n lineAnnotation !== undefined\n ? lineAnnotation.split(',')[1]\n : lineIndex\n );\n if (lineIndexNum < change.lineCount) {\n break;\n }\n child.remove();\n }\n }\n }\n }\n\n // fix grid layout\n if (change.lineDelta !== 0) {\n gutterEl.style.gridRow = 'span ' + gutterEl.children.length;\n contentEl.style.gridRow = 'span ' + contentEl.children.length;\n }\n\n component.applyLineChange?.(dirtyLines, tokenizer.themeType);\n if (change.lineDelta !== 0 || isAdvancedMode) {\n component.applyLayoutChange(\n textDocument,\n newLineAnnotations,\n shouldUpdateBuffer\n );\n }\n\n if (this.#options.__debug === true) {\n console.log(\n `[diffs/editor] re-render in: ${round(performance.now() - t2)}ms,`,\n `tokenize in: ${round(t2 - t)}ms (${dirtyLines.size} dirty lines)`\n );\n }\n }\n\n #handleInput(inputType: string, data: string | null) {\n switch (inputType) {\n case 'insertText':\n this.#replaceSelectionText(data ?? '');\n break;\n case 'insertParagraph':\n // TODO(@ije): use document.EOF instead of '\\n'\n this.#replaceSelectionText('\\n');\n break;\n case 'deleteContentBackward':\n this.#deleteSelectionText();\n break;\n case 'deleteContentForward':\n this.#deleteSelectionText(true);\n break;\n // TODO(@ije): Safari and Firefox does not support this input type\n // use command instead\n case 'deleteHardLineForward':\n this.#deleteHardLineForward();\n break;\n case 'insertTranspose':\n this.#insertTranspose();\n break;\n default:\n console.warn(`[diffs] Unknown input type: ${inputType}`);\n break;\n }\n }\n\n #updateSelections(selections: EditorSelection[]) {\n if (selections.length === 0) {\n return;\n }\n const gutterBuffer = this.#contentElement?.previousElementSibling;\n const normalizedSelections = mergeOverlappingSelections(selections);\n const primarySelection = normalizedSelections.at(-1)!;\n this.#selections = normalizedSelections;\n this.#primaryCaretElement = undefined;\n this.#component?.setSelectedLines(null);\n gutterBuffer\n ?.querySelectorAll('[data-active]')\n .forEach((el) => el.removeAttribute('data-active'));\n if (isCollapsedSelection(primarySelection)) {\n const line = primarySelection.start.line + 1;\n this.#component?.setSelectedLines({\n start: line,\n end: line,\n });\n } else {\n if (gutterBuffer !== undefined && gutterBuffer instanceof HTMLElement) {\n const pos = getCaretPosition(primarySelection);\n gutterBuffer\n .querySelector(`[data-column-number=\"${pos.line + 1}\"]`)\n ?.setAttribute('data-active', '');\n }\n }\n const fragment = document.createDocumentFragment();\n const renderCtx = {\n fragment,\n elements: new Map<string, HTMLElement>(),\n };\n for (const selection of normalizedSelections) {\n if (!isCollapsedSelection(selection)) {\n this.#renderSelection(renderCtx, selection);\n }\n this.#renderCaret(renderCtx, selection, selection === primarySelection);\n }\n if (\n this.#options.enabledQuickEdit === true &&\n !isCollapsedSelection(primarySelection)\n ) {\n this.#renderQuickEditIcon(renderCtx, primarySelection);\n }\n this.#overlayElement?.appendChild(fragment);\n this.#selectionElements?.forEach((el) => el.remove());\n this.#selectionElements?.clear();\n this.#selectionElements = renderCtx.elements;\n }\n\n // update window native selection to match the selection\n #updateWindowSelection(selection: EditorSelection) {\n const winSelection = window.getSelection();\n if (winSelection === null) {\n return;\n }\n let { start, end, direction } = selection;\n if (comparePosition(start, end) > 0) {\n [start, end] = [end, start];\n }\n const startLineElement = this.#getLineElement(start.line);\n const endLineElement = this.#getLineElement(end.line);\n if (startLineElement === undefined || endLineElement === undefined) {\n return;\n }\n let [anchorNode, anchorOffset] = getSelectionAnchor(\n startLineElement,\n start.character\n );\n let [focusNode, focusOffset] = getSelectionAnchor(\n endLineElement,\n end.character\n );\n if (direction === DirectionBackward) {\n [anchorNode, anchorOffset, focusNode, focusOffset] = [\n focusNode,\n focusOffset,\n anchorNode,\n anchorOffset,\n ];\n }\n try {\n winSelection.setBaseAndExtent(\n anchorNode,\n clampDomOffset(anchorNode, anchorOffset),\n focusNode,\n clampDomOffset(focusNode, focusOffset)\n );\n } catch (err) {\n console.error('[diffs/editor] failed to update window selection:', err);\n }\n }\n\n #focus(position?: Position, preventScroll = true) {\n if (position !== undefined) {\n this.#shouldIgnoreSelectionChange = true;\n this.#updateWindowSelection({\n start: position,\n end: position,\n direction: DirectionNone,\n });\n requestAnimationFrame(() => {\n this.#contentElement?.focus({ preventScroll });\n requestAnimationFrame(() => {\n this.#shouldIgnoreSelectionChange = false;\n });\n });\n } else {\n requestAnimationFrame(() => {\n this.#contentElement?.focus({ preventScroll });\n });\n }\n }\n\n #scrollToPrimaryCaret() {\n const primaryCaretElement = this.#primaryCaretElement;\n const primarySelection = this.#selections?.at(-1);\n if (primarySelection === undefined) {\n return;\n }\n if (primaryCaretElement !== undefined) {\n primaryCaretElement.scrollIntoView({\n block: 'nearest',\n inline: 'nearest',\n });\n this.#focus(\n primarySelection.direction === DirectionBackward\n ? primarySelection.end\n : primarySelection.start\n );\n } else {\n const pos = getCaretPosition(primarySelection);\n this.#scrollToLine(pos.line, pos.character);\n }\n }\n\n // add scroll margin to the primary caret element to prevent\n // the caret from being hidden by the gutter\n #getScrollMargin() {\n const componentTop = this.#component?.top ?? 0;\n const top = this.#searchPanel !== undefined ? 48 : 0;\n const start = this.#getGutterWidth() + this.#metrics.ch;\n const end = this.#metrics.ch;\n return `${componentTop + top}px ${end}px 0 ${start}px`;\n }\n\n #scrollToLine(line: number, char = 0) {\n const virtualCaret = h('div', {\n style: {\n position: 'absolute',\n left: '0',\n width: '2px',\n height: this.#metrics.lineHeight + 'px',\n scrollMargin: this.#getScrollMargin(),\n },\n });\n if (this.#getLineElement(line) !== undefined) {\n const [left, wrapLine] = this.#getCharX(line, char);\n const lineY = this.#getLineY(line) + wrapLine * this.#metrics.lineHeight;\n virtualCaret.style.top = lineY + 'px';\n virtualCaret.style.left = left + 'px';\n this.#overlayElement?.appendChild(virtualCaret);\n virtualCaret.scrollIntoView({ block: 'center', inline: 'nearest' });\n this.#focus({ line, character: char });\n requestAnimationFrame(() => virtualCaret.remove());\n }\n // if the line is not rendered yet(virtualized),\n // scroll to the approximate line position to trigger\n // the line to be rendered, then recall this function\n // to ensure the line is scrolled into view\n else {\n const lineAnnotations = (this.#lineAnnotations ?? []).filter(\n (annotation) => annotation.lineNumber < line\n ).length;\n const approximateLineY =\n (lineAnnotations + line) * this.#metrics.lineHeight;\n virtualCaret.style.top = approximateLineY + 'px';\n this.#componentContainer?.shadowRoot?.appendChild(virtualCaret);\n this.#scrollingToLine = line;\n this.#scrollingToLineChar = char;\n virtualCaret.scrollIntoView({ block: 'center', inline: 'nearest' });\n requestAnimationFrame(() => virtualCaret.remove());\n }\n }\n\n #renderSelection(\n renderCtx: {\n fragment: DocumentFragment;\n elements: Map<string, HTMLElement>;\n },\n selection: EditorSelection\n ) {\n if (this.#textDocument === undefined) {\n return;\n }\n\n const { start, end } = selection;\n for (let ln = start.line; ln <= end.line; ln++) {\n if (!this.#isLineVisible(ln)) {\n continue;\n }\n\n const lineText = this.#textDocument.getLineText(ln);\n const startChar = ln === start.line ? start.character : 0;\n const endChar = ln === end.line ? end.character : lineText.length;\n\n if (this.#wrap) {\n const paddingInline = this.#metrics.ch; // 1ch, align to diff css: padding-inline: 1ch\n const contentWidth = this.#getContentWidth();\n const textWidth =\n 2 * paddingInline + this.#metrics.measureTextWidth(lineText);\n if (textWidth > contentWidth) {\n this.#renderWrappedSelection(\n renderCtx,\n selection,\n ln,\n lineText,\n startChar,\n endChar,\n paddingInline\n );\n continue;\n }\n }\n\n let left = 0;\n let width = 0;\n if (startChar === endChar && startChar === 0) {\n left = this.#getGutterWidth() + this.#metrics.ch; // gutter width + inline padding (1ch)\n width = ln === end.line ? 0 : this.#metrics.ch;\n } else {\n left = this.#getCharX(ln, startChar)[0];\n width =\n endChar === startChar ? 0 : this.#getCharX(ln, endChar)[0] - left;\n }\n this.#renderSelectionRange(\n renderCtx,\n selection,\n ln,\n 0,\n startChar,\n endChar,\n width,\n left\n );\n }\n }\n\n // Render the selection on a wrapped logical line by splitting it into one\n // selection-range div per visual sub-line. For each wrap segment, we compute\n // the intersection with the line's selection range and render the slice in\n // segment-local coordinates so left/width line up with the visually wrapped\n // text. Zero-width slices that fall on intermediate segment boundaries are\n // skipped to avoid duplicate markers across consecutive visual lines.\n #renderWrappedSelection(\n renderCtx: {\n fragment: DocumentFragment;\n elements: Map<string, HTMLElement>;\n },\n selection: EditorSelection,\n line: number,\n lineText: string,\n startChar: number,\n endChar: number,\n paddingInline: number\n ) {\n const wrapOffsets = this.#wrapLineText(line);\n const segmentCount = wrapOffsets.length - 1;\n const lastSegmentIndex = segmentCount - 1;\n const offsetLeft = this.#getGutterWidth() + paddingInline;\n\n for (let w = 0; w < segmentCount; w++) {\n const segmentStart = wrapOffsets[w];\n const segmentEnd = wrapOffsets[w + 1];\n const wrapStartChar = Math.max(startChar, segmentStart);\n const wrapEndChar = Math.min(endChar, segmentEnd);\n\n // Selection range doesn't reach this visual segment.\n if (wrapStartChar > wrapEndChar) {\n continue;\n }\n\n // Zero-width slices on segment boundaries can appear on two consecutive\n // segments (end of one, start of the next). Only render at the natural\n // anchor positions: the very beginning of the first visual line, or the\n // very end of the last visual line.\n if (wrapStartChar === wrapEndChar) {\n const isAtLineStart = wrapStartChar === 0 && w === 0;\n const isAtLineEnd =\n wrapEndChar === lineText.length && w === lastSegmentIndex;\n if (!isAtLineStart && !isAtLineEnd) {\n continue;\n }\n }\n\n let segmentLeft: number;\n let segmentWidth: number;\n if (wrapStartChar === 0 && wrapEndChar === 0) {\n // Empty range pinned to line start (e.g. multi-line selection ending\n // with end.character === 0). Mirrors the non-wrap path.\n segmentLeft = offsetLeft;\n segmentWidth = line === selection.end.line ? 0 : paddingInline;\n } else {\n const prefixInSegment = lineText.slice(segmentStart, wrapStartChar);\n const prefixAsciiColumns = getExpandedAsciiTextColumns(\n prefixInSegment,\n this.#metrics.tabSize\n );\n segmentLeft =\n offsetLeft +\n (prefixAsciiColumns !== -1\n ? prefixAsciiColumns * this.#metrics.ch\n : this.#metrics.measureTextWidth(prefixInSegment));\n\n if (wrapStartChar === wrapEndChar) {\n segmentWidth = 0;\n } else {\n const selectionInSegment = lineText.slice(wrapStartChar, wrapEndChar);\n const selectionAsciiWidth = getExpandedAsciiTextColumns(\n selectionInSegment,\n this.#metrics.tabSize\n );\n segmentWidth =\n selectionAsciiWidth !== -1\n ? selectionAsciiWidth * this.#metrics.ch\n : this.#metrics.measureTextWidth(selectionInSegment);\n }\n }\n\n this.#renderSelectionRange(\n renderCtx,\n selection,\n line,\n w,\n wrapStartChar,\n wrapEndChar,\n segmentWidth,\n segmentLeft,\n w === lastSegmentIndex\n );\n }\n }\n\n // Render one selection range div for a single visual line. `applyEolSpacing`\n // controls whether the trailing one-character \"line continuation\" marker is\n // appended at the end. For wrapped logical lines this must be false on every\n // visual segment except the last one, since an intra-line wrap is not a real\n // newline and shouldn't visually extend past the wrapped content.\n #renderSelectionRange(\n renderCtx: {\n fragment: DocumentFragment;\n elements: Map<string, HTMLElement>;\n },\n selection: EditorSelection,\n ln: number,\n wrapLine: number,\n startChar: number,\n endChar: number,\n width: number,\n left: number,\n applyEolSpacing = true\n ) {\n const spacing =\n !applyEolSpacing ||\n selection.end.line === ln ||\n (startChar === endChar && ln !== selection.start.line)\n ? 0\n : this.#metrics.ch;\n const css = `width:${width + spacing}px;transform:translateY(${this.#getLineY(ln) + wrapLine * this.#metrics.lineHeight}px) translateX(${left}px);`;\n const cacheKey = 'selection-range-' + css;\n const selectionEls = this.#selectionElements;\n\n if (renderCtx.elements.has(cacheKey)) {\n return;\n }\n\n let rangeEl: HTMLElement | undefined;\n if (selectionEls?.has(cacheKey) === true) {\n rangeEl = selectionEls.get(cacheKey)!;\n selectionEls.delete(cacheKey);\n } else {\n rangeEl = h(\n 'div',\n {\n dataset: 'selectionRange',\n style: { cssText: css },\n },\n renderCtx.fragment\n );\n }\n\n renderCtx.elements.set(cacheKey, rangeEl);\n }\n\n #renderCaret(\n renderCtx: {\n fragment: DocumentFragment;\n elements: Map<string, HTMLElement>;\n },\n selection: EditorSelection,\n isPrimary: boolean\n ) {\n const { line, character } = getCaretPosition(selection);\n if (!this.#isLineVisible(line)) {\n return;\n }\n const [left, wrapLine] = this.#getCharX(line, character);\n const cacheKey = 'caret-' + line + '(' + wrapLine + ')-' + character;\n if (renderCtx.elements.has(cacheKey)) {\n return;\n }\n const caretEl = h(\n 'div',\n {\n dataset: 'caret',\n style: {\n transform: `translateY(${this.#getLineY(line) + wrapLine * this.#metrics.lineHeight}px) translateX(${left - 1}px)`,\n },\n },\n renderCtx.fragment\n );\n renderCtx.elements.set(cacheKey, caretEl);\n if (isPrimary) {\n caretEl.style.scrollMargin = this.#getScrollMargin();\n this.#primaryCaretElement = caretEl;\n }\n }\n\n #renderQuickEditIcon(\n renderCtx: {\n fragment: DocumentFragment;\n elements: Map<string, HTMLElement>;\n },\n selection: EditorSelection\n ) {\n const line = getCaretPosition(selection).line;\n if (!this.#isLineVisible(line)) {\n return;\n }\n\n const [left, wrapLine] = this.#getCharX(line, 0);\n const cacheKey = 'quickEditIcon-' + line + '(' + wrapLine + ')';\n if (renderCtx.elements.has(cacheKey)) {\n return;\n }\n\n const quickEditIcon = QuickEditWidget.renderIcon(\n left,\n this.#getLineY(line) + wrapLine * this.#metrics.lineHeight,\n renderCtx.fragment,\n () => {\n const cleanUpQuickEdit = () => {\n this.#quickEdit?.cleanup();\n this.#quickEdit = undefined;\n };\n\n const handleWidgetDomResize = () => {\n // the line y cache is invalidated by the DOM change,\n // clear the line y cache and re-render the selection\n this.#lineYCache.clear();\n if (this.#selections !== undefined) {\n this.#updateSelections(this.#selections);\n }\n };\n\n // remove the existing quick edit element\n cleanUpQuickEdit();\n\n const textDocument = this.#textDocument;\n const renderQuickEdit = this.#options.renderQuickEdit;\n const fileContainer = this.#componentContainer;\n if (\n textDocument === undefined ||\n renderQuickEdit === undefined ||\n fileContainer == null\n ) {\n return;\n }\n\n const line = selection.end.line;\n const lineText = textDocument.getLineText(line);\n const quickEditElement = renderQuickEdit({\n textDocument,\n selection,\n applyEdits: (edits: TextEdit[]) => {\n const change = textDocument.applyEdits(\n edits,\n true,\n this.#selections\n );\n if (change !== undefined) {\n this.#applyChange(change);\n }\n },\n getSelectionText: () => {\n return this.#textDocument?.getText(selection) ?? '';\n },\n replaceSelectionText: (text: string) => {\n this.#replaceSelectionText(text);\n },\n close: () => {\n cleanUpQuickEdit();\n handleWidgetDomResize();\n this.#scrollToPrimaryCaret();\n },\n });\n let leadingWhitespaces = 0;\n for (let i = 0; i < lineText.length; i++) {\n const charCode = lineText.charCodeAt(i);\n if (charCode === /* space */ 32) {\n leadingWhitespaces++;\n } else if (charCode === /* tab */ 9) {\n leadingWhitespaces += this.#metrics.tabSize;\n } else {\n break;\n }\n }\n this.#quickEdit = new QuickEditWidget(\n line,\n quickEditElement,\n fileContainer,\n leadingWhitespaces,\n handleWidgetDomResize\n );\n this.#updateSelections([selection]);\n if (this.#isLineVisible(line) && this.#contentElement !== undefined) {\n this.#quickEdit.render(this.#contentElement);\n }\n }\n );\n renderCtx.elements.set(cacheKey, quickEditIcon);\n }\n\n // TODO(@ije): render search highlight\n #renderSearchPanel() {\n // cleanup the existing search panel\n this.#searchPanel?.cleanup();\n\n const textDocument = this.#textDocument;\n const preElement =\n this.#componentContainer?.shadowRoot?.querySelector<HTMLElement>('pre');\n if (textDocument === undefined || preElement == null) {\n return;\n }\n\n let defaultQuery = '';\n let initialMatch: [number, number] | undefined = undefined;\n\n const selections = this.#selections;\n if (selections !== undefined && selections.length > 0) {\n let primarySelection = selections.at(-1)!;\n if (isCollapsedSelection(primarySelection)) {\n primarySelection = expandCollapsedSelectionToWord(\n textDocument,\n primarySelection\n );\n this.#updateSelections([...selections.slice(0, -1), primarySelection]);\n const selectionText = textDocument.getText(primarySelection);\n if (!selectionText.includes('\\n')) {\n defaultQuery = selectionText;\n initialMatch = [\n textDocument.offsetAt(primarySelection.start),\n textDocument.offsetAt(primarySelection.end),\n ];\n }\n }\n }\n\n this.#searchPanel = new SearchPanelWidget({\n textDocument,\n containerElement: preElement,\n defaultQuery,\n initialMatch,\n getCurrentSearchRange: () => this.#selections?.at(-1),\n postSearch: (kind, [startOffset, endOffset], retainFocus) => {\n if (\n kind === 'findNext' ||\n kind === 'findPrevious' ||\n kind === 'replace'\n ) {\n const nextSelection = createSelectionFromAnchorAndFocusOffsets(\n textDocument,\n startOffset,\n endOffset\n );\n this.#updateSelections([nextSelection]);\n this.#scrollToPrimaryCaret();\n if (retainFocus === true) {\n this.#retainSearchPanelFocus = true;\n requestAnimationFrame(() => {\n this.#searchPanel?.focus();\n });\n }\n } else if (kind === 'findAll' || kind === 'replaceAll') {\n const { line, character } = textDocument.positionAt(startOffset);\n this.#scrollToLine(line, character);\n }\n },\n onClose: () => {\n this.#searchPanel = undefined;\n this.#retainSearchPanelFocus = false;\n },\n });\n this.#retainSearchPanelFocus = false;\n }\n\n #getSelectionText() {\n const textDocument = this.#textDocument;\n const selections = this.#selections;\n if (textDocument === undefined || selections === undefined) {\n return '';\n }\n return getSelectionText(textDocument, selections);\n }\n\n // replace the selection text\n #replaceSelectionText(text: string | string[]) {\n const selections = this.#selections;\n if (selections === undefined) {\n return;\n }\n const textDocument = this.#textDocument;\n const primarySelection = selections.at(-1);\n if (textDocument === undefined || primarySelection === undefined) {\n return;\n }\n const { nextSelections, change } =\n Array.isArray(text) && text.length === selections.length\n ? applyTextReplaceToSelections<LAnnotation>(\n textDocument,\n selections,\n text,\n this.#lineAnnotations\n )\n : applyTextChangeToSelections<LAnnotation>(\n textDocument,\n selections,\n {\n start: textDocument.offsetAt(primarySelection.start),\n end: textDocument.offsetAt(primarySelection.end),\n text: Array.isArray(text) ? text.join('\\n') : text,\n },\n this.#lineAnnotations\n );\n\n if (change !== undefined) {\n this.#applyChange(\n change,\n nextSelections,\n this.#applyChangeToLineAnnotations(change)\n );\n }\n }\n\n #deleteSelectionText(forward: boolean = false) {\n const selections = this.#selections;\n const textDocument = this.#textDocument;\n if (selections === undefined || textDocument === undefined) {\n return;\n }\n\n const primarySelection = selections.at(-1);\n if (primarySelection === undefined) {\n return;\n }\n\n const edit = isCollapsedSelection(primarySelection)\n ? (() => {\n const offset = textDocument.offsetAt(primarySelection.start);\n const nextOffset = forward\n ? Math.min(textDocument.getText().length, offset + 1)\n : Math.max(0, offset - 1);\n return {\n start: Math.min(offset, nextOffset),\n end: Math.max(offset, nextOffset),\n text: '',\n };\n })()\n : {\n start: textDocument.offsetAt(primarySelection.start),\n end: textDocument.offsetAt(primarySelection.end),\n text: '',\n };\n\n this.#applyResolvedTextEdit(edit);\n }\n\n #deleteHardLineForward() {\n const selections = this.#selections;\n const textDocument = this.#textDocument;\n if (selections === undefined || textDocument === undefined) {\n return;\n }\n const { nextSelections, change } =\n applyDeleteHardLineForwardToSelections<LAnnotation>(\n textDocument,\n selections,\n this.#lineAnnotations\n );\n if (change !== undefined) {\n this.#applyChange(\n change,\n nextSelections,\n this.#applyChangeToLineAnnotations(change)\n );\n }\n }\n\n #insertTranspose() {\n const selections = this.#selections;\n const textDocument = this.#textDocument;\n if (selections === undefined || textDocument === undefined) {\n return;\n }\n const { nextSelections, change } = applyTransposeToSelections<LAnnotation>(\n textDocument,\n selections,\n this.#lineAnnotations\n );\n if (change !== undefined) {\n this.#applyChange(\n change,\n nextSelections,\n this.#applyChangeToLineAnnotations(change)\n );\n }\n }\n\n #applyResolvedTextEdit(edit: ResolvedTextEdit) {\n if (this.#selections === undefined || this.#textDocument === undefined) {\n return;\n }\n const { nextSelections, change } = applyTextChangeToSelections<LAnnotation>(\n this.#textDocument,\n this.#selections,\n edit,\n this.#lineAnnotations,\n this.#metrics.tabSize\n );\n if (change !== undefined) {\n this.#applyChange(\n change,\n nextSelections,\n this.#applyChangeToLineAnnotations(change)\n );\n }\n }\n\n #applyChange(\n change: TextDocumentChange,\n selections?: EditorSelection[],\n newLineAnnotations?: DiffLineAnnotation<LAnnotation>[]\n ) {\n const fileContents = this.#fileContents;\n const textDocument = this.#textDocument;\n const onChange = this.#options.onChange;\n if (\n fileContents !== undefined &&\n textDocument !== undefined &&\n onChange !== undefined\n ) {\n const { contents: _, ...file } = fileContents;\n let contents: string | undefined;\n // tradeoff: using a getter for the 'contents' property\n // to avoid pre-concactinating the text content of the textDocument\n // but the user may get newer contents when accessing\n // the 'contents' property\n Object.defineProperty(file, 'contents', {\n get: () => (contents ??= textDocument.getText()),\n });\n this.#emitChange(\n file as FileContents,\n newLineAnnotations ?? this.#lineAnnotations\n );\n }\n\n // Invalidate layout caches touched by the edit.\n // - line inserts/deletes shift line numbers, so clear from startLine onward\n // - wrapped edits can change visual height, which shifts downstream line Y\n if (change.lineDelta !== 0) {\n for (const line of this.#lineYCache.keys()) {\n if (line >= change.startLine) {\n this.#lineYCache.delete(line);\n }\n }\n }\n if (this.#wrap) {\n for (const line of this.#wrapLineOffsetsCache.keys()) {\n if (line >= change.startLine) {\n this.#wrapLineOffsetsCache.delete(line);\n }\n }\n }\n this.#lastCharX = undefined;\n\n let renderRange = this.#renderRange;\n let shouldUpdateBuffer: boolean | undefined;\n if (\n renderRange !== undefined &&\n selections !== undefined &&\n selections.length > 0\n ) {\n const primarySelection = selections.at(-1)!;\n const renderRangeEndLine =\n renderRange.startingLine + renderRange.totalLines;\n // when typing new line at the end of the file,\n // extend the render range +1 to trigger the re-render of the new line\n if (primarySelection.end.line === renderRangeEndLine) {\n renderRange = {\n ...renderRange,\n totalLines: renderRange.totalLines + 1,\n };\n } else if (primarySelection.end.line > renderRangeEndLine) {\n shouldUpdateBuffer = true;\n }\n }\n this.#rerender(change, newLineAnnotations, renderRange, shouldUpdateBuffer);\n\n if (selections !== undefined) {\n // re-render selection range and caret, focus to the editor to update the window selection,\n // and scroll to the crate to mock the 'contenteditable' behavior\n this.#updateSelections(selections);\n this.focus({ preventScroll: true });\n requestAnimationFrame(() => {\n if (this.#primaryCaretElement !== undefined) {\n this.#primaryCaretElement.scrollIntoView({\n block: 'nearest',\n inline: 'nearest',\n });\n } else if (selections.length > 0) {\n const pos = getCaretPosition(selections.at(-1)!);\n this.#scrollToLine(pos.line, pos.character);\n }\n });\n }\n }\n\n #applyChangeToLineAnnotations(\n change: TextDocumentChange\n ): DiffLineAnnotation<LAnnotation>[] | undefined {\n if (this.#lineAnnotations !== undefined) {\n const nextLineAnnotations =\n applyDocumentChangeToLineAnnotations<LAnnotation>(\n change,\n this.#lineAnnotations\n );\n if (nextLineAnnotations !== undefined) {\n this.#textDocument?.setLastUndoLineAnnotations(\n this.#lineAnnotations,\n nextLineAnnotations\n );\n return nextLineAnnotations;\n }\n }\n return undefined;\n }\n\n #getLineElement(line: number): HTMLElement | undefined {\n const contentElement = this.#contentElement;\n if (contentElement === undefined) {\n return undefined;\n }\n // check if the line is within the render range\n if (this.#renderRange !== undefined && this.#editMode === 'simple') {\n const { startingLine } = this.#renderRange;\n const { children } = contentElement;\n for (let i = line - startingLine; i <= children.length; i++) {\n const child = children[i] as HTMLElement | undefined;\n const lineNumber = child?.dataset.line;\n const lineType = child?.dataset.lineType;\n if (\n lineNumber !== undefined &&\n lineType !== undefined &&\n isLineEditable(lineType) &&\n Number(lineNumber) === line + 1\n ) {\n return child;\n }\n }\n }\n // fallback to query selector (ignoring `change-deletion` lines)\n if (this.#editMode === 'advanced') {\n return (\n contentElement.querySelector<HTMLElement>(\n `[data-line=\"${line + 1}\"]:not([data-line-type=\"change-deletion\"])`\n ) ?? undefined\n );\n }\n return (\n contentElement.querySelector<HTMLElement>(`[data-line=\"${line + 1}\"]`) ??\n undefined\n );\n }\n\n #getGutterWidth(): number {\n const gutterElement = this.#contentElement?.previousElementSibling;\n if (\n gutterElement == null ||\n !(gutterElement instanceof HTMLElement) ||\n !gutterElement.hasAttribute('data-gutter')\n ) {\n return 0;\n }\n\n if (this.#gutterWidthCache === undefined) {\n const diffsColumnNumberWidth =\n this.#contentElement?.parentElement?.style.getPropertyValue(\n '--diffs-column-number-width'\n );\n if (\n diffsColumnNumberWidth !== undefined &&\n diffsColumnNumberWidth.length > 2 &&\n diffsColumnNumberWidth.endsWith('px')\n ) {\n this.#gutterWidthCache = Number(diffsColumnNumberWidth.slice(0, -2));\n } else {\n this.#gutterWidthCache = gutterElement.offsetWidth;\n }\n }\n\n return this.#gutterWidthCache;\n }\n\n #getContentWidth(): number {\n if (this.#contentElement === undefined) {\n return 0;\n }\n\n if (this.#contentWidthCache === undefined) {\n const diffsColumnContentWidth =\n this.#contentElement.parentElement?.style.getPropertyValue(\n '--diffs-column-content-width'\n );\n if (\n diffsColumnContentWidth !== undefined &&\n diffsColumnContentWidth.length > 2 &&\n diffsColumnContentWidth.endsWith('px')\n ) {\n this.#contentWidthCache = Number(diffsColumnContentWidth.slice(0, -2));\n } else {\n this.#contentWidthCache = this.#contentElement.offsetWidth;\n }\n }\n return this.#contentWidthCache;\n }\n\n // get line top(y-coordinate) position\n #getLineY(line: number) {\n const cachedY = this.#lineYCache.get(line);\n if (cachedY !== undefined) {\n return cachedY;\n }\n\n const lineElement = this.#getLineElement(line);\n if (lineElement === undefined) {\n return -1;\n }\n\n // cold(slow) path: measure line top position from DOM (will cause reflow)\n const y = lineElement.offsetTop + this.#codePaddingTop;\n this.#lineYCache.set(line, y);\n return y;\n }\n\n // Return the visual position for a character. Wrapped lines include the\n // visual line index so carets can be placed on the correct row.\n #getCharX(line: number, char: number): [x: number, wrapLine: number] {\n if (\n this.#lastCharX !== undefined &&\n this.#lastCharX[0] === line &&\n this.#lastCharX[1] === char\n ) {\n return [this.#lastCharX[2], this.#lastCharX[3]];\n }\n\n const lineText = this.#textDocument?.getLineText(line);\n const offsetLeft = this.#getGutterWidth() + this.#metrics.ch; // gutter width + inline padding (1ch)\n if (lineText === undefined || lineText.length === 0 || char <= 0) {\n return [offsetLeft, 0];\n }\n\n const boundedCharacter = snapTextOffsetToUnicodeBoundary(\n lineText,\n Math.min(char, lineText.length)\n );\n const textBeforeCharacter = lineText.slice(0, boundedCharacter);\n const asciiColumns = getExpandedAsciiTextColumns(\n textBeforeCharacter,\n this.#metrics.tabSize\n );\n\n let left = 0;\n let wrapLine = 0;\n if (asciiColumns !== -1) {\n left = offsetLeft + asciiColumns * this.#metrics.ch;\n } else {\n left = offsetLeft + this.#metrics.measureTextWidth(textBeforeCharacter);\n }\n\n if (this.#wrap) {\n const contentWidth = this.#getContentWidth();\n const textWidth =\n 2 * this.#metrics.ch + this.#metrics.measureTextWidth(lineText);\n if (textWidth > contentWidth) {\n const wrapOffsets = this.#wrapLineText(line);\n for (let w = 0; w + 1 < wrapOffsets.length; w++) {\n const segmentStart = wrapOffsets[w];\n const segmentEnd = wrapOffsets[w + 1];\n if (boundedCharacter <= segmentEnd) {\n wrapLine = w;\n const prefixInSegment = lineText.slice(\n segmentStart,\n boundedCharacter\n );\n const segmentAsciiColumns = getExpandedAsciiTextColumns(\n prefixInSegment,\n this.#metrics.tabSize\n );\n if (segmentAsciiColumns !== -1) {\n left = offsetLeft + segmentAsciiColumns * this.#metrics.ch;\n } else {\n left =\n offsetLeft + this.#metrics.measureTextWidth(prefixInSegment);\n }\n break;\n }\n }\n }\n }\n\n if (this.#lastCharX !== undefined) {\n this.#lastCharX[0] = line;\n this.#lastCharX[1] = char;\n this.#lastCharX[2] = left;\n this.#lastCharX[3] = wrapLine;\n } else {\n this.#lastCharX = [line, char, left, wrapLine];\n }\n\n return [left, wrapLine];\n }\n\n // Compute how a logical line of text is broken into visual lines when line\n // wrapping is enabled.\n #wrapLineText(line: number): Uint32Array {\n const cachedOffsets = this.#wrapLineOffsetsCache.get(line);\n if (cachedOffsets !== undefined) {\n return cachedOffsets;\n }\n\n const lineText = this.#textDocument?.getLineText(line);\n if (lineText === undefined || lineText.length === 0) {\n const offsets = new Uint32Array([0]);\n this.#wrapLineOffsetsCache.set(line, offsets);\n return offsets;\n }\n\n const div = h(\n 'div',\n {\n style: {\n position: 'absolute',\n top: '0',\n left: '0',\n width: '100%',\n boxSizing: 'border-box',\n visibility: 'hidden',\n pointerEvents: 'none',\n whiteSpace: 'pre-wrap',\n wordBreak: 'break-word',\n font: 'inherit',\n paddingInline: '1ch',\n tabSize: this.#metrics.tabSize.toString(),\n },\n textContent: lineText,\n },\n this.#contentElement\n );\n const textNode = div.firstChild as Text;\n const range = document.createRange();\n const starts: number[] = [];\n\n try {\n const unicodeOffsets = getUnicodeMeasurementOffsets(lineText);\n const wrapLineStartLeft =\n div.getBoundingClientRect().left + this.#metrics.ch;\n\n let previousOffset = 0;\n let lastTop = Number.NEGATIVE_INFINITY;\n\n for (let i = 0, offsetIndex = 0; i < lineText.length; ) {\n const nextOffset =\n unicodeOffsets === undefined\n ? i + 1\n : unicodeOffsets[offsetIndex + 1];\n range.setStart(textNode, i);\n range.setEnd(textNode, nextOffset);\n\n // A new visual line starts whenever the character's top edge moves\n // below the previous character's top edge.\n const { left, top } = range.getBoundingClientRect();\n if (top > lastTop) {\n // Safari can report the first range on a wrapped visual line as\n // starting one character past the visual line start. Use the previous\n // offset so segment-local caret math begins at the actual wrap point.\n const startsPastLineStart =\n isSafari() &&\n starts.length > 0 &&\n left - wrapLineStartLeft > this.#metrics.ch / 2;\n starts.push(startsPastLineStart ? previousOffset : i);\n lastTop = top;\n }\n previousOffset = i;\n i = nextOffset;\n offsetIndex++;\n }\n\n const offsets = new Uint32Array(starts.length + 1);\n for (let i = 0; i < starts.length; i++) {\n offsets[i] = starts[i]!;\n }\n offsets[starts.length] = lineText.length;\n this.#wrapLineOffsetsCache.set(line, offsets);\n return offsets;\n } finally {\n div.remove();\n }\n }\n\n // check if the web selection belongs to editor\n #rangeBelongsToEditor({ startContainer, endContainer }: StaticRange) {\n const contentEl = this.#contentElement;\n if (contentEl === undefined) {\n return false;\n }\n return (\n contentEl.contains(startContainer) && contentEl.contains(endContainer)\n );\n }\n\n // Check whether a line is visible in the currently rendered line window.\n #isLineVisible(line: number): boolean {\n const lineCount = this.#textDocument?.lineCount ?? 0;\n if (line < 0 || line >= lineCount) {\n return false;\n }\n if (this.#renderRange === undefined) {\n return true;\n }\n const { startingLine, totalLines } = this.#renderRange;\n if (line < startingLine) {\n return false;\n }\n if (totalLines === Infinity) {\n return true;\n }\n return line < startingLine + totalLines;\n }\n}\n"],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { Position, Range, ResolvedTextEdit, TextDocument, TextDocumentChange, TextEdit } from "./textDocument.js";
2
+ import { Editor, EditorOptions } from "./editor.js";
3
+ export { Editor, EditorOptions, Position, Range, ResolvedTextEdit, TextDocument, TextDocumentChange, TextEdit };
@@ -0,0 +1,4 @@
1
+ import { TextDocument } from "./textDocument.js";
2
+ import { Editor } from "./editor.js";
3
+
4
+ export { Editor, TextDocument };
@@ -0,0 +1,8 @@
1
+ import { DiffLineAnnotation } from "../types.js";
2
+ import { TextDocumentChange } from "./textDocument.js";
3
+
4
+ //#region src/editor/lineAnnotations.d.ts
5
+ declare function applyDocumentChangeToLineAnnotations<T>(change: TextDocumentChange, lineAnnotations: DiffLineAnnotation<T>[]): DiffLineAnnotation<T>[] | undefined;
6
+ //#endregion
7
+ export { applyDocumentChangeToLineAnnotations };
8
+ //# sourceMappingURL=lineAnnotations.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lineAnnotations.d.ts","names":["DiffLineAnnotation","TextDocumentChange","applyDocumentChangeToLineAnnotations","T"],"sources":["../../src/editor/lineAnnotations.d.ts"],"sourcesContent":["import type { DiffLineAnnotation } from '../types';\nimport type { TextDocumentChange } from './textDocument';\nexport declare function applyDocumentChangeToLineAnnotations<T>(change: TextDocumentChange, lineAnnotations: DiffLineAnnotation<T>[]): DiffLineAnnotation<T>[] | undefined;\n//# sourceMappingURL=lineAnnotations.d.ts.map"],"mappings":";;;;iBAEwBE,gDAAgDD,qCAAqCD,mBAAmBG,OAAOH,mBAAmBG"}
@@ -0,0 +1,32 @@
1
+ //#region src/editor/lineAnnotations.ts
2
+ function applyDocumentChangeToLineAnnotations(change, lineAnnotations) {
3
+ if (change.lineDelta === 0) return;
4
+ const startCharacter = change.startCharacter;
5
+ const removedLineCount = Math.max(0, -change.lineDelta);
6
+ const deletedStartLine = removedLineCount === 0 ? void 0 : change.startLine + (startCharacter === 0 ? 0 : 1);
7
+ const deletedEndLine = deletedStartLine === void 0 ? void 0 : deletedStartLine + removedLineCount;
8
+ const shiftFromLine = removedLineCount > 0 ? change.startLine + removedLineCount : change.startLine + (startCharacter === 0 ? 0 : 1);
9
+ const nextLineAnnotations = [];
10
+ let changed = false;
11
+ for (const annotation of lineAnnotations) {
12
+ const line = annotation.lineNumber - 1;
13
+ if (deletedStartLine !== void 0 && deletedEndLine !== void 0 && line >= deletedStartLine && line < deletedEndLine) {
14
+ changed = true;
15
+ continue;
16
+ }
17
+ if (line >= shiftFromLine) {
18
+ nextLineAnnotations.push({
19
+ ...annotation,
20
+ lineNumber: line + change.lineDelta + 1
21
+ });
22
+ changed = true;
23
+ continue;
24
+ }
25
+ nextLineAnnotations.push(annotation);
26
+ }
27
+ return changed ? nextLineAnnotations : void 0;
28
+ }
29
+
30
+ //#endregion
31
+ export { applyDocumentChangeToLineAnnotations };
32
+ //# sourceMappingURL=lineAnnotations.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lineAnnotations.js","names":["nextLineAnnotations: DiffLineAnnotation<T>[]"],"sources":["../../src/editor/lineAnnotations.ts"],"sourcesContent":["import type { DiffLineAnnotation } from '../types';\nimport type { TextDocumentChange } from './textDocument';\n\nexport function applyDocumentChangeToLineAnnotations<T>(\n change: TextDocumentChange,\n lineAnnotations: DiffLineAnnotation<T>[]\n): DiffLineAnnotation<T>[] | undefined {\n if (change.lineDelta === 0) {\n return undefined;\n }\n\n const startCharacter = change.startCharacter;\n const removedLineCount = Math.max(0, -change.lineDelta);\n const deletedStartLine =\n removedLineCount === 0\n ? undefined\n : change.startLine + (startCharacter === 0 ? 0 : 1);\n const deletedEndLine =\n deletedStartLine === undefined\n ? undefined\n : deletedStartLine + removedLineCount;\n const shiftFromLine =\n removedLineCount > 0\n ? change.startLine + removedLineCount\n : change.startLine + (startCharacter === 0 ? 0 : 1);\n const nextLineAnnotations: DiffLineAnnotation<T>[] = [];\n\n let changed = false;\n for (const annotation of lineAnnotations) {\n const line = annotation.lineNumber - 1;\n if (\n deletedStartLine !== undefined &&\n deletedEndLine !== undefined &&\n line >= deletedStartLine &&\n line < deletedEndLine\n ) {\n changed = true;\n continue;\n }\n\n if (line >= shiftFromLine) {\n nextLineAnnotations.push({\n ...annotation,\n lineNumber: line + change.lineDelta + 1,\n });\n changed = true;\n continue;\n }\n\n nextLineAnnotations.push(annotation);\n }\n\n return changed ? nextLineAnnotations : undefined;\n}\n"],"mappings":";AAGA,SAAgB,qCACd,QACA,iBACqC;AACrC,KAAI,OAAO,cAAc,EACvB;CAGF,MAAM,iBAAiB,OAAO;CAC9B,MAAM,mBAAmB,KAAK,IAAI,GAAG,CAAC,OAAO,UAAU;CACvD,MAAM,mBACJ,qBAAqB,IACjB,SACA,OAAO,aAAa,mBAAmB,IAAI,IAAI;CACrD,MAAM,iBACJ,qBAAqB,SACjB,SACA,mBAAmB;CACzB,MAAM,gBACJ,mBAAmB,IACf,OAAO,YAAY,mBACnB,OAAO,aAAa,mBAAmB,IAAI,IAAI;CACrD,MAAMA,sBAA+C,EAAE;CAEvD,IAAI,UAAU;AACd,MAAK,MAAM,cAAc,iBAAiB;EACxC,MAAM,OAAO,WAAW,aAAa;AACrC,MACE,qBAAqB,UACrB,mBAAmB,UACnB,QAAQ,oBACR,OAAO,gBACP;AACA,aAAU;AACV;;AAGF,MAAI,QAAQ,eAAe;AACzB,uBAAoB,KAAK;IACvB,GAAG;IACH,YAAY,OAAO,OAAO,YAAY;IACvC,CAAC;AACF,aAAU;AACV;;AAGF,sBAAoB,KAAK,WAAW;;AAGtC,QAAO,UAAU,sBAAsB"}
@@ -0,0 +1,33 @@
1
+ import { SearchParams } from "./searchPanel.js";
2
+ import { Position, Range, ResolvedTextEdit } from "./textDocument.js";
3
+
4
+ //#region src/editor/pieceTable.d.ts
5
+
6
+ /**
7
+ * A piece table is a data structure that allows for efficient insertion and deletion of text.
8
+ * It is a tree of pieces, where each piece is a segment of text that is either original or added.
9
+ * The tree is rebuilt as a balanced tree after edits to keep lookups efficient.
10
+ * Inspired by https://code.visualstudio.com/blogs/2018/03/23/text-buffer-reimplementation
11
+ */
12
+ declare class PieceTable {
13
+ #private;
14
+ constructor(originalText: string);
15
+ get lineCount(): number;
16
+ getText(range?: Range): string;
17
+ getLineText(line: number, trimEOF?: boolean): string;
18
+ getTextSlice(start: number, end: number, trimEOF?: boolean): string;
19
+ charAt(offset: number): string;
20
+ includes(needle: string): boolean;
21
+ findNextNonOverlappingSubstring(needle: string, occupied: readonly [start: number, end: number][]): number | undefined;
22
+ search(kind: 'findNext' | 'findPrevious' | 'findAll' | 'replace' | 'replaceAll', searchParams: SearchParams, range?: Range): [start: number, end: number][];
23
+ insert(text: string, offset: number): void;
24
+ delete(offset: number, length: number): void;
25
+ applyEdits(edits: readonly ResolvedTextEdit[]): void;
26
+ positionAt(offset: number): Position;
27
+ positionsAt(offsets: readonly number[]): Position[];
28
+ offsetAt(position: Position): number;
29
+ offsetsAt(positions: readonly Position[]): number[];
30
+ }
31
+ //#endregion
32
+ export { PieceTable };
33
+ //# sourceMappingURL=pieceTable.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pieceTable.d.ts","names":["SearchParams","Position","Range","ResolvedTextEdit","PieceTable"],"sources":["../../src/editor/pieceTable.d.ts"],"sourcesContent":["import type { SearchParams } from './searchPanel';\nimport type { Position, Range, ResolvedTextEdit } from './textDocument';\n/**\n * A piece table is a data structure that allows for efficient insertion and deletion of text.\n * It is a tree of pieces, where each piece is a segment of text that is either original or added.\n * The tree is rebuilt as a balanced tree after edits to keep lookups efficient.\n * Inspired by https://code.visualstudio.com/blogs/2018/03/23/text-buffer-reimplementation\n */\nexport declare class PieceTable {\n #private;\n constructor(originalText: string);\n get lineCount(): number;\n getText(range?: Range): string;\n getLineText(line: number, trimEOF?: boolean): string;\n getTextSlice(start: number, end: number, trimEOF?: boolean): string;\n charAt(offset: number): string;\n includes(needle: string): boolean;\n findNextNonOverlappingSubstring(needle: string, occupied: readonly [start: number, end: number][]): number | undefined;\n search(kind: 'findNext' | 'findPrevious' | 'findAll' | 'replace' | 'replaceAll', searchParams: SearchParams, range?: Range): [start: number, end: number][];\n insert(text: string, offset: number): void;\n delete(offset: number, length: number): void;\n applyEdits(edits: readonly ResolvedTextEdit[]): void;\n positionAt(offset: number): Position;\n positionsAt(offsets: readonly number[]): Position[];\n offsetAt(position: Position): number;\n offsetsAt(positions: readonly Position[]): number[];\n}\n//# sourceMappingURL=pieceTable.d.ts.map"],"mappings":";;;;;;;AAQA;;;;AAa+BG,cAbVC,UAAAA,CAaUD;EACCF,CAAAA,OAAAA;EACaA,WAAAA,CAAAA,YAAAA,EAAAA,MAAAA;EACtBA,IAAAA,SAAAA,CAAAA,CAAAA,EAAAA,MAAAA;EACWA,OAAAA,CAAAA,KAAAA,CAAAA,EAbdC,KAacD,CAAAA,EAAAA,MAAAA;EAAQ,WAAA,CAAA,IAAA,EAAA,MAAA,EAAA,OAAA,CAAA,EAAA,OAAA,CAAA,EAAA,MAAA;;;;;iGAPyDD,sBAAsBE;;;6BAG1FC;8BACCF;2CACaA;qBACtBA;gCACWA"}