@pierre/diffs 1.3.0-beta.10 → 1.3.0-beta.11

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 (67) hide show
  1. package/dist/components/CodeView.d.ts.map +1 -1
  2. package/dist/components/CodeView.js +1 -16
  3. package/dist/components/CodeView.js.map +1 -1
  4. package/dist/components/File.d.ts +2 -1
  5. package/dist/components/File.d.ts.map +1 -1
  6. package/dist/components/File.js +6 -2
  7. package/dist/components/File.js.map +1 -1
  8. package/dist/components/FileDiff.d.ts +8 -2
  9. package/dist/components/FileDiff.d.ts.map +1 -1
  10. package/dist/components/FileDiff.js +26 -8
  11. package/dist/components/FileDiff.js.map +1 -1
  12. package/dist/components/VirtualizedFileDiff.d.ts +1 -0
  13. package/dist/components/VirtualizedFileDiff.d.ts.map +1 -1
  14. package/dist/components/VirtualizedFileDiff.js +4 -0
  15. package/dist/components/VirtualizedFileDiff.js.map +1 -1
  16. package/dist/editor/editStack.d.ts +5 -0
  17. package/dist/editor/editStack.d.ts.map +1 -1
  18. package/dist/editor/editStack.js +53 -12
  19. package/dist/editor/editStack.js.map +1 -1
  20. package/dist/editor/editor.d.ts.map +1 -1
  21. package/dist/editor/editor.js +52 -32
  22. package/dist/editor/editor.js.map +1 -1
  23. package/dist/editor/editor2.js +1 -1
  24. package/dist/editor/marker.d.ts +3 -3
  25. package/dist/editor/marker.d.ts.map +1 -1
  26. package/dist/editor/marker.js +89 -89
  27. package/dist/editor/marker.js.map +1 -1
  28. package/dist/editor/pieceTable.d.ts.map +1 -1
  29. package/dist/editor/pieceTable.js +55 -20
  30. package/dist/editor/pieceTable.js.map +1 -1
  31. package/dist/editor/popover.js +4 -0
  32. package/dist/editor/popover.js.map +1 -1
  33. package/dist/editor/selection.d.ts +2 -2
  34. package/dist/editor/selection.d.ts.map +1 -1
  35. package/dist/editor/selection.js +2 -2
  36. package/dist/editor/selection.js.map +1 -1
  37. package/dist/editor/textDocument.js +1 -1
  38. package/dist/editor/textDocument.js.map +1 -1
  39. package/dist/editor/tokenizer.d.ts.map +1 -1
  40. package/dist/editor/tokenizer.js +7 -2
  41. package/dist/editor/tokenizer.js.map +1 -1
  42. package/dist/index.d.ts +2 -2
  43. package/dist/managers/InteractionManager.d.ts +18 -7
  44. package/dist/managers/InteractionManager.d.ts.map +1 -1
  45. package/dist/managers/InteractionManager.js +154 -99
  46. package/dist/managers/InteractionManager.js.map +1 -1
  47. package/dist/react/index.d.ts +2 -2
  48. package/dist/react/utils/useFileDiffInstance.js +1 -6
  49. package/dist/react/utils/useFileDiffInstance.js.map +1 -1
  50. package/dist/react/utils/useFileInstance.js +1 -4
  51. package/dist/react/utils/useFileInstance.js.map +1 -1
  52. package/dist/ssr/index.d.ts +2 -2
  53. package/dist/style.js +1 -1
  54. package/dist/types.d.ts +7 -1
  55. package/dist/types.d.ts.map +1 -1
  56. package/dist/utils/computeFileOffsets.d.ts.map +1 -1
  57. package/dist/utils/computeFileOffsets.js +34 -5
  58. package/dist/utils/computeFileOffsets.js.map +1 -1
  59. package/dist/utils/isGutterUtilityPath.d.ts +5 -0
  60. package/dist/utils/isGutterUtilityPath.d.ts.map +1 -0
  61. package/dist/utils/isGutterUtilityPath.js +12 -0
  62. package/dist/utils/isGutterUtilityPath.js.map +1 -0
  63. package/dist/worker/worker-portable.js +34 -5
  64. package/dist/worker/worker-portable.js.map +1 -1
  65. package/dist/worker/worker.js +34 -5
  66. package/dist/worker/worker.js.map +1 -1
  67. package/package.json +1 -1
@@ -1,5 +1,5 @@
1
1
  //#region src/editor/editor.css?inline
