@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.
- package/dist/components/CodeView.d.ts.map +1 -1
- package/dist/components/CodeView.js +1 -16
- package/dist/components/CodeView.js.map +1 -1
- package/dist/components/File.d.ts +2 -1
- package/dist/components/File.d.ts.map +1 -1
- package/dist/components/File.js +6 -2
- package/dist/components/File.js.map +1 -1
- package/dist/components/FileDiff.d.ts +8 -2
- package/dist/components/FileDiff.d.ts.map +1 -1
- package/dist/components/FileDiff.js +26 -8
- package/dist/components/FileDiff.js.map +1 -1
- package/dist/components/VirtualizedFileDiff.d.ts +1 -0
- package/dist/components/VirtualizedFileDiff.d.ts.map +1 -1
- package/dist/components/VirtualizedFileDiff.js +4 -0
- package/dist/components/VirtualizedFileDiff.js.map +1 -1
- package/dist/editor/editStack.d.ts +5 -0
- package/dist/editor/editStack.d.ts.map +1 -1
- package/dist/editor/editStack.js +53 -12
- package/dist/editor/editStack.js.map +1 -1
- package/dist/editor/editor.d.ts.map +1 -1
- package/dist/editor/editor.js +52 -32
- package/dist/editor/editor.js.map +1 -1
- package/dist/editor/editor2.js +1 -1
- package/dist/editor/marker.d.ts +3 -3
- package/dist/editor/marker.d.ts.map +1 -1
- package/dist/editor/marker.js +89 -89
- package/dist/editor/marker.js.map +1 -1
- package/dist/editor/pieceTable.d.ts.map +1 -1
- package/dist/editor/pieceTable.js +55 -20
- package/dist/editor/pieceTable.js.map +1 -1
- package/dist/editor/popover.js +4 -0
- package/dist/editor/popover.js.map +1 -1
- package/dist/editor/selection.d.ts +2 -2
- package/dist/editor/selection.d.ts.map +1 -1
- package/dist/editor/selection.js +2 -2
- package/dist/editor/selection.js.map +1 -1
- package/dist/editor/textDocument.js +1 -1
- package/dist/editor/textDocument.js.map +1 -1
- package/dist/editor/tokenizer.d.ts.map +1 -1
- package/dist/editor/tokenizer.js +7 -2
- package/dist/editor/tokenizer.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/managers/InteractionManager.d.ts +18 -7
- package/dist/managers/InteractionManager.d.ts.map +1 -1
- package/dist/managers/InteractionManager.js +154 -99
- package/dist/managers/InteractionManager.js.map +1 -1
- package/dist/react/index.d.ts +2 -2
- package/dist/react/utils/useFileDiffInstance.js +1 -6
- package/dist/react/utils/useFileDiffInstance.js.map +1 -1
- package/dist/react/utils/useFileInstance.js +1 -4
- package/dist/react/utils/useFileInstance.js.map +1 -1
- package/dist/ssr/index.d.ts +2 -2
- package/dist/style.js +1 -1
- package/dist/types.d.ts +7 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/computeFileOffsets.d.ts.map +1 -1
- package/dist/utils/computeFileOffsets.js +34 -5
- package/dist/utils/computeFileOffsets.js.map +1 -1
- package/dist/utils/isGutterUtilityPath.d.ts +5 -0
- package/dist/utils/isGutterUtilityPath.d.ts.map +1 -0
- package/dist/utils/isGutterUtilityPath.js +12 -0
- package/dist/utils/isGutterUtilityPath.js.map +1 -0
- package/dist/worker/worker-portable.js +34 -5
- package/dist/worker/worker-portable.js.map +1 -1
- package/dist/worker/worker.js +34 -5
- package/dist/worker/worker.js.map +1 -1
- package/package.json +1 -1
package/dist/editor/editor2.js
CHANGED
|
@@ -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
|
|
package/dist/editor/marker.d.ts
CHANGED
|
@@ -25,11 +25,11 @@ declare class MarkerRenderer {
|
|
|
25
25
|
#private;
|
|
26
26
|
constructor(editor: MarkerRenderOptions);
|
|
27
27
|
get markers(): readonly Marker[];
|
|
28
|
-
|
|
29
|
-
|
|
28
|
+
isPopoverVisible(): boolean;
|
|
29
|
+
updatePopoverPosition(): void;
|
|
30
30
|
setMarkers<LAnnotation>(markers: Marker[], textDocument: TextDocument<LAnnotation>): void;
|
|
31
31
|
listenHover(contentEl: HTMLElement): void;
|
|
32
|
-
|
|
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,
|
|
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"}
|
package/dist/editor/marker.js
CHANGED
|
@@ -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
|
|
6
|
-
const
|
|
7
|
-
const
|
|
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
|
-
#
|
|
13
|
-
#
|
|
12
|
+
#markerPopoverElement;
|
|
13
|
+
#markerPopoverEventDisposes;
|
|
14
14
|
#markerEventDisposes;
|
|
15
|
-
#
|
|
16
|
-
#
|
|
17
|
-
#
|
|
15
|
+
#markerPopoverShowTimeout;
|
|
16
|
+
#markerPopoverHideTimeout;
|
|
17
|
+
#pendingMarkerPopoverIndex;
|
|
18
18
|
#hoveredMarkerIndex;
|
|
19
|
-
#
|
|
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
|
-
|
|
26
|
+
isPopoverVisible() {
|
|
27
27
|
return this.#hoveredMarkerIndex !== void 0;
|
|
28
28
|
}
|
|
29
|
-
|
|
29
|
+
updatePopoverPosition() {
|
|
30
30
|
const hoveredMarkerIndex = this.#hoveredMarkerIndex;
|
|
31
|
-
const
|
|
32
|
-
if (hoveredMarkerIndex === void 0 ||
|
|
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.
|
|
35
|
+
this.removePopover();
|
|
36
36
|
return;
|
|
37
37
|
}
|
|
38
|
-
this.#
|
|
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.
|
|
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.#
|
|
58
|
+
if (hoverMarkerIndex !== void 0) this.#scheduleMarkerPopover(hoverMarkerIndex);
|
|
59
59
|
else {
|
|
60
|
-
this.#
|
|
61
|
-
this.#
|
|
60
|
+
this.#cancelMarkerPopoverShow();
|
|
61
|
+
this.#scheduleMarkerPopoverHide();
|
|
62
62
|
}
|
|
63
63
|
}), addEventListener(contentEl, "mouseleave", () => {
|
|
64
|
-
this.#
|
|
65
|
-
this.#
|
|
64
|
+
this.#cancelMarkerPopoverShow();
|
|
65
|
+
this.#scheduleMarkerPopoverHide();
|
|
66
66
|
})];
|
|
67
67
|
}
|
|
68
|
-
|
|
69
|
-
this.#
|
|
70
|
-
this.#
|
|
71
|
-
this.#
|
|
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.
|
|
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
|
-
#
|
|
102
|
-
if (this.#
|
|
103
|
-
clearTimeout(this.#
|
|
104
|
-
this.#
|
|
101
|
+
#cancelMarkerPopoverShow() {
|
|
102
|
+
if (this.#markerPopoverShowTimeout !== void 0) {
|
|
103
|
+
clearTimeout(this.#markerPopoverShowTimeout);
|
|
104
|
+
this.#markerPopoverShowTimeout = void 0;
|
|
105
105
|
}
|
|
106
|
-
this.#
|
|
106
|
+
this.#pendingMarkerPopoverIndex = void 0;
|
|
107
107
|
}
|
|
108
|
-
#
|
|
109
|
-
if (this.#
|
|
110
|
-
clearTimeout(this.#
|
|
111
|
-
this.#
|
|
108
|
+
#cancelMarkerPopoverHide() {
|
|
109
|
+
if (this.#markerPopoverHideTimeout !== void 0) {
|
|
110
|
+
clearTimeout(this.#markerPopoverHideTimeout);
|
|
111
|
+
this.#markerPopoverHideTimeout = void 0;
|
|
112
112
|
}
|
|
113
113
|
}
|
|
114
|
-
#
|
|
115
|
-
if (markerIndex === this.#hoveredMarkerIndex || markerIndex === this.#
|
|
116
|
-
this.#
|
|
114
|
+
#scheduleMarkerPopover(markerIndex) {
|
|
115
|
+
if (markerIndex === this.#hoveredMarkerIndex || markerIndex === this.#pendingMarkerPopoverIndex) {
|
|
116
|
+
this.#cancelMarkerPopoverHide();
|
|
117
117
|
return;
|
|
118
118
|
}
|
|
119
|
-
this.#
|
|
120
|
-
this.#
|
|
121
|
-
if (this.#
|
|
122
|
-
this.#
|
|
119
|
+
this.#cancelMarkerPopoverShow();
|
|
120
|
+
this.#cancelMarkerPopoverHide();
|
|
121
|
+
if (this.#markerPopoverElement !== void 0) {
|
|
122
|
+
this.#renderMarkerPopover(markerIndex);
|
|
123
123
|
return;
|
|
124
124
|
}
|
|
125
|
-
this.#
|
|
126
|
-
this.#
|
|
127
|
-
this.#
|
|
128
|
-
this.#
|
|
129
|
-
this.#
|
|
130
|
-
},
|
|
131
|
-
}
|
|
132
|
-
#
|
|
133
|
-
if (this.#
|
|
134
|
-
this.#
|
|
135
|
-
this.#
|
|
136
|
-
this.#
|
|
137
|
-
if (!this.#
|
|
138
|
-
},
|
|
139
|
-
}
|
|
140
|
-
#
|
|
141
|
-
setPopoverPositionStyles(
|
|
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
|
-
#
|
|
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 =
|
|
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:
|
|
171
|
+
placementKey: MARKER_POPOVER_PLACEMENT_KEY
|
|
172
172
|
}) === "fallback";
|
|
173
|
-
this.#
|
|
173
|
+
this.#setMarkerPopoverPosition(popover, left, placeAbove ? rowTop : rowTop + lineHeight, placeAbove, viewport);
|
|
174
174
|
}
|
|
175
|
-
#
|
|
176
|
-
this.#
|
|
177
|
-
this.#
|
|
178
|
-
this.#
|
|
179
|
-
this.#
|
|
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.#
|
|
182
|
-
this.#options.popoverManager.resetPlacement(
|
|
181
|
+
this.#isMarkerPopoverHovered = false;
|
|
182
|
+
this.#options.popoverManager.resetPlacement(MARKER_POPOVER_PLACEMENT_KEY);
|
|
183
183
|
}
|
|
184
|
-
#
|
|
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
|
|
191
|
-
this.#options.popoverManager.resetPlacement(
|
|
192
|
-
if (
|
|
193
|
-
|
|
194
|
-
const content =
|
|
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.#
|
|
198
|
+
this.#positionMarkerPopover(popover, line, character);
|
|
199
199
|
this.#hoveredMarkerIndex = hoveredMarkerIndex;
|
|
200
200
|
return;
|
|
201
201
|
}
|
|
202
|
-
this.#
|
|
202
|
+
this.#markerPopoverElement = h("div", {
|
|
203
203
|
dataset: {
|
|
204
204
|
editorWidget: "",
|
|
205
|
-
|
|
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.#
|
|
213
|
+
this.#positionMarkerPopover(this.#markerPopoverElement, line, character);
|
|
214
214
|
this.#hoveredMarkerIndex = hoveredMarkerIndex;
|
|
215
|
-
this.#
|
|
216
|
-
this.#
|
|
217
|
-
this.#
|
|
218
|
-
}), addEventListener(this.#
|
|
219
|
-
this.#
|
|
220
|
-
this.#
|
|
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
|
|
231
|
-
for (const candidate of MARKER_SEVERITIES) delete
|
|
232
|
-
|
|
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":";;;;;;;
|
|
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
|
-
|
|
42
|
-
|
|
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
|
|
240
|
-
const
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
const lineStart =
|
|
244
|
-
|
|
245
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
617
|
-
const beforeOk = docStart <= 0 || isWordSeparatorCharCode(
|
|
618
|
-
const afterOk = 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" : ""}`);
|