@pierre/diffs 1.3.0-beta.7 → 1.3.0-beta.8

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 (110) hide show
  1. package/dist/components/CodeView.d.ts +86 -4
  2. package/dist/components/CodeView.d.ts.map +1 -1
  3. package/dist/components/CodeView.js +246 -32
  4. package/dist/components/CodeView.js.map +1 -1
  5. package/dist/components/File.d.ts +1 -0
  6. package/dist/components/File.d.ts.map +1 -1
  7. package/dist/components/File.js +15 -4
  8. package/dist/components/File.js.map +1 -1
  9. package/dist/components/FileDiff.d.ts +2 -0
  10. package/dist/components/FileDiff.d.ts.map +1 -1
  11. package/dist/components/FileDiff.js +21 -6
  12. package/dist/components/FileDiff.js.map +1 -1
  13. package/dist/components/VirtualizedFile.d.ts.map +1 -1
  14. package/dist/components/VirtualizedFile.js +3 -1
  15. package/dist/components/VirtualizedFile.js.map +1 -1
  16. package/dist/components/VirtualizedFileDiff.d.ts +3 -1
  17. package/dist/components/VirtualizedFileDiff.d.ts.map +1 -1
  18. package/dist/components/VirtualizedFileDiff.js +14 -6
  19. package/dist/components/VirtualizedFileDiff.js.map +1 -1
  20. package/dist/components/Virtualizer.d.ts +2 -0
  21. package/dist/components/Virtualizer.d.ts.map +1 -1
  22. package/dist/components/Virtualizer.js +16 -3
  23. package/dist/components/Virtualizer.js.map +1 -1
  24. package/dist/constants.d.ts +3 -1
  25. package/dist/constants.d.ts.map +1 -1
  26. package/dist/constants.js +3 -1
  27. package/dist/constants.js.map +1 -1
  28. package/dist/editor/command.d.ts +1 -1
  29. package/dist/editor/command.d.ts.map +1 -1
  30. package/dist/editor/command.js +8 -0
  31. package/dist/editor/command.js.map +1 -1
  32. package/dist/editor/editor.d.ts +8 -1
  33. package/dist/editor/editor.d.ts.map +1 -1
  34. package/dist/editor/editor.js +171 -38
  35. package/dist/editor/editor.js.map +1 -1
  36. package/dist/editor/editor2.js +1 -1
  37. package/dist/editor/lineAnnotations.d.ts.map +1 -1
  38. package/dist/editor/lineAnnotations.js +84 -12
  39. package/dist/editor/lineAnnotations.js.map +1 -1
  40. package/dist/editor/marker.d.ts +5 -3
  41. package/dist/editor/marker.d.ts.map +1 -1
  42. package/dist/editor/marker.js +35 -12
  43. package/dist/editor/marker.js.map +1 -1
  44. package/dist/editor/matchBrackets.d.ts +8 -0
  45. package/dist/editor/matchBrackets.d.ts.map +1 -0
  46. package/dist/editor/matchBrackets.js +146 -0
  47. package/dist/editor/matchBrackets.js.map +1 -0
  48. package/dist/editor/popover.d.ts +45 -0
  49. package/dist/editor/popover.d.ts.map +1 -0
  50. package/dist/editor/popover.js +145 -0
  51. package/dist/editor/popover.js.map +1 -0
  52. package/dist/editor/selection.d.ts +13 -1
  53. package/dist/editor/selection.d.ts.map +1 -1
  54. package/dist/editor/selection.js +55 -4
  55. package/dist/editor/selection.js.map +1 -1
  56. package/dist/editor/selectionAction.d.ts +20 -3
  57. package/dist/editor/selectionAction.d.ts.map +1 -1
  58. package/dist/editor/selectionAction.js +41 -10
  59. package/dist/editor/selectionAction.js.map +1 -1
  60. package/dist/editor/textDocument.d.ts +2 -0
  61. package/dist/editor/textDocument.d.ts.map +1 -1
  62. package/dist/editor/textDocument.js +22 -6
  63. package/dist/editor/textDocument.js.map +1 -1
  64. package/dist/editor/tokenzier.d.ts +4 -7
  65. package/dist/editor/tokenzier.d.ts.map +1 -1
  66. package/dist/editor/tokenzier.js +76 -35
  67. package/dist/editor/tokenzier.js.map +1 -1
  68. package/dist/index.d.ts +6 -6
  69. package/dist/index.js +4 -4
  70. package/dist/managers/ResizeManager.d.ts +10 -2
  71. package/dist/managers/ResizeManager.d.ts.map +1 -1
  72. package/dist/managers/ResizeManager.js +33 -13
  73. package/dist/managers/ResizeManager.js.map +1 -1
  74. package/dist/react/CodeView.d.ts +25 -1
  75. package/dist/react/CodeView.d.ts.map +1 -1
  76. package/dist/react/CodeView.js +76 -17
  77. package/dist/react/CodeView.js.map +1 -1
  78. package/dist/react/EditorContext.d.ts +2 -2
  79. package/dist/react/EditorContext.d.ts.map +1 -1
  80. package/dist/react/EditorContext.js.map +1 -1
  81. package/dist/react/index.d.ts +2 -2
  82. package/dist/renderers/DiffHunksRenderer.d.ts +1 -1
  83. package/dist/renderers/DiffHunksRenderer.d.ts.map +1 -1
  84. package/dist/renderers/DiffHunksRenderer.js +24 -15
  85. package/dist/renderers/DiffHunksRenderer.js.map +1 -1
  86. package/dist/renderers/FileRenderer.d.ts +2 -1
  87. package/dist/renderers/FileRenderer.d.ts.map +1 -1
  88. package/dist/renderers/FileRenderer.js +58 -38
  89. package/dist/renderers/FileRenderer.js.map +1 -1
  90. package/dist/ssr/index.d.ts +2 -2
  91. package/dist/types.d.ts +42 -2
  92. package/dist/types.d.ts.map +1 -1
  93. package/dist/utils/applyLineTextWithNewline.d.ts +5 -0
  94. package/dist/utils/applyLineTextWithNewline.d.ts.map +1 -0
  95. package/dist/utils/applyLineTextWithNewline.js +11 -0
  96. package/dist/utils/applyLineTextWithNewline.js.map +1 -0
  97. package/dist/utils/areManagedSnapshotsEqual.d.ts +2 -2
  98. package/dist/utils/areManagedSnapshotsEqual.d.ts.map +1 -1
  99. package/dist/utils/areManagedSnapshotsEqual.js +5 -0
  100. package/dist/utils/areManagedSnapshotsEqual.js.map +1 -1
  101. package/dist/utils/createCodeViewHeaderFooterHostElement.d.ts +5 -0
  102. package/dist/utils/createCodeViewHeaderFooterHostElement.d.ts.map +1 -0
  103. package/dist/utils/createCodeViewHeaderFooterHostElement.js +19 -0
  104. package/dist/utils/createCodeViewHeaderFooterHostElement.js.map +1 -0
  105. package/dist/utils/updateDiffHunks.d.ts.map +1 -1
  106. package/dist/utils/updateDiffHunks.js +23 -1
  107. package/dist/utils/updateDiffHunks.js.map +1 -1
  108. package/dist/worker/worker-portable.js.map +1 -1
  109. package/dist/worker/worker.js.map +1 -1
  110. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"selectionAction.js","names":["#popover"],"sources":["../../src/editor/selectionAction.ts"],"sourcesContent":["import type { EditorSelection } from './selection';\nimport type { TextDocument, TextEdit } from './textDocument';\nimport { h } from './utils';\n\nexport interface SelectionActionContext<LAnnotation> {\n /** The current selection (live: reflects keyboard-driven changes). */\n selection: EditorSelection;\n /** The text document. */\n textDocument: TextDocument<LAnnotation>;\n /** Applies the edits to the text document. */\n applyEdits: (edits: TextEdit[]) => void;\n /** Gets the text of the current selection. */\n getSelectionText: () => string;\n /** Replaces the text of the current selection. */\n replaceSelectionText: (text: string) => void;\n /** Closes the selection action. */\n close: () => void;\n}\n\n// Floating popover that hosts the consumer's selection-action element. It mounts\n// into the editor's overlay layer and is positioned via CSS custom properties\n// (the shared popover rule in editor.css), mirroring the marker hover popover, so\n// it never reflows the document the way the old inline gutter-triggered row did.\n// The consumer's element can hold any number of actions; the editor only owns\n// where the popover sits.\nexport class SelectionActionWidget {\n // The line the popover is anchored to (the selection's head). The editor reads\n // this to decide whether the anchor is still on a visible line.\n line: number;\n #popover: HTMLElement;\n\n constructor(\n line: number,\n selectionActionElement: HTMLElement,\n overlayElement: HTMLElement\n ) {\n this.line = line;\n this.#popover = h(\n 'div',\n {\n dataset: { editorWidget: '', selectionActionPopover: '' },\n contentEditable: 'false',\n children: [selectionActionElement],\n },\n overlayElement\n );\n }\n\n // Anchor the popover at `(left, top)`, expressed in the overlay's coordinate\n // space (the same space caret/selection overlays use). Horizontal placement and\n // sizing are handled in CSS via the shared popover rule; `gutterWidth` lets it\n // keep the popover clear of the line-number gutter.\n reposition(left: number, top: number, gutterWidth: number): void {\n this.#popover.style.setProperty('--gutter-width', gutterWidth + 'px');\n this.#popover.style.setProperty('--popover-x', left + 'px');\n this.#popover.style.setProperty('--popover-y', top + 'px');\n }\n\n cleanup(): void {\n this.#popover.remove();\n }\n}\n"],"mappings":";;AAyBA,IAAa,wBAAb,MAAmC;CAGjC;CACA;CAEA,YACE,MACA,wBACA,gBACA;EACA,KAAK,OAAO;EACZ,KAAKA,WAAW,EACd,OACA;GACE,SAAS;IAAE,cAAc;IAAI,wBAAwB;GAAG;GACxD,iBAAiB;GACjB,UAAU,CAAC,sBAAsB;EACnC,GACA,cACF;CACF;CAMA,WAAW,MAAc,KAAa,aAA2B;EAC/D,KAAKA,SAAS,MAAM,YAAY,kBAAkB,cAAc,IAAI;EACpE,KAAKA,SAAS,MAAM,YAAY,eAAe,OAAO,IAAI;EAC1D,KAAKA,SAAS,MAAM,YAAY,eAAe,MAAM,IAAI;CAC3D;CAEA,UAAgB;EACd,KAAKA,SAAS,OAAO;CACvB;AACF"}