2
- var editor_default = "::selection {\n background-color: #0000;\n}\n\n[data-deleted-text-selection] [data-deletions] ::selection, [data-deleted-text-selection] [data-line-type=\"change-deletion\"] ::selection {\n background-color: var(--diffs-editor-selection-bg);\n}\n\n@keyframes blinking {\n 0% {\n opacity: 1;\n }\n\n 50% {\n opacity: 0;\n }\n\n 100% {\n opacity: 1;\n }\n}\n\n:host, [data-code], [data-content], [data-diff-type=\"split\"][data-overflow=\"wrap\"] {\n position: relative;\n}\n\n[data-code] {\n container-type: inline-size;\n}\n\n[data-content] {\n cursor: text;\n caret-color: var(--diffs-bg-caret);\n background-color: #0000;\n outline: none;\n}\n\n[data-line] {\n cursor: text;\n background-color: #0000;\n}\n\n[data-line]:after {\n content: \"\";\n z-index: -20;\n background-color: var(--diffs-line-bg);\n pointer-events: none;\n position: absolute;\n inset: 0;\n}\n\n[data-line][data-selected-line]:after {\n background-color: var(--diffs-computed-diff-line-bg, var(--diffs-bg));\n background-image: linear-gradient(var(--diffs-editor-line-highlight-bg),\n var(--diffs-editor-line-highlight-bg));\n}\n\n[data-editor-overlay] {\n display: contents;\n}\n\n[data-caret], [data-selection-range], [data-match-range], [data-bracket-match-range], [data-marker-range] {\n height: 1lh;\n line-height: var(--diffs-line-height);\n pointer-events: none;\n position: absolute;\n top: 0;\n left: 0;\n}\n\n[data-caret] {\n background-color: var(--diffs-bg-caret-override, var(--diffs-editor-cursor-fg, light-dark(color-mix(in lab, var(--diffs-fg) 50%, var(--diffs-bg)), color-mix(in lab, var(--diffs-fg) 75%, var(--diffs-bg)))));\n visibility: hidden;\n width: 2px;\n}\n\n@media (prefers-reduced-motion: no-preference) {\n [data-caret] {\n animation: 1.2s .8s infinite blinking;\n }\n}\n\n[data-selection-range] {\n z-index: -10;\n background-color: var(--diffs-editor-selection-bg);\n}\n\n[data-selection-corner] {\n background-color: var(--diffs-selection-corner-bg, var(--diffs-bg));\n width: 100%;\n height: 100%;\n}\n\n[data-match-range] {\n z-index: -10;\n background-color: var(--diffs-editor-match-bg, var(--diffs-editor-selection-bg));\n}\n\n[data-match-range]:not([data-focus]) {\n background-color: var(--diffs-editor-match-highlight-bg, light-dark(#ff963288, #ff963266));\n}\n\n[data-bracket-match-range] {\n z-index: -9;\n box-sizing: border-box;\n border-bottom: 1px solid\n var(--diffs-editor-bracket-match-border, color-mix(in lab, var(--diffs-fg) 60%, transparent));\n background-color: var(--diffs-editor-bracket-match-bg, color-mix(in lab, var(--diffs-fg) 5%, transparent));\n}\n\n[data-rtl] {\n border-top-left-radius: 3px;\n}\n\n[data-rtr] {\n border-top-right-radius: 3px;\n}\n\n[data-rbl] {\n border-bottom-left-radius: 3px;\n}\n\n[data-rbr] {\n border-bottom-right-radius: 3px;\n}\n\n[data-marker-range] {\n z-index: 1;\n background-color: var(--diffs-marker-bg);\n mask-image: url(\"data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI2IiBoZWlnaHQ9IjMiPjxwYXRoIGQ9Im0wIDIuNSBsMiAtMS41IGwxIDAgbDIgMS41IGwxIDAiIHN0cm9rZT0iI2ZmZiIgZmlsbD0ibm9uZSIgc3Ryb2tlLXdpZHRoPSIxIi8+PC9zdmc+\");\n mask-position: 0 100%;\n mask-size: 6px 3px;\n mask-repeat: repeat-x;\n}\n\n[data-marker-error] {\n --diffs-marker-contrast: #fff;\n --diffs-marker-bg: var(--diffs-editor-error-fg, var(--diffs-deletion-base));\n}\n\n[data-marker-warning] {\n --diffs-marker-contrast: #000;\n --diffs-marker-bg: var(--diffs-editor-warning-fg, light-dark(var(--diffs-warning-light), var(--diffs-warning-dark)));\n}\n\n[data-marker-info] {\n --diffs-marker-contrast: #fff;\n --diffs-marker-bg: var(--diffs-editor-info-fg, var(--diffs-modified-base));\n}\n\n[data-marker-hint] {\n --diffs-marker-contrast: light-dark(#fff, #000);\n --diffs-marker-bg: var(--diffs-editor-hint-fg, var(--diffs-fg-number));\n}\n\n@media (width >= 480px) {\n [data-content] {\n caret-color: #0000;\n }\n\n [data-content]:focus ~ [data-editor-overlay] [data-caret] {\n visibility: visible;\n }\n}\n\n[data-editor-widget] {\n --diffs-widget-fg: var(--diffs-fg);\n --diffs-widget-bg: color-mix(in lab, var(--diffs-fg) 4%, var(--diffs-bg));\n --diffs-widget-border: color-mix(in lab, var(--diffs-fg) 20%, transparent);\n --diffs-widget-shadow: inset 0 0 0 1px var(--diffs-bg), 0 4px 8px #00000013,\n 0 6px 18px #00000013;\n z-index: 100;\n width: fit-content;\n max-width: calc(100% - 24px);\n font: 14px/20px var(--diffs-header-font-fallback);\n border: 1px solid var(--diffs-widget-border);\n background-color: var(--diffs-widget-bg);\n box-shadow: var(--diffs-widget-shadow);\n background-clip: padding-box;\n border-radius: 9px;\n position: absolute;\n top: 0;\n left: 0;\n}\n\n[data-marker-popup], [data-selection-action-popover] {\n --popover-viewport-left: 0px;\n --popover-viewport-right: 100cqw;\n --popover-min-left: calc(var(--popover-viewport-left) + var(--gutter-width, 0px) + 8px);\n --popover-available-width: max(0px,\n calc(var(--popover-viewport-right) - var(--popover-min-left) - 8px));\n max-width: min(640px, var(--popover-available-width));\n translate: clamp(var(--popover-min-left),\n var(--popover-x, var(--popover-min-left)),\n calc(var(--popover-viewport-right) - 8px - 100%))\n calc(var(--popover-y, 0px) + var(--popover-y-shift, 0px));\n}\n\n[data-marker-popup] {\n --diffs-widget-bg: var(--diffs-marker-bg);\n --diffs-widget-shadow: 0 4px 8px #00000026, 0 6px 18px #00000026;\n min-width: min(180px, var(--popover-available-width));\n overflow-wrap: anywhere;\n color: var(--diffs-marker-contrast, contrast-color(#fff, #000));\n white-space: normal;\n pointer-events: auto;\n border: 0;\n padding: 8px 12px;\n\n & [data-marker-message] {\n white-space: normal;\n overflow-wrap: anywhere;\n\n & code {\n white-space: normal;\n color: inherit;\n background-color: #0000;\n display: inline;\n }\n }\n}\n\n[data-selection-action-popover] {\n pointer-events: auto;\n flex-wrap: wrap;\n align-items: center;\n gap: 4px;\n width: max-content;\n padding: 4px;\n display: flex;\n}\n\n[data-search-panel] {\n z-index: 100;\n flex-direction: column;\n justify-content: right;\n width: 100%;\n height: 0;\n display: flex;\n position: sticky;\n top: 16px;\n right: 16px;\n container: search-panel / inline-size;\n\n & [data-editor-widget] {\n z-index: 100;\n flex-shrink: 0;\n align-items: stretch;\n gap: 8px;\n min-width: 260px;\n max-width: 100%;\n margin-inline: auto 16px;\n padding: 4px;\n display: flex;\n position: relative;\n }\n\n & svg {\n fill: currentColor;\n width: 12px;\n height: 12px;\n display: block;\n }\n}\n\n[data-search-grid] {\n grid-template-columns: auto auto auto;\n grid-template-areas: \"find matches nav\"\n \"replace actions .\";\n align-items: center;\n gap: 4px 6px;\n width: 100%;\n display: grid;\n}\n\n[data-input-box][data-find] {\n grid-area: find;\n}\n\n[data-search-nav] {\n grid-area: nav;\n}\n\n[data-input-box][data-replace] {\n grid-area: replace;\n}\n\n[data-replace-actions] {\n grid-area: actions;\n}\n\n[data-search-grid][data-mode=\"find\"] {\n grid-template-areas: \"find matches nav\";\n}\n\n[data-search-grid][data-mode=\"find\"] [data-replace-cell] {\n display: none;\n}\n\n@container search-panel (width < 400px) {\n [data-search-panel] [data-editor-widget] {\n padding: 10px;\n }\n\n [data-search-grid][data-mode=\"replace\"] {\n grid-template-columns: auto 1fr auto;\n grid-template-areas: \"find find find\"\n \"replace replace replace\"\n \"nav matches actions\";\n }\n\n [data-search-grid][data-mode=\"find\"] {\n grid-template-columns: auto 1fr auto;\n grid-template-areas: \"find find find\"\n \"nav matches matches\";\n }\n\n [data-replace-actions] {\n justify-self: end;\n }\n\n [data-search-grid] [data-input-box] {\n width: auto;\n }\n}\n\n[data-input-box] {\n align-items: center;\n width: 200px;\n display: flex;\n position: relative;\n\n & input {\n width: 100%;\n min-width: 0;\n color: var(--diffs-fg);\n background-color: var(--diffs-bg);\n border: 1px solid color-mix(in lab, var(--diffs-fg) 12%, var(--diffs-bg));\n border-radius: 6px;\n outline: none;\n flex-grow: 1;\n padding-inline: 6px;\n font-size: 13px;\n line-height: 24px;\n\n &::selection {\n background-color: color-mix(in lab, var(--diffs-fg) 8%, var(--diffs-bg));\n }\n\n &:focus-visible {\n outline: 1px solid var(--diffs-modified-base);\n }\n }\n\n &[data-find] input {\n padding-inline-end: 72px;\n }\n\n & [data-search-icon] {\n --diffs-search-icon-size: 20px;\n }\n}\n\n[data-search-toggles] {\n align-items: center;\n gap: 1px;\n display: flex;\n position: absolute;\n top: 50%;\n right: 4px;\n transform: translateY(-50%);\n}\n\n[data-matches] {\n white-space: nowrap;\n min-width: 50px;\n color: color-mix(in lab, var(--diffs-fg) 50%, var(--diffs-bg));\n flex-shrink: 0;\n grid-area: matches;\n font-size: 12px;\n font-weight: 500;\n line-height: 20px;\n\n &[data-no-matches] {\n color: color-mix(in lab, var(--diffs-fg) 35%, var(--diffs-bg));\n }\n}\n\n[data-replace-actions], [data-search-nav] {\n align-items: center;\n display: flex;\n}\n\n[data-search-icon] {\n appearance: none;\n width: var(--diffs-search-icon-size, 24px);\n height: var(--diffs-search-icon-size, 24px);\n color: color-mix(in lab, var(--diffs-fg) 65%, var(--diffs-bg));\n border-radius: var(--diffs-search-icon-radius, 4px);\n cursor: pointer;\n background: none;\n border: 0;\n flex-shrink: 0;\n justify-content: center;\n align-items: center;\n margin: 0;\n padding: 0;\n transition: background-color .1s ease-in-out, color .1s ease-in-out;\n display: flex;\n\n &:disabled {\n opacity: .25;\n cursor: default;\n }\n\n &:not(:disabled):hover {\n color: var(--diffs-fg);\n }\n\n &:focus-visible {\n outline: 1px solid var(--diffs-modified-base);\n }\n\n &[aria-pressed=\"true\"] {\n color: var(--diffs-modified-base);\n }\n}\n\n[data-search-close] {\n --diffs-search-icon-size: 20px;\n --diffs-search-icon-radius: 50%;\n color: var(--diffs-widget-bg);\n background-color: color-mix(in lab,\n var(--diffs-widget-fg) 50%,\n var(--diffs-bg));\n position: absolute;\n top: 0;\n right: 0;\n transform: translate(50%, -50%);\n\n &:not(:disabled):hover {\n opacity: 1;\n color: var(--diffs-widget-bg);\n background-color: var(--diffs-widget-fg);\n }\n}\n";
2
+ var editor_default = "::selection {\n background-color: #0000;\n}\n\n[data-deleted-text-selection] [data-deletions] ::selection, [data-deleted-text-selection] [data-line-type=\"change-deletion\"] ::selection {\n background-color: var(--diffs-editor-selection-bg);\n}\n\n@keyframes blinking {\n 0% {\n opacity: 1;\n }\n\n 50% {\n opacity: 0;\n }\n\n 100% {\n opacity: 1;\n }\n}\n\n:host, [data-code], [data-content], [data-diff-type=\"split\"][data-overflow=\"wrap\"] {\n position: relative;\n}\n\n[data-code] {\n container-type: inline-size;\n}\n\n[data-content] {\n cursor: text;\n caret-color: var(--diffs-bg-caret);\n background-color: #0000;\n outline: none;\n}\n\n[data-line] {\n cursor: text;\n background-color: #0000;\n}\n\n[data-line]:after {\n content: \"\";\n z-index: -20;\n background-color: var(--diffs-line-bg);\n pointer-events: none;\n position: absolute;\n inset: 0;\n}\n\n[data-line][data-editor-active-line]:after {\n box-shadow: inset 0 0 0 1px var(--diffs-editor-line-highlight-border);\n}\n\n[data-editor-overlay] {\n display: contents;\n}\n\n[data-caret], [data-selection-range], [data-match-range], [data-bracket-match-range], [data-marker-range] {\n height: 1lh;\n line-height: var(--diffs-line-height);\n pointer-events: none;\n position: absolute;\n top: 0;\n left: 0;\n}\n\n[data-caret] {\n background-color: var(--diffs-bg-caret-override, var(--diffs-editor-cursor-fg, light-dark(color-mix(in lab, var(--diffs-fg) 50%, var(--diffs-bg)), color-mix(in lab, var(--diffs-fg) 75%, var(--diffs-bg)))));\n visibility: hidden;\n width: 2px;\n}\n\n@media (prefers-reduced-motion: no-preference) {\n [data-caret] {\n animation: 1.2s .8s infinite blinking;\n }\n}\n\n[data-selection-range] {\n z-index: -10;\n background-color: var(--diffs-editor-selection-bg);\n}\n\n[data-selection-corner] {\n background-color: var(--diffs-selection-corner-bg, var(--diffs-bg));\n width: 100%;\n height: 100%;\n}\n\n[data-match-range] {\n z-index: -10;\n background-color: var(--diffs-editor-match-bg, var(--diffs-editor-selection-bg));\n}\n\n[data-match-range]:not([data-focus]) {\n background-color: var(--diffs-editor-match-highlight-bg, light-dark(#ff963288, #ff963266));\n}\n\n[data-bracket-match-range] {\n z-index: -9;\n box-sizing: border-box;\n border-bottom: 1px solid\n var(--diffs-editor-bracket-match-border, color-mix(in lab, var(--diffs-fg) 60%, transparent));\n background-color: var(--diffs-editor-bracket-match-bg, color-mix(in lab, var(--diffs-fg) 5%, transparent));\n}\n\n[data-rtl] {\n border-top-left-radius: 3px;\n}\n\n[data-rtr] {\n border-top-right-radius: 3px;\n}\n\n[data-rbl] {\n border-bottom-left-radius: 3px;\n}\n\n[data-rbr] {\n border-bottom-right-radius: 3px;\n}\n\n[data-marker-range] {\n z-index: 1;\n background-color: var(--diffs-marker-bg);\n mask-image: url(\"data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI2IiBoZWlnaHQ9IjMiPjxwYXRoIGQ9Im0wIDIuNSBsMiAtMS41IGwxIDAgbDIgMS41IGwxIDAiIHN0cm9rZT0iI2ZmZiIgZmlsbD0ibm9uZSIgc3Ryb2tlLXdpZHRoPSIxIi8+PC9zdmc+\");\n mask-position: 0 100%;\n mask-size: 6px 3px;\n mask-repeat: repeat-x;\n}\n\n[data-marker-error] {\n --diffs-marker-contrast: light-dark(#fff, #000);\n --diffs-marker-bg: var(--diffs-editor-error-fg, var(--diffs-deletion-base));\n}\n\n[data-marker-warning] {\n --diffs-marker-contrast: #000;\n --diffs-marker-bg: var(--diffs-editor-warning-fg, light-dark(var(--diffs-warning-light), var(--diffs-warning-dark)));\n}\n\n[data-marker-info] {\n --diffs-marker-contrast: #000;\n --diffs-marker-bg: var(--diffs-editor-info-fg, var(--diffs-modified-base));\n}\n\n[data-marker-hint] {\n --diffs-marker-contrast: light-dark(#fff, #000);\n --diffs-marker-bg: var(--diffs-editor-hint-fg, var(--diffs-fg-number));\n}\n\n@media (width >= 480px) {\n [data-content] {\n caret-color: #0000;\n }\n\n [data-content]:focus ~ [data-editor-overlay] [data-caret] {\n visibility: visible;\n }\n}\n\n[data-editor-widget] {\n --diffs-widget-fg: var(--diffs-fg);\n --diffs-widget-bg: color-mix(in lab, var(--diffs-fg) 4%, var(--diffs-bg));\n --diffs-widget-border: color-mix(in lab, var(--diffs-fg) 20%, transparent);\n --diffs-widget-shadow: inset 0 0 0 1px var(--diffs-bg), 0 4px 8px #00000013,\n 0 6px 18px #00000013;\n z-index: 100;\n width: fit-content;\n max-width: calc(100% - 24px);\n font: 14px/20px var(--diffs-header-font-fallback);\n border: 1px solid var(--diffs-widget-border);\n background-color: var(--diffs-widget-bg);\n box-shadow: var(--diffs-widget-shadow);\n background-clip: padding-box;\n border-radius: 9px;\n position: absolute;\n top: 0;\n left: 0;\n}\n\n[data-marker-popover], [data-selection-action-popover] {\n --popover-gap: var(--diffs-popover-gap, var(--diffs-gap-fallback, 8px));\n --popover-viewport-left: 0px;\n --popover-viewport-right: 100cqw;\n --popover-viewport-top: -99999px;\n --popover-viewport-bottom: 99999px;\n --popover-min-left: calc(var(--popover-viewport-left) + var(--gutter-width, 0px) + var(--popover-gap));\n --popover-available-width: max(0px,\n calc(var(--popover-viewport-right) - var(--popover-min-left) -\n var(--popover-gap)));\n max-width: min(640px, var(--popover-available-width));\n translate: clamp(var(--popover-min-left),\n var(--popover-x, var(--popover-min-left)),\n calc(var(--popover-viewport-right) - var(--popover-gap) - 100%))\n /* Clamp into the scrollport so a popover with no fitting side stays in view. */\n clamp(var(--popover-viewport-top),\n calc(var(--popover-y, 0px) + var(--popover-y-shift, 0px)),\n calc(var(--popover-viewport-bottom) - var(--popover-gap) - 100%));\n}\n\n[data-marker-popover] {\n --diffs-widget-bg: var(--diffs-marker-bg);\n --diffs-widget-shadow: 0 4px 8px #00000026, 0 6px 18px #00000026;\n min-width: min(180px, var(--popover-available-width));\n overflow-wrap: anywhere;\n color: var(--diffs-marker-contrast);\n white-space: normal;\n pointer-events: auto;\n border: 0;\n padding: 8px 12px;\n\n @supports (color: contrast-color(red)) {\n color: contrast-color(var(--diffs-marker-bg), var(--diffs-bg));\n }\n\n & [data-marker-message] {\n white-space: normal;\n overflow-wrap: anywhere;\n\n & code {\n white-space: normal;\n color: inherit;\n background-color: #0000;\n display: inline;\n }\n }\n}\n\n[data-selection-action-popover] {\n pointer-events: auto;\n flex-wrap: wrap;\n align-items: center;\n gap: 4px;\n width: max-content;\n padding: 4px;\n display: flex;\n}\n\n[data-search-panel] {\n z-index: 100;\n flex-direction: column;\n justify-content: right;\n width: 100%;\n height: 0;\n display: flex;\n position: sticky;\n top: 16px;\n right: 16px;\n container: search-panel / inline-size;\n\n & [data-editor-widget] {\n z-index: 100;\n flex-shrink: 0;\n align-items: stretch;\n gap: 8px;\n min-width: 260px;\n max-width: 100%;\n margin-inline: auto 16px;\n padding: 4px;\n display: flex;\n position: relative;\n }\n\n & svg {\n fill: currentColor;\n width: 12px;\n height: 12px;\n display: block;\n }\n}\n\n[data-search-grid] {\n grid-template-columns: auto auto auto;\n grid-template-areas: \"find matches nav\"\n \"replace actions .\";\n align-items: center;\n gap: 4px 6px;\n width: 100%;\n display: grid;\n}\n\n[data-input-box][data-find] {\n grid-area: find;\n}\n\n[data-search-nav] {\n grid-area: nav;\n}\n\n[data-input-box][data-replace] {\n grid-area: replace;\n}\n\n[data-replace-actions] {\n grid-area: actions;\n}\n\n[data-search-grid][data-mode=\"find\"] {\n grid-template-areas: \"find matches nav\";\n}\n\n[data-search-grid][data-mode=\"find\"] [data-replace-cell] {\n display: none;\n}\n\n@container search-panel (width < 400px) {\n [data-search-panel] [data-editor-widget] {\n padding: 10px;\n }\n\n [data-search-grid][data-mode=\"replace\"] {\n grid-template-columns: auto 1fr auto;\n grid-template-areas: \"find find find\"\n \"replace replace replace\"\n \"nav matches actions\";\n }\n\n [data-search-grid][data-mode=\"find\"] {\n grid-template-columns: auto 1fr auto;\n grid-template-areas: \"find find find\"\n \"nav matches matches\";\n }\n\n [data-replace-actions] {\n justify-self: end;\n }\n\n [data-search-grid] [data-input-box] {\n width: auto;\n }\n}\n\n[data-input-box] {\n align-items: center;\n width: 200px;\n display: flex;\n position: relative;\n\n & input {\n width: 100%;\n min-width: 0;\n color: var(--diffs-fg);\n background-color: var(--diffs-bg);\n border: 1px solid color-mix(in lab, var(--diffs-fg) 12%, var(--diffs-bg));\n border-radius: 6px;\n outline: none;\n flex-grow: 1;\n padding-inline: 6px;\n font-size: 13px;\n line-height: 24px;\n\n &::selection {\n background-color: color-mix(in lab, var(--diffs-fg) 8%, var(--diffs-bg));\n }\n\n &:focus-visible {\n outline: 1px solid var(--diffs-modified-base);\n }\n }\n\n &[data-find] input {\n padding-inline-end: 72px;\n }\n\n & [data-search-icon] {\n --diffs-search-icon-size: 20px;\n }\n}\n\n[data-search-toggles] {\n align-items: center;\n gap: 1px;\n display: flex;\n position: absolute;\n top: 50%;\n right: 4px;\n transform: translateY(-50%);\n}\n\n[data-matches] {\n white-space: nowrap;\n min-width: 50px;\n color: color-mix(in lab, var(--diffs-fg) 50%, var(--diffs-bg));\n flex-shrink: 0;\n grid-area: matches;\n font-size: 12px;\n font-weight: 500;\n line-height: 20px;\n\n &[data-no-matches] {\n color: color-mix(in lab, var(--diffs-fg) 35%, var(--diffs-bg));\n }\n}\n\n[data-replace-actions], [data-search-nav] {\n align-items: center;\n display: flex;\n}\n\n[data-search-icon] {\n appearance: none;\n width: var(--diffs-search-icon-size, 24px);\n height: var(--diffs-search-icon-size, 24px);\n color: color-mix(in lab, var(--diffs-fg) 65%, var(--diffs-bg));\n border-radius: var(--diffs-search-icon-radius, 4px);\n cursor: pointer;\n background: none;\n border: 0;\n flex-shrink: 0;\n justify-content: center;\n align-items: center;\n margin: 0;\n padding: 0;\n transition: background-color .1s ease-in-out, color .1s ease-in-out;\n display: flex;\n\n &:disabled {\n opacity: .25;\n cursor: default;\n }\n\n &:not(:disabled):hover {\n color: var(--diffs-fg);\n }\n\n &:focus-visible {\n outline: 1px solid var(--diffs-modified-base);\n }\n\n &[aria-pressed=\"true\"] {\n color: var(--diffs-modified-base);\n }\n}\n\n[data-search-close] {\n --diffs-search-icon-size: 20px;\n --diffs-search-icon-radius: 50%;\n color: var(--diffs-widget-bg);\n background-color: color-mix(in lab,\n var(--diffs-widget-fg) 50%,\n var(--diffs-bg));\n position: absolute;\n top: 0;\n right: 0;\n transform: translate(50%, -50%);\n\n &:not(:disabled):hover {\n opacity: 1;\n color: var(--diffs-widget-bg);\n background-color: var(--diffs-widget-fg);\n }\n}\n";
3
3
  //#endregion
4
4
  export { editor_default as default };
5
5
 
@@ -25,11 +25,11 @@ declare class MarkerRenderer {
25
25
  #private;
26
26
  constructor(editor: MarkerRenderOptions);
27
27
  get markers(): readonly Marker[];
28
- isPopupVisible(): boolean;
29
- updatePopupPosition(): void;
28
+ isPopoverVisible(): boolean;
29
+ updatePopoverPosition(): void;
30
30
  setMarkers<LAnnotation>(markers: Marker[], textDocument: TextDocument<LAnnotation>): void;
31
31
  listenHover(contentEl: HTMLElement): void;
32
- removePopup(): void;
32
+ removePopover(): void;
33
33
  cleanup(): void;
34
34
  }
35
35
  declare function markerSeverityDatasetKey(severity: MarkerSeverity): string;
@@ -1 +1 @@
1
- {"version":3,"file":"marker.d.ts","names":[],"sources":["../../src/editor/marker.ts"],"mappings":";;;;;KAeY,cAAA;AAAA,UAEK,MAAA,SAAe,KAAA;EAC9B,QAAA,EAAU,cAAA;EACV,OAAA;IAAoB,IAAA;EAAA,IAAiB,WAAA;EACrC,MAAA;EACA,QAAA,GAAW,MAAA;AAAA;AAAA,UAGI,mBAAA;EACf,cAAA,EAAgB,cAAA;EAChB,aAAA;EACA,iBAAA,QAAyB,WAAW;EACpC,cAAA;EACA,QAAA,GAAW,IAAA,UAAc,SAAA;EACzB,QAAA,GAAW,IAAA;EACX,WAAA;AAAA;AAAA,cAGW,cAAA;EAAA;EAcX,WAAA,CAAY,MAAA,EAAQ,mBAAA;EAAA,IAIhB,OAAA,aAAoB,MAAA;EAIxB,cAAA;EAIA,mBAAA;EAcA,UAAA,cACE,OAAA,EAAS,MAAA,IACT,YAAA,EAAc,YAAA,CAAa,WAAA;EAW7B,WAAA,CAAY,SAAA,EAAW,WAAA;EAgCvB,WAAA;EAMA,OAAA;AAAA;AAAA,iBAyQc,wBAAA,CAAyB,QAAwB,EAAd,cAAc"}
1
+ {"version":3,"file":"marker.d.ts","names":[],"sources":["../../src/editor/marker.ts"],"mappings":";;;;;KAeY,cAAA;AAAA,UAEK,MAAA,SAAe,KAAA;EAC9B,QAAA,EAAU,cAAA;EACV,OAAA;IAAoB,IAAA;EAAA,IAAiB,WAAA;EACrC,MAAA;EACA,QAAA,GAAW,MAAA;AAAA;AAAA,UAGI,mBAAA;EACf,cAAA,EAAgB,cAAA;EAChB,aAAA;EACA,iBAAA,QAAyB,WAAW;EACpC,cAAA;EACA,QAAA,GAAW,IAAA,UAAc,SAAA;EACzB,QAAA,GAAW,IAAA;EACX,WAAA;AAAA;AAAA,cAGW,cAAA;EAAA;EAcX,WAAA,CAAY,MAAA,EAAQ,mBAAA;EAAA,IAIhB,OAAA,aAAoB,MAAA;EAIxB,gBAAA;EAIA,qBAAA;EAkBA,UAAA,cACE,OAAA,EAAS,MAAA,IACT,YAAA,EAAc,YAAA,CAAa,WAAA;EAW7B,WAAA,CAAY,SAAA,EAAW,WAAA;EAgCvB,aAAA;EAMA,OAAA;AAAA;AAAA,iBAyQc,wBAAA,CAAyB,QAAwB,EAAd,cAAc"}
@@ -2,40 +2,40 @@ import { addEventListener, getLineNumberAttr, h } from "./utils.js";
2
2
  import { setPopoverPositionStyles } from "./popover.js";