1
+ {"version":3,"file":"selectionAction.js","names":["#root","#height","#resizeObserver"],"sources":["../../src/editor/selectionAction.ts"],"sourcesContent":["import type { EditorSelection } from './selection';\nimport type { TextDocument, TextEdit } from './textDocument';\nimport { h } from './utils';\n\nexport interface SelectionActionContext<LAnnotation> {\n /** The current selection (live: reflects keyboard-driven changes). */\n selection: EditorSelection;\n /** The text document. */\n textDocument: TextDocument<LAnnotation>;\n /** Applies the edits to the text document. */\n applyEdits: (edits: TextEdit[]) => void;\n /** Gets the text of the current selection. */\n getSelectionText: () => string;\n /** Replaces the text of the current selection. */\n replaceSelectionText: (text: string) => void;\n /** Closes the selection action. */\n close: () => void;\n}\n\n/**\n * Selection action widget.\n */\nexport class SelectionActionWidget {\n #root: HTMLElement;\n // Cached border-box height, refreshed only when the popover's own size\n // actually changes (via #resizeObserver below)\n #height: number;\n #resizeObserver: ResizeObserver;\n\n constructor(\n selectionActionElement: HTMLElement,\n overlayElement: HTMLElement,\n onHeightChange: () => void\n ) {\n this.#root = h(\n 'div',\n {\n dataset: { editorWidget: '', selectionActionPopover: '' },\n contentEditable: 'false',\n children: [selectionActionElement],\n },\n overlayElement\n );\n this.#height = this.#root.offsetHeight;\n this.#resizeObserver = new ResizeObserver(() => {\n const height = this.#root.offsetHeight;\n if (height !== this.#height) {\n this.#height = height;\n onHeightChange();\n }\n });\n this.#resizeObserver.observe(this.#root);\n }\n\n /**\n * Repositions the selection action widget.\n * @param left - The left position of the selection action widget.\n * @param top - The top position of the selection action widget.\n * @param gutterWidth - The width of the gutter.\n * @param placeAbove - Whether the selection action widget should be placed above the anchor.\n */\n reposition(\n left: number,\n top: number,\n gutterWidth: number,\n placeAbove: boolean\n ): void {\n this.#root.style.setProperty('--gutter-width', gutterWidth + 'px');\n this.#root.style.setProperty('--popover-x', left + 'px');\n this.#root.style.setProperty('--popover-y', top + 'px');\n this.#root.style.setProperty(\n '--popover-y-shift',\n placeAbove ? '-100%' : '0px'\n );\n }\n\n /**\n * Gets the height of the selection action widget.\n * @returns The height of the selection action widget.\n */\n get height(): number {\n return this.#height;\n }\n\n /**\n * Cleans up the selection action widget.\n */\n cleanup(): void {\n this.#resizeObserver.disconnect();\n this.#root.remove();\n }\n}\n"],"mappings":";;;;;AAsBA,IAAa,wBAAb,MAAmC;CACjC;CAGA;CACA;CAEA,YACE,wBACA,gBACA,gBACA;EACA,KAAKA,QAAQ,EACX,OACA;GACE,SAAS;IAAE,cAAc;IAAI,wBAAwB;GAAG;GACxD,iBAAiB;GACjB,UAAU,CAAC,sBAAsB;EACnC,GACA,cACF;EACA,KAAKC,UAAU,KAAKD,MAAM;EAC1B,KAAKE,kBAAkB,IAAI,qBAAqB;GAC9C,MAAM,SAAS,KAAKF,MAAM;GAC1B,IAAI,WAAW,KAAKC,SAAS;IAC3B,KAAKA,UAAU;IACf,eAAe;GACjB;EACF,CAAC;EACD,KAAKC,gBAAgB,QAAQ,KAAKF,KAAK;CACzC;;;;;;;;CASA,WACE,MACA,KACA,aACA,YACM;EACN,KAAKA,MAAM,MAAM,YAAY,kBAAkB,cAAc,IAAI;EACjE,KAAKA,MAAM,MAAM,YAAY,eAAe,OAAO,IAAI;EACvD,KAAKA,MAAM,MAAM,YAAY,eAAe,MAAM,IAAI;EACtD,KAAKA,MAAM,MAAM,YACf,qBACA,aAAa,UAAU,KACzB;CACF;;;;;CAMA,IAAI,SAAiB;EACnB,OAAO,KAAKC;CACd;;;;CAKA,UAAgB;EACd,KAAKC,gBAAgB,WAAW;EAChC,KAAKF,MAAM,OAAO;CACpB;AACF"}
@@ -101,6 +101,8 @@ interface TextDocumentChange {
101
101
  readonly lineDelta: number;
102
102
  /** Exact rendered line ranges touched by each edit after the edit was applied. */
103
103
  readonly changedLineRanges: readonly [startLine: number, endLine: number][];
104
+ /** Per-edit rendered line ranges before adjacent ranges are coalesced. */
105
+ readonly changedLineChanges?: readonly [startLine: number, endLine: number, lineDelta: number][];
104
106
  }