3
3
  import { selectionIntersects } from "./selection.js";
4
4
  //#region src/editor/marker.ts
5
- const MARKER_POPUP_SHOW_DELAY_MS = 300;
6
- const MARKER_POPUP_HIDE_DELAY_MS = 100;
7
- const MARKER_POPUP_PLACEMENT_KEY = "marker-popup";
5
+ const MARKER_POPOVER_SHOW_DELAY_MS = 300;
6
+ const MARKER_POPOVER_HIDE_DELAY_MS = 100;
7
+ const MARKER_POPOVER_PLACEMENT_KEY = "marker-popover";
8
8
  var MarkerRenderer = class {
9
9
  #options;
10
10
  #markers = [];
11
11
  #lineCount = 0;
12
- #markerPopupElement;
13
- #markerPopupEventDisposes;
12
+ #markerPopoverElement;
13
+ #markerPopoverEventDisposes;
14
14
  #markerEventDisposes;
15
- #markerPopupShowTimeout;
16
- #markerPopupHideTimeout;
17
- #pendingMarkerPopupIndex;
15
+ #markerPopoverShowTimeout;
16
+ #markerPopoverHideTimeout;
17
+ #pendingMarkerPopoverIndex;
18
18
  #hoveredMarkerIndex;
19
- #isMarkerPopupHovered = false;
19
+ #isMarkerPopoverHovered = false;
20
20
  constructor(editor) {
21
21
  this.#options = editor;
22
22
  }
23
23
  get markers() {
24
24
  return this.#markers;
25
25
  }
26
- isPopupVisible() {
26
+ isPopoverVisible() {
27
27
  return this.#hoveredMarkerIndex !== void 0;
28
28
  }
29
- updatePopupPosition() {
29
+ updatePopoverPosition() {
30
30
  const hoveredMarkerIndex = this.#hoveredMarkerIndex;
31
- const popup = this.#markerPopupElement;
32
- if (hoveredMarkerIndex === void 0 || popup === void 0) return;
31
+ const popover = this.#markerPopoverElement;
32
+ if (hoveredMarkerIndex === void 0 || popover === void 0) return;
33
33
  const marker = this.#markers[hoveredMarkerIndex];
34
34
  if (marker === void 0) {
35
- this.removePopup();
35
+ this.removePopover();
36
36
  return;
37
37
  }
38
- this.#positionMarkerPopup(popup, marker.start.line, marker.start.character);
38
+ this.#positionMarkerPopover(popover, marker.start.line, marker.start.character);
39
39
  }
40
40
  setMarkers(markers, textDocument) {
41
41
  this.#lineCount = textDocument.lineCount;
@@ -44,7 +44,7 @@ var MarkerRenderer = class {
44
44
  start: textDocument.normalizePosition(marker.start),
45
45
  end: textDocument.normalizePosition(marker.end)
46
46
  }));
47
- this.removePopup();
47
+ this.removePopover();
48
48
  }
49
49
  listenHover(contentEl) {
50
50
  this.#markerEventDisposes?.forEach((dispose) => dispose());
@@ -55,25 +55,25 @@ var MarkerRenderer = class {
55
55
  const target = e.composedPath()[0];
56
56
  if (target === void 0) return;
57
57
  const hoverMarkerIndex = this.#findHoveredMarkerIndex(target);
58
- if (hoverMarkerIndex !== void 0) this.#scheduleMarkerPopup(hoverMarkerIndex);
58
+ if (hoverMarkerIndex !== void 0) this.#scheduleMarkerPopover(hoverMarkerIndex);
59
59
  else {
60
- this.#cancelMarkerPopupShow();
61
- this.#scheduleMarkerPopupHide();
60
+ this.#cancelMarkerPopoverShow();
61
+ this.#scheduleMarkerPopoverHide();
62
62
  }
63
63
  }), addEventListener(contentEl, "mouseleave", () => {
64
- this.#cancelMarkerPopupShow();
65
- this.#scheduleMarkerPopupHide();
64
+ this.#cancelMarkerPopoverShow();
65
+ this.#scheduleMarkerPopoverHide();
66
66
  })];
67
67
  }
68
- removePopup() {
69
- this.#cancelMarkerPopupShow();
70
- this.#cancelMarkerPopupHide();
71
- this.#dismissMarkerPopup();
68
+ removePopover() {
69
+ this.#cancelMarkerPopoverShow();
70
+ this.#cancelMarkerPopoverHide();
71
+ this.#dismissMarkerPopover();
72
72
  }
73
73
  cleanup() {
74
74
  this.#markerEventDisposes?.forEach((dispose) => dispose());
75
75
  this.#markerEventDisposes = void 0;
76
- this.removePopup();
76
+ this.removePopover();
77
77
  this.#markers = [];
78
78
  }
79
79
  #findHoveredMarkerIndex(target) {
@@ -98,47 +98,47 @@ var MarkerRenderer = class {
98
98
  end: position
99
99
  }, this.#markers[i])) return i;
100
100
  }
101
- #cancelMarkerPopupShow() {
102
- if (this.#markerPopupShowTimeout !== void 0) {
103
- clearTimeout(this.#markerPopupShowTimeout);
104
- this.#markerPopupShowTimeout = void 0;
101
+ #cancelMarkerPopoverShow() {
102
+ if (this.#markerPopoverShowTimeout !== void 0) {
103
+ clearTimeout(this.#markerPopoverShowTimeout);
104
+ this.#markerPopoverShowTimeout = void 0;
105
105
  }
106
- this.#pendingMarkerPopupIndex = void 0;
106
+ this.#pendingMarkerPopoverIndex = void 0;
107
107
  }
108
- #cancelMarkerPopupHide() {
109
- if (this.#markerPopupHideTimeout !== void 0) {
110
- clearTimeout(this.#markerPopupHideTimeout);
111
- this.#markerPopupHideTimeout = void 0;
108
+ #cancelMarkerPopoverHide() {
109
+ if (this.#markerPopoverHideTimeout !== void 0) {
110
+ clearTimeout(this.#markerPopoverHideTimeout);
111
+ this.#markerPopoverHideTimeout = void 0;
112
112
  }
113
113
  }
114
- #scheduleMarkerPopup(markerIndex) {
115
- if (markerIndex === this.#hoveredMarkerIndex || markerIndex === this.#pendingMarkerPopupIndex) {
116
- this.#cancelMarkerPopupHide();
114
+ #scheduleMarkerPopover(markerIndex) {
115
+ if (markerIndex === this.#hoveredMarkerIndex || markerIndex === this.#pendingMarkerPopoverIndex) {
116
+ this.#cancelMarkerPopoverHide();
117
117
  return;
118
118
  }
119
- this.#cancelMarkerPopupShow();
120
- this.#cancelMarkerPopupHide();
121
- if (this.#markerPopupElement !== void 0) {
122
- this.#renderMarkerPopup(markerIndex);
119
+ this.#cancelMarkerPopoverShow();
120
+ this.#cancelMarkerPopoverHide();
121
+ if (this.#markerPopoverElement !== void 0) {
122
+ this.#renderMarkerPopover(markerIndex);
123
123
  return;
124
124
  }
125
- this.#pendingMarkerPopupIndex = markerIndex;
126
- this.#markerPopupShowTimeout = setTimeout(() => {
127
- this.#markerPopupShowTimeout = void 0;
128
- this.#pendingMarkerPopupIndex = void 0;
129
- this.#renderMarkerPopup(markerIndex);
130
- }, MARKER_POPUP_SHOW_DELAY_MS);
131
- }
132
- #scheduleMarkerPopupHide() {
133
- if (this.#isMarkerPopupHovered) return;
134
- this.#cancelMarkerPopupHide();
135
- this.#markerPopupHideTimeout = setTimeout(() => {
136
- this.#markerPopupHideTimeout = void 0;
137
- if (!this.#isMarkerPopupHovered) this.removePopup();
138
- }, MARKER_POPUP_HIDE_DELAY_MS);
139
- }
140
- #setMarkerPopupPosition(popup, x, y, placeAbove, viewport = this.#options.popoverManager.getPlacementBounds()) {
141
- setPopoverPositionStyles(popup, {
125
+ this.#pendingMarkerPopoverIndex = markerIndex;
126
+ this.#markerPopoverShowTimeout = setTimeout(() => {
127
+ this.#markerPopoverShowTimeout = void 0;
128
+ this.#pendingMarkerPopoverIndex = void 0;
129
+ this.#renderMarkerPopover(markerIndex);
130
+ }, MARKER_POPOVER_SHOW_DELAY_MS);
131
+ }
132
+ #scheduleMarkerPopoverHide() {
133
+ if (this.#isMarkerPopoverHovered) return;
134
+ this.#cancelMarkerPopoverHide();
135
+ this.#markerPopoverHideTimeout = setTimeout(() => {
136
+ this.#markerPopoverHideTimeout = void 0;
137
+ if (!this.#isMarkerPopoverHovered) this.removePopover();
138
+ }, MARKER_POPOVER_HIDE_DELAY_MS);
139
+ }
140
+ #setMarkerPopoverPosition(popover, x, y, placeAbove, viewport = this.#options.popoverManager.getPlacementBounds()) {
141
+ setPopoverPositionStyles(popover, {
142
142
  gutterWidth: this.#options.getGutterWidth(),
143
143
  placeAbove,
144
144
  viewport,
@@ -146,12 +146,12 @@ var MarkerRenderer = class {
146
146
  y
147
147
  });
148
148
  }
149
- #positionMarkerPopup(popup, line, character) {
149
+ #positionMarkerPopover(popover, line, character) {
150
150
  const { getCharX, getLineY, getLineHeight, popoverManager } = this.#options;
151
151
  const [left, wrapLine] = getCharX(line, character);
152
152
  const lineHeight = getLineHeight();
153
153
  const rowTop = getLineY(line) + wrapLine * lineHeight;
154
- const popoverHeight = popup.offsetHeight;
154
+ const popoverHeight = popover.offsetHeight;
155
155
  const preferred = {
156
156
  top: rowTop + lineHeight,
157
157
  bottom: rowTop + lineHeight + popoverHeight
@@ -168,41 +168,41 @@ var MarkerRenderer = class {
168
168
  viewport,
169
169
  popoverHeight,
170
170
  atDocumentEdge,
171
- placementKey: MARKER_POPUP_PLACEMENT_KEY
171
+ placementKey: MARKER_POPOVER_PLACEMENT_KEY
172
172
  }) === "fallback";
173
- this.#setMarkerPopupPosition(popup, left, placeAbove ? rowTop : rowTop + lineHeight, placeAbove, viewport);
173
+ this.#setMarkerPopoverPosition(popover, left, placeAbove ? rowTop : rowTop + lineHeight, placeAbove, viewport);
174
174
  }
175
- #dismissMarkerPopup() {
176
- this.#markerPopupEventDisposes?.forEach((dispose) => dispose());
177
- this.#markerPopupEventDisposes = void 0;
178
- this.#markerPopupElement?.remove();
179
- this.#markerPopupElement = void 0;
175
+ #dismissMarkerPopover() {
176
+ this.#markerPopoverEventDisposes?.forEach((dispose) => dispose());
177
+ this.#markerPopoverEventDisposes = void 0;
178
+ this.#markerPopoverElement?.remove();
179
+ this.#markerPopoverElement = void 0;
180
180
  this.#hoveredMarkerIndex = void 0;
181
- this.#isMarkerPopupHovered = false;
182
- this.#options.popoverManager.resetPlacement(MARKER_POPUP_PLACEMENT_KEY);
181
+ this.#isMarkerPopoverHovered = false;
182
+ this.#options.popoverManager.resetPlacement(MARKER_POPOVER_PLACEMENT_KEY);
183
183
  }
184
- #renderMarkerPopup(hoveredMarkerIndex) {
184
+ #renderMarkerPopover(hoveredMarkerIndex) {
185
185
  if (hoveredMarkerIndex === this.#hoveredMarkerIndex) return;
186
186
  const overlayElement = this.#options.getOverlayElement();
187
187
  if (hoveredMarkerIndex >= this.#markers.length || overlayElement == null) return;
188
188
  const { start, message, severity } = this.#markers[hoveredMarkerIndex];
189
189
  const { line, character } = start;
190
- const popup = this.#markerPopupElement;
191
- this.#options.popoverManager.resetPlacement(MARKER_POPUP_PLACEMENT_KEY);
192
- if (popup !== void 0) {
193
- setMarkerPopupSeverity(popup, severity);
194
- const content = popup.firstElementChild;
190
+ const popover = this.#markerPopoverElement;
191
+ this.#options.popoverManager.resetPlacement(MARKER_POPOVER_PLACEMENT_KEY);
192
+ if (popover !== void 0) {
193
+ setMarkerPopoverSeverity(popover, severity);
194
+ const content = popover.firstElementChild;
195
195
  if (content?.dataset.markerMessage !== void 0) if (typeof message === "string") content.textContent = message;
196
196
  else if (message instanceof HTMLElement) content.replaceChildren(message);
197
197
  else content.innerHTML = message.html;
198
- this.#positionMarkerPopup(popup, line, character);
198
+ this.#positionMarkerPopover(popover, line, character);
199
199
  this.#hoveredMarkerIndex = hoveredMarkerIndex;
200
200
  return;
201
201
  }
202
- this.#markerPopupElement = h("div", {
202
+ this.#markerPopoverElement = h("div", {
203
203
  dataset: {
204
204
  editorWidget: "",
205
- markerPopup: "",
205
+ markerPopover: "",
206
206
  [markerSeverityDatasetKey(severity)]: ""
207
207
  },
208
208
  children: [h("div", {
@@ -210,14 +210,14 @@ var MarkerRenderer = class {
210
210
  ...typeof message === "string" ? { textContent: message } : message instanceof HTMLElement ? { children: [message] } : { innerHTML: message.html }
211
211
  })]
212
212
  }, overlayElement);
213
- this.#positionMarkerPopup(this.#markerPopupElement, line, character);
213
+ this.#positionMarkerPopover(this.#markerPopoverElement, line, character);
214
214
  this.#hoveredMarkerIndex = hoveredMarkerIndex;
215
- this.#markerPopupEventDisposes = [addEventListener(this.#markerPopupElement, "mouseenter", () => {
216
- this.#isMarkerPopupHovered = true;
217
- this.#cancelMarkerPopupHide();
218
- }), addEventListener(this.#markerPopupElement, "mouseleave", () => {
219
- this.#isMarkerPopupHovered = false;
220
- this.#scheduleMarkerPopupHide();
215
+ this.#markerPopoverEventDisposes = [addEventListener(this.#markerPopoverElement, "mouseenter", () => {
216
+ this.#isMarkerPopoverHovered = true;
217
+ this.#cancelMarkerPopoverHide();
218
+ }), addEventListener(this.#markerPopoverElement, "mouseleave", () => {
219
+ this.#isMarkerPopoverHovered = false;
220
+ this.#scheduleMarkerPopoverHide();
221
221
  })];
222
222
  }
223
223
  };
@@ -227,9 +227,9 @@ const MARKER_SEVERITIES = [
227
227
  "info",
228
228
  "hint"
229
229
  ];
230
- function setMarkerPopupSeverity(popup, severity) {
231
- for (const candidate of MARKER_SEVERITIES) delete popup.dataset[markerSeverityDatasetKey(candidate)];
232
- popup.dataset[markerSeverityDatasetKey(severity)] = "";
230
+ function setMarkerPopoverSeverity(popover, severity) {
231
+ for (const candidate of MARKER_SEVERITIES) delete popover.dataset[markerSeverityDatasetKey(candidate)];
232
+ popover.dataset[markerSeverityDatasetKey(severity)] = "";
233
233
  }
234
234
  function markerSeverityDatasetKey(severity) {
235
235
  switch (severity) {
@@ -1 +1 @@
1
- {"version":3,"file":"marker.js","names":["#options","#markers","#hoveredMarkerIndex","#markerPopupElement","#positionMarkerPopup","#lineCount","#markerEventDisposes","#findHoveredMarkerIndex","#scheduleMarkerPopup","#cancelMarkerPopupShow","#scheduleMarkerPopupHide","#cancelMarkerPopupHide","#dismissMarkerPopup","#markerPopupShowTimeout","#pendingMarkerPopupIndex","#markerPopupHideTimeout","#renderMarkerPopup","#isMarkerPopupHovered","#setMarkerPopupPosition","#markerPopupEventDisposes"],"sources":["../../src/editor/marker.ts"],"sourcesContent":["import type { Position, Range } from '../types';\nimport {\n POPOVER_BOUNDARY_LINES,\n type PopoverManager,\n type PopoverPlacementBounds,\n setPopoverPositionStyles,\n} from './popover';\nimport { selectionIntersects } from './selection';\nimport type { TextDocument } from './textDocument';\nimport { addEventListener, getLineNumberAttr, h } from './utils';\n\nconst MARKER_POPUP_SHOW_DELAY_MS = 300;\nconst MARKER_POPUP_HIDE_DELAY_MS = 100;\nconst MARKER_POPUP_PLACEMENT_KEY = 'marker-popup';\n\nexport type MarkerSeverity = 'error' | 'warning' | 'info' | 'hint';\n\nexport interface Marker extends Range {\n severity: MarkerSeverity;\n message: string | { html: string } | HTMLElement;\n source?: string;\n metadata?: Record<string, unknown>;\n}\n\nexport interface MarkerRenderOptions {\n popoverManager: PopoverManager;\n getLineHeight: () => number;\n getOverlayElement: () => HTMLElement | undefined;\n getGutterWidth: () => number;\n getCharX: (line: number, character: number) => [number, number];\n getLineY: (line: number) => number;\n isMouseDown: () => boolean;\n}\n\nexport class MarkerRenderer {\n #options: MarkerRenderOptions;\n #markers: Marker[] = [];\n // Document line count, used only by the no-viewport document-edge fallback.\n #lineCount = 0;\n #markerPopupElement?: HTMLElement;\n #markerPopupEventDisposes?: (() => void)[];\n #markerEventDisposes?: (() => void)[];\n #markerPopupShowTimeout?: ReturnType<typeof setTimeout>;\n #markerPopupHideTimeout?: ReturnType<typeof setTimeout>;\n #pendingMarkerPopupIndex?: number;\n #hoveredMarkerIndex?: number;\n #isMarkerPopupHovered = false;\n\n constructor(editor: MarkerRenderOptions) {\n this.#options = editor;\n }\n\n get markers(): readonly Marker[] {\n return this.#markers;\n }\n\n isPopupVisible(): boolean {\n return this.#hoveredMarkerIndex !== undefined;\n }\n\n updatePopupPosition(): void {\n const hoveredMarkerIndex = this.#hoveredMarkerIndex;\n const popup = this.#markerPopupElement;\n if (hoveredMarkerIndex === undefined || popup === undefined) {\n return;\n }\n const marker = this.#markers[hoveredMarkerIndex];\n if (marker === undefined) {\n this.removePopup();\n return;\n }\n this.#positionMarkerPopup(popup, marker.start.line, marker.start.character);\n }\n\n setMarkers<LAnnotation>(\n markers: Marker[],\n textDocument: TextDocument<LAnnotation>\n ): void {\n this.#lineCount = textDocument.lineCount;\n this.#markers = markers.map((marker) => ({\n ...marker,\n start: textDocument.normalizePosition(marker.start),\n end: textDocument.normalizePosition(marker.end),\n }));\n this.removePopup();\n }\n\n listenHover(contentEl: HTMLElement): void {\n this.#markerEventDisposes?.forEach((dispose) => dispose());\n this.#markerEventDisposes = undefined;\n if (this.#markers.length === 0) {\n return;\n }\n\n this.#markerEventDisposes = [\n addEventListener(contentEl, 'mouseover', (e) => {\n if (this.#options.isMouseDown()) {\n return;\n }\n const target = e.composedPath()[0] as HTMLElement | undefined;\n if (target === undefined) {\n return;\n }\n\n const hoverMarkerIndex = this.#findHoveredMarkerIndex(target);\n if (hoverMarkerIndex !== undefined) {\n this.#scheduleMarkerPopup(hoverMarkerIndex);\n } else {\n this.#cancelMarkerPopupShow();\n this.#scheduleMarkerPopupHide();\n }\n }),\n addEventListener(contentEl, 'mouseleave', () => {\n this.#cancelMarkerPopupShow();\n this.#scheduleMarkerPopupHide();\n }),\n ];\n }\n\n removePopup(): void {\n this.#cancelMarkerPopupShow();\n this.#cancelMarkerPopupHide();\n this.#dismissMarkerPopup();\n }\n\n cleanup(): void {\n this.#markerEventDisposes?.forEach((dispose) => dispose());\n this.#markerEventDisposes = undefined;\n this.removePopup();\n this.#markers = [];\n }\n\n #findHoveredMarkerIndex(target: HTMLElement): number | undefined {\n const lineElement = target.closest('[data-line]');\n if (lineElement == null) {\n return;\n }\n\n const lineNumber = getLineNumberAttr(lineElement as HTMLElement);\n if (lineNumber === undefined) {\n return;\n }\n\n let character: number | undefined;\n if (target.tagName === 'SPAN') {\n const char = target.dataset.char;\n if (char === undefined) {\n return;\n }\n character = parseInt(char, 10);\n if (Number.isNaN(character)) {\n return;\n }\n } else if (target.tagName === 'BR') {\n character = 0;\n } else {\n return;\n }\n\n const position: Position = { line: lineNumber - 1, character };\n for (let i = this.#markers.length - 1; i >= 0; i--) {\n if (\n selectionIntersects(\n { start: position, end: position },\n this.#markers[i]\n )\n ) {\n return i;\n }\n }\n return undefined;\n }\n\n #cancelMarkerPopupShow(): void {\n if (this.#markerPopupShowTimeout !== undefined) {\n clearTimeout(this.#markerPopupShowTimeout);\n this.#markerPopupShowTimeout = undefined;\n }\n this.#pendingMarkerPopupIndex = undefined;\n }\n\n #cancelMarkerPopupHide(): void {\n if (this.#markerPopupHideTimeout !== undefined) {\n clearTimeout(this.#markerPopupHideTimeout);\n this.#markerPopupHideTimeout = undefined;\n }\n }\n\n #scheduleMarkerPopup(markerIndex: number): void {\n if (\n markerIndex === this.#hoveredMarkerIndex ||\n markerIndex === this.#pendingMarkerPopupIndex\n ) {\n this.#cancelMarkerPopupHide();\n return;\n }\n\n this.#cancelMarkerPopupShow();\n this.#cancelMarkerPopupHide();\n if (this.#markerPopupElement !== undefined) {\n this.#renderMarkerPopup(markerIndex);\n return;\n }\n\n this.#pendingMarkerPopupIndex = markerIndex;\n this.#markerPopupShowTimeout = setTimeout(() => {\n this.#markerPopupShowTimeout = undefined;\n this.#pendingMarkerPopupIndex = undefined;\n this.#renderMarkerPopup(markerIndex);\n }, MARKER_POPUP_SHOW_DELAY_MS);\n }\n\n #scheduleMarkerPopupHide(): void {\n if (this.#isMarkerPopupHovered) {\n return;\n }\n\n this.#cancelMarkerPopupHide();\n this.#markerPopupHideTimeout = setTimeout(() => {\n this.#markerPopupHideTimeout = undefined;\n if (!this.#isMarkerPopupHovered) {\n this.removePopup();\n }\n }, MARKER_POPUP_HIDE_DELAY_MS);\n }\n\n // Positions the popup in overlay coordinate space (see [data-marker-popup]\n // in editor.css). When `placeAbove` is true, `y` is the top edge of the\n // marker's row and the popup is shifted up by its own height.\n #setMarkerPopupPosition(\n popup: HTMLElement,\n x: number,\n y: number,\n placeAbove: boolean,\n viewport = this.#options.popoverManager.getPlacementBounds()\n ): void {\n setPopoverPositionStyles(popup, {\n gutterWidth: this.#options.getGutterWidth(),\n placeAbove,\n viewport,\n x,\n y,\n });\n }\n\n // Positions the popup for a marker at `(line, character)`: prefers below\n // (the default), flipping above when below would be clipped by the visible\n // scrollport. Must run after the popup's content is final, since it reads\n // the popup's rendered height to decide whether either side fits.\n #positionMarkerPopup(\n popup: HTMLElement,\n line: number,\n character: number\n ): void {\n const { getCharX, getLineY, getLineHeight, popoverManager } = this.#options;\n const [left, wrapLine] = getCharX(line, character);\n const lineHeight = getLineHeight();\n const rowTop = getLineY(line) + wrapLine * lineHeight;\n const popoverHeight = popup.offsetHeight;\n\n const preferred: PopoverPlacementBounds = {\n top: rowTop + lineHeight,\n bottom: rowTop + lineHeight + popoverHeight,\n };\n const fallback: PopoverPlacementBounds = {\n top: rowTop - popoverHeight,\n bottom: rowTop,\n };\n const atDocumentEdge = line >= this.#lineCount - POPOVER_BOUNDARY_LINES;\n const viewport = popoverManager.getPlacementBounds();\n const placeAbove =\n popoverManager.choosePlacement({\n preferred,\n fallback,\n viewport,\n popoverHeight,\n atDocumentEdge,\n placementKey: MARKER_POPUP_PLACEMENT_KEY,\n }) === 'fallback';\n\n this.#setMarkerPopupPosition(\n popup,\n left,\n placeAbove ? rowTop : rowTop + lineHeight,\n placeAbove,\n viewport\n );\n }\n\n #dismissMarkerPopup(): void {\n this.#markerPopupEventDisposes?.forEach((dispose) => dispose());\n this.#markerPopupEventDisposes = undefined;\n this.#markerPopupElement?.remove();\n this.#markerPopupElement = undefined;\n this.#hoveredMarkerIndex = undefined;\n this.#isMarkerPopupHovered = false;\n this.#options.popoverManager.resetPlacement(MARKER_POPUP_PLACEMENT_KEY);\n }\n\n #renderMarkerPopup(hoveredMarkerIndex: number): void {\n if (hoveredMarkerIndex === this.#hoveredMarkerIndex) {\n return;\n }\n\n const overlayElement = this.#options.getOverlayElement();\n if (hoveredMarkerIndex >= this.#markers.length || overlayElement == null) {\n return;\n }\n\n const { start, message, severity } = this.#markers[hoveredMarkerIndex];\n const { line, character } = start;\n const popup = this.#markerPopupElement;\n this.#options.popoverManager.resetPlacement(MARKER_POPUP_PLACEMENT_KEY);\n\n if (popup !== undefined) {\n setMarkerPopupSeverity(popup, severity);\n const content = popup.firstElementChild as HTMLElement | null;\n if (content?.dataset.markerMessage !== undefined) {\n if (typeof message === 'string') {\n content.textContent = message;\n } else if (message instanceof HTMLElement) {\n content.replaceChildren(message);\n } else {\n content.innerHTML = message.html;\n }\n }\n // Position after updating content: a different message size changes\n // the offsetHeight #positionMarkerPopup reads to decide placement.\n this.#positionMarkerPopup(popup, line, character);\n this.#hoveredMarkerIndex = hoveredMarkerIndex;\n return;\n }\n\n this.#markerPopupElement = h(\n 'div',\n {\n dataset: {\n editorWidget: '',\n markerPopup: '',\n [markerSeverityDatasetKey(severity)]: '',\n },\n children: [\n h('div', {\n dataset: 'markerMessage',\n ...(typeof message === 'string'\n ? { textContent: message }\n : message instanceof HTMLElement\n ? { children: [message] }\n : { innerHTML: message.html }),\n }),\n ],\n },\n overlayElement\n );\n this.#positionMarkerPopup(this.#markerPopupElement, line, character);\n this.#hoveredMarkerIndex = hoveredMarkerIndex;\n this.#markerPopupEventDisposes = [\n addEventListener(this.#markerPopupElement, 'mouseenter', () => {\n this.#isMarkerPopupHovered = true;\n this.#cancelMarkerPopupHide();\n }),\n addEventListener(this.#markerPopupElement, 'mouseleave', () => {\n this.#isMarkerPopupHovered = false;\n this.#scheduleMarkerPopupHide();\n }),\n ];\n }\n}\n\nconst MARKER_SEVERITIES: readonly MarkerSeverity[] = [\n 'error',\n 'warning',\n 'info',\n 'hint',\n];\n\n// Marks the popup with data-marker-<severity> (the same boolean attribute the\n// squiggle range element uses) so the CSS severity palette can target both with\n// a single selector. The popup element is reused across hovers, so any\n// previously applied severity attribute is cleared first.\nfunction setMarkerPopupSeverity(\n popup: HTMLElement,\n severity: MarkerSeverity\n): void {\n for (const candidate of MARKER_SEVERITIES) {\n delete popup.dataset[markerSeverityDatasetKey(candidate)];\n }\n popup.dataset[markerSeverityDatasetKey(severity)] = '';\n}\n\nexport function markerSeverityDatasetKey(severity: MarkerSeverity): string {\n switch (severity) {\n case 'error':\n return 'markerError';\n case 'warning':\n return 'markerWarning';\n case 'info':\n return 'markerInfo';\n case 'hint':\n return 'markerHint';\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"marker.js","names":["#options","#markers","#hoveredMarkerIndex","#markerPopoverElement","#positionMarkerPopover","#lineCount","#markerEventDisposes","#findHoveredMarkerIndex","#scheduleMarkerPopover","#cancelMarkerPopoverShow","#scheduleMarkerPopoverHide","#cancelMarkerPopoverHide","#dismissMarkerPopover","#markerPopoverShowTimeout","#pendingMarkerPopoverIndex","#markerPopoverHideTimeout","#renderMarkerPopover","#isMarkerPopoverHovered","#setMarkerPopoverPosition","#markerPopoverEventDisposes"],"sources":["../../src/editor/marker.ts"],"sourcesContent":["import type { Position, Range } from '../types';\nimport {\n POPOVER_BOUNDARY_LINES,\n type PopoverManager,\n type PopoverPlacementBounds,\n setPopoverPositionStyles,\n} from './popover';\nimport { selectionIntersects } from './selection';\nimport type { TextDocument } from './textDocument';\nimport { addEventListener, getLineNumberAttr, h } from './utils';\n\nconst MARKER_POPOVER_SHOW_DELAY_MS = 300;\nconst MARKER_POPOVER_HIDE_DELAY_MS = 100;\nconst MARKER_POPOVER_PLACEMENT_KEY = 'marker-popover';\n\nexport type MarkerSeverity = 'error' | 'warning' | 'info' | 'hint';\n\nexport interface Marker extends Range {\n severity: MarkerSeverity;\n message: string | { html: string } | HTMLElement;\n source?: string;\n metadata?: Record<string, unknown>;\n}\n\nexport interface MarkerRenderOptions {\n popoverManager: PopoverManager;\n getLineHeight: () => number;\n getOverlayElement: () => HTMLElement | undefined;\n getGutterWidth: () => number;\n getCharX: (line: number, character: number) => [number, number];\n getLineY: (line: number) => number;\n isMouseDown: () => boolean;\n}\n\nexport class MarkerRenderer {\n #options: MarkerRenderOptions;\n #markers: Marker[] = [];\n // Document line count, used only by the no-viewport document-edge fallback.\n #lineCount = 0;\n #markerPopoverElement?: HTMLElement;\n #markerPopoverEventDisposes?: (() => void)[];\n #markerEventDisposes?: (() => void)[];\n #markerPopoverShowTimeout?: ReturnType<typeof setTimeout>;\n #markerPopoverHideTimeout?: ReturnType<typeof setTimeout>;\n #pendingMarkerPopoverIndex?: number;\n #hoveredMarkerIndex?: number;\n #isMarkerPopoverHovered = false;\n\n constructor(editor: MarkerRenderOptions) {\n this.#options = editor;\n }\n\n get markers(): readonly Marker[] {\n return this.#markers;\n }\n\n isPopoverVisible(): boolean {\n return this.#hoveredMarkerIndex !== undefined;\n }\n\n updatePopoverPosition(): void {\n const hoveredMarkerIndex = this.#hoveredMarkerIndex;\n const popover = this.#markerPopoverElement;\n if (hoveredMarkerIndex === undefined || popover === undefined) {\n return;\n }\n const marker = this.#markers[hoveredMarkerIndex];\n if (marker === undefined) {\n this.removePopover();\n return;\n }\n this.#positionMarkerPopover(\n popover,\n marker.start.line,\n marker.start.character\n );\n }\n\n setMarkers<LAnnotation>(\n markers: Marker[],\n textDocument: TextDocument<LAnnotation>\n ): void {\n this.#lineCount = textDocument.lineCount;\n this.#markers = markers.map((marker) => ({\n ...marker,\n start: textDocument.normalizePosition(marker.start),\n end: textDocument.normalizePosition(marker.end),\n }));\n this.removePopover();\n }\n\n listenHover(contentEl: HTMLElement): void {\n this.#markerEventDisposes?.forEach((dispose) => dispose());\n this.#markerEventDisposes = undefined;\n if (this.#markers.length === 0) {\n return;\n }\n\n this.#markerEventDisposes = [\n addEventListener(contentEl, 'mouseover', (e) => {\n if (this.#options.isMouseDown()) {\n return;\n }\n const target = e.composedPath()[0] as HTMLElement | undefined;\n if (target === undefined) {\n return;\n }\n\n const hoverMarkerIndex = this.#findHoveredMarkerIndex(target);\n if (hoverMarkerIndex !== undefined) {\n this.#scheduleMarkerPopover(hoverMarkerIndex);\n } else {\n this.#cancelMarkerPopoverShow();\n this.#scheduleMarkerPopoverHide();\n }\n }),\n addEventListener(contentEl, 'mouseleave', () => {\n this.#cancelMarkerPopoverShow();\n this.#scheduleMarkerPopoverHide();\n }),\n ];\n }\n\n removePopover(): void {\n this.#cancelMarkerPopoverShow();\n this.#cancelMarkerPopoverHide();\n this.#dismissMarkerPopover();\n }\n\n cleanup(): void {\n this.#markerEventDisposes?.forEach((dispose) => dispose());\n this.#markerEventDisposes = undefined;\n this.removePopover();\n this.#markers = [];\n }\n\n #findHoveredMarkerIndex(target: HTMLElement): number | undefined {\n const lineElement = target.closest('[data-line]');\n if (lineElement == null) {\n return;\n }\n\n const lineNumber = getLineNumberAttr(lineElement as HTMLElement);\n if (lineNumber === undefined) {\n return;\n }\n\n let character: number | undefined;\n if (target.tagName === 'SPAN') {\n const char = target.dataset.char;\n if (char === undefined) {\n return;\n }\n character = parseInt(char, 10);\n if (Number.isNaN(character)) {\n return;\n }\n } else if (target.tagName === 'BR') {\n character = 0;\n } else {\n return;\n }\n\n const position: Position = { line: lineNumber - 1, character };\n for (let i = this.#markers.length - 1; i >= 0; i--) {\n if (\n selectionIntersects(\n { start: position, end: position },\n this.#markers[i]\n )\n ) {\n return i;\n }\n }\n return undefined;\n }\n\n #cancelMarkerPopoverShow(): void {\n if (this.#markerPopoverShowTimeout !== undefined) {\n clearTimeout(this.#markerPopoverShowTimeout);\n this.#markerPopoverShowTimeout = undefined;\n }\n this.#pendingMarkerPopoverIndex = undefined;\n }\n\n #cancelMarkerPopoverHide(): void {\n if (this.#markerPopoverHideTimeout !== undefined) {\n clearTimeout(this.#markerPopoverHideTimeout);\n this.#markerPopoverHideTimeout = undefined;\n }\n }\n\n #scheduleMarkerPopover(markerIndex: number): void {\n if (\n markerIndex === this.#hoveredMarkerIndex ||\n markerIndex === this.#pendingMarkerPopoverIndex\n ) {\n this.#cancelMarkerPopoverHide();\n return;\n }\n\n this.#cancelMarkerPopoverShow();\n this.#cancelMarkerPopoverHide();\n if (this.#markerPopoverElement !== undefined) {\n this.#renderMarkerPopover(markerIndex);\n return;\n }\n\n this.#pendingMarkerPopoverIndex = markerIndex;\n this.#markerPopoverShowTimeout = setTimeout(() => {\n this.#markerPopoverShowTimeout = undefined;\n this.#pendingMarkerPopoverIndex = undefined;\n this.#renderMarkerPopover(markerIndex);\n }, MARKER_POPOVER_SHOW_DELAY_MS);\n }\n\n #scheduleMarkerPopoverHide(): void {\n if (this.#isMarkerPopoverHovered) {\n return;\n }\n\n this.#cancelMarkerPopoverHide();\n this.#markerPopoverHideTimeout = setTimeout(() => {\n this.#markerPopoverHideTimeout = undefined;\n if (!this.#isMarkerPopoverHovered) {\n this.removePopover();\n }\n }, MARKER_POPOVER_HIDE_DELAY_MS);\n }\n\n // Positions the popover in overlay coordinate space (see [data-marker-popover]\n // in editor.css). When `placeAbove` is true, `y` is the top edge of the\n // marker's row and the popover is shifted up by its own height.\n #setMarkerPopoverPosition(\n popover: HTMLElement,\n x: number,\n y: number,\n placeAbove: boolean,\n viewport = this.#options.popoverManager.getPlacementBounds()\n ): void {\n setPopoverPositionStyles(popover, {\n gutterWidth: this.#options.getGutterWidth(),\n placeAbove,\n viewport,\n x,\n y,\n });\n }\n\n // Positions the popover for a marker at `(line, character)`: prefers below\n // (the default), flipping above when below would be clipped by the visible\n // scrollport. Must run after the popover's content is final, since it reads\n // the popover's rendered height to decide whether either side fits.\n #positionMarkerPopover(\n popover: HTMLElement,\n line: number,\n character: number\n ): void {\n const { getCharX, getLineY, getLineHeight, popoverManager } = this.#options;\n const [left, wrapLine] = getCharX(line, character);\n const lineHeight = getLineHeight();\n const rowTop = getLineY(line) + wrapLine * lineHeight;\n const popoverHeight = popover.offsetHeight;\n\n const preferred: PopoverPlacementBounds = {\n top: rowTop + lineHeight,\n bottom: rowTop + lineHeight + popoverHeight,\n };\n const fallback: PopoverPlacementBounds = {\n top: rowTop - popoverHeight,\n bottom: rowTop,\n };\n const atDocumentEdge = line >= this.#lineCount - POPOVER_BOUNDARY_LINES;\n const viewport = popoverManager.getPlacementBounds();\n const placeAbove =\n popoverManager.choosePlacement({\n preferred,\n fallback,\n viewport,\n popoverHeight,\n atDocumentEdge,\n placementKey: MARKER_POPOVER_PLACEMENT_KEY,\n }) === 'fallback';\n\n this.#setMarkerPopoverPosition(\n popover,\n left,\n placeAbove ? rowTop : rowTop + lineHeight,\n placeAbove,\n viewport\n );\n }\n\n #dismissMarkerPopover(): void {\n this.#markerPopoverEventDisposes?.forEach((dispose) => dispose());\n this.#markerPopoverEventDisposes = undefined;\n this.#markerPopoverElement?.remove();\n this.#markerPopoverElement = undefined;\n this.#hoveredMarkerIndex = undefined;\n this.#isMarkerPopoverHovered = false;\n this.#options.popoverManager.resetPlacement(MARKER_POPOVER_PLACEMENT_KEY);\n }\n\n #renderMarkerPopover(hoveredMarkerIndex: number): void {\n if (hoveredMarkerIndex === this.#hoveredMarkerIndex) {\n return;\n }\n\n const overlayElement = this.#options.getOverlayElement();\n if (hoveredMarkerIndex >= this.#markers.length || overlayElement == null) {\n return;\n }\n\n const { start, message, severity } = this.#markers[hoveredMarkerIndex];\n const { line, character } = start;\n const popover = this.#markerPopoverElement;\n this.#options.popoverManager.resetPlacement(MARKER_POPOVER_PLACEMENT_KEY);\n\n if (popover !== undefined) {\n setMarkerPopoverSeverity(popover, severity);\n const content = popover.firstElementChild as HTMLElement | null;\n if (content?.dataset.markerMessage !== undefined) {\n if (typeof message === 'string') {\n content.textContent = message;\n } else if (message instanceof HTMLElement) {\n content.replaceChildren(message);\n } else {\n content.innerHTML = message.html;\n }\n }\n // Position after updating content: a different message size changes\n // the offsetHeight #positionMarkerPopover reads to decide placement.\n this.#positionMarkerPopover(popover, line, character);\n this.#hoveredMarkerIndex = hoveredMarkerIndex;\n return;\n }\n\n this.#markerPopoverElement = h(\n 'div',\n {\n dataset: {\n editorWidget: '',\n markerPopover: '',\n [markerSeverityDatasetKey(severity)]: '',\n },\n children: [\n h('div', {\n dataset: 'markerMessage',\n ...(typeof message === 'string'\n ? { textContent: message }\n : message instanceof HTMLElement\n ? { children: [message] }\n : { innerHTML: message.html }),\n }),\n ],\n },\n overlayElement\n );\n this.#positionMarkerPopover(this.#markerPopoverElement, line, character);\n this.#hoveredMarkerIndex = hoveredMarkerIndex;\n this.#markerPopoverEventDisposes = [\n addEventListener(this.#markerPopoverElement, 'mouseenter', () => {\n this.#isMarkerPopoverHovered = true;\n this.#cancelMarkerPopoverHide();\n }),\n addEventListener(this.#markerPopoverElement, 'mouseleave', () => {\n this.#isMarkerPopoverHovered = false;\n this.#scheduleMarkerPopoverHide();\n }),\n ];\n }\n}\n\nconst MARKER_SEVERITIES: readonly MarkerSeverity[] = [\n 'error',\n 'warning',\n 'info',\n 'hint',\n];\n\n// Marks the popover with data-marker-<severity> (the same boolean attribute the\n// squiggle range element uses) so the CSS severity palette can target both with\n// a single selector. The popover element is reused across hovers, so any\n// previously applied severity attribute is cleared first.\nfunction setMarkerPopoverSeverity(\n popover: HTMLElement,\n severity: MarkerSeverity\n): void {\n for (const candidate of MARKER_SEVERITIES) {\n delete popover.dataset[markerSeverityDatasetKey(candidate)];\n }\n popover.dataset[markerSeverityDatasetKey(severity)] = '';\n}\n\nexport function markerSeverityDatasetKey(severity: MarkerSeverity): string {\n switch (severity) {\n case 'error':\n return 'markerError';\n case 'warning':\n return 'markerWarning';\n case 'info':\n return 'markerInfo';\n case 'hint':\n return 'markerHint';\n }\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"pieceTable.d.ts","names":[],"sources":["../../src/editor/pieceTable.ts"],"mappings":";;;;;;;AA6GA;;;;;;;cAAa,UAAA;EAAA;EAcX,WAAA,CAAY,YAAA;EAAA,IAQR,SAAA;EAIJ,OAAA,CAAQ,KAAA,GAAQ,KAAA;EAShB,WAAA,CAAY,IAAA,UAAc,gBAAA;EAkB1B,aAAA,CAAc,IAAA,UAAc,gBAAA;EAqC5B,YAAA,CAAa,KAAA,UAAe,GAAA,UAAa,OAAA;EAsCzC,MAAA,CAAO,MAAA;EAWP,QAAA,CAAS,MAAA;EA2BT,+BAAA,CACE,MAAA,UACA,QAAA,YAAoB,KAAA,UAAe,GAAA;EA0CrC,MAAA,CAAO,YAAA,EAAc,YAAA,IAAgB,KAAA,UAAe,GAAA;EA4EpD,MAAA,CAAO,IAAA,UAAc,MAAA;EAQrB,MAAA,CAAO,MAAA,UAAgB,MAAA;EAYvB,UAAA,CAAW,KAAA,WAAgB,gBAAA;EAgB3B,UAAA,CAAW,MAAA,WAAiB,QAAA;EAa5B,WAAA,CAAY,OAAA,sBAA6B,QAAA;EAgBzC,QAAA,CAAS,QAAA,EAAU,QAAA;AAAA;;;;;iBAioBL,0BAAA,CACd,UAAA,GAAa,MAAA,aAAmB,QAAA,EAChC,QAAA,GAAW,QAAA,EAAU,QAAA,aACrB,WAAA,GAAc,IAAA,qBACd,YAAA,EAAc,YAAA,EACd,UAAA,UACA,QAAA"}
1
+ {"version":3,"file":"pieceTable.d.ts","names":[],"sources":["../../src/editor/pieceTable.ts"],"mappings":";;;;;;;AAsHA;;;;;;;cAAa,UAAA;EAAA;EAiBX,WAAA,CAAY,YAAA;EAAA,IAQR,SAAA;EAIJ,OAAA,CAAQ,KAAA,GAAQ,KAAA;EAShB,WAAA,CAAY,IAAA,UAAc,gBAAA;EAkB1B,aAAA,CAAc,IAAA,UAAc,gBAAA;EAqC5B,YAAA,CAAa,KAAA,UAAe,GAAA,UAAa,OAAA;EAsCzC,MAAA,CAAO,MAAA;EAWP,QAAA,CAAS,MAAA;EA2BT,+BAAA,CACE,MAAA,UACA,QAAA,YAAoB,KAAA,UAAe,GAAA;EA0CrC,MAAA,CAAO,YAAA,EAAc,YAAA,IAAgB,KAAA,UAAe,GAAA;EAsFpD,MAAA,CAAO,IAAA,UAAc,MAAA;EASrB,MAAA,CAAO,MAAA,UAAgB,MAAA;EAavB,UAAA,CAAW,KAAA,WAAgB,gBAAA;EAiB3B,UAAA,CAAW,MAAA,WAAiB,QAAA;EAY5B,WAAA,CAAY,OAAA,sBAA6B,QAAA;EAgBzC,QAAA,CAAS,QAAA,EAAU,QAAA;AAAA;;;;;iBA6qBL,0BAAA,CACd,UAAA,GAAa,MAAA,aAAmB,QAAA,EAChC,QAAA,GAAW,QAAA,EAAU,QAAA,aACrB,WAAA,GAAc,IAAA,qBACd,YAAA,EAAc,YAAA,EACd,UAAA,UACA,QAAA"}
@@ -38,8 +38,12 @@ var TextBuffer = class {
38
38
  }
39
39
  append(text) {
40
40
  const offset = this.text.length;
41
- const appendedLineOffsets = computeLineOffsets(text);
42
- for (let i = 1; i < appendedLineOffsets.length; i++) this.lineOffsets.push(offset + appendedLineOffsets[i]);
41
+ for (let i = 0; i < text.length; i++) {
42
+ const charCode = text.charCodeAt(i);
43
+ if (charCode !== LINE_FEED && charCode !== CARRIAGE_RETURN) continue;
44
+ if (charCode === CARRIAGE_RETURN && text.charCodeAt(i + 1) === LINE_FEED) i++;
45
+ this.lineOffsets.push(offset + i + 1);
46
+ }
43
47
  this.text += text;
44
48
  return offset;
45
49
  }
@@ -85,6 +89,7 @@ var PieceTable = class {
85
89
  #lineCount = 0;
86
90
  #lastVisitedLine = null;
87
91
  #lastVisitedLineLength = null;
92
+ #lastPosition = null;
88
93
  #priorityState = 2654435769;
89
94
  constructor(originalText) {
90
95
  this.#original = new TextBuffer(originalText);
@@ -236,14 +241,14 @@ var PieceTable = class {
236
241
  }
237
242
  #collectSearchMatchesLineByLine(pattern, wholeWord, limit) {
238
243
  const out = [];
239
- const docLength = this.#length;
240
- const charAt = (offset) => this.charAt(offset);
241
- for (let line = 0; line < this.#lineCount; line++) {
242
- const lineText = this.getLineText(line);
243
- const lineStart = this.offsetAt({
244
- line,
245
- character: 0
246
- });
244
+ const documentText = this.#textFromPieces();
245
+ const docLength = documentText.length;
246
+ const lineOffsets = computeLineOffsets(documentText);
247
+ for (let line = 0; line < lineOffsets.length; line++) {
248
+ const lineStart = lineOffsets[line];
249
+ let lineEnd = lineOffsets[line + 1] ?? docLength;
250
+ while (lineEnd > lineStart && isEOL(documentText.charCodeAt(lineEnd - 1))) lineEnd--;
251
+ const lineText = documentText.slice(lineStart, lineEnd);
247
252
  pattern.lastIndex = 0;
248
253
  let match;
249
254
  while ((match = pattern.exec(lineText)) !== null) {
@@ -254,7 +259,7 @@ var PieceTable = class {
254
259
  continue;
255
260
  }
256
261
  const docStart = lineStart + rel;
257
- if (!wholeWord || isWholeWordAtDocOffsets(docStart, fragment.length, docLength, charAt)) {
262
+ if (!wholeWord || isWholeWordAtDocOffsets(documentText, docStart, fragment.length)) {
258
263
  out.push([docStart, docStart + fragment.length]);
259
264
  if (out.length >= limit) return out;
260
265
  }
@@ -267,6 +272,7 @@ var PieceTable = class {
267
272
  if (text.length === 0) return;
268
273
  const start = clamp(offset, 0, this.#length);
269
274
  this.#replaceRangeIncremental(start, start, text);
275
+ this.#invalidateCaches();
270
276
  }
271
277
  delete(offset, length) {
272
278
  if (length <= 0 || this.#length === 0) return;
@@ -274,6 +280,7 @@ var PieceTable = class {
274
280
  const end = clamp(start + length, start, this.#length);
275
281
  if (start === end) return;
276
282
  this.#replaceRangeIncremental(start, end, "");
283
+ this.#invalidateCaches();
277
284
  }
278
285
  applyEdits(edits) {
279
286
  if (edits.length === 0) return;
@@ -283,6 +290,7 @@ var PieceTable = class {
283
290
  const end = clamp(edit.end, start, this.#length);
284
291
  this.#replaceRangeIncremental(start, end, edit.text);
285
292
  }
293
+ this.#invalidateCaches();
286
294
  }
287
295
  positionAt(offset) {
288
296
  const clampedOffset = clamp(offset, 0, this.#length);
@@ -291,9 +299,15 @@ var PieceTable = class {
291
299
  character: 0
292
300
  };
293
301
  const line = this.#lineAtOffset(clampedOffset);
302
+ const character = clampedOffset - (line === 0 ? 0 : this.#lineBreakOffset(line - 1));
303
+ this.#lastPosition = [
304
+ line,
305
+ character,
306
+ clampedOffset
307
+ ];
294
308
  return {
295
309
  line,
296
- character: clampedOffset - (line === 0 ? 0 : this.#lineBreakOffset(line - 1))
310
+ character
297
311
  };
298
312
  }
299
313
  positionsAt(offsets) {
@@ -309,6 +323,8 @@ var PieceTable = class {
309
323
  offsetAt(position) {
310
324
  if (position.line < 0 || this.#length === 0) return 0;
311
325
  if (position.line >= this.#lineCount) throw new Error(`Line index out of range: ${position.line}`);
326
+ const lastPosition = this.#lastPosition;
327
+ if (lastPosition !== null && lastPosition[0] === position.line && lastPosition[1] === position.character) return lastPosition[2];
312
328
  const offset = this.#getLineOffset(position.line);
313
329
  if (offset === void 0) throw new Error(`Line index out of range: ${position.line}`);
314
330
  const character = clamp(position.character, 0, offset[1] - offset[0]);
@@ -437,7 +453,7 @@ var PieceTable = class {
437
453
  #replaceRangeIncremental(start, end, text) {
438
454
  if (start === end && text.length === 0) return;
439
455
  const [left, rest] = this.#split(this.#root, start);
440
- const [, right] = this.#split(rest, end - start);
456
+ const right = this.#dropPrefix(rest, end - start);
441
457
  let root;
442
458
  if (text.length > 0) {
443
459
  const insertedPiece = this.#createPiece(Piece.Added, this.#add.append(text), text.length);
@@ -450,8 +466,11 @@ var PieceTable = class {
450
466
  this.#root = root;
451
467
  this.#length = root?.subtreeLength ?? 0;
452
468
  this.#lineCount = (root?.subtreeLineBreakCount ?? 0) + 1;
469
+ }
470
+ #invalidateCaches() {
453
471
  this.#lastVisitedLine = null;
454
472
  this.#lastVisitedLineLength = null;
473
+ this.#lastPosition = null;
455
474
  }
456
475
  #nextPriority() {
457
476
  this.#priorityState = Math.imul(this.#priorityState, 1664525) + 1013904223 >>> 0;
@@ -472,6 +491,8 @@ var PieceTable = class {
472
491
  }
473
492
  #split(node, offset) {
474
493
  if (node === null) return [null, null];
494
+ if (offset <= 0) return [null, node];
495
+ if (offset >= node.subtreeLength) return [node, null];
475
496
  const leftLength = node.left?.subtreeLength ?? 0;
476
497
  if (offset <= leftLength) {
477
498
  const [left, right] = this.#split(node.left, offset);
@@ -497,6 +518,24 @@ var PieceTable = class {
497
518
  rightNode.updateSubtreeLength();
498
519
  return [leftNode, rightNode];
499
520
  }
521
+ #dropPrefix(node, offset) {
522
+ if (node === null || offset >= node.subtreeLength) return null;
523
+ if (offset <= 0) return node;
524
+ const leftLength = node.left?.subtreeLength ?? 0;
525
+ if (offset <= leftLength) {
526
+ this.#setLeft(node, this.#dropPrefix(node.left, offset));
527
+ node.updateSubtreeLength();
528
+ return node;
529
+ }
530
+ const pieceEnd = leftLength + node.piece.length;
531
+ if (offset >= pieceEnd) return this.#dropPrefix(node.right, offset - pieceEnd);
532
+ const inPiece = offset - leftLength;
533
+ const rightNode = new PieceNode(this.#createPiece(node.piece.source, node.piece.offset + inPiece, node.piece.length - inPiece));
534
+ rightNode.priority = node.priority;
535
+ this.#setRight(rightNode, node.right);
536
+ rightNode.updateSubtreeLength();
537
+ return rightNode;
538
+ }
500
539
  #mergeNodes(left, right) {
501
540
  if (left === null) return right;
502
541
  if (right === null) return left;
@@ -613,15 +652,11 @@ function isWordSeparatorCharCode(charCode) {
613
652
  const ch = String.fromCharCode(charCode);
614
653
  return WORD_SEPARATORS.includes(ch);
615
654
  }
616
- function isWholeWordAtDocOffsets(docStart, length, docLength, charAt) {
617
- const beforeOk = docStart <= 0 || isWordSeparatorCharCode(charCodeUnitAt(charAt, docStart - 1));
618
- const afterOk = docStart + length >= docLength || isWordSeparatorCharCode(charCodeUnitAt(charAt, docStart + length));
655
+ function isWholeWordAtDocOffsets(text, docStart, length) {
656
+ const beforeOk = docStart <= 0 || isWordSeparatorCharCode(text.charCodeAt(docStart - 1));
657
+ const afterOk = docStart + length >= text.length || isWordSeparatorCharCode(text.charCodeAt(docStart + length));
619
658
  return beforeOk && afterOk;
620
659
  }
621
- function charCodeUnitAt(charAt, offset) {
622
- const unit = charAt(offset);
623
- return unit.length === 0 ? 0 : unit.charCodeAt(0);
624
- }
625
660
  function compileSearchRegExp(source, isRegex, caseSensitive) {
626
661
  const body = isRegex ? source : escapeRegExp(source);
627
662
  return new RegExp(body, `g${caseSensitive ? "" : "i"}${isRegex ? "m" : ""}`);