105
107
  /**
106
108
  * A vscode-languageserver-textdocument compatible text document.
@@ -1 +1 @@
1
- {"version":3,"file":"textDocument.d.ts","names":[],"sources":["../../src/editor/textDocument.ts"],"mappings":";;;;;;;;AAsBA;;;;AAoBoB;AAgBpB;;;UApCiB,QAAA;EAwCN;;;;;AAIa;AAMxB;;;EAVW,SA9BA,IAAA;EA6CA;;;;AAKO;AAIlB;;;;EATW,SAnCA,SAAS;AAAA;;;AAqDL;AAGf;;;;;;;;;;UAxCiB,KAAA;EAsDuB;;;EAAA,SAlD7B,KAAA,EAAO,QAAA;EAwDL;;;EAAA,SApDF,GAAA,EAAK,QAAQ;AAAA;;;;UAMP,QAAA;EAyJE;;;;EAAA,SApJR,KAAA,EAAO,KAAK;EAiLlB;;;;EAAA,SA5KM,OAAA;AAAA;;UAIM,gBAAA;EAsO4B;EAAA,SApOlC,KAAA;EA8OK;EAAA,SA5OL,GAAA;EA8OkC;;;;EAAA,SAzOlC,IAAA;AAAA;AAAA,UAGM,kBAAA;EAgRwB;EAAA,SA9Q9B,SAAA;EA8QsC;EAAA,SA5QtC,cAAA;;WAEA,OAAA;EAsBP;EAAA,SApBO,iBAAA;EAsBP;EAAA,SApBO,SAAA;EAsBI;EAAA,SApBJ,SAAA;EAoBP;EAAA,SAlBO,iBAAA,YAA6B,SAAA,UAAmB,OAAA;AAAA;;;;cAM9C,YAAA;EAAA;EAOX,WAAA,CACE,GAAA,UACA,IAAA,UACA,UAAA,WACA,OAAA,WACA,SAAA,GAAW,SAAA,CAAU,WAAA;EAAA,IASnB,GAAA;EAAA,IAIA,UAAA;EAAA,IAIA,OAAA;EAAA,IAIA,SAAA;EAAA,IASA,GAAA;EAAA,IAaA,OAAA;EAAA,IAIA,OAAA;EAIJ,UAAA,CAAW,MAAA,WAAiB,QAAA;EAI5B,WAAA,CAAY,OAAA,sBAA6B,QAAA;EAIzC,QAAA,CAAS,QAAA,EAAU,QAAA;EAInB,OAAA,CAAQ,KAAA,GAAQ,KAAA;EAgBhB,WAAA,CAAY,IAAA,UAAc,gBAAA;EAO1B,YAAA,CAAa,IAAA;EAIb,aAAA,CAAc,IAAA,UAAc,gBAAA;EAI5B,MAAA,CAAO,MAAA;EACP,MAAA,CAAO,QAAA,EAAU,QAAA;EAQjB,YAAA,CAAa,KAAA,UAAe,GAAA;EAI5B,+BAAA,CACE,MAAA,UACA,QAAA,YAAoB,KAAA,UAAe,GAAA;EAKrC,MAAA,CAAO,YAAA,EAAc,YAAA,IAAgB,KAAA,UAAe,GAAA;EAIpD,UAAA,CACE,KAAA,EAAO,QAAA,IACP,aAAA,YACA,gBAAA,GAAmB,eAAA,IACnB,eAAA,GAAkB,eAAA,IAClB,YAAA,aACC,kBAAA;EAaH,kBAAA,CACE,KAAA,EAAO,gBAAA,IACP,aAAA,YACA,gBAAA,GAAmB,eAAA,IACnB,eAAA,GAAkB,eAAA,IAClB,YAAA,aACC,kBAAA;EAqCH,0BAAA,CAA2B,UAAA,EAAY,eAAA;EAIvC,0BAAA,CACE,qBAAA,EAAuB,kBAAA,CAAmB,WAAA,KAC1C,oBAAA,EAAsB,kBAAA,CAAmB,WAAA;EAQ3C,IAAA,KAEM,MAAA,EAAQ,kBAAA,EACR,UAAA,GAAa,eAAA,IACb,eAAA,GAAkB,kBAAA,CAAmB,WAAA;EAmB3C,IAAA,KAEM,MAAA,EAAQ,kBAAA,EACR,UAAA,GAAa,eAAA,IACb,eAAA,GAAkB,kBAAA,CAAmB,WAAA;EAmB3C,iBAAA,CAAkB,QAAA,EAAU,QAAA,GAAW,QAAA;AAAA"}
1
+ {"version":3,"file":"textDocument.d.ts","names":[],"sources":["../../src/editor/textDocument.ts"],"mappings":";;;;;;;;AAsBA;;;;AAoBoB;AAgBpB;;;UApCiB,QAAA;EAwCN;;;;;AAIa;AAMxB;;;EAVW,SA9BA,IAAA;EA6CA;;;;AAKO;AAIlB;;;;EATW,SAnCA,SAAS;AAAA;;;AAqDL;AAGf;;;;;;;;;;UAxCiB,KAAA;EAsDuB;;;EAAA,SAlD7B,KAAA,EAAO,QAAA;EAsDd;;;EAAA,SAlDO,GAAA,EAAK,QAAQ;AAAA;;;;UAMP,QAAA;EAmHa;;;;EAAA,SA9GnB,KAAA,EAAO,KAAK;EA6KA;;;;EAAA,SAxKZ,OAAA;AAAA;;UAIM,gBAAA;EAiMZ;EAAA,SA/LM,KAAA;EAyOmC;EAAA,SAvOnC,GAAA;EAwOkC;;;;EAAA,SAnOlC,IAAA;AAAA;AAAA,UAGM,kBAAA;EAkQI;EAAA,SAhQV,SAAA;EAiQe;EAAA,SA/Pf,cAAA;EAkR8B;EAAA,SAhR9B,OAAA;EAgRsC;EAAA,SA9QtC,iBAAA;;WAEA,SAAA;EAwBP;EAAA,SAtBO,SAAA;EAwBP;EAAA,SAtBO,iBAAA,YAA6B,SAAA,UAAmB,OAAA;EAwB5C;EAAA,SAtBJ,kBAAA,aACP,SAAA,UACA,OAAA,UACA,SAAA;AAAA;;;;cAOS,YAAA;EAAA;EAOX,WAAA,CACE,GAAA,UACA,IAAA,UACA,UAAA,WACA,OAAA,WACA,SAAA,GAAW,SAAA,CAAU,WAAA;EAAA,IASnB,GAAA;EAAA,IAIA,UAAA;EAAA,IAIA,OAAA;EAAA,IAIA,SAAA;EAAA,IASA,GAAA;EAAA,IAaA,OAAA;EAAA,IAIA,OAAA;EAIJ,UAAA,CAAW,MAAA,WAAiB,QAAA;EAI5B,WAAA,CAAY,OAAA,sBAA6B,QAAA;EAIzC,QAAA,CAAS,QAAA,EAAU,QAAA;EAInB,OAAA,CAAQ,KAAA,GAAQ,KAAA;EAgBhB,WAAA,CAAY,IAAA,UAAc,gBAAA;EAO1B,YAAA,CAAa,IAAA;EAIb,aAAA,CAAc,IAAA,UAAc,gBAAA;EAI5B,MAAA,CAAO,MAAA;EACP,MAAA,CAAO,QAAA,EAAU,QAAA;EAQjB,YAAA,CAAa,KAAA,UAAe,GAAA;EAI5B,+BAAA,CACE,MAAA,UACA,QAAA,YAAoB,KAAA,UAAe,GAAA;EAKrC,MAAA,CAAO,YAAA,EAAc,YAAA,IAAgB,KAAA,UAAe,GAAA;EAIpD,UAAA,CACE,KAAA,EAAO,QAAA,IACP,aAAA,YACA,gBAAA,GAAmB,eAAA,IACnB,eAAA,GAAkB,eAAA,IAClB,YAAA,aACC,kBAAA;EAaH,kBAAA,CACE,KAAA,EAAO,gBAAA,IACP,aAAA,YACA,gBAAA,GAAmB,eAAA,IACnB,eAAA,GAAkB,eAAA,IAClB,YAAA,aACC,kBAAA;EAqCH,0BAAA,CAA2B,UAAA,EAAY,eAAA;EAIvC,0BAAA,CACE,qBAAA,EAAuB,kBAAA,CAAmB,WAAA,KAC1C,oBAAA,EAAsB,kBAAA,CAAmB,WAAA;EAQ3C,IAAA,KAEM,MAAA,EAAQ,kBAAA,EACR,UAAA,GAAa,eAAA,IACb,eAAA,GAAkB,kBAAA,CAAmB,WAAA;EAmB3C,IAAA,KAEM,MAAA,EAAQ,kBAAA,EACR,UAAA,GAAa,eAAA,IACb,eAAA,GAAkB,kBAAA,CAAmB,WAAA;EAmB3C,iBAAA,CAAkB,QAAA,EAAU,QAAA,GAAW,QAAA;AAAA"}
@@ -173,7 +173,8 @@ var TextDocument = class {
173
173
  previousLineCount,
174
174
  lineCount,
175
175
  lineDelta: lineCount - previousLineCount,
176
- changedLineRanges: changedLineRange.ranges
176
+ changedLineRanges: changedLineRange.ranges,
177
+ changedLineChanges: changedLineRange.changes
177
178
  };
178
179
  }
179
180
  #computeChangedLineRange(edits, editPositions) {
@@ -181,29 +182,44 @@ var TextDocument = class {
181
182
  let endLine = 0;
182
183
  let lineDeltaBeforeEdit = 0;
183
184
  const ranges = [];
185
+ const changes = [];
184
186
  for (let i = 0; i < edits.length; i++) {
185
187
  const edit = edits[i];
186
- const editStartLine = editPositions[i * 2].line;
187
- const editEndLine = editPositions[i * 2 + 1].line;
188
+ const editStart = editPositions[i * 2];
189
+ const editEnd = editPositions[i * 2 + 1];
190
+ const editStartLine = editStart.line;
191
+ const editEndLine = editEnd.line;
188
192
  const insertedLineSpan = countLineBreaks(edit.text);
189
193
  const changedStartLine = editStartLine + lineDeltaBeforeEdit;
190
194
  const changedEndLine = changedStartLine + insertedLineSpan;
195
+ const lineDelta = insertedLineSpan - (editEndLine - editStartLine);
191
196
  startLine = Math.min(startLine, editStartLine);
192
197
  endLine = Math.max(endLine, changedEndLine);
193
198
  const lastRange = ranges[ranges.length - 1];
194
199
  if (lastRange !== void 0 && changedStartLine <= lastRange[1] + 1) ranges[ranges.length - 1] = [lastRange[0], Math.max(lastRange[1], changedEndLine)];
195
200
  else ranges.push([changedStartLine, changedEndLine]);
196
- lineDeltaBeforeEdit += insertedLineSpan - (editEndLine - editStartLine);
201
+ changes.push([
202
+ changedStartLine,
203
+ changedEndLine,
204
+ lineDelta
205
+ ]);
206
+ lineDeltaBeforeEdit += lineDelta;
197
207
  }
198
208
  if (startLine === Infinity) return {
199
209
  startLine: 0,
200
210
  endLine: 0,
201
- ranges: [[0, 0]]
211
+ ranges: [[0, 0]],
212
+ changes: [[
213
+ 0,
214
+ 0,
215
+ 0
216
+ ]]
202
217
  };
203
218
  return {
204
219
  startLine,
205
220
  endLine,
206
- ranges
221
+ ranges,
222
+ changes
207
223
  };
208
224
  }
209
225
  };
@@ -1 +1 @@
1
- {"version":3,"file":"textDocument.js","names":["#uri","#languageId","#version","#pieceTable","#editStack","#resolveEdit","#sortAndValidateResolvedEdits","#applyResolvedEditsToBuffer","#computeChangedLineRange"],"sources":["../../src/editor/textDocument.ts"],"sourcesContent":["import type { DiffLineAnnotation } from '../types';\nimport { countLineBreaks } from '../utils/computeFileOffsets';\nimport {\n coalesceEditStackEntries,\n createEditStackEntry,\n EditStack,\n shouldCoalesceEditStackEntry,\n} from './editStack';\nimport { PieceTable } from './pieceTable';\nimport type { SearchParams } from './searchPanel';\nimport { type EditorSelection } from './selection';\n\n/**\n * Position in a text document expressed as zero-based line and character offset.\n * The offsets are based on a UTF-16 string representation. So a string of the form\n * `a𐐀b` the character offset of the character `a` is 0, the character offset of `𐐀`\n * is 1 and the character offset of b is 3 since `𐐀` is represented using two code\n * units in UTF-16.\n *\n * Positions are line end character agnostic. So you can not specify a position that\n * denotes `\\r|\\n` or `\\n|` where `|` represents the character offset.\n */\nexport interface Position {\n /**\n * Line position in a document (zero-based).\n *\n * If a line number is greater than the number of lines in a document, it\n * defaults back to the number of lines in the document.\n * If a line number is negative, it defaults to 0.\n *\n * The above two properties are implementation specific.\n */\n readonly line: number;\n /**\n * Character offset on a line in a document (zero-based).\n *\n * The meaning of this offset is determined by the negotiated\n * `PositionEncodingKind`.\n *\n * If the character value is greater than the line length it defaults back\n * to the line length. This property is implementation specific.\n */\n readonly character: number;\n}\n\n/**\n * A range in a text document expressed as (zero-based) start and end positions.\n *\n * If you want to specify a range that contains a line including the line ending\n * character(s) then use an end position denoting the start of the next line.\n * For example:\n * ```ts\n * {\n * start: { line: 5, character: 23 }\n * end : { line 6, character : 0 }\n * }\n * ```\n */\nexport interface Range {\n /**\n * The range's start position.\n */\n readonly start: Position;\n /**\n * The range's end position.\n */\n readonly end: Position;\n}\n\n/**\n * A text edit applicable to a text document.\n */\nexport interface TextEdit {\n /**\n * The range of the text document to be manipulated. To insert\n * text into a document create a range where start === end.\n */\n readonly range: Range;\n /**\n * The string to be inserted. For delete operations use an\n * empty string.\n */\n readonly newText: string;\n}\n\n/** Different with `TextEdit`, the range has been resolved to offsets. */\nexport interface ResolvedTextEdit {\n /** The start offset of the text change. */\n readonly start: number;\n /** The end offset of the text change. */\n readonly end: number;\n /**\n * The string to be inserted. For delete operations use an\n * empty string.\n */\n readonly text: string;\n}\n\nexport interface TextDocumentChange {\n /** First line whose rendered content or tokenizer state may have changed. */\n readonly startLine: number;\n /** Character on the first changed line where the edit began. */\n readonly startCharacter: number;\n /** Last line whose rendered content may have changed after the edit. */\n readonly endLine: number;\n /** Line count before the edit was applied. */\n readonly previousLineCount: number;\n /** Line count after the edit was applied. */\n readonly lineCount: number;\n /** Difference between the old and new line counts. */\n readonly lineDelta: number;\n /** Exact rendered line ranges touched by each edit after the edit was applied. */\n readonly changedLineRanges: readonly [startLine: number, endLine: number][];\n}\n\n/**\n * A vscode-languageserver-textdocument compatible text document.\n */\nexport class TextDocument<LAnnotation> {\n #uri: string;\n #languageId: string;\n #version: number;\n #pieceTable: PieceTable;\n #editStack: EditStack<LAnnotation>;\n\n constructor(\n uri: string,\n text: string,\n languageId = 'plaintext',\n version = 0,\n editStack: EditStack<LAnnotation> = new EditStack()\n ) {\n this.#uri = new URL(uri, 'file://').toString();\n this.#languageId = languageId;\n this.#version = version;\n this.#pieceTable = new PieceTable(text);\n this.#editStack = editStack;\n }\n\n get uri(): string {\n return this.#uri;\n }\n\n get languageId(): string {\n return this.#languageId;\n }\n\n get version(): number {\n return this.#version;\n }\n\n get lineCount(): number {\n return this.#pieceTable.lineCount;\n }\n\n // The line ending the document uses, detected from its first line. Lets\n // inserted or pasted text match the rest of the file instead of leaving\n // mixed endings behind. Recognizes Windows `\\r\\n` and classic-Mac lone `\\r`\n // breaks (both of which the piece table already splits on), defaulting to\n // Unix `\\n`.\n get eol(): string {\n if (this.lineCount > 1) {\n const firstLineBreak = this.getLineText(0, true);\n if (firstLineBreak.endsWith('\\r\\n')) {\n return '\\r\\n';\n }\n if (firstLineBreak.endsWith('\\r')) {\n return '\\r';\n }\n }\n return '\\n';\n }\n\n get canUndo(): boolean {\n return this.#editStack.canUndo;\n }\n\n get canRedo(): boolean {\n return this.#editStack.canRedo;\n }\n\n positionAt(offset: number): Position {\n return this.#pieceTable.positionAt(offset);\n }\n\n positionsAt(offsets: readonly number[]): Position[] {\n return this.#pieceTable.positionsAt(offsets);\n }\n\n offsetAt(position: Position): number {\n return this.#pieceTable.offsetAt(this.normalizePosition(position));\n }\n\n getText(range?: Range): string {\n if (range === undefined) {\n return this.#pieceTable.getText();\n }\n // Clamp the range to visible line content before extracting text. A\n // preserved vertical-move \"goal column\" can leave a selection focus whose\n // character overshoots a shorter line; without this, the piece table clamps\n // to the line's offset span (which includes the trailing line break) and\n // copy/cut would pull in that newline. Mirrors `offsetAt`, which normalizes\n // positions the same way.\n return this.#pieceTable.getText({\n start: this.normalizePosition(range.start),\n end: this.normalizePosition(range.end),\n });\n }\n\n getLineText(line: number, includeLineBreak?: boolean): string {\n return this.#pieceTable.getLineText(line, includeLineBreak);\n }\n\n // Rewrites every line break in `text` to the document's EOL. Clipboard text\n // can carry Windows (`\\r\\n`) or classic-Mac (`\\r`) breaks; inserting it\n // verbatim would leave mixed line endings in a file that uses one style.\n normalizeEol(text: string): string {\n return text.replace(/\\r\\n|\\r|\\n/g, this.eol);\n }\n\n getLineLength(line: number, includeLineBreak?: boolean): number {\n return this.#pieceTable.getLineLength(line, includeLineBreak);\n }\n\n charAt(offset: number): string;\n charAt(position: Position): string;\n charAt(positionOrOffset: Position | number): string {\n if (typeof positionOrOffset === 'number') {\n return this.#pieceTable.charAt(positionOrOffset);\n }\n return this.#pieceTable.charAt(this.offsetAt(positionOrOffset));\n }\n\n getTextSlice(start: number, end: number): string {\n return this.#pieceTable.getTextSlice(start, end);\n }\n\n findNextNonOverlappingSubstring(\n needle: string,\n occupied: readonly [start: number, end: number][]\n ): number | undefined {\n return this.#pieceTable.findNextNonOverlappingSubstring(needle, occupied);\n }\n\n search(searchParams: SearchParams): [start: number, end: number][] {\n return this.#pieceTable.search(searchParams);\n }\n\n applyEdits(\n edits: TextEdit[],\n updateHistory = false,\n selectionsBefore?: EditorSelection[],\n selectionsAfter?: EditorSelection[],\n undoBoundary = false\n ): TextDocumentChange | undefined {\n if (edits.length === 0) {\n return;\n }\n return this.applyResolvedEdits(\n edits.map((edit) => this.#resolveEdit(edit)),\n updateHistory,\n selectionsBefore,\n selectionsAfter,\n undoBoundary\n );\n }\n\n applyResolvedEdits(\n edits: ResolvedTextEdit[],\n updateHistory = false,\n selectionsBefore?: EditorSelection[],\n selectionsAfter?: EditorSelection[],\n undoBoundary = false\n ): TextDocumentChange | undefined {\n if (edits.length === 0) {\n return undefined;\n }\n const resolvedEdits = this.#sortAndValidateResolvedEdits(edits);\n if (updateHistory) {\n const entry = createEditStackEntry(\n this,\n resolvedEdits,\n this.#version,\n this.#version + 1,\n selectionsBefore,\n selectionsAfter\n );\n if (undoBoundary) {\n entry.undoBoundary = true;\n }\n const previousEntry = this.#editStack.peekUndo();\n const change = this.#applyResolvedEditsToBuffer(resolvedEdits);\n this.#version++;\n if (\n change.lineDelta === 0 &&\n shouldCoalesceEditStackEntry(previousEntry, entry)\n ) {\n this.#editStack.replaceLastUndo(\n coalesceEditStackEntries(previousEntry!, entry)\n );\n } else {\n this.#editStack.push(entry);\n }\n return change;\n }\n const change = this.#applyResolvedEditsToBuffer(resolvedEdits);\n this.#version++;\n return change;\n }\n\n setLastUndoSelectionsAfter(selections: EditorSelection[]): void {\n this.#editStack.setLastUndoSelectionsAfter(selections);\n }\n\n setLastUndoLineAnnotations(\n lineAnnotationsBefore: DiffLineAnnotation<LAnnotation>[],\n lineAnnotationsAfter: DiffLineAnnotation<LAnnotation>[]\n ): void {\n this.#editStack.setLastUndoLineAnnotations(\n lineAnnotationsBefore,\n lineAnnotationsAfter\n );\n }\n\n undo():\n | [\n change: TextDocumentChange,\n selections?: EditorSelection[],\n lineAnnotations?: DiffLineAnnotation<LAnnotation>[],\n ]\n | undefined {\n const entry = this.#editStack.popUndoToRedo();\n if (entry === undefined) {\n return undefined;\n }\n const change = this.#applyResolvedEditsToBuffer(entry.inverseEdits);\n if (change === undefined) {\n return undefined;\n }\n this.#version = entry.versionBefore;\n return [\n change,\n entry.selectionsBefore?.slice(),\n entry.lineAnnotationsBefore?.slice(),\n ];\n }\n\n redo():\n | [\n change: TextDocumentChange,\n selections?: EditorSelection[],\n lineAnnotations?: DiffLineAnnotation<LAnnotation>[],\n ]\n | undefined {\n const entry = this.#editStack.popRedoToUndo();\n if (entry === undefined) {\n return undefined;\n }\n const change = this.#applyResolvedEditsToBuffer(entry.forwardEdits);\n if (change === undefined) {\n return undefined;\n }\n this.#version = entry.versionAfter;\n return [\n change,\n entry.selectionsAfter?.slice(),\n entry.lineAnnotationsAfter?.slice(),\n ];\n }\n\n normalizePosition(position: Position): Position {\n const line = Math.max(0, Math.min(position.line, this.lineCount - 1));\n return {\n line,\n character: Math.max(\n 0,\n Math.min(position.character, this.getLineLength(line))\n ),\n };\n }\n\n #resolveEdit(edit: TextEdit): ResolvedTextEdit {\n let start = this.offsetAt(edit.range.start);\n let end = this.offsetAt(edit.range.end);\n if (start > end) {\n const t = start;\n start = end;\n end = t;\n }\n return { start, end, text: edit.newText };\n }\n\n #sortAndValidateResolvedEdits(edits: ResolvedTextEdit[]): ResolvedTextEdit[] {\n const sortedEdits = [...edits].sort((a, b) => a.start - b.start);\n for (let i = 0; i < sortedEdits.length - 1; i++) {\n if (sortedEdits[i].end > sortedEdits[i + 1].start) {\n throw new Error('Overlapping text edits are not supported');\n }\n }\n return sortedEdits;\n }\n\n #applyResolvedEditsToBuffer(edits: ResolvedTextEdit[]): TextDocumentChange {\n const previousLineCount = this.#pieceTable.lineCount;\n const editPositions = this.positionsAt(\n edits.flatMap((edit) => [edit.start, edit.end])\n );\n const changedLineRange = this.#computeChangedLineRange(\n edits,\n editPositions\n );\n const startPosition = editPositions[0];\n this.#pieceTable.applyEdits(edits);\n const lineCount = this.#pieceTable.lineCount;\n const change: TextDocumentChange = {\n startLine: changedLineRange.startLine,\n startCharacter: startPosition.character,\n endLine: Math.min(changedLineRange.endLine, Math.max(0, lineCount - 1)),\n previousLineCount,\n lineCount,\n lineDelta: lineCount - previousLineCount,\n changedLineRanges: changedLineRange.ranges,\n };\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 = countLineBreaks(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"],"mappings":";;;;;;;AAsHA,IAAa,eAAb,MAAuC;CACrC;CACA;CACA;CACA;CACA;CAEA,YACE,KACA,MACA,aAAa,aACb,UAAU,GACV,YAAoC,IAAI,UAAU,GAClD;EACA,KAAKA,OAAO,IAAI,IAAI,KAAK,SAAS,CAAC,CAAC,SAAS;EAC7C,KAAKC,cAAc;EACnB,KAAKC,WAAW;EAChB,KAAKC,cAAc,IAAI,WAAW,IAAI;EACtC,KAAKC,aAAa;CACpB;CAEA,IAAI,MAAc;EAChB,OAAO,KAAKJ;CACd;CAEA,IAAI,aAAqB;EACvB,OAAO,KAAKC;CACd;CAEA,IAAI,UAAkB;EACpB,OAAO,KAAKC;CACd;CAEA,IAAI,YAAoB;EACtB,OAAO,KAAKC,YAAY;CAC1B;CAOA,IAAI,MAAc;EAChB,IAAI,KAAK,YAAY,GAAG;GACtB,MAAM,iBAAiB,KAAK,YAAY,GAAG,IAAI;GAC/C,IAAI,eAAe,SAAS,MAAM,GAChC,OAAO;GAET,IAAI,eAAe,SAAS,IAAI,GAC9B,OAAO;EAEX;EACA,OAAO;CACT;CAEA,IAAI,UAAmB;EACrB,OAAO,KAAKC,WAAW;CACzB;CAEA,IAAI,UAAmB;EACrB,OAAO,KAAKA,WAAW;CACzB;CAEA,WAAW,QAA0B;EACnC,OAAO,KAAKD,YAAY,WAAW,MAAM;CAC3C;CAEA,YAAY,SAAwC;EAClD,OAAO,KAAKA,YAAY,YAAY,OAAO;CAC7C;CAEA,SAAS,UAA4B;EACnC,OAAO,KAAKA,YAAY,SAAS,KAAK,kBAAkB,QAAQ,CAAC;CACnE;CAEA,QAAQ,OAAuB;EAC7B,IAAI,UAAU,KAAA,GACZ,OAAO,KAAKA,YAAY,QAAQ;EAQlC,OAAO,KAAKA,YAAY,QAAQ;GAC9B,OAAO,KAAK,kBAAkB,MAAM,KAAK;GACzC,KAAK,KAAK,kBAAkB,MAAM,GAAG;EACvC,CAAC;CACH;CAEA,YAAY,MAAc,kBAAoC;EAC5D,OAAO,KAAKA,YAAY,YAAY,MAAM,gBAAgB;CAC5D;CAKA,aAAa,MAAsB;EACjC,OAAO,KAAK,QAAQ,eAAe,KAAK,GAAG;CAC7C;CAEA,cAAc,MAAc,kBAAoC;EAC9D,OAAO,KAAKA,YAAY,cAAc,MAAM,gBAAgB;CAC9D;CAIA,OAAO,kBAA6C;EAClD,IAAI,OAAO,qBAAqB,UAC9B,OAAO,KAAKA,YAAY,OAAO,gBAAgB;EAEjD,OAAO,KAAKA,YAAY,OAAO,KAAK,SAAS,gBAAgB,CAAC;CAChE;CAEA,aAAa,OAAe,KAAqB;EAC/C,OAAO,KAAKA,YAAY,aAAa,OAAO,GAAG;CACjD;CAEA,gCACE,QACA,UACoB;EACpB,OAAO,KAAKA,YAAY,gCAAgC,QAAQ,QAAQ;CAC1E;CAEA,OAAO,cAA4D;EACjE,OAAO,KAAKA,YAAY,OAAO,YAAY;CAC7C;CAEA,WACE,OACA,gBAAgB,OAChB,kBACA,iBACA,eAAe,OACiB;EAChC,IAAI,MAAM,WAAW,GACnB;EAEF,OAAO,KAAK,mBACV,MAAM,KAAK,SAAS,KAAKE,aAAa,IAAI,CAAC,GAC3C,eACA,kBACA,iBACA,YACF;CACF;CAEA,mBACE,OACA,gBAAgB,OAChB,kBACA,iBACA,eAAe,OACiB;EAChC,IAAI,MAAM,WAAW,GACnB;EAEF,MAAM,gBAAgB,KAAKC,8BAA8B,KAAK;EAC9D,IAAI,eAAe;GACjB,MAAM,QAAQ,qBACZ,MACA,eACA,KAAKJ,UACL,KAAKA,WAAW,GAChB,kBACA,eACF;GACA,IAAI,cACF,MAAM,eAAe;GAEvB,MAAM,gBAAgB,KAAKE,WAAW,SAAS;GAC/C,MAAM,SAAS,KAAKG,4BAA4B,aAAa;GAC7D,KAAKL;GACL,IACE,OAAO,cAAc,KACrB,6BAA6B,eAAe,KAAK,GAEjD,KAAKE,WAAW,gBACd,yBAAyB,eAAgB,KAAK,CAChD;QAEA,KAAKA,WAAW,KAAK,KAAK;GAE5B,OAAO;EACT;EACA,MAAM,SAAS,KAAKG,4BAA4B,aAAa;EAC7D,KAAKL;EACL,OAAO;CACT;CAEA,2BAA2B,YAAqC;EAC9D,KAAKE,WAAW,2BAA2B,UAAU;CACvD;CAEA,2BACE,uBACA,sBACM;EACN,KAAKA,WAAW,2BACd,uBACA,oBACF;CACF;CAEA,OAMc;EACZ,MAAM,QAAQ,KAAKA,WAAW,cAAc;EAC5C,IAAI,UAAU,KAAA,GACZ;EAEF,MAAM,SAAS,KAAKG,4BAA4B,MAAM,YAAY;EAClE,IAAI,WAAW,KAAA,GACb;EAEF,KAAKL,WAAW,MAAM;EACtB,OAAO;GACL;GACA,MAAM,kBAAkB,MAAM;GAC9B,MAAM,uBAAuB,MAAM;EACrC;CACF;CAEA,OAMc;EACZ,MAAM,QAAQ,KAAKE,WAAW,cAAc;EAC5C,IAAI,UAAU,KAAA,GACZ;EAEF,MAAM,SAAS,KAAKG,4BAA4B,MAAM,YAAY;EAClE,IAAI,WAAW,KAAA,GACb;EAEF,KAAKL,WAAW,MAAM;EACtB,OAAO;GACL;GACA,MAAM,iBAAiB,MAAM;GAC7B,MAAM,sBAAsB,MAAM;EACpC;CACF;CAEA,kBAAkB,UAA8B;EAC9C,MAAM,OAAO,KAAK,IAAI,GAAG,KAAK,IAAI,SAAS,MAAM,KAAK,YAAY,CAAC,CAAC;EACpE,OAAO;GACL;GACA,WAAW,KAAK,IACd,GACA,KAAK,IAAI,SAAS,WAAW,KAAK,cAAc,IAAI,CAAC,CACvD;EACF;CACF;CAEA,aAAa,MAAkC;EAC7C,IAAI,QAAQ,KAAK,SAAS,KAAK,MAAM,KAAK;EAC1C,IAAI,MAAM,KAAK,SAAS,KAAK,MAAM,GAAG;EACtC,IAAI,QAAQ,KAAK;GACf,MAAM,IAAI;GACV,QAAQ;GACR,MAAM;EACR;EACA,OAAO;GAAE;GAAO;GAAK,MAAM,KAAK;EAAQ;CAC1C;CAEA,8BAA8B,OAA+C;EAC3E,MAAM,cAAc,CAAC,GAAG,KAAK,CAAC,CAAC,MAAM,GAAG,MAAM,EAAE,QAAQ,EAAE,KAAK;EAC/D,KAAK,IAAI,IAAI,GAAG,IAAI,YAAY,SAAS,GAAG,KAC1C,IAAI,YAAY,EAAE,CAAC,MAAM,YAAY,IAAI,EAAE,CAAC,OAC1C,MAAM,IAAI,MAAM,0CAA0C;EAG9D,OAAO;CACT;CAEA,4BAA4B,OAA+C;EACzE,MAAM,oBAAoB,KAAKC,YAAY;EAC3C,MAAM,gBAAgB,KAAK,YACzB,MAAM,SAAS,SAAS,CAAC,KAAK,OAAO,KAAK,GAAG,CAAC,CAChD;EACA,MAAM,mBAAmB,KAAKK,yBAC5B,OACA,aACF;EACA,MAAM,gBAAgB,cAAc;EACpC,KAAKL,YAAY,WAAW,KAAK;EACjC,MAAM,YAAY,KAAKA,YAAY;EAUnC,OAAO;GARL,WAAW,iBAAiB;GAC5B,gBAAgB,cAAc;GAC9B,SAAS,KAAK,IAAI,iBAAiB,SAAS,KAAK,IAAI,GAAG,YAAY,CAAC,CAAC;GACtE;GACA;GACA,WAAW,YAAY;GACvB,mBAAmB,iBAAiB;EAE1B;CACd;CAEA,yBACE,OACA,eAKA;EACA,IAAI,YAAY;EAChB,IAAI,UAAU;EACd,IAAI,sBAAsB;EAC1B,MAAM,SAA6B,CAAC;EACpC,KAAK,IAAI,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;GACrC,MAAM,OAAO,MAAM;GACnB,MAAM,gBAAgB,cAAc,IAAI,EAAE,CAAC;GAC3C,MAAM,cAAc,cAAc,IAAI,IAAI,EAAE,CAAC;GAC7C,MAAM,mBAAmB,gBAAgB,KAAK,IAAI;GAClD,MAAM,mBAAmB,gBAAgB;GACzC,MAAM,iBAAiB,mBAAmB;GAC1C,YAAY,KAAK,IAAI,WAAW,aAAa;GAC7C,UAAU,KAAK,IAAI,SAAS,cAAc;GAC1C,MAAM,YAAY,OAAO,OAAO,SAAS;GACzC,IAAI,cAAc,KAAA,KAAa,oBAAoB,UAAU,KAAK,GAChE,OAAO,OAAO,SAAS,KAAK,CAC1B,UAAU,IACV,KAAK,IAAI,UAAU,IAAI,cAAc,CACvC;QAEA,OAAO,KAAK,CAAC,kBAAkB,cAAc,CAAC;GAEhD,uBAAuB,oBAAoB,cAAc;EAC3D;EACA,IAAI,cAAc,UAChB,OAAO;GACL,WAAW;GACX,SAAS;GACT,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAC;EACjB;EAEF,OAAO;GAAE;GAAW;GAAS;EAAO;CACtC;AACF"}
1
+ {"version":3,"file":"textDocument.js","names":["#uri","#languageId","#version","#pieceTable","#editStack","#resolveEdit","#sortAndValidateResolvedEdits","#applyResolvedEditsToBuffer","#computeChangedLineRange"],"sources":["../../src/editor/textDocument.ts"],"sourcesContent":["import type { DiffLineAnnotation } from '../types';\nimport { countLineBreaks } from '../utils/computeFileOffsets';\nimport {\n coalesceEditStackEntries,\n createEditStackEntry,\n EditStack,\n shouldCoalesceEditStackEntry,\n} from './editStack';\nimport { PieceTable } from './pieceTable';\nimport type { SearchParams } from './searchPanel';\nimport { type EditorSelection } from './selection';\n\n/**\n * Position in a text document expressed as zero-based line and character offset.\n * The offsets are based on a UTF-16 string representation. So a string of the form\n * `a𐐀b` the character offset of the character `a` is 0, the character offset of `𐐀`\n * is 1 and the character offset of b is 3 since `𐐀` is represented using two code\n * units in UTF-16.\n *\n * Positions are line end character agnostic. So you can not specify a position that\n * denotes `\\r|\\n` or `\\n|` where `|` represents the character offset.\n */\nexport interface Position {\n /**\n * Line position in a document (zero-based).\n *\n * If a line number is greater than the number of lines in a document, it\n * defaults back to the number of lines in the document.\n * If a line number is negative, it defaults to 0.\n *\n * The above two properties are implementation specific.\n */\n readonly line: number;\n /**\n * Character offset on a line in a document (zero-based).\n *\n * The meaning of this offset is determined by the negotiated\n * `PositionEncodingKind`.\n *\n * If the character value is greater than the line length it defaults back\n * to the line length. This property is implementation specific.\n */\n readonly character: number;\n}\n\n/**\n * A range in a text document expressed as (zero-based) start and end positions.\n *\n * If you want to specify a range that contains a line including the line ending\n * character(s) then use an end position denoting the start of the next line.\n * For example:\n * ```ts\n * {\n * start: { line: 5, character: 23 }\n * end : { line 6, character : 0 }\n * }\n * ```\n */\nexport interface Range {\n /**\n * The range's start position.\n */\n readonly start: Position;\n /**\n * The range's end position.\n */\n readonly end: Position;\n}\n\n/**\n * A text edit applicable to a text document.\n */\nexport interface TextEdit {\n /**\n * The range of the text document to be manipulated. To insert\n * text into a document create a range where start === end.\n */\n readonly range: Range;\n /**\n * The string to be inserted. For delete operations use an\n * empty string.\n */\n readonly newText: string;\n}\n\n/** Different with `TextEdit`, the range has been resolved to offsets. */\nexport interface ResolvedTextEdit {\n /** The start offset of the text change. */\n readonly start: number;\n /** The end offset of the text change. */\n readonly end: number;\n /**\n * The string to be inserted. For delete operations use an\n * empty string.\n */\n readonly text: string;\n}\n\nexport interface TextDocumentChange {\n /** First line whose rendered content or tokenizer state may have changed. */\n readonly startLine: number;\n /** Character on the first changed line where the edit began. */\n readonly startCharacter: number;\n /** Last line whose rendered content may have changed after the edit. */\n readonly endLine: number;\n /** Line count before the edit was applied. */\n readonly previousLineCount: number;\n /** Line count after the edit was applied. */\n readonly lineCount: number;\n /** Difference between the old and new line counts. */\n readonly lineDelta: number;\n /** Exact rendered line ranges touched by each edit after the edit was applied. */\n readonly changedLineRanges: readonly [startLine: number, endLine: number][];\n /** Per-edit rendered line ranges before adjacent ranges are coalesced. */\n readonly changedLineChanges?: readonly [\n startLine: number,\n endLine: number,\n lineDelta: number,\n ][];\n}\n\n/**\n * A vscode-languageserver-textdocument compatible text document.\n */\nexport class TextDocument<LAnnotation> {\n #uri: string;\n #languageId: string;\n #version: number;\n #pieceTable: PieceTable;\n #editStack: EditStack<LAnnotation>;\n\n constructor(\n uri: string,\n text: string,\n languageId = 'plaintext',\n version = 0,\n editStack: EditStack<LAnnotation> = new EditStack()\n ) {\n this.#uri = new URL(uri, 'file://').toString();\n this.#languageId = languageId;\n this.#version = version;\n this.#pieceTable = new PieceTable(text);\n this.#editStack = editStack;\n }\n\n get uri(): string {\n return this.#uri;\n }\n\n get languageId(): string {\n return this.#languageId;\n }\n\n get version(): number {\n return this.#version;\n }\n\n get lineCount(): number {\n return this.#pieceTable.lineCount;\n }\n\n // The line ending the document uses, detected from its first line. Lets\n // inserted or pasted text match the rest of the file instead of leaving\n // mixed endings behind. Recognizes Windows `\\r\\n` and classic-Mac lone `\\r`\n // breaks (both of which the piece table already splits on), defaulting to\n // Unix `\\n`.\n get eol(): string {\n if (this.lineCount > 1) {\n const firstLineBreak = this.getLineText(0, true);\n if (firstLineBreak.endsWith('\\r\\n')) {\n return '\\r\\n';\n }\n if (firstLineBreak.endsWith('\\r')) {\n return '\\r';\n }\n }\n return '\\n';\n }\n\n get canUndo(): boolean {\n return this.#editStack.canUndo;\n }\n\n get canRedo(): boolean {\n return this.#editStack.canRedo;\n }\n\n positionAt(offset: number): Position {\n return this.#pieceTable.positionAt(offset);\n }\n\n positionsAt(offsets: readonly number[]): Position[] {\n return this.#pieceTable.positionsAt(offsets);\n }\n\n offsetAt(position: Position): number {\n return this.#pieceTable.offsetAt(this.normalizePosition(position));\n }\n\n getText(range?: Range): string {\n if (range === undefined) {\n return this.#pieceTable.getText();\n }\n // Clamp the range to visible line content before extracting text. A\n // preserved vertical-move \"goal column\" can leave a selection focus whose\n // character overshoots a shorter line; without this, the piece table clamps\n // to the line's offset span (which includes the trailing line break) and\n // copy/cut would pull in that newline. Mirrors `offsetAt`, which normalizes\n // positions the same way.\n return this.#pieceTable.getText({\n start: this.normalizePosition(range.start),\n end: this.normalizePosition(range.end),\n });\n }\n\n getLineText(line: number, includeLineBreak?: boolean): string {\n return this.#pieceTable.getLineText(line, includeLineBreak);\n }\n\n // Rewrites every line break in `text` to the document's EOL. Clipboard text\n // can carry Windows (`\\r\\n`) or classic-Mac (`\\r`) breaks; inserting it\n // verbatim would leave mixed line endings in a file that uses one style.\n normalizeEol(text: string): string {\n return text.replace(/\\r\\n|\\r|\\n/g, this.eol);\n }\n\n getLineLength(line: number, includeLineBreak?: boolean): number {\n return this.#pieceTable.getLineLength(line, includeLineBreak);\n }\n\n charAt(offset: number): string;\n charAt(position: Position): string;\n charAt(positionOrOffset: Position | number): string {\n if (typeof positionOrOffset === 'number') {\n return this.#pieceTable.charAt(positionOrOffset);\n }\n return this.#pieceTable.charAt(this.offsetAt(positionOrOffset));\n }\n\n getTextSlice(start: number, end: number): string {\n return this.#pieceTable.getTextSlice(start, end);\n }\n\n findNextNonOverlappingSubstring(\n needle: string,\n occupied: readonly [start: number, end: number][]\n ): number | undefined {\n return this.#pieceTable.findNextNonOverlappingSubstring(needle, occupied);\n }\n\n search(searchParams: SearchParams): [start: number, end: number][] {\n return this.#pieceTable.search(searchParams);\n }\n\n applyEdits(\n edits: TextEdit[],\n updateHistory = false,\n selectionsBefore?: EditorSelection[],\n selectionsAfter?: EditorSelection[],\n undoBoundary = false\n ): TextDocumentChange | undefined {\n if (edits.length === 0) {\n return;\n }\n return this.applyResolvedEdits(\n edits.map((edit) => this.#resolveEdit(edit)),\n updateHistory,\n selectionsBefore,\n selectionsAfter,\n undoBoundary\n );\n }\n\n applyResolvedEdits(\n edits: ResolvedTextEdit[],\n updateHistory = false,\n selectionsBefore?: EditorSelection[],\n selectionsAfter?: EditorSelection[],\n undoBoundary = false\n ): TextDocumentChange | undefined {\n if (edits.length === 0) {\n return undefined;\n }\n const resolvedEdits = this.#sortAndValidateResolvedEdits(edits);\n if (updateHistory) {\n const entry = createEditStackEntry(\n this,\n resolvedEdits,\n this.#version,\n this.#version + 1,\n selectionsBefore,\n selectionsAfter\n );\n if (undoBoundary) {\n entry.undoBoundary = true;\n }\n const previousEntry = this.#editStack.peekUndo();\n const change = this.#applyResolvedEditsToBuffer(resolvedEdits);\n this.#version++;\n if (\n change.lineDelta === 0 &&\n shouldCoalesceEditStackEntry(previousEntry, entry)\n ) {\n this.#editStack.replaceLastUndo(\n coalesceEditStackEntries(previousEntry!, entry)\n );\n } else {\n this.#editStack.push(entry);\n }\n return change;\n }\n const change = this.#applyResolvedEditsToBuffer(resolvedEdits);\n this.#version++;\n return change;\n }\n\n setLastUndoSelectionsAfter(selections: EditorSelection[]): void {\n this.#editStack.setLastUndoSelectionsAfter(selections);\n }\n\n setLastUndoLineAnnotations(\n lineAnnotationsBefore: DiffLineAnnotation<LAnnotation>[],\n lineAnnotationsAfter: DiffLineAnnotation<LAnnotation>[]\n ): void {\n this.#editStack.setLastUndoLineAnnotations(\n lineAnnotationsBefore,\n lineAnnotationsAfter\n );\n }\n\n undo():\n | [\n change: TextDocumentChange,\n selections?: EditorSelection[],\n lineAnnotations?: DiffLineAnnotation<LAnnotation>[],\n ]\n | undefined {\n const entry = this.#editStack.popUndoToRedo();\n if (entry === undefined) {\n return undefined;\n }\n const change = this.#applyResolvedEditsToBuffer(entry.inverseEdits);\n if (change === undefined) {\n return undefined;\n }\n this.#version = entry.versionBefore;\n return [\n change,\n entry.selectionsBefore?.slice(),\n entry.lineAnnotationsBefore?.slice(),\n ];\n }\n\n redo():\n | [\n change: TextDocumentChange,\n selections?: EditorSelection[],\n lineAnnotations?: DiffLineAnnotation<LAnnotation>[],\n ]\n | undefined {\n const entry = this.#editStack.popRedoToUndo();\n if (entry === undefined) {\n return undefined;\n }\n const change = this.#applyResolvedEditsToBuffer(entry.forwardEdits);\n if (change === undefined) {\n return undefined;\n }\n this.#version = entry.versionAfter;\n return [\n change,\n entry.selectionsAfter?.slice(),\n entry.lineAnnotationsAfter?.slice(),\n ];\n }\n\n normalizePosition(position: Position): Position {\n const line = Math.max(0, Math.min(position.line, this.lineCount - 1));\n return {\n line,\n character: Math.max(\n 0,\n Math.min(position.character, this.getLineLength(line))\n ),\n };\n }\n\n #resolveEdit(edit: TextEdit): ResolvedTextEdit {\n let start = this.offsetAt(edit.range.start);\n let end = this.offsetAt(edit.range.end);\n if (start > end) {\n const t = start;\n start = end;\n end = t;\n }\n return { start, end, text: edit.newText };\n }\n\n #sortAndValidateResolvedEdits(edits: ResolvedTextEdit[]): ResolvedTextEdit[] {\n const sortedEdits = [...edits].sort((a, b) => a.start - b.start);\n for (let i = 0; i < sortedEdits.length - 1; i++) {\n if (sortedEdits[i].end > sortedEdits[i + 1].start) {\n throw new Error('Overlapping text edits are not supported');\n }\n }\n return sortedEdits;\n }\n\n #applyResolvedEditsToBuffer(edits: ResolvedTextEdit[]): TextDocumentChange {\n const previousLineCount = this.#pieceTable.lineCount;\n const editPositions = this.positionsAt(\n edits.flatMap((edit) => [edit.start, edit.end])\n );\n const changedLineRange = this.#computeChangedLineRange(\n edits,\n editPositions\n );\n const startPosition = editPositions[0];\n this.#pieceTable.applyEdits(edits);\n const lineCount = this.#pieceTable.lineCount;\n const change: TextDocumentChange = {\n startLine: changedLineRange.startLine,\n startCharacter: startPosition.character,\n endLine: Math.min(changedLineRange.endLine, Math.max(0, lineCount - 1)),\n previousLineCount,\n lineCount,\n lineDelta: lineCount - previousLineCount,\n changedLineRanges: changedLineRange.ranges,\n changedLineChanges: changedLineRange.changes,\n };\n return change;\n }\n\n #computeChangedLineRange(\n edits: ResolvedTextEdit[],\n editPositions: Position[]\n ): {\n startLine: number;\n endLine: number;\n ranges: [number, number][];\n changes: [startLine: number, endLine: number, lineDelta: number][];\n } {\n let startLine = Infinity;\n let endLine = 0;\n let lineDeltaBeforeEdit = 0;\n const ranges: [number, number][] = [];\n const changes: [startLine: number, endLine: number, lineDelta: number][] =\n [];\n for (let i = 0; i < edits.length; i++) {\n const edit = edits[i];\n const editStart = editPositions[i * 2];\n const editEnd = editPositions[i * 2 + 1];\n const editStartLine = editStart.line;\n const editEndLine = editEnd.line;\n const insertedLineSpan = countLineBreaks(edit.text);\n const changedStartLine = editStartLine + lineDeltaBeforeEdit;\n const changedEndLine = changedStartLine + insertedLineSpan;\n const lineDelta = insertedLineSpan - (editEndLine - editStartLine);\n startLine = Math.min(startLine, editStartLine);\n endLine = Math.max(endLine, changedEndLine);\n const lastRange = ranges[ranges.length - 1];\n if (lastRange !== undefined && changedStartLine <= lastRange[1] + 1) {\n ranges[ranges.length - 1] = [\n lastRange[0],\n Math.max(lastRange[1], changedEndLine),\n ];\n } else {\n ranges.push([changedStartLine, changedEndLine]);\n }\n changes.push([changedStartLine, changedEndLine, lineDelta]);\n lineDeltaBeforeEdit += lineDelta;\n }\n if (startLine === Infinity) {\n return {\n startLine: 0,\n endLine: 0,\n ranges: [[0, 0]],\n changes: [[0, 0, 0]],\n };\n }\n return { startLine, endLine, ranges, changes };\n }\n}\n"],"mappings":"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"}
@@ -1,12 +1,12 @@
1
1
  import { BaseCodeOptions, DiffsHighlighter, HighlightedToken, RenderRange } from "../types.js";
2
2
  import { TextDocument, TextDocumentChange } from "./textDocument.js";
3
- import { IGrammar, StateStack } from "shiki/textmate";
4
3
 
5
4
  //#region src/editor/tokenzier.d.ts
6
5
  interface EditorTokenizerProps {
7
6
  highlighter: DiffsHighlighter;
8
7
  textDocument: TextDocument<unknown>;
9
8
  codeOptions: BaseCodeOptions;
9
+ matchBrackets?: boolean;
10
10
  setStyle: (style: string) => void;
11
11
  onDeferTokenize: (lines: Map<number, Array<HighlightedToken>>, themeType: 'dark' | 'light') => void;
12
12
  onThemeChange?: () => void;
@@ -15,12 +15,13 @@ interface EditorTokenizerProps {
15
15
  /** Stoppable code tokenizer for the editor */
16
16
  declare class EditorTokenizer {
17
17
  #private;
18
- static TOKENIZE_TIME_LIMIT: number;
19
18
  get themeType(): 'light' | 'dark';
19
+ getStringCommentRegexpRangesInLine(lineIndex: number): [number, number][] | null;
20
20
  constructor({
21
21
  codeOptions,
22
22
  highlighter,
23
23
  textDocument,
24
+ matchBrackets,
24
25
  setStyle,
25
26
  onDeferTokenize,
26
27
  onThemeChange,
@@ -34,11 +35,7 @@ declare class EditorTokenizer {
34
35
  pauseBackgroundTokenize(): void;
35
36
  resumeBackgroundTokenize(): void;
36
37
  }
37
- declare function tokenizeLine(grammar: IGrammar, colorMap: string[], lineText: string, stateStack: StateStack, timeLimit?: number): {
38
- ruleStack: StateStack;
39
- resolvedTokens: Array<HighlightedToken>;
40
- };
41
38
  declare function renderLineTokens(tokens: Array<HighlightedToken>, themeType: 'light' | 'dark'): (HTMLElement | string)[];
42
39
  //#endregion
43
- export { EditorTokenizer, EditorTokenizerProps, renderLineTokens, tokenizeLine };
40
+ export { EditorTokenizer, EditorTokenizerProps, renderLineTokens };
44
41
  //# sourceMappingURL=tokenzier.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"tokenzier.d.ts","names":[],"sources":["../../src/editor/tokenzier.ts"],"mappings":";;;;;UAiBiB,oBAAA;EACf,WAAA,EAAa,gBAAA;EACb,YAAA,EAAc,YAAA;EACd,WAAA,EAAa,eAAA;EACb,QAAA,GAAW,KAAA;EACX,eAAA,GACE,KAAA,EAAO,GAAA,SAAY,KAAA,CAAM,gBAAA,IACzB,SAAA;EAKF,aAAA;EACA,OAAA;AAAA;;cAIW,eAAA;EAAA;SACJ,mBAAA;EAAA,IAgEH,SAAA;EAIJ,WAAA;IACE,WAAA;IACA,WAAA;IACA,YAAA;IACA,QAAA;IACA,eAAA;IACA,aAAA;IACA;EAAA,GACC,oBAAA;EAgFH,SAAA,CAAU,WAAA,EAAa,eAAA;EA8CvB,OAAA;EASA,QAAA,CACE,MAAA,EAAQ,kBAAA,EACR,WAAA,GAAc,WAAA,GACb,GAAA,SAAY,KAAA,CAAM,gBAAA;EA0LrB,kBAAA,CAAmB,WAAA,GAAc,WAAA;EAmBjC,sBAAA;EAYA,uBAAA;EAYA,wBAAA;AAAA;AAAA,iBA4Nc,YAAA,CACd,OAAA,EAAS,QAAA,EACT,QAAA,YACA,QAAA,UACA,UAAA,EAAY,UAAA,EACZ,SAAA;EAEA,SAAA,EAAW,UAAA;EACX,cAAA,EAAgB,KAAA,CAAM,gBAAA;AAAA;AAAA,iBA+BR,gBAAA,CACd,MAAA,EAAQ,KAAA,CAAM,gBAAA,GACd,SAAA,sBACE,WAAA"}
1
+ {"version":3,"file":"tokenzier.d.ts","names":[],"sources":["../../src/editor/tokenzier.ts"],"mappings":";;;;UAmBiB,oBAAA;EACf,WAAA,EAAa,gBAAA;EACb,YAAA,EAAc,YAAA;EACd,WAAA,EAAa,eAAA;EACb,aAAA;EACA,QAAA,GAAW,KAAA;EACX,eAAA,GACE,KAAA,EAAO,GAAA,SAAY,KAAA,CAAM,gBAAA,IACzB,SAAA;EAKF,aAAA;EACA,OAAA;AAAA;;cAIW,eAAA;EAAA;MA8DP,SAAA;EAIJ,kCAAA,CACE,SAAA;EAsBF,WAAA;IACE,WAAA;IACA,WAAA;IACA,YAAA;IACA,aAAA;IACA,QAAA;IACA,eAAA;IACA,aAAA;IACA;EAAA,GACC,oBAAA;EAiFH,SAAA,CAAU,WAAA,EAAa,eAAA;EAkDvB,OAAA;EASA,QAAA,CACE,MAAA,EAAQ,kBAAA,EACR,WAAA,GAAc,WAAA,GACb,GAAA,SAAY,KAAA,CAAM,gBAAA;EAmMrB,kBAAA,CAAmB,WAAA,GAAc,WAAA;EAKjC,sBAAA;EAYA,uBAAA;EAYA,wBAAA;AAAA;AAAA,iBAkTc,gBAAA,CACd,MAAA,EAAQ,KAAA,CAAM,gBAAA,GACd,SAAA,sBACE,WAAA"}
@@ -2,9 +2,9 @@ import { DEFAULT_THEMES } from "../constants.js";
2
2
  import { addEventListener, debounce, h } from "./utils.js";
3
3
  import { EncodedTokenMetadata, INITIAL } from "shiki/textmate";
4
4
  //#region src/editor/tokenzier.ts
5
+ const TOKENIZE_TIME_LIMIT = 500;
5
6
  /** Stoppable code tokenizer for the editor */
6
- var EditorTokenizer = class EditorTokenizer {
7
- static TOKENIZE_TIME_LIMIT = 500;
7
+ var EditorTokenizer = class {
8
8
  #highlighter;
9
9
  #grammar;
10
10
  #mediaQueryList;
@@ -16,6 +16,7 @@ var EditorTokenizer = class EditorTokenizer {
16
16
  #setStyle;
17
17
  #onDeferTokenize;
18
18
  #onThemeChange;
19
+ #matchBrackets;
19
20
  #debug;
20
21
  #disposes;
21
22
  #stateStack = [INITIAL];
@@ -25,6 +26,7 @@ var EditorTokenizer = class EditorTokenizer {
25
26
  #backgroundJobId = 0;
26
27
  #backgroundChangedLineRanges;
27
28
  #backgroundChangedRangeIndex = 0;
29
+ #bracketIgnoredRanges = /* @__PURE__ */ new Map();
28
30
  #isMessageListenerAttached = false;
29
31
  #prebuildStateStack = debounce(async (renderRange) => {
30
32
  const { startingLine = 0, totalLines = Infinity } = renderRange ?? {};
@@ -43,7 +45,19 @@ var EditorTokenizer = class EditorTokenizer {
43
45
  get themeType() {
44
46
  return this.#themeType;
45
47
  }
46
- constructor({ codeOptions, highlighter, textDocument, setStyle, onDeferTokenize, onThemeChange, __debug }) {
48
+ getStringCommentRegexpRangesInLine(lineIndex) {
49
+ if (!this.#matchBrackets || lineIndex < 0 || lineIndex >= this.#textDocument.lineCount) return null;
50
+ this.#ensureGrammar();
51
+ if (this.#grammar === void 0) return null;
52
+ if (!this.#bracketIgnoredRanges.has(lineIndex)) {
53
+ this.#buildStateStack(lineIndex);
54
+ const state = this.#stateStack[lineIndex] ?? INITIAL;
55
+ const result = this.#tokenizeLineAt(lineIndex, state);
56
+ this.#stateStack[lineIndex + 1] = result.state;
57
+ }
58
+ return this.#bracketIgnoredRanges.get(lineIndex) ?? null;
59
+ }
60
+ constructor({ codeOptions, highlighter, textDocument, matchBrackets, setStyle, onDeferTokenize, onThemeChange, __debug }) {
47
61
  const { themeType = "system", theme = DEFAULT_THEMES, tokenizeMaxLineLength = 1e3 } = codeOptions;
48
62
  this.#mediaQueryList = window.matchMedia("(prefers-color-scheme: dark)");
49
63
  if (themeType === "system") this.#themeType = this.#mediaQueryList.matches ? "dark" : "light";
@@ -69,6 +83,7 @@ var EditorTokenizer = class EditorTokenizer {
69
83
  this.#setStyle = setStyle;
70
84
  this.#onDeferTokenize = onDeferTokenize;
71
85
  this.#onThemeChange = onThemeChange;
86
+ this.#matchBrackets = matchBrackets !== false;
72
87
  this.#debug = __debug ?? false;
73
88
  this.#ensureGrammar();
74
89
  this.#colorMap = [];
@@ -98,6 +113,8 @@ var EditorTokenizer = class EditorTokenizer {
98
113
  const cursorForeground = colors["editorCursor.foreground"];
99
114
  const findMatchBackground = colors["editor.findMatchBackground"];
100
115
  const findMatchHighlightBackground = colors["editor.findMatchHighlightBackground"];
116
+ const bracketMatchBackground = colors["editorBracketMatch.background"];
117
+ const bracketMatchBorder = colors["editorBracketMatch.border"];
101
118
  const hintForeground = colors["editorHint.foreground"];
102
119
  const infoForeground = colors["editorInfo.foreground"];
103
120
  const warningForeground = colors["editorWarning.foreground"];
@@ -105,13 +122,15 @@ var EditorTokenizer = class EditorTokenizer {
105
122
  this.#setStyle(`:host {
106
123
  --diffs-editor-selection-bg: ${selectionBackground ?? "var(--diffs-line-bg)"};
107
124
  --diffs-editor-line-highlight-bg: ${lineHighlightBackground ?? "var(--diffs-line-bg)"};
108
- --diffs-editor-match-bg: ${findMatchBackground ?? "unset"};
109
- --diffs-editor-match-highlight-bg: ${findMatchHighlightBackground ?? "unset"};
110
- --diffs-editor-cursor-fg: ${cursorForeground ?? "unset"};
111
- --diffs-editor-hint-fg: ${hintForeground ?? "unset"};
112
- --diffs-editor-info-fg: ${infoForeground ?? "unset"};
113
- --diffs-editor-warning-fg: ${warningForeground ?? "unset"};
114
- --diffs-editor-error-fg: ${errorForeground ?? "unset"};
125
+ --diffs-editor-match-bg: ${findMatchBackground ?? "initial"};
126
+ --diffs-editor-match-highlight-bg: ${findMatchHighlightBackground ?? "initial"};
127
+ --diffs-editor-bracket-match-bg: ${bracketMatchBackground ?? "initial"};
128
+ --diffs-editor-bracket-match-border: ${bracketMatchBorder ?? "initial"};
129
+ --diffs-editor-cursor-fg: ${cursorForeground ?? "initial"};
130
+ --diffs-editor-hint-fg: ${hintForeground ?? "initial"};
131
+ --diffs-editor-info-fg: ${infoForeground ?? "initial"};
132
+ --diffs-editor-warning-fg: ${warningForeground ?? "initial"};
133
+ --diffs-editor-error-fg: ${errorForeground ?? "initial"};
115
134
  }`);
116
135
  }
117
136
  cleanUp() {
@@ -123,6 +142,9 @@ var EditorTokenizer = class EditorTokenizer {
123
142
  tokenize(change, renderRange) {
124
143
  this.#ensureGrammar();
125
144
  if (this.#grammar === void 0 && !isGrammarlessLanguage(this.#textDocument.languageId)) throw new Error(`Grammar for language "${this.#textDocument.languageId}" not loaded`);
145
+ if (this.#matchBrackets) {
146
+ for (const line of this.#bracketIgnoredRanges.keys()) if (line >= change.startLine) this.#bracketIgnoredRanges.delete(line);
147
+ }
126
148
  const { lineCount } = this.#textDocument;
127
149
  const { startingLine = 0, totalLines = Infinity } = renderRange ?? {};
128
150
  const renderRangeEndLine = totalLines === Infinity ? lineCount : Math.min(startingLine + totalLines, lineCount);
@@ -210,9 +232,6 @@ var EditorTokenizer = class EditorTokenizer {
210
232
  this.#ensureGrammar();
211
233
  this.#prebuildStateStack(renderRange);
212
234
  }
213
- #ensureGrammar() {
214
- if (this.#grammar === void 0 && !isGrammarlessLanguage(this.#textDocument.languageId) && this.#highlighter.getLoadedLanguages().includes(this.#textDocument.languageId)) this.#grammar = this.#highlighter.getLanguage(this.#textDocument.languageId);
215
- }
216
235
  stopBackgroundTokenize() {
217
236
  if (this.#isStopped) return;
218
237
  this.#isStopped = true;
@@ -233,6 +252,9 @@ var EditorTokenizer = class EditorTokenizer {
233
252
  this.#isPaused = false;
234
253
  this.#postTokenizeMessage(this.#backgroundJobId);
235
254
  }
255
+ #ensureGrammar() {
256
+ if (this.#grammar === void 0 && !isGrammarlessLanguage(this.#textDocument.languageId) && this.#highlighter.getLoadedLanguages().includes(this.#textDocument.languageId)) this.#grammar = this.#highlighter.getLanguage(this.#textDocument.languageId);
257
+ }
236
258
  #attachMessageListener() {
237
259
  if (this.#isMessageListenerAttached) return;
238
260
  globalThis.addEventListener("message", this.#onMessage);
@@ -270,6 +292,7 @@ var EditorTokenizer = class EditorTokenizer {
270
292
  const lineText = this.#textDocument.getLineText(line);
271
293
  if (lineText.length > this.#tokenizeMaxLineLength) {
272
294
  console.warn(`[diffs] Line(${line}) too long to tokenize: ${lineText.length}`);
295
+ this.#cacheBracketIgnoredRanges(line, null);
273
296
  return {
274
297
  resolvedTokens: [[
275
298
  0,
@@ -279,20 +302,27 @@ var EditorTokenizer = class EditorTokenizer {
279
302
  state
280
303
  };
281
304
  }
282
- if (this.#grammar === void 0 || lineText === "" || lineText.trim() === "") return {
283
- resolvedTokens: [[
284
- 0,
285
- "",
286
- lineText
287
- ]],
288
- state
289
- };
290
- const result = tokenizeLine(this.#grammar, this.#colorMap, lineText, state, EditorTokenizer.TOKENIZE_TIME_LIMIT);
305
+ if (this.#grammar === void 0 || lineText === "" || lineText.trim() === "") {
306
+ this.#cacheBracketIgnoredRanges(line, null);
307
+ return {
308
+ resolvedTokens: [[
309
+ 0,
310
+ "",
311
+ lineText
312
+ ]],
313
+ state
314
+ };
315
+ }
316
+ const result = tokenizeLine(this.#grammar, this.#colorMap, lineText, state, TOKENIZE_TIME_LIMIT, this.#matchBrackets);
317
+ this.#cacheBracketIgnoredRanges(line, result.bracketIgnoredRanges);
291
318
  return {
292
319
  resolvedTokens: result.resolvedTokens,
293
320
  state: result.ruleStack
294
321
  };
295
322
  }
323
+ #cacheBracketIgnoredRanges(line, ranges) {
324
+ if (this.#matchBrackets) this.#bracketIgnoredRanges.set(line, ranges);
325
+ }
296
326
  #buildStateStack(endAt) {
297
327
  const boundedEndAt = Math.min(Math.max(0, endAt), this.#textDocument.lineCount);
298
328
  if (this.#stateStack.length > boundedEndAt || this.#grammar === void 0) return;
@@ -301,7 +331,11 @@ var EditorTokenizer = class EditorTokenizer {
301
331
  for (; line < boundedEndAt; line++) {
302
332
  this.#stateStack[line] = state;
303
333
  const lineText = this.#textDocument.getLineText(line);
304
- if (lineText.length <= this.#tokenizeMaxLineLength && lineText !== "" && lineText.trim() !== "") state = this.#grammar.tokenizeLine2(lineText, state, EditorTokenizer.TOKENIZE_TIME_LIMIT).ruleStack;
334
+ if (lineText.length <= this.#tokenizeMaxLineLength && lineText !== "" && lineText.trim() !== "") {
335
+ const result = tokenizeLine(this.#grammar, this.#colorMap, lineText, state, TOKENIZE_TIME_LIMIT, this.#matchBrackets);
336
+ this.#cacheBracketIgnoredRanges(line, result.bracketIgnoredRanges);
337
+ state = result.ruleStack;
338
+ } else this.#cacheBracketIgnoredRanges(line, null);
305
339
  }
306
340
  this.#stateStack[line] = state;
307
341
  }
@@ -327,14 +361,18 @@ var EditorTokenizer = class EditorTokenizer {
327
361
  "",
328
362
  lineText
329
363
  ]]);
330
- } else if (lineText === "" || lineText.trim() === "") lines.set(line, [[
331
- 0,
332
- "",
333
- lineText
334
- ]]);
335
- else {
336
- const ret = tokenizeLine(this.#grammar, this.#colorMap, lineText, state, EditorTokenizer.TOKENIZE_TIME_LIMIT);
364
+ this.#cacheBracketIgnoredRanges(line, null);
365
+ } else if (lineText === "" || lineText.trim() === "") {
366
+ lines.set(line, [[
367
+ 0,
368
+ "",
369
+ lineText
370
+ ]]);
371
+ this.#cacheBracketIgnoredRanges(line, null);
372
+ } else {
373
+ const ret = tokenizeLine(this.#grammar, this.#colorMap, lineText, state, TOKENIZE_TIME_LIMIT, this.#matchBrackets);
337
374
  lines.set(line, ret.resolvedTokens);
375
+ this.#cacheBracketIgnoredRanges(line, ret.bracketIgnoredRanges);
338
376
  state = ret.ruleStack;
339
377
  }
340
378
  this.#stateStack[line + 1] = state;
@@ -366,28 +404,31 @@ var EditorTokenizer = class EditorTokenizer {
366
404
  this.#postTokenizeMessage(jobId);
367
405
  }
368
406
  };
369
- function tokenizeLine(grammar, colorMap, lineText, stateStack, timeLimit) {
407
+ function tokenizeLine(grammar, colorMap, lineText, stateStack, timeLimit, collectBracketIgnoredRanges = true) {
370
408
  const result = grammar.tokenizeLine2(lineText, stateStack, timeLimit);
371
409
  if (result.stoppedEarly) console.warn(`[diffs] Time limit reached when tokenizing line: ${lineText.substring(0, 100)}`);
372
410
  const rawTokens = result.tokens;
373
411
  const tokensLength = rawTokens.length / 2;
374
412
  const resolvedTokens = [];
413
+ const bracketIgnoredRanges = [];
375
414
  for (let j = 0; j < tokensLength; j++) {
376
415
  const offset = rawTokens[2 * j];
377
416
  const nextOffset = j + 1 < tokensLength ? rawTokens[2 * j + 2] : lineText.length;
378
417
  if (offset === nextOffset) continue;
379
418
  const metadata = rawTokens[2 * j + 1];
380
- const fg = colorMap[EncodedTokenMetadata.getForeground(metadata)];
419
+ const fg = EncodedTokenMetadata.getForeground(metadata);
381
420
  const tokenText = lineText.slice(offset, nextOffset);
382
421
  resolvedTokens.push([
383
422
  offset,
384
- fg,
423
+ colorMap[fg],
385
424
  tokenText
386
425
  ]);
426
+ if (collectBracketIgnoredRanges && EncodedTokenMetadata.getTokenType(metadata) > 0) bracketIgnoredRanges.push([offset, nextOffset]);
387
427
  }
388
428
  return {
389
429
  ruleStack: result.ruleStack,
390
- resolvedTokens
430
+ resolvedTokens,
431
+ bracketIgnoredRanges
391
432
  };
392
433
  }
393
434
  function renderLineTokens(tokens, themeType) {
@@ -407,6 +448,6 @@ function isGrammarlessLanguage(languageId) {
407
448
  return languageId === "text" || languageId === "ansi";
408
449
  }
409
450
  //#endregion
410
- export { EditorTokenizer, renderLineTokens, tokenizeLine };
451
+ export { EditorTokenizer, renderLineTokens };
411
452
 
412
453
  //# sourceMappingURL=tokenzier.js.map