@pierre/diffs 1.3.4 → 1.3.5

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.
@@ -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-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";
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
 
@@ -29,7 +29,7 @@ declare class EditorTokenizer {
29
29
  }: EditorTokenizerProps);
30
30
  syncTheme(codeOptions: BaseCodeOptions): void;
31
31
  cleanUp(): void;
32
- tokenize(change: TextDocumentChange, renderRange?: RenderRange): Map<number, Array<HighlightedToken>>;
32
+ tokenize(change: TextDocumentChange, renderRange?: RenderRange, hostRealignsRows?: boolean): Map<number, Array<HighlightedToken>>;
33
33
  prebuildStateStack(renderRange?: RenderRange): void;
34
34
  stopBackgroundTokenize(): void;
35
35
  pauseBackgroundTokenize(): void;
@@ -1 +1 @@
1
- {"version":3,"file":"tokenizer.d.ts","names":[],"sources":["../../src/editor/tokenizer.ts"],"mappings":";;;;UAqBiB,oBAAA;EACf,WAAA,EAAa,gBAAA;EACb,YAAA,EAAc,YAAA;EACd,WAAA,EAAa,eAAA;EACb,aAAA;EACA,QAAA,GAAW,KAAA;EACX,eAAA,GACE,KAAA,EAAO,GAAA,SAAY,KAAA,CAAM,gBAAA,IACzB,SAAA;EAKF,aAAA;EACA,OAAA;AAAA;;cAIW,eAAA;EAAA;MAyFP,SAAA;EAIJ,kCAAA,CACE,SAAA;EAsBF,WAAA;IACE,WAAA;IACA,WAAA;IACA,YAAA;IACA,aAAA;IACA,QAAA;IACA,eAAA;IACA,aAAA;IACA;EAAA,GACC,oBAAA;EAsHH,SAAA,CAAU,WAAA,EAAa,eAAA;EAyFvB,OAAA;EAUA,QAAA,CACE,MAAA,EAAQ,kBAAA,EACR,WAAA,GAAc,WAAA,GACb,GAAA,SAAY,KAAA,CAAM,gBAAA;EAmMrB,kBAAA,CAAmB,WAAA,GAAc,WAAA;EAKjC,sBAAA;EAiBA,uBAAA;EAYA,wBAAA;AAAA;AAAA,iBAocc,gBAAA,CACd,MAAA,EAAQ,KAAA,CAAM,gBAAA,KACZ,WAAA"}
1
+ {"version":3,"file":"tokenizer.d.ts","names":[],"sources":["../../src/editor/tokenizer.ts"],"mappings":";;;;UAqBiB,oBAAA;EACf,WAAA,EAAa,gBAAA;EACb,YAAA,EAAc,YAAA;EACd,WAAA,EAAa,eAAA;EACb,aAAA;EACA,QAAA,GAAW,KAAA;EACX,eAAA,GACE,KAAA,EAAO,GAAA,SAAY,KAAA,CAAM,gBAAA,IACzB,SAAA;EAKF,aAAA;EACA,OAAA;AAAA;;cAIW,eAAA;EAAA;MAyFP,SAAA;EAIJ,kCAAA,CACE,SAAA;EAsBF,WAAA;IACE,WAAA;IACA,WAAA;IACA,YAAA;IACA,aAAA;IACA,QAAA;IACA,eAAA;IACA,aAAA;IACA;EAAA,GACC,oBAAA;EAsHH,SAAA,CAAU,WAAA,EAAa,eAAA;EAyFvB,OAAA;EAUA,QAAA,CACE,MAAA,EAAQ,kBAAA,EACR,WAAA,GAAc,WAAA,EACd,gBAAA,aACC,GAAA,SAAY,KAAA,CAAM,gBAAA;EAkOrB,kBAAA,CAAmB,WAAA,GAAc,WAAA;EAKjC,sBAAA;EAiBA,uBAAA;EAYA,wBAAA;AAAA;AAAA,iBAocc,gBAAA,CACd,MAAA,EAAQ,KAAA,CAAM,gBAAA,KACZ,WAAA"}
@@ -184,7 +184,7 @@ var EditorTokenizer = class {
184
184
  this.#disposes?.forEach((dispose) => dispose());
185
185
  this.#disposes = void 0;
186
186
  }
187
- tokenize(change, renderRange) {
187
+ tokenize(change, renderRange, hostRealignsRows = false) {
188
188
  this.#ensureGrammar();
189
189
  this.#ensureActiveTheme();
190
190
  if (this.#grammar === void 0 && !isGrammarlessLanguage(this.#textDocument.languageId)) throw new Error(`Grammar for language "${this.#textDocument.languageId}" not loaded`);
@@ -196,6 +196,7 @@ var EditorTokenizer = class {
196
196
  const viewStart = Math.max(startingLine, dirtyStart);
197
197
  const crossesRenderRangeEnd = renderRange !== void 0 && totalLines !== Infinity && change.lineDelta > 0 && dirtyStart < renderRangeEndLine && change.endLine >= renderRangeEndLine;
198
198
  const canReuseCachedStates = change.lineDelta === 0 && (change.changedLineChanges?.every(([, , lineDelta]) => lineDelta === 0) ?? true);
199
+ const canReuseShiftedStates = hostRealignsRows && change.lineDelta !== 0 && dirtyStart >= startingLine;
199
200
  const canCacheTokenizedStates = canReuseCachedStates || renderRange === void 0 || dirtyStart >= viewStart;
200
201
  const changedLineRanges = change.changedLineRanges ?? [[dirtyStart, change.endLine]];
201
202
  this.#comparisonStateStack = [];
@@ -235,14 +236,14 @@ var EditorTokenizer = class {
235
236
  }
236
237
  let state = this.#stateStack[line] ?? INITIAL;
237
238
  for (; line < renderRangeEndLine;) {
238
- const previousNextState = canReuseCachedStates ? this.#stateStack[line + 1] : void 0;
239
+ const previousNextState = canReuseCachedStates ? this.#stateStack[line + 1] : canReuseShiftedStates ? this.#getPreviousEndState(line + 1) : void 0;
239
240
  if (canCacheTokenizedStates) this.#stateStack[line] = state;
240
241
  const { resolvedTokens, state: nextState } = this.#tokenizeLineAt(line, state);
241
242
  state = nextState;
242
243
  if (line >= viewStart) dirtyLines.set(line, resolvedTokens);
243
244
  else offscreenDirtyLines?.set(line, resolvedTokens);
244
245
  if (canCacheTokenizedStates) this.#stateStack[line + 1] = state;
245
- settled = line >= currentChangedRangeEnd && canReuseCachedStates && previousNextState !== void 0 && state.equals(previousNextState);
246
+ settled = line >= currentChangedRangeEnd && (canReuseCachedStates || canReuseShiftedStates) && previousNextState !== void 0 && state.equals(previousNextState);
246
247
  if (settled) {
247
248
  changedRangeIndex++;
248
249
  const nextRange = changedLineRanges[changedRangeIndex];
@@ -252,12 +253,18 @@ var EditorTokenizer = class {
252
253
  backgroundChangedRangeIndex = changedRangeIndex;
253
254
  break;
254
255
  }
255
- if (this.#stateStack[nextRange[0]] === void 0) {
256
+ let nextState = this.#stateStack[nextRange[0]];
257
+ if (canReuseShiftedStates) for (let stateLine = line + 2; stateLine <= nextRange[0]; stateLine++) {
258
+ nextState = this.#getPreviousEndState(stateLine);
259
+ if (nextState === void 0) break;
260
+ this.#stateStack[stateLine] = nextState;
261
+ }
262
+ if (nextState === void 0) {
256
263
  currentChangedRangeEnd = nextRange[1];
257
264
  line++;
258
265
  } else {
259
266
  line = nextRange[0];
260
- state = this.#stateStack[line] ?? state;
267
+ state = nextState;
261
268
  currentChangedRangeEnd = nextRange[1];
262
269
  }
263
270
  settled = false;
@@ -267,6 +274,16 @@ var EditorTokenizer = class {
267
274
  }
268
275
  if (canCacheTokenizedStates) if (line < renderRangeEndLine) this.#stateStack[line + 1] = state;
269
276
  else this.#stateStack[line] = state;
277
+ if (settled && canReuseShiftedStates && backgroundStartLine === void 0) {
278
+ for (let stateLine = line + 2; stateLine <= lineCount; stateLine++) {
279
+ const previousState = this.#getPreviousEndState(stateLine);
280
+ if (previousState === void 0) break;
281
+ this.#stateStack[stateLine] = previousState;
282
+ }
283
+ this.#comparisonStateStack = [];
284
+ this.#comparisonStateStackStart = 0;
285
+ this.#comparisonLineChanges = [];
286
+ }
270
287
  if (offscreenDirtyLines !== void 0 && offscreenDirtyLines.size > 0) this.#onDeferTokenize(offscreenDirtyLines, this.#themeType);
271
288
  if (backgroundStartLine !== void 0) this.#scheduleBackgroundTokenize(backgroundStartLine, changedLineRanges, backgroundChangedRangeIndex);
272
289
  else if (!settled && line < lineCount) {
@@ -1 +1 @@
1
- {"version":3,"file":"tokenizer.js","names":["#isCleanedUp","#textDocument","#grammar","#highlighter","#ensureActiveTheme","#scheduleStatePrebuild","#tokenizerId","#backgroundJobId","#backgroundPrebuildEndLine","#backgroundPrebuild","#backgroundTokenize","#themeType","#matchBrackets","#ensureGrammar","#bracketIgnoredRanges","#buildStateStack","#stateStack","#tokenizeLineAt","#mediaQueryList","#resolveSystemThemeType","#emitThemeChange","#disposes","#tokenizeMaxLineLength","#setStyle","#onDeferTokenize","#onThemeChange","#debug","#colorMap","#setTheme","#themeName","#comparisonStateStack","#comparisonStateStackStart","#comparisonLineChanges","#scheduleBackgroundTokenize","#detachMessageListener","#shiftComparisonStateStack","#prebuildStateStack","#pendingPrebuildEndLine","#isStopped","#isPaused","#lastLine","#backgroundChangedLineRanges","#backgroundChangedRangeIndex","#postTokenizeMessage","#isMessageListenerAttached","#onMessage","#attachMessageListener","#cacheBracketIgnoredRanges","#getPreviousEndState"],"sources":["../../src/editor/tokenizer.ts"],"sourcesContent":["import { colorUtils } from '@pierre/theming/color';\nimport {\n EncodedTokenMetadata,\n type IGrammar,\n INITIAL,\n type StateStack,\n} from 'shiki/textmate';\n\nimport { DEFAULT_THEMES } from '../constants';\nimport type {\n BaseCodeOptions,\n DiffsHighlighter,\n HighlightedToken,\n RenderRange,\n} from '../types';\nimport type { TextDocument, TextDocumentChange } from './textDocument';\nimport { addEventListener, debounce, h } from './utils';\n\nconst TOKENIZE_TIME_LIMIT = 500;\nlet nextTokenizerId = 0;\n\nexport interface EditorTokenizerProps {\n highlighter: DiffsHighlighter;\n textDocument: TextDocument<unknown>;\n codeOptions: BaseCodeOptions;\n matchBrackets?: boolean;\n setStyle: (style: string) => void;\n onDeferTokenize: (\n lines: Map<number, Array<HighlightedToken>>,\n themeType: 'dark' | 'light'\n ) => void;\n // Fired after the active theme (light/dark mode or theme name) changes and the\n // new theme CSS has been applied. Lets the editor recompute overlay pieces\n // that captured a resolved theme color, e.g. rounded selection corner masks.\n onThemeChange?: () => void;\n __debug?: boolean;\n}\n\n/** Stoppable code tokenizer for the editor */\nexport class EditorTokenizer {\n #highlighter: DiffsHighlighter;\n #grammar: IGrammar | undefined;\n #mediaQueryList: MediaQueryList;\n #themeType: 'light' | 'dark' = 'dark';\n // The resolved name of the theme currently applied to the editor (e.g.\n // `github-light`). Tracked so `syncTheme` can detect a host-driven theme swap\n // even when the light/dark mode itself is unchanged.\n #themeName = '';\n #colorMap: string[];\n #textDocument: TextDocument<unknown>;\n #tokenizeMaxLineLength: number;\n #setStyle: EditorTokenizerProps['setStyle'];\n #onDeferTokenize: EditorTokenizerProps['onDeferTokenize'];\n #onThemeChange: EditorTokenizerProps['onThemeChange'];\n #matchBrackets: boolean;\n #debug: boolean;\n #disposes?: (() => void)[];\n #isCleanedUp = false;\n\n // state\n #stateStack: StateStack[] = [INITIAL]; // cached state stack by line index\n #comparisonStateStack: StateStack[] = [];\n #comparisonStateStackStart = 0;\n #comparisonLineChanges: NonNullable<\n TextDocumentChange['changedLineChanges']\n > = [];\n #lastLine: number = -1;\n #isStopped: boolean = true;\n #isPaused: boolean = false;\n #backgroundJobId: number = 0;\n #tokenizerId = ++nextTokenizerId;\n #backgroundPrebuildEndLine = -1;\n #pendingPrebuildEndLine = -1;\n #backgroundChangedLineRanges: readonly [number, number][] | undefined;\n #backgroundChangedRangeIndex: number = 0;\n #bracketIgnoredRanges: ([number, number][] | null | undefined)[] = [];\n #isMessageListenerAttached: boolean = false;\n\n #prebuildStateStack = debounce(async (renderRange?: RenderRange) => {\n // Drop work scheduled before cleanUp; a late timer must not call setTheme\n // on a highlighter that tests (or hosts) have already disposed.\n if (this.#isCleanedUp) {\n return;\n }\n const { startingLine = 0, totalLines = Infinity } = renderRange ?? {};\n const endLine = Math.min(\n totalLines === Infinity ? Infinity : startingLine + totalLines,\n this.#textDocument.lineCount\n );\n if (\n this.#grammar === undefined &&\n !isGrammarlessLanguage(this.#textDocument.languageId)\n ) {\n await this.#highlighter.loadLanguage(this.#textDocument.languageId);\n if (this.#isCleanedUp) {\n return;\n }\n this.#grammar = this.#highlighter.getLanguage(\n this.#textDocument.languageId\n );\n }\n this.#ensureActiveTheme();\n this.#scheduleStatePrebuild(endLine);\n }, 500);\n\n #onMessage = ({ data }: MessageEvent<unknown>) => {\n if (typeof data !== 'object' || data === null) {\n return;\n }\n const { type, tokenizerId, jobId } = data as {\n type?: unknown;\n tokenizerId?: unknown;\n jobId?: unknown;\n };\n if (\n type === 'tokenize' &&\n tokenizerId === this.#tokenizerId &&\n typeof jobId === 'number' &&\n jobId === this.#backgroundJobId\n ) {\n if (this.#backgroundPrebuildEndLine >= 0) {\n this.#backgroundPrebuild(jobId);\n } else {\n this.#backgroundTokenize(jobId);\n }\n }\n };\n\n get themeType(): 'light' | 'dark' {\n return this.#themeType;\n }\n\n getStringCommentRegexpRangesInLine(\n lineIndex: number\n ): [number, number][] | null {\n if (\n !this.#matchBrackets ||\n lineIndex < 0 ||\n lineIndex >= this.#textDocument.lineCount\n ) {\n return null;\n }\n this.#ensureGrammar();\n if (this.#grammar === undefined) {\n return null;\n }\n if (this.#bracketIgnoredRanges[lineIndex] === undefined) {\n this.#buildStateStack(lineIndex);\n const state = this.#stateStack[lineIndex] ?? INITIAL;\n const result = this.#tokenizeLineAt(lineIndex, state);\n this.#stateStack[lineIndex + 1] = result.state;\n }\n return this.#bracketIgnoredRanges[lineIndex] ?? null;\n }\n\n constructor({\n codeOptions,\n highlighter,\n textDocument,\n matchBrackets,\n setStyle,\n onDeferTokenize,\n onThemeChange,\n __debug,\n }: EditorTokenizerProps) {\n const {\n themeType: themeTypeOption = 'system',\n theme = DEFAULT_THEMES,\n tokenizeMaxLineLength = 1000,\n } = codeOptions;\n this.#mediaQueryList = window.matchMedia('(prefers-color-scheme: dark)');\n let themeType: 'light' | 'dark' | undefined;\n if (themeTypeOption === 'system') {\n // Prefer the host document's computed color-scheme (page CSS/classes can\n // force light/dark while the OS media query differs) over matchMedia.\n themeType = this.#resolveSystemThemeType();\n } else {\n themeType = themeTypeOption;\n }\n // Only track the document/system color scheme when the surface follows it\n // (`themeType: 'system'`). A surface pinned to an explicit 'dark'/'light'\n // theme keeps that theme regardless of the page, so re-tokenizing after an\n // edit must emit the same `--diffs-token-{theme}` variable the SSR markup\n // used; otherwise the edited tokens fall back to the default foreground.\n if (typeof theme !== 'string' && themeTypeOption === 'system') {\n const observer = new MutationObserver((mutations) => {\n for (const { type, attributeName } of mutations) {\n if (\n type === 'attributes' &&\n attributeName !== null &&\n (attributeName === 'class' || attributeName.startsWith('data-'))\n ) {\n const themeType = this.#resolveSystemThemeType();\n this.#emitThemeChange(theme[themeType], themeType);\n break;\n }\n }\n });\n observer.observe(document.documentElement, { attributes: true });\n observer.observe(document.body, { attributes: true });\n this.#disposes = [\n addEventListener(this.#mediaQueryList, 'change', () => {\n // Re-read computed color-scheme so a host-forced scheme still wins\n // when the OS preference changes underneath it.\n const themeType = this.#resolveSystemThemeType();\n this.#emitThemeChange(theme[themeType], themeType);\n }),\n () => observer.disconnect(),\n ];\n }\n this.#highlighter = highlighter;\n this.#textDocument = textDocument;\n this.#tokenizeMaxLineLength = tokenizeMaxLineLength;\n this.#setStyle = setStyle;\n this.#onDeferTokenize = onDeferTokenize;\n this.#onThemeChange = onThemeChange;\n this.#matchBrackets = matchBrackets !== false;\n this.#debug = __debug ?? false;\n this.#ensureGrammar();\n this.#colorMap = [];\n this.#setTheme(\n typeof theme === 'string' ? theme : theme[themeType],\n typeof theme === 'string' ? undefined : themeType\n );\n }\n\n // By default, diffs components support dual themes, but the tokenizer only renders\n // the preferred theme. When the theme type is changed, the tokenizer will re-tokenize the document.\n #emitThemeChange(themeName: string, themeType: 'light' | 'dark') {\n if (themeName === this.#themeName && themeType === this.#themeType) {\n return;\n }\n this.#setTheme(themeName, themeType);\n this.stopBackgroundTokenize();\n this.#stateStack = [INITIAL];\n this.#comparisonStateStack = [];\n this.#comparisonStateStackStart = 0;\n this.#comparisonLineChanges = [];\n if (this.#grammar !== undefined && this.#textDocument.lineCount > 0) {\n this.#scheduleBackgroundTokenize(0);\n }\n // The theme CSS is now applied, so overlay pieces that captured a resolved\n // theme color (e.g. rounded selection corner masks) can recompute against\n // the new colors instead of keeping the old light/dark value.\n this.#onThemeChange?.();\n }\n\n // Respect an explicit host color-scheme override. When the computed value\n // advertises support for both schemes, let the OS preference choose one.\n #resolveSystemThemeType(): 'light' | 'dark' {\n try {\n if (\n typeof document !== 'undefined' &&\n typeof getComputedStyle === 'function' &&\n document.body != null\n ) {\n const colorSchemes = getComputedStyle(document.body).colorScheme.split(\n /\\s+/\n );\n const supportsDark = colorSchemes.includes('dark');\n const supportsLight = colorSchemes.includes('light');\n // A single host-forced scheme wins. `light dark` only declares support\n // for both schemes, so the media query still selects the active one.\n if (supportsDark !== supportsLight) {\n return supportsDark ? 'dark' : 'light';\n }\n }\n } catch {\n // jsdom and similar harnesses may lack getComputedStyle or throw; fall\n // through to the OS media query.\n }\n return this.#mediaQueryList.matches ? 'dark' : 'light';\n }\n\n // Re-apply the editor's theme from the surface's current code options. Edit\n // mode reuses a single tokenizer across re-renders, so when the host swaps the\n // theme — a theme picker, a light/dark toggle, etc. — we must recompute the\n // active theme and re-tokenize. Without this the editor keeps rendering the\n // theme it captured when it first attached (stale line-highlight background\n // and token colors). System-driven changes are still handled by the\n // observers wired up in the constructor; this covers explicit `themeType`/\n // `theme` option changes that those observers don't see.\n syncTheme(codeOptions: BaseCodeOptions): void {\n const { themeType = 'system', theme = DEFAULT_THEMES } = codeOptions;\n // A single pinned theme does not follow the themeType option or system\n // scheme flips; its own classification stays authoritative.\n if (typeof theme === 'string') {\n const pinnedThemeType = this.#highlighter.getTheme(theme).type;\n if (theme === this.#themeName && pinnedThemeType === this.#themeType) {\n return;\n }\n this.#emitThemeChange(theme, pinnedThemeType);\n return;\n }\n const nextThemeType =\n themeType === 'system' ? this.#resolveSystemThemeType() : themeType;\n const nextThemeName = theme[nextThemeType];\n if (\n nextThemeType === this.#themeType &&\n nextThemeName === this.#themeName\n ) {\n return;\n }\n this.#emitThemeChange(nextThemeName, nextThemeType);\n }\n\n #setTheme(themeName: string, themeType?: 'light' | 'dark') {\n const { theme, colorMap } = this.#highlighter.setTheme(themeName);\n const { colors = {} } = this.#highlighter.getTheme(themeName);\n const selectionBackground = colors['editor.selectionBackground'];\n const themeLineHighlightBackground =\n colors['editor.lineHighlightBackground'];\n const lineHighlightBackground =\n themeLineHighlightBackground != null &&\n themeLineHighlightBackground.trim() !== '' &&\n !colorUtils.isFullyTransparent(themeLineHighlightBackground)\n ? themeLineHighlightBackground\n : undefined;\n // A usable theme background opts into the semantic active-line mix.\n // Missing backgrounds retain the resolved row color and rely on a border.\n const lineHighlightBorder =\n colors['editor.lineHighlightBorder'] ??\n (lineHighlightBackground == null\n ? 'color-mix(in lab, var(--diffs-bg) 70%, var(--diffs-fg))'\n : 'transparent');\n const activeLineSourceMix =\n lineHighlightBackground == null ? '100%' : '85%';\n const cursorForeground = colors['editorCursor.foreground'];\n const findMatchBackground = colors['editor.findMatchBackground'];\n const findMatchHighlightBackground =\n colors['editor.findMatchHighlightBackground'];\n const bracketMatchBackground = colors['editorBracketMatch.background'];\n const bracketMatchBorder = colors['editorBracketMatch.border'];\n const hintForeground = colors['editorHint.foreground'];\n const infoForeground = colors['editorInfo.foreground'];\n const warningForeground = colors['editorWarning.foreground'];\n const errorForeground = colors['editorError.foreground'];\n this.#setStyle(`:host {\n --diffs-editor-selection-bg: ${selectionBackground ?? 'var(--diffs-line-bg)'};\n --diffs-editor-line-highlight-border: ${lineHighlightBorder};\n --diffs-editor-active-line-source-mix: ${activeLineSourceMix};\n --diffs-editor-match-bg: ${findMatchBackground ?? 'initial'};\n --diffs-editor-match-highlight-bg: ${findMatchHighlightBackground ?? 'initial'};\n --diffs-editor-bracket-match-bg: ${bracketMatchBackground ?? 'initial'};\n --diffs-editor-bracket-match-border: ${bracketMatchBorder ?? 'initial'};\n --diffs-editor-cursor-fg: ${cursorForeground ?? 'initial'};\n --diffs-editor-hint-fg: ${hintForeground ?? 'initial'};\n --diffs-editor-info-fg: ${infoForeground ?? 'initial'};\n --diffs-editor-warning-fg: ${warningForeground ?? 'initial'};\n --diffs-editor-error-fg: ${errorForeground ?? 'initial'};\n }`);\n this.#themeName = themeName;\n this.#themeType = themeType ?? theme.type;\n this.#colorMap = colorMap;\n }\n\n // The shared highlighter is also used for dual-theme SSR (`themes: {dark,light}`),\n // which leaves its active theme on whichever pass finished last (usually light).\n // The tokenizer caches a single-theme colorMap from construction; if we tokenize\n // without re-activating that theme, grammar color indices are looked up in the\n // wrong map — property names resolve to a near-foreground gray while types and\n // comments (stable across maps) still look correct. Re-apply before every\n // tokenize path so a first edit after load matches a later file-switch re-attach.\n #ensureActiveTheme(): void {\n if (this.#themeName === '') {\n return;\n }\n const { colorMap } = this.#highlighter.setTheme(this.#themeName);\n this.#colorMap = colorMap;\n }\n\n cleanUp(): void {\n this.#isCleanedUp = true;\n this.stopBackgroundTokenize();\n this.#detachMessageListener();\n this.#disposes?.forEach((dispose) => dispose());\n this.#disposes = undefined;\n }\n\n // to use `tokenize`, call `prebuildStateStackMap` first to prebuild\n // the state stack map for the given render range.\n tokenize(\n change: TextDocumentChange,\n renderRange?: RenderRange\n ): Map<number, Array<HighlightedToken>> {\n this.#ensureGrammar();\n this.#ensureActiveTheme();\n if (\n this.#grammar === undefined &&\n !isGrammarlessLanguage(this.#textDocument.languageId)\n ) {\n throw new Error(\n `Grammar for language \"${this.#textDocument.languageId}\" not loaded`\n );\n }\n\n if (this.#matchBrackets) {\n // Clear ignored token ranges for lines invalidated by the edit.\n this.#bracketIgnoredRanges.length = Math.min(\n this.#bracketIgnoredRanges.length,\n change.startLine\n );\n }\n\n const { lineCount } = this.#textDocument;\n const { startingLine = 0, totalLines = Infinity } = renderRange ?? {};\n const renderRangeEndLine =\n totalLines === Infinity\n ? lineCount\n : Math.min(startingLine + totalLines, lineCount);\n\n const dirtyStart = change.startLine;\n const viewStart = Math.max(startingLine, dirtyStart);\n const crossesRenderRangeEnd =\n renderRange !== undefined &&\n totalLines !== Infinity &&\n change.lineDelta > 0 &&\n dirtyStart < renderRangeEndLine &&\n change.endLine >= renderRangeEndLine;\n const canReuseCachedStates =\n change.lineDelta === 0 &&\n (change.changedLineChanges?.every(([, , lineDelta]) => lineDelta === 0) ??\n true);\n const canCacheTokenizedStates =\n canReuseCachedStates ||\n renderRange === undefined ||\n dirtyStart >= viewStart;\n const changedLineRanges: readonly [number, number][] =\n change.changedLineRanges ?? [[dirtyStart, change.endLine]];\n this.#comparisonStateStack = [];\n this.#comparisonStateStackStart = 0;\n this.#comparisonLineChanges = [];\n let offscreenSyncEnd = -1;\n if (dirtyStart < viewStart) {\n for (const [rangeStart, rangeEnd] of changedLineRanges) {\n if (rangeStart < viewStart) {\n offscreenSyncEnd = Math.max(\n offscreenSyncEnd,\n Math.min(rangeEnd, viewStart - 1)\n );\n }\n }\n }\n const shouldFlushOffscreenLines =\n offscreenSyncEnd >= dirtyStart &&\n (canReuseCachedStates || change.lineDelta < 0);\n if (canReuseCachedStates) {\n this.#buildStateStack(dirtyStart);\n } else {\n this.#shiftComparisonStateStack(change);\n if (renderRange === undefined || dirtyStart >= viewStart) {\n this.#buildStateStack(viewStart);\n }\n }\n\n let changedRangeIndex = 0;\n let currentChangedRangeEnd = changedLineRanges[changedRangeIndex][1];\n let backgroundStartLine: number | undefined;\n let backgroundChangedRangeIndex = 0;\n let line = canReuseCachedStates\n ? changedLineRanges[changedRangeIndex][0]\n : viewStart;\n let settled = false;\n const dirtyLines: Map<number, Array<HighlightedToken>> = new Map();\n const offscreenDirtyLines:\n | Map<number, Array<HighlightedToken>>\n | undefined = shouldFlushOffscreenLines ? new Map() : undefined;\n if (offscreenDirtyLines !== undefined && !canReuseCachedStates) {\n const offscreenEnd = Math.min(\n offscreenSyncEnd + 1,\n viewStart,\n renderRangeEndLine\n );\n if (offscreenEnd > dirtyStart) {\n this.#buildStateStack(offscreenEnd);\n let offscreenLine = dirtyStart;\n let offscreenState = this.#stateStack[offscreenLine] ?? INITIAL;\n for (; offscreenLine < offscreenEnd; offscreenLine++) {\n const resolved = this.#tokenizeLineAt(offscreenLine, offscreenState);\n offscreenState = resolved.state;\n offscreenDirtyLines.set(offscreenLine, resolved.resolvedTokens);\n }\n this.#stateStack[offscreenEnd] = offscreenState;\n }\n }\n // Seed the loop's grammar state after the offscreen flush, not before it.\n // When a delete's removed lines reach the viewport's first line, the flush\n // rebuilds the cached state up to `line`; reading it earlier would capture\n // the truncated INITIAL state and color the viewport as if outside an open\n // construct (block comment, template literal) it is actually inside.\n let state = this.#stateStack[line] ?? INITIAL;\n for (; line < renderRangeEndLine; ) {\n const previousNextState = canReuseCachedStates\n ? this.#stateStack[line + 1]\n : undefined;\n if (canCacheTokenizedStates) {\n this.#stateStack[line] = state;\n }\n\n const { resolvedTokens, state: nextState } = this.#tokenizeLineAt(\n line,\n state\n );\n state = nextState;\n\n if (line >= viewStart) {\n dirtyLines.set(line, resolvedTokens);\n } else {\n offscreenDirtyLines?.set(line, resolvedTokens);\n }\n\n if (canCacheTokenizedStates) {\n this.#stateStack[line + 1] = state;\n }\n settled =\n line >= currentChangedRangeEnd &&\n canReuseCachedStates &&\n previousNextState !== undefined &&\n state.equals(previousNextState);\n if (settled) {\n changedRangeIndex++;\n const nextRange = changedLineRanges[changedRangeIndex];\n if (nextRange === undefined) {\n break;\n }\n if (nextRange[0] >= renderRangeEndLine) {\n backgroundStartLine = nextRange[0];\n backgroundChangedRangeIndex = changedRangeIndex;\n break;\n }\n if (this.#stateStack[nextRange[0]] === undefined) {\n currentChangedRangeEnd = nextRange[1];\n line++;\n } else {\n line = nextRange[0];\n state = this.#stateStack[line] ?? state;\n currentChangedRangeEnd = nextRange[1];\n }\n settled = false;\n continue;\n }\n line++;\n }\n\n if (canCacheTokenizedStates) {\n if (line < renderRangeEndLine) {\n this.#stateStack[line + 1] = state;\n } else {\n this.#stateStack[line] = state;\n }\n }\n\n if (offscreenDirtyLines !== undefined && offscreenDirtyLines.size > 0) {\n this.#onDeferTokenize(offscreenDirtyLines, this.#themeType);\n }\n\n if (backgroundStartLine !== undefined) {\n this.#scheduleBackgroundTokenize(\n backgroundStartLine,\n changedLineRanges,\n backgroundChangedRangeIndex\n );\n } else if (!settled && line < lineCount) {\n const backgroundLine =\n crossesRenderRangeEnd && dirtyStart >= viewStart\n ? renderRangeEndLine\n : dirtyStart < viewStart && !canReuseCachedStates\n ? dirtyStart\n : line;\n this.#scheduleBackgroundTokenize(\n backgroundLine,\n changedLineRanges,\n changedRangeIndex\n );\n }\n\n return dirtyLines;\n }\n\n prebuildStateStack(renderRange?: RenderRange): void {\n this.#ensureGrammar();\n this.#prebuildStateStack(renderRange);\n }\n\n stopBackgroundTokenize(): void {\n this.#pendingPrebuildEndLine = -1;\n if (this.#isStopped) {\n return;\n }\n this.#isStopped = true;\n this.#isPaused = false;\n this.#lastLine = -1;\n this.#backgroundPrebuildEndLine = -1;\n this.#backgroundChangedLineRanges = undefined;\n this.#backgroundChangedRangeIndex = 0;\n this.#comparisonStateStack = [];\n this.#comparisonStateStackStart = 0;\n this.#comparisonLineChanges = [];\n this.#detachMessageListener();\n }\n\n pauseBackgroundTokenize(): void {\n if (this.#isStopped || this.#isPaused) {\n return;\n }\n if (this.#debug) {\n console.log('[diffs/editor] background tokenization paused', {\n jobId: this.#backgroundJobId,\n });\n }\n this.#isPaused = true;\n }\n\n resumeBackgroundTokenize(): void {\n if (\n this.#isStopped ||\n !this.#isPaused ||\n this.#grammar === undefined ||\n this.#lastLine < 0\n ) {\n return;\n }\n if (this.#debug) {\n console.log('[diffs/editor] background tokenization resumed', {\n jobId: this.#backgroundJobId,\n });\n }\n this.#isPaused = false;\n this.#postTokenizeMessage(this.#backgroundJobId);\n }\n\n #ensureGrammar(): void {\n if (\n this.#grammar === undefined &&\n !isGrammarlessLanguage(this.#textDocument.languageId) &&\n this.#highlighter\n .getLoadedLanguages()\n .includes(this.#textDocument.languageId)\n ) {\n this.#grammar = this.#highlighter.getLanguage(\n this.#textDocument.languageId\n );\n }\n }\n\n #attachMessageListener(): void {\n if (this.#isMessageListenerAttached) {\n return;\n }\n globalThis.addEventListener('message', this.#onMessage);\n this.#isMessageListenerAttached = true;\n }\n\n #detachMessageListener(): void {\n if (!this.#isMessageListenerAttached) {\n return;\n }\n globalThis.removeEventListener('message', this.#onMessage);\n this.#isMessageListenerAttached = false;\n }\n\n #postTokenizeMessage(jobId: number): void {\n // use `postMessage` instead of `setTimeout(fn, 0)` to avoid 4ms delay\n globalThis.postMessage({\n type: 'tokenize',\n tokenizerId: this.#tokenizerId,\n jobId,\n });\n }\n\n #scheduleBackgroundTokenize(\n startLine: number,\n changedLineRanges?: readonly [number, number][],\n changedRangeIndex = 0\n ): void {\n if (isGrammarlessLanguage(this.#textDocument.languageId)) {\n return;\n }\n\n const jobId = ++this.#backgroundJobId;\n\n if (this.#debug) {\n console.log('[diffs/editor] background tokenization scheduled', {\n jobId,\n startLine,\n changedLineRanges,\n changedRangeIndex,\n });\n }\n\n this.#isStopped = false;\n this.#isPaused = false;\n this.#lastLine = startLine;\n if (this.#backgroundPrebuildEndLine >= 0) {\n this.#pendingPrebuildEndLine = Math.max(\n this.#pendingPrebuildEndLine,\n this.#backgroundPrebuildEndLine\n );\n }\n this.#backgroundPrebuildEndLine = -1;\n this.#backgroundChangedLineRanges = changedLineRanges;\n this.#backgroundChangedRangeIndex = changedRangeIndex;\n this.#attachMessageListener();\n this.#postTokenizeMessage(jobId);\n }\n\n #scheduleStatePrebuild(endLine: number): void {\n if (this.#grammar === undefined || this.#stateStack.length > endLine) {\n return;\n }\n // Extend an active prebuild, or retain the target until the foreground\n // edit job reconverges and releases the state cache.\n if (!this.#isStopped) {\n if (this.#backgroundPrebuildEndLine >= 0) {\n this.#backgroundPrebuildEndLine = Math.max(\n this.#backgroundPrebuildEndLine,\n endLine\n );\n } else {\n this.#pendingPrebuildEndLine = Math.max(\n this.#pendingPrebuildEndLine,\n endLine\n );\n }\n return;\n }\n\n const jobId = ++this.#backgroundJobId;\n this.#isStopped = false;\n this.#isPaused = false;\n this.#lastLine = this.#stateStack.length - 1;\n this.#backgroundPrebuildEndLine = endLine;\n this.#pendingPrebuildEndLine = -1;\n this.#backgroundChangedLineRanges = undefined;\n this.#backgroundChangedRangeIndex = 0;\n this.#attachMessageListener();\n this.#postTokenizeMessage(jobId);\n }\n\n #tokenizeLineAt(\n line: number,\n state: StateStack\n ): { resolvedTokens: Array<HighlightedToken>; state: StateStack } {\n const lineText = this.#textDocument.getLineText(line);\n if (lineText.length > this.#tokenizeMaxLineLength) {\n console.warn(\n `[diffs] Line(${line}) too long to tokenize: ${lineText.length}`\n );\n this.#cacheBracketIgnoredRanges(line, null);\n return { resolvedTokens: [[0, '', lineText]], state };\n }\n if (\n this.#grammar === undefined ||\n lineText === '' ||\n lineText.trim() === ''\n ) {\n this.#cacheBracketIgnoredRanges(line, null);\n return { resolvedTokens: [[0, '', lineText]], state };\n }\n const result = tokenizeLine(\n this.#grammar,\n this.#colorMap,\n lineText,\n state,\n TOKENIZE_TIME_LIMIT,\n this.#matchBrackets\n );\n this.#cacheBracketIgnoredRanges(line, result.bracketIgnoredRanges);\n return {\n resolvedTokens: result.resolvedTokens,\n state: result.ruleStack,\n };\n }\n\n #cacheBracketIgnoredRanges(\n line: number,\n ranges: [number, number][] | null\n ): void {\n if (this.#matchBrackets) {\n this.#bracketIgnoredRanges[line] = ranges;\n }\n }\n\n // Preserve old end states as comparison-only sentinels, copying whichever\n // side of the edit is smaller. Index shifts are resolved lazily on lookup.\n #shiftComparisonStateStack(change: TextDocumentChange): void {\n const lineChanges =\n change.changedLineChanges ??\n ([[change.startLine, change.endLine, change.lineDelta]] as const);\n const comparisonStart = change.startLine + 1;\n const comparisonLength = this.#stateStack.length - comparisonStart;\n if (comparisonStart <= comparisonLength) {\n this.#comparisonStateStack = this.#stateStack;\n this.#comparisonStateStackStart = 0;\n this.#stateStack = this.#stateStack.slice(0, comparisonStart);\n } else {\n this.#comparisonStateStackStart = comparisonStart;\n this.#comparisonStateStack = this.#stateStack.slice(comparisonStart);\n this.#stateStack.length = Math.min(\n this.#stateStack.length,\n comparisonStart\n );\n }\n this.#comparisonLineChanges = lineChanges;\n }\n\n #getPreviousEndState(line: number): StateStack | undefined {\n let previousLine = line;\n for (\n let index = this.#comparisonLineChanges.length - 1;\n index >= 0;\n index--\n ) {\n const [startLine, endLine, lineDelta] =\n this.#comparisonLineChanges[index];\n if (lineDelta === 0) {\n continue;\n }\n if (previousLine > endLine) {\n previousLine -= lineDelta;\n } else if (previousLine > startLine) {\n return this.#stateStack[line];\n }\n }\n return (\n this.#comparisonStateStack[\n previousLine - this.#comparisonStateStackStart\n ] ?? this.#stateStack[line]\n );\n }\n\n #buildStateStack(endAt: number, timeBudget?: number): boolean {\n const boundedEndAt = Math.min(\n Math.max(0, endAt),\n this.#textDocument.lineCount\n );\n if (this.#stateStack.length > boundedEndAt || this.#grammar === undefined) {\n return true;\n }\n const startedAt = timeBudget === undefined ? 0 : performance.now();\n let line = this.#stateStack.length - 1;\n let state = this.#stateStack[line] ?? INITIAL;\n while (line < boundedEndAt) {\n this.#stateStack[line] = state;\n const lineText = this.#textDocument.getLineText(line);\n if (\n lineText.length <= this.#tokenizeMaxLineLength &&\n lineText !== '' &&\n lineText.trim() !== ''\n ) {\n const result = tokenizeLine(\n this.#grammar,\n this.#colorMap,\n lineText,\n state,\n TOKENIZE_TIME_LIMIT,\n this.#matchBrackets,\n false\n );\n this.#cacheBracketIgnoredRanges(line, result.bracketIgnoredRanges);\n state = result.ruleStack;\n } else {\n this.#cacheBracketIgnoredRanges(line, null);\n }\n line++;\n this.#stateStack[line] = state;\n if (\n timeBudget !== undefined &&\n performance.now() - startedAt > timeBudget\n ) {\n break;\n }\n }\n return line >= boundedEndAt;\n }\n\n #backgroundPrebuild(jobId: number): void {\n if (\n this.#isStopped ||\n this.#isPaused ||\n this.#grammar === undefined ||\n jobId !== this.#backgroundJobId\n ) {\n return;\n }\n\n this.#ensureActiveTheme();\n // State prebuilds intentionally omit rendered tokens and yield between\n // short chunks so a deep viewport does not monopolize the main thread.\n const complete = this.#buildStateStack(this.#backgroundPrebuildEndLine, 1);\n if (this.#isStopped || this.#isPaused || jobId !== this.#backgroundJobId) {\n return;\n }\n if (complete) {\n this.stopBackgroundTokenize();\n return;\n }\n this.#lastLine = this.#stateStack.length - 1;\n this.#postTokenizeMessage(jobId);\n }\n\n #backgroundTokenize(jobId: number) {\n if (\n this.#isStopped ||\n this.#isPaused ||\n this.#grammar === undefined ||\n jobId !== this.#backgroundJobId\n ) {\n return;\n }\n\n this.#ensureActiveTheme();\n\n const t = performance.now();\n const lines = new Map<number, Array<HighlightedToken>>();\n const totalLines = this.#textDocument.lineCount;\n const changedLineRanges = this.#backgroundChangedLineRanges;\n\n let line = this.#lastLine;\n let state = this.#stateStack[line] ?? INITIAL;\n let settled = false;\n let changedRangeIndex = this.#backgroundChangedRangeIndex;\n let currentChangedRangeEnd = changedLineRanges?.[changedRangeIndex]?.[1];\n for (; line < totalLines; ) {\n this.#stateStack[line] = state;\n\n const previousNextState =\n currentChangedRangeEnd !== undefined\n ? this.#getPreviousEndState(line + 1)\n : undefined;\n const lineText = this.#textDocument.getLineText(line);\n if (lineText.length > this.#tokenizeMaxLineLength) {\n console.warn(\n `[diffs] Line(${line}) too long to tokenize: ${lineText.length}`\n );\n lines.set(line, [[0, '', lineText]]);\n this.#cacheBracketIgnoredRanges(line, null);\n } else if (lineText === '' || lineText.trim() === '') {\n lines.set(line, [[0, '', lineText]]);\n this.#cacheBracketIgnoredRanges(line, null);\n } else {\n const ret = tokenizeLine(\n this.#grammar,\n this.#colorMap,\n lineText,\n state,\n TOKENIZE_TIME_LIMIT,\n this.#matchBrackets\n );\n lines.set(line, ret.resolvedTokens);\n this.#cacheBracketIgnoredRanges(line, ret.bracketIgnoredRanges);\n state = ret.ruleStack;\n }\n\n this.#stateStack[line + 1] = state;\n settled =\n currentChangedRangeEnd !== undefined &&\n line >= currentChangedRangeEnd &&\n previousNextState !== undefined &&\n state.equals(previousNextState);\n line++;\n if (settled) {\n changedRangeIndex++;\n const nextRange = changedLineRanges?.[changedRangeIndex];\n if (nextRange === undefined) {\n break;\n }\n currentChangedRangeEnd = nextRange[1];\n if (this.#stateStack[nextRange[0]] === undefined) {\n settled = false;\n } else {\n line = nextRange[0];\n state = this.#stateStack[line] ?? state;\n settled = false;\n continue;\n }\n }\n\n // limit the time of partial tokenize to 1ms\n if (performance.now() - t > 1) {\n break;\n }\n }\n\n this.#onDeferTokenize(lines, this.#themeType);\n if (this.#isStopped || this.#isPaused || jobId !== this.#backgroundJobId) {\n return;\n }\n\n if (settled || line >= totalLines) {\n const pendingPrebuildEndLine = this.#pendingPrebuildEndLine;\n this.stopBackgroundTokenize();\n if (pendingPrebuildEndLine >= 0) {\n this.#scheduleStatePrebuild(pendingPrebuildEndLine);\n }\n return;\n }\n\n this.#lastLine = line;\n this.#backgroundChangedRangeIndex = changedRangeIndex;\n this.#postTokenizeMessage(jobId);\n }\n}\n\nfunction tokenizeLine(\n grammar: IGrammar,\n colorMap: string[],\n lineText: string,\n stateStack: StateStack,\n timeLimit?: number,\n collectBracketIgnoredRanges = true,\n resolveTokens = true\n): {\n ruleStack: StateStack;\n resolvedTokens: Array<HighlightedToken>;\n bracketIgnoredRanges: [number, number][];\n} {\n const result = grammar.tokenizeLine2(lineText, stateStack, timeLimit);\n if (result.stoppedEarly) {\n console.warn(\n `[diffs] Time limit reached when tokenizing line: ${lineText.substring(0, 100)}`\n );\n }\n const rawTokens = result.tokens;\n const tokensLength = rawTokens.length / 2;\n const resolvedTokens: Array<HighlightedToken> = [];\n const bracketIgnoredRanges: [number, number][] = [];\n if (!resolveTokens && !collectBracketIgnoredRanges) {\n return {\n ruleStack: result.ruleStack,\n resolvedTokens,\n bracketIgnoredRanges,\n };\n }\n for (let j = 0; j < tokensLength; j++) {\n const offset = rawTokens[2 * j];\n const nextOffset =\n j + 1 < tokensLength ? rawTokens[2 * j + 2] : lineText.length;\n if (offset === nextOffset) {\n // should never reach here, skip if happens anyway\n continue;\n }\n const metadata = rawTokens[2 * j + 1];\n if (resolveTokens) {\n const fg = EncodedTokenMetadata.getForeground(metadata);\n resolvedTokens.push([\n offset,\n colorMap[fg],\n lineText.slice(offset, nextOffset),\n ]);\n }\n if (\n collectBracketIgnoredRanges &&\n EncodedTokenMetadata.getTokenType(metadata) > 0\n ) {\n bracketIgnoredRanges.push([offset, nextOffset]);\n }\n }\n return {\n ruleStack: result.ruleStack,\n resolvedTokens,\n bracketIgnoredRanges,\n };\n}\n\nexport function renderLineTokens(\n tokens: Array<HighlightedToken>\n): (HTMLElement | string)[] {\n return tokens.map(([char, fg, textContent]) => {\n if (char === 0 && fg === '') {\n if (textContent === '') {\n return h('br');\n }\n return textContent;\n }\n return h('span', {\n dataset: {\n char: char.toString(),\n },\n style: `color:${fg};`,\n textContent: textContent,\n });\n });\n}\n\n// Shiki special-cases `text` and `ansi` in codeToHast but does not expose grammars.\nfunction isGrammarlessLanguage(languageId: string): boolean {\n return languageId === 'text' || languageId === 'ansi';\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"tokenizer.js","names":["#isCleanedUp","#textDocument","#grammar","#highlighter","#ensureActiveTheme","#scheduleStatePrebuild","#tokenizerId","#backgroundJobId","#backgroundPrebuildEndLine","#backgroundPrebuild","#backgroundTokenize","#themeType","#matchBrackets","#ensureGrammar","#bracketIgnoredRanges","#buildStateStack","#stateStack","#tokenizeLineAt","#mediaQueryList","#resolveSystemThemeType","#emitThemeChange","#disposes","#tokenizeMaxLineLength","#setStyle","#onDeferTokenize","#onThemeChange","#debug","#colorMap","#setTheme","#themeName","#comparisonStateStack","#comparisonStateStackStart","#comparisonLineChanges","#scheduleBackgroundTokenize","#detachMessageListener","#shiftComparisonStateStack","#getPreviousEndState","#prebuildStateStack","#pendingPrebuildEndLine","#isStopped","#isPaused","#lastLine","#backgroundChangedLineRanges","#backgroundChangedRangeIndex","#postTokenizeMessage","#isMessageListenerAttached","#onMessage","#attachMessageListener","#cacheBracketIgnoredRanges"],"sources":["../../src/editor/tokenizer.ts"],"sourcesContent":["import { colorUtils } from '@pierre/theming/color';\nimport {\n EncodedTokenMetadata,\n type IGrammar,\n INITIAL,\n type StateStack,\n} from 'shiki/textmate';\n\nimport { DEFAULT_THEMES } from '../constants';\nimport type {\n BaseCodeOptions,\n DiffsHighlighter,\n HighlightedToken,\n RenderRange,\n} from '../types';\nimport type { TextDocument, TextDocumentChange } from './textDocument';\nimport { addEventListener, debounce, h } from './utils';\n\nconst TOKENIZE_TIME_LIMIT = 500;\nlet nextTokenizerId = 0;\n\nexport interface EditorTokenizerProps {\n highlighter: DiffsHighlighter;\n textDocument: TextDocument<unknown>;\n codeOptions: BaseCodeOptions;\n matchBrackets?: boolean;\n setStyle: (style: string) => void;\n onDeferTokenize: (\n lines: Map<number, Array<HighlightedToken>>,\n themeType: 'dark' | 'light'\n ) => void;\n // Fired after the active theme (light/dark mode or theme name) changes and the\n // new theme CSS has been applied. Lets the editor recompute overlay pieces\n // that captured a resolved theme color, e.g. rounded selection corner masks.\n onThemeChange?: () => void;\n __debug?: boolean;\n}\n\n/** Stoppable code tokenizer for the editor */\nexport class EditorTokenizer {\n #highlighter: DiffsHighlighter;\n #grammar: IGrammar | undefined;\n #mediaQueryList: MediaQueryList;\n #themeType: 'light' | 'dark' = 'dark';\n // The resolved name of the theme currently applied to the editor (e.g.\n // `github-light`). Tracked so `syncTheme` can detect a host-driven theme swap\n // even when the light/dark mode itself is unchanged.\n #themeName = '';\n #colorMap: string[];\n #textDocument: TextDocument<unknown>;\n #tokenizeMaxLineLength: number;\n #setStyle: EditorTokenizerProps['setStyle'];\n #onDeferTokenize: EditorTokenizerProps['onDeferTokenize'];\n #onThemeChange: EditorTokenizerProps['onThemeChange'];\n #matchBrackets: boolean;\n #debug: boolean;\n #disposes?: (() => void)[];\n #isCleanedUp = false;\n\n // state\n #stateStack: StateStack[] = [INITIAL]; // cached state stack by line index\n #comparisonStateStack: StateStack[] = [];\n #comparisonStateStackStart = 0;\n #comparisonLineChanges: NonNullable<\n TextDocumentChange['changedLineChanges']\n > = [];\n #lastLine: number = -1;\n #isStopped: boolean = true;\n #isPaused: boolean = false;\n #backgroundJobId: number = 0;\n #tokenizerId = ++nextTokenizerId;\n #backgroundPrebuildEndLine = -1;\n #pendingPrebuildEndLine = -1;\n #backgroundChangedLineRanges: readonly [number, number][] | undefined;\n #backgroundChangedRangeIndex: number = 0;\n #bracketIgnoredRanges: ([number, number][] | null | undefined)[] = [];\n #isMessageListenerAttached: boolean = false;\n\n #prebuildStateStack = debounce(async (renderRange?: RenderRange) => {\n // Drop work scheduled before cleanUp; a late timer must not call setTheme\n // on a highlighter that tests (or hosts) have already disposed.\n if (this.#isCleanedUp) {\n return;\n }\n const { startingLine = 0, totalLines = Infinity } = renderRange ?? {};\n const endLine = Math.min(\n totalLines === Infinity ? Infinity : startingLine + totalLines,\n this.#textDocument.lineCount\n );\n if (\n this.#grammar === undefined &&\n !isGrammarlessLanguage(this.#textDocument.languageId)\n ) {\n await this.#highlighter.loadLanguage(this.#textDocument.languageId);\n if (this.#isCleanedUp) {\n return;\n }\n this.#grammar = this.#highlighter.getLanguage(\n this.#textDocument.languageId\n );\n }\n this.#ensureActiveTheme();\n this.#scheduleStatePrebuild(endLine);\n }, 500);\n\n #onMessage = ({ data }: MessageEvent<unknown>) => {\n if (typeof data !== 'object' || data === null) {\n return;\n }\n const { type, tokenizerId, jobId } = data as {\n type?: unknown;\n tokenizerId?: unknown;\n jobId?: unknown;\n };\n if (\n type === 'tokenize' &&\n tokenizerId === this.#tokenizerId &&\n typeof jobId === 'number' &&\n jobId === this.#backgroundJobId\n ) {\n if (this.#backgroundPrebuildEndLine >= 0) {\n this.#backgroundPrebuild(jobId);\n } else {\n this.#backgroundTokenize(jobId);\n }\n }\n };\n\n get themeType(): 'light' | 'dark' {\n return this.#themeType;\n }\n\n getStringCommentRegexpRangesInLine(\n lineIndex: number\n ): [number, number][] | null {\n if (\n !this.#matchBrackets ||\n lineIndex < 0 ||\n lineIndex >= this.#textDocument.lineCount\n ) {\n return null;\n }\n this.#ensureGrammar();\n if (this.#grammar === undefined) {\n return null;\n }\n if (this.#bracketIgnoredRanges[lineIndex] === undefined) {\n this.#buildStateStack(lineIndex);\n const state = this.#stateStack[lineIndex] ?? INITIAL;\n const result = this.#tokenizeLineAt(lineIndex, state);\n this.#stateStack[lineIndex + 1] = result.state;\n }\n return this.#bracketIgnoredRanges[lineIndex] ?? null;\n }\n\n constructor({\n codeOptions,\n highlighter,\n textDocument,\n matchBrackets,\n setStyle,\n onDeferTokenize,\n onThemeChange,\n __debug,\n }: EditorTokenizerProps) {\n const {\n themeType: themeTypeOption = 'system',\n theme = DEFAULT_THEMES,\n tokenizeMaxLineLength = 1000,\n } = codeOptions;\n this.#mediaQueryList = window.matchMedia('(prefers-color-scheme: dark)');\n let themeType: 'light' | 'dark' | undefined;\n if (themeTypeOption === 'system') {\n // Prefer the host document's computed color-scheme (page CSS/classes can\n // force light/dark while the OS media query differs) over matchMedia.\n themeType = this.#resolveSystemThemeType();\n } else {\n themeType = themeTypeOption;\n }\n // Only track the document/system color scheme when the surface follows it\n // (`themeType: 'system'`). A surface pinned to an explicit 'dark'/'light'\n // theme keeps that theme regardless of the page, so re-tokenizing after an\n // edit must emit the same `--diffs-token-{theme}` variable the SSR markup\n // used; otherwise the edited tokens fall back to the default foreground.\n if (typeof theme !== 'string' && themeTypeOption === 'system') {\n const observer = new MutationObserver((mutations) => {\n for (const { type, attributeName } of mutations) {\n if (\n type === 'attributes' &&\n attributeName !== null &&\n (attributeName === 'class' || attributeName.startsWith('data-'))\n ) {\n const themeType = this.#resolveSystemThemeType();\n this.#emitThemeChange(theme[themeType], themeType);\n break;\n }\n }\n });\n observer.observe(document.documentElement, { attributes: true });\n observer.observe(document.body, { attributes: true });\n this.#disposes = [\n addEventListener(this.#mediaQueryList, 'change', () => {\n // Re-read computed color-scheme so a host-forced scheme still wins\n // when the OS preference changes underneath it.\n const themeType = this.#resolveSystemThemeType();\n this.#emitThemeChange(theme[themeType], themeType);\n }),\n () => observer.disconnect(),\n ];\n }\n this.#highlighter = highlighter;\n this.#textDocument = textDocument;\n this.#tokenizeMaxLineLength = tokenizeMaxLineLength;\n this.#setStyle = setStyle;\n this.#onDeferTokenize = onDeferTokenize;\n this.#onThemeChange = onThemeChange;\n this.#matchBrackets = matchBrackets !== false;\n this.#debug = __debug ?? false;\n this.#ensureGrammar();\n this.#colorMap = [];\n this.#setTheme(\n typeof theme === 'string' ? theme : theme[themeType],\n typeof theme === 'string' ? undefined : themeType\n );\n }\n\n // By default, diffs components support dual themes, but the tokenizer only renders\n // the preferred theme. When the theme type is changed, the tokenizer will re-tokenize the document.\n #emitThemeChange(themeName: string, themeType: 'light' | 'dark') {\n if (themeName === this.#themeName && themeType === this.#themeType) {\n return;\n }\n this.#setTheme(themeName, themeType);\n this.stopBackgroundTokenize();\n this.#stateStack = [INITIAL];\n this.#comparisonStateStack = [];\n this.#comparisonStateStackStart = 0;\n this.#comparisonLineChanges = [];\n if (this.#grammar !== undefined && this.#textDocument.lineCount > 0) {\n this.#scheduleBackgroundTokenize(0);\n }\n // The theme CSS is now applied, so overlay pieces that captured a resolved\n // theme color (e.g. rounded selection corner masks) can recompute against\n // the new colors instead of keeping the old light/dark value.\n this.#onThemeChange?.();\n }\n\n // Respect an explicit host color-scheme override. When the computed value\n // advertises support for both schemes, let the OS preference choose one.\n #resolveSystemThemeType(): 'light' | 'dark' {\n try {\n if (\n typeof document !== 'undefined' &&\n typeof getComputedStyle === 'function' &&\n document.body != null\n ) {\n const colorSchemes = getComputedStyle(document.body).colorScheme.split(\n /\\s+/\n );\n const supportsDark = colorSchemes.includes('dark');\n const supportsLight = colorSchemes.includes('light');\n // A single host-forced scheme wins. `light dark` only declares support\n // for both schemes, so the media query still selects the active one.\n if (supportsDark !== supportsLight) {\n return supportsDark ? 'dark' : 'light';\n }\n }\n } catch {\n // jsdom and similar harnesses may lack getComputedStyle or throw; fall\n // through to the OS media query.\n }\n return this.#mediaQueryList.matches ? 'dark' : 'light';\n }\n\n // Re-apply the editor's theme from the surface's current code options. Edit\n // mode reuses a single tokenizer across re-renders, so when the host swaps the\n // theme — a theme picker, a light/dark toggle, etc. — we must recompute the\n // active theme and re-tokenize. Without this the editor keeps rendering the\n // theme it captured when it first attached (stale line-highlight background\n // and token colors). System-driven changes are still handled by the\n // observers wired up in the constructor; this covers explicit `themeType`/\n // `theme` option changes that those observers don't see.\n syncTheme(codeOptions: BaseCodeOptions): void {\n const { themeType = 'system', theme = DEFAULT_THEMES } = codeOptions;\n // A single pinned theme does not follow the themeType option or system\n // scheme flips; its own classification stays authoritative.\n if (typeof theme === 'string') {\n const pinnedThemeType = this.#highlighter.getTheme(theme).type;\n if (theme === this.#themeName && pinnedThemeType === this.#themeType) {\n return;\n }\n this.#emitThemeChange(theme, pinnedThemeType);\n return;\n }\n const nextThemeType =\n themeType === 'system' ? this.#resolveSystemThemeType() : themeType;\n const nextThemeName = theme[nextThemeType];\n if (\n nextThemeType === this.#themeType &&\n nextThemeName === this.#themeName\n ) {\n return;\n }\n this.#emitThemeChange(nextThemeName, nextThemeType);\n }\n\n #setTheme(themeName: string, themeType?: 'light' | 'dark') {\n const { theme, colorMap } = this.#highlighter.setTheme(themeName);\n const { colors = {} } = this.#highlighter.getTheme(themeName);\n const selectionBackground = colors['editor.selectionBackground'];\n const themeLineHighlightBackground =\n colors['editor.lineHighlightBackground'];\n const lineHighlightBackground =\n themeLineHighlightBackground != null &&\n themeLineHighlightBackground.trim() !== '' &&\n !colorUtils.isFullyTransparent(themeLineHighlightBackground)\n ? themeLineHighlightBackground\n : undefined;\n // A usable theme background opts into the semantic active-line mix.\n // Missing backgrounds retain the resolved row color and rely on a border.\n const lineHighlightBorder =\n colors['editor.lineHighlightBorder'] ??\n (lineHighlightBackground == null\n ? 'color-mix(in lab, var(--diffs-bg) 70%, var(--diffs-fg))'\n : 'transparent');\n const activeLineSourceMix =\n lineHighlightBackground == null ? '100%' : '85%';\n const cursorForeground = colors['editorCursor.foreground'];\n const findMatchBackground = colors['editor.findMatchBackground'];\n const findMatchHighlightBackground =\n colors['editor.findMatchHighlightBackground'];\n const bracketMatchBackground = colors['editorBracketMatch.background'];\n const bracketMatchBorder = colors['editorBracketMatch.border'];\n const hintForeground = colors['editorHint.foreground'];\n const infoForeground = colors['editorInfo.foreground'];\n const warningForeground = colors['editorWarning.foreground'];\n const errorForeground = colors['editorError.foreground'];\n this.#setStyle(`:host {\n --diffs-editor-selection-bg: ${selectionBackground ?? 'var(--diffs-line-bg)'};\n --diffs-editor-line-highlight-border: ${lineHighlightBorder};\n --diffs-editor-active-line-source-mix: ${activeLineSourceMix};\n --diffs-editor-match-bg: ${findMatchBackground ?? 'initial'};\n --diffs-editor-match-highlight-bg: ${findMatchHighlightBackground ?? 'initial'};\n --diffs-editor-bracket-match-bg: ${bracketMatchBackground ?? 'initial'};\n --diffs-editor-bracket-match-border: ${bracketMatchBorder ?? 'initial'};\n --diffs-editor-cursor-fg: ${cursorForeground ?? 'initial'};\n --diffs-editor-hint-fg: ${hintForeground ?? 'initial'};\n --diffs-editor-info-fg: ${infoForeground ?? 'initial'};\n --diffs-editor-warning-fg: ${warningForeground ?? 'initial'};\n --diffs-editor-error-fg: ${errorForeground ?? 'initial'};\n }`);\n this.#themeName = themeName;\n this.#themeType = themeType ?? theme.type;\n this.#colorMap = colorMap;\n }\n\n // The shared highlighter is also used for dual-theme SSR (`themes: {dark,light}`),\n // which leaves its active theme on whichever pass finished last (usually light).\n // The tokenizer caches a single-theme colorMap from construction; if we tokenize\n // without re-activating that theme, grammar color indices are looked up in the\n // wrong map — property names resolve to a near-foreground gray while types and\n // comments (stable across maps) still look correct. Re-apply before every\n // tokenize path so a first edit after load matches a later file-switch re-attach.\n #ensureActiveTheme(): void {\n if (this.#themeName === '') {\n return;\n }\n const { colorMap } = this.#highlighter.setTheme(this.#themeName);\n this.#colorMap = colorMap;\n }\n\n cleanUp(): void {\n this.#isCleanedUp = true;\n this.stopBackgroundTokenize();\n this.#detachMessageListener();\n this.#disposes?.forEach((dispose) => dispose());\n this.#disposes = undefined;\n }\n\n // to use `tokenize`, call `prebuildStateStackMap` first to prebuild\n // the state stack map for the given render range.\n tokenize(\n change: TextDocumentChange,\n renderRange?: RenderRange,\n hostRealignsRows = false\n ): Map<number, Array<HighlightedToken>> {\n this.#ensureGrammar();\n this.#ensureActiveTheme();\n if (\n this.#grammar === undefined &&\n !isGrammarlessLanguage(this.#textDocument.languageId)\n ) {\n throw new Error(\n `Grammar for language \"${this.#textDocument.languageId}\" not loaded`\n );\n }\n\n if (this.#matchBrackets) {\n // Clear ignored token ranges for lines invalidated by the edit.\n this.#bracketIgnoredRanges.length = Math.min(\n this.#bracketIgnoredRanges.length,\n change.startLine\n );\n }\n\n const { lineCount } = this.#textDocument;\n const { startingLine = 0, totalLines = Infinity } = renderRange ?? {};\n const renderRangeEndLine =\n totalLines === Infinity\n ? lineCount\n : Math.min(startingLine + totalLines, lineCount);\n\n const dirtyStart = change.startLine;\n const viewStart = Math.max(startingLine, dirtyStart);\n const crossesRenderRangeEnd =\n renderRange !== undefined &&\n totalLines !== Infinity &&\n change.lineDelta > 0 &&\n dirtyStart < renderRangeEndLine &&\n change.endLine >= renderRangeEndLine;\n const canReuseCachedStates =\n change.lineDelta === 0 &&\n (change.changedLineChanges?.every(([, , lineDelta]) => lineDelta === 0) ??\n true);\n const canReuseShiftedStates =\n hostRealignsRows && change.lineDelta !== 0 && dirtyStart >= startingLine;\n const canCacheTokenizedStates =\n canReuseCachedStates ||\n renderRange === undefined ||\n dirtyStart >= viewStart;\n const changedLineRanges: readonly [number, number][] =\n change.changedLineRanges ?? [[dirtyStart, change.endLine]];\n this.#comparisonStateStack = [];\n this.#comparisonStateStackStart = 0;\n this.#comparisonLineChanges = [];\n let offscreenSyncEnd = -1;\n if (dirtyStart < viewStart) {\n for (const [rangeStart, rangeEnd] of changedLineRanges) {\n if (rangeStart < viewStart) {\n offscreenSyncEnd = Math.max(\n offscreenSyncEnd,\n Math.min(rangeEnd, viewStart - 1)\n );\n }\n }\n }\n const shouldFlushOffscreenLines =\n offscreenSyncEnd >= dirtyStart &&\n (canReuseCachedStates || change.lineDelta < 0);\n if (canReuseCachedStates) {\n this.#buildStateStack(dirtyStart);\n } else {\n this.#shiftComparisonStateStack(change);\n if (renderRange === undefined || dirtyStart >= viewStart) {\n this.#buildStateStack(viewStart);\n }\n }\n\n let changedRangeIndex = 0;\n let currentChangedRangeEnd = changedLineRanges[changedRangeIndex][1];\n let backgroundStartLine: number | undefined;\n let backgroundChangedRangeIndex = 0;\n let line = canReuseCachedStates\n ? changedLineRanges[changedRangeIndex][0]\n : viewStart;\n let settled = false;\n const dirtyLines: Map<number, Array<HighlightedToken>> = new Map();\n const offscreenDirtyLines:\n | Map<number, Array<HighlightedToken>>\n | undefined = shouldFlushOffscreenLines ? new Map() : undefined;\n if (offscreenDirtyLines !== undefined && !canReuseCachedStates) {\n const offscreenEnd = Math.min(\n offscreenSyncEnd + 1,\n viewStart,\n renderRangeEndLine\n );\n if (offscreenEnd > dirtyStart) {\n this.#buildStateStack(offscreenEnd);\n let offscreenLine = dirtyStart;\n let offscreenState = this.#stateStack[offscreenLine] ?? INITIAL;\n for (; offscreenLine < offscreenEnd; offscreenLine++) {\n const resolved = this.#tokenizeLineAt(offscreenLine, offscreenState);\n offscreenState = resolved.state;\n offscreenDirtyLines.set(offscreenLine, resolved.resolvedTokens);\n }\n this.#stateStack[offscreenEnd] = offscreenState;\n }\n }\n // Seed the loop's grammar state after the offscreen flush, not before it.\n // When a delete's removed lines reach the viewport's first line, the flush\n // rebuilds the cached state up to `line`; reading it earlier would capture\n // the truncated INITIAL state and color the viewport as if outside an open\n // construct (block comment, template literal) it is actually inside.\n let state = this.#stateStack[line] ?? INITIAL;\n for (; line < renderRangeEndLine; ) {\n const previousNextState = canReuseCachedStates\n ? this.#stateStack[line + 1]\n : canReuseShiftedStates\n ? this.#getPreviousEndState(line + 1)\n : undefined;\n if (canCacheTokenizedStates) {\n this.#stateStack[line] = state;\n }\n\n const { resolvedTokens, state: nextState } = this.#tokenizeLineAt(\n line,\n state\n );\n state = nextState;\n\n if (line >= viewStart) {\n dirtyLines.set(line, resolvedTokens);\n } else {\n offscreenDirtyLines?.set(line, resolvedTokens);\n }\n\n if (canCacheTokenizedStates) {\n this.#stateStack[line + 1] = state;\n }\n settled =\n line >= currentChangedRangeEnd &&\n (canReuseCachedStates || canReuseShiftedStates) &&\n previousNextState !== undefined &&\n state.equals(previousNextState);\n if (settled) {\n changedRangeIndex++;\n const nextRange = changedLineRanges[changedRangeIndex];\n if (nextRange === undefined) {\n break;\n }\n if (nextRange[0] >= renderRangeEndLine) {\n backgroundStartLine = nextRange[0];\n backgroundChangedRangeIndex = changedRangeIndex;\n break;\n }\n let nextState: StateStack | undefined = this.#stateStack[nextRange[0]];\n if (canReuseShiftedStates) {\n for (\n let stateLine = line + 2;\n stateLine <= nextRange[0];\n stateLine++\n ) {\n nextState = this.#getPreviousEndState(stateLine);\n if (nextState === undefined) {\n break;\n }\n this.#stateStack[stateLine] = nextState;\n }\n }\n if (nextState === undefined) {\n currentChangedRangeEnd = nextRange[1];\n line++;\n } else {\n line = nextRange[0];\n state = nextState;\n currentChangedRangeEnd = nextRange[1];\n }\n settled = false;\n continue;\n }\n line++;\n }\n\n if (canCacheTokenizedStates) {\n if (line < renderRangeEndLine) {\n this.#stateStack[line + 1] = state;\n } else {\n this.#stateStack[line] = state;\n }\n }\n\n if (settled && canReuseShiftedStates && backgroundStartLine === undefined) {\n for (let stateLine = line + 2; stateLine <= lineCount; stateLine++) {\n const previousState = this.#getPreviousEndState(stateLine);\n if (previousState === undefined) {\n break;\n }\n this.#stateStack[stateLine] = previousState;\n }\n this.#comparisonStateStack = [];\n this.#comparisonStateStackStart = 0;\n this.#comparisonLineChanges = [];\n }\n\n if (offscreenDirtyLines !== undefined && offscreenDirtyLines.size > 0) {\n this.#onDeferTokenize(offscreenDirtyLines, this.#themeType);\n }\n\n if (backgroundStartLine !== undefined) {\n this.#scheduleBackgroundTokenize(\n backgroundStartLine,\n changedLineRanges,\n backgroundChangedRangeIndex\n );\n } else if (!settled && line < lineCount) {\n const backgroundLine =\n crossesRenderRangeEnd && dirtyStart >= viewStart\n ? renderRangeEndLine\n : dirtyStart < viewStart && !canReuseCachedStates\n ? dirtyStart\n : line;\n this.#scheduleBackgroundTokenize(\n backgroundLine,\n changedLineRanges,\n changedRangeIndex\n );\n }\n\n return dirtyLines;\n }\n\n prebuildStateStack(renderRange?: RenderRange): void {\n this.#ensureGrammar();\n this.#prebuildStateStack(renderRange);\n }\n\n stopBackgroundTokenize(): void {\n this.#pendingPrebuildEndLine = -1;\n if (this.#isStopped) {\n return;\n }\n this.#isStopped = true;\n this.#isPaused = false;\n this.#lastLine = -1;\n this.#backgroundPrebuildEndLine = -1;\n this.#backgroundChangedLineRanges = undefined;\n this.#backgroundChangedRangeIndex = 0;\n this.#comparisonStateStack = [];\n this.#comparisonStateStackStart = 0;\n this.#comparisonLineChanges = [];\n this.#detachMessageListener();\n }\n\n pauseBackgroundTokenize(): void {\n if (this.#isStopped || this.#isPaused) {\n return;\n }\n if (this.#debug) {\n console.log('[diffs/editor] background tokenization paused', {\n jobId: this.#backgroundJobId,\n });\n }\n this.#isPaused = true;\n }\n\n resumeBackgroundTokenize(): void {\n if (\n this.#isStopped ||\n !this.#isPaused ||\n this.#grammar === undefined ||\n this.#lastLine < 0\n ) {\n return;\n }\n if (this.#debug) {\n console.log('[diffs/editor] background tokenization resumed', {\n jobId: this.#backgroundJobId,\n });\n }\n this.#isPaused = false;\n this.#postTokenizeMessage(this.#backgroundJobId);\n }\n\n #ensureGrammar(): void {\n if (\n this.#grammar === undefined &&\n !isGrammarlessLanguage(this.#textDocument.languageId) &&\n this.#highlighter\n .getLoadedLanguages()\n .includes(this.#textDocument.languageId)\n ) {\n this.#grammar = this.#highlighter.getLanguage(\n this.#textDocument.languageId\n );\n }\n }\n\n #attachMessageListener(): void {\n if (this.#isMessageListenerAttached) {\n return;\n }\n globalThis.addEventListener('message', this.#onMessage);\n this.#isMessageListenerAttached = true;\n }\n\n #detachMessageListener(): void {\n if (!this.#isMessageListenerAttached) {\n return;\n }\n globalThis.removeEventListener('message', this.#onMessage);\n this.#isMessageListenerAttached = false;\n }\n\n #postTokenizeMessage(jobId: number): void {\n // use `postMessage` instead of `setTimeout(fn, 0)` to avoid 4ms delay\n globalThis.postMessage({\n type: 'tokenize',\n tokenizerId: this.#tokenizerId,\n jobId,\n });\n }\n\n #scheduleBackgroundTokenize(\n startLine: number,\n changedLineRanges?: readonly [number, number][],\n changedRangeIndex = 0\n ): void {\n if (isGrammarlessLanguage(this.#textDocument.languageId)) {\n return;\n }\n\n const jobId = ++this.#backgroundJobId;\n\n if (this.#debug) {\n console.log('[diffs/editor] background tokenization scheduled', {\n jobId,\n startLine,\n changedLineRanges,\n changedRangeIndex,\n });\n }\n\n this.#isStopped = false;\n this.#isPaused = false;\n this.#lastLine = startLine;\n if (this.#backgroundPrebuildEndLine >= 0) {\n this.#pendingPrebuildEndLine = Math.max(\n this.#pendingPrebuildEndLine,\n this.#backgroundPrebuildEndLine\n );\n }\n this.#backgroundPrebuildEndLine = -1;\n this.#backgroundChangedLineRanges = changedLineRanges;\n this.#backgroundChangedRangeIndex = changedRangeIndex;\n this.#attachMessageListener();\n this.#postTokenizeMessage(jobId);\n }\n\n #scheduleStatePrebuild(endLine: number): void {\n if (this.#grammar === undefined || this.#stateStack.length > endLine) {\n return;\n }\n // Extend an active prebuild, or retain the target until the foreground\n // edit job reconverges and releases the state cache.\n if (!this.#isStopped) {\n if (this.#backgroundPrebuildEndLine >= 0) {\n this.#backgroundPrebuildEndLine = Math.max(\n this.#backgroundPrebuildEndLine,\n endLine\n );\n } else {\n this.#pendingPrebuildEndLine = Math.max(\n this.#pendingPrebuildEndLine,\n endLine\n );\n }\n return;\n }\n\n const jobId = ++this.#backgroundJobId;\n this.#isStopped = false;\n this.#isPaused = false;\n this.#lastLine = this.#stateStack.length - 1;\n this.#backgroundPrebuildEndLine = endLine;\n this.#pendingPrebuildEndLine = -1;\n this.#backgroundChangedLineRanges = undefined;\n this.#backgroundChangedRangeIndex = 0;\n this.#attachMessageListener();\n this.#postTokenizeMessage(jobId);\n }\n\n #tokenizeLineAt(\n line: number,\n state: StateStack\n ): { resolvedTokens: Array<HighlightedToken>; state: StateStack } {\n const lineText = this.#textDocument.getLineText(line);\n if (lineText.length > this.#tokenizeMaxLineLength) {\n console.warn(\n `[diffs] Line(${line}) too long to tokenize: ${lineText.length}`\n );\n this.#cacheBracketIgnoredRanges(line, null);\n return { resolvedTokens: [[0, '', lineText]], state };\n }\n if (\n this.#grammar === undefined ||\n lineText === '' ||\n lineText.trim() === ''\n ) {\n this.#cacheBracketIgnoredRanges(line, null);\n return { resolvedTokens: [[0, '', lineText]], state };\n }\n const result = tokenizeLine(\n this.#grammar,\n this.#colorMap,\n lineText,\n state,\n TOKENIZE_TIME_LIMIT,\n this.#matchBrackets\n );\n this.#cacheBracketIgnoredRanges(line, result.bracketIgnoredRanges);\n return {\n resolvedTokens: result.resolvedTokens,\n state: result.ruleStack,\n };\n }\n\n #cacheBracketIgnoredRanges(\n line: number,\n ranges: [number, number][] | null\n ): void {\n if (this.#matchBrackets) {\n this.#bracketIgnoredRanges[line] = ranges;\n }\n }\n\n // Preserve old end states as comparison-only sentinels, copying whichever\n // side of the edit is smaller. Index shifts are resolved lazily on lookup.\n #shiftComparisonStateStack(change: TextDocumentChange): void {\n const lineChanges =\n change.changedLineChanges ??\n ([[change.startLine, change.endLine, change.lineDelta]] as const);\n const comparisonStart = change.startLine + 1;\n const comparisonLength = this.#stateStack.length - comparisonStart;\n if (comparisonStart <= comparisonLength) {\n this.#comparisonStateStack = this.#stateStack;\n this.#comparisonStateStackStart = 0;\n this.#stateStack = this.#stateStack.slice(0, comparisonStart);\n } else {\n this.#comparisonStateStackStart = comparisonStart;\n this.#comparisonStateStack = this.#stateStack.slice(comparisonStart);\n this.#stateStack.length = Math.min(\n this.#stateStack.length,\n comparisonStart\n );\n }\n this.#comparisonLineChanges = lineChanges;\n }\n\n #getPreviousEndState(line: number): StateStack | undefined {\n let previousLine = line;\n for (\n let index = this.#comparisonLineChanges.length - 1;\n index >= 0;\n index--\n ) {\n const [startLine, endLine, lineDelta] =\n this.#comparisonLineChanges[index];\n if (lineDelta === 0) {\n continue;\n }\n if (previousLine > endLine) {\n previousLine -= lineDelta;\n } else if (previousLine > startLine) {\n return this.#stateStack[line];\n }\n }\n return (\n this.#comparisonStateStack[\n previousLine - this.#comparisonStateStackStart\n ] ?? this.#stateStack[line]\n );\n }\n\n #buildStateStack(endAt: number, timeBudget?: number): boolean {\n const boundedEndAt = Math.min(\n Math.max(0, endAt),\n this.#textDocument.lineCount\n );\n if (this.#stateStack.length > boundedEndAt || this.#grammar === undefined) {\n return true;\n }\n const startedAt = timeBudget === undefined ? 0 : performance.now();\n let line = this.#stateStack.length - 1;\n let state = this.#stateStack[line] ?? INITIAL;\n while (line < boundedEndAt) {\n this.#stateStack[line] = state;\n const lineText = this.#textDocument.getLineText(line);\n if (\n lineText.length <= this.#tokenizeMaxLineLength &&\n lineText !== '' &&\n lineText.trim() !== ''\n ) {\n const result = tokenizeLine(\n this.#grammar,\n this.#colorMap,\n lineText,\n state,\n TOKENIZE_TIME_LIMIT,\n this.#matchBrackets,\n false\n );\n this.#cacheBracketIgnoredRanges(line, result.bracketIgnoredRanges);\n state = result.ruleStack;\n } else {\n this.#cacheBracketIgnoredRanges(line, null);\n }\n line++;\n this.#stateStack[line] = state;\n if (\n timeBudget !== undefined &&\n performance.now() - startedAt > timeBudget\n ) {\n break;\n }\n }\n return line >= boundedEndAt;\n }\n\n #backgroundPrebuild(jobId: number): void {\n if (\n this.#isStopped ||\n this.#isPaused ||\n this.#grammar === undefined ||\n jobId !== this.#backgroundJobId\n ) {\n return;\n }\n\n this.#ensureActiveTheme();\n // State prebuilds intentionally omit rendered tokens and yield between\n // short chunks so a deep viewport does not monopolize the main thread.\n const complete = this.#buildStateStack(this.#backgroundPrebuildEndLine, 1);\n if (this.#isStopped || this.#isPaused || jobId !== this.#backgroundJobId) {\n return;\n }\n if (complete) {\n this.stopBackgroundTokenize();\n return;\n }\n this.#lastLine = this.#stateStack.length - 1;\n this.#postTokenizeMessage(jobId);\n }\n\n #backgroundTokenize(jobId: number) {\n if (\n this.#isStopped ||\n this.#isPaused ||\n this.#grammar === undefined ||\n jobId !== this.#backgroundJobId\n ) {\n return;\n }\n\n this.#ensureActiveTheme();\n\n const t = performance.now();\n const lines = new Map<number, Array<HighlightedToken>>();\n const totalLines = this.#textDocument.lineCount;\n const changedLineRanges = this.#backgroundChangedLineRanges;\n\n let line = this.#lastLine;\n let state = this.#stateStack[line] ?? INITIAL;\n let settled = false;\n let changedRangeIndex = this.#backgroundChangedRangeIndex;\n let currentChangedRangeEnd = changedLineRanges?.[changedRangeIndex]?.[1];\n for (; line < totalLines; ) {\n this.#stateStack[line] = state;\n\n const previousNextState =\n currentChangedRangeEnd !== undefined\n ? this.#getPreviousEndState(line + 1)\n : undefined;\n const lineText = this.#textDocument.getLineText(line);\n if (lineText.length > this.#tokenizeMaxLineLength) {\n console.warn(\n `[diffs] Line(${line}) too long to tokenize: ${lineText.length}`\n );\n lines.set(line, [[0, '', lineText]]);\n this.#cacheBracketIgnoredRanges(line, null);\n } else if (lineText === '' || lineText.trim() === '') {\n lines.set(line, [[0, '', lineText]]);\n this.#cacheBracketIgnoredRanges(line, null);\n } else {\n const ret = tokenizeLine(\n this.#grammar,\n this.#colorMap,\n lineText,\n state,\n TOKENIZE_TIME_LIMIT,\n this.#matchBrackets\n );\n lines.set(line, ret.resolvedTokens);\n this.#cacheBracketIgnoredRanges(line, ret.bracketIgnoredRanges);\n state = ret.ruleStack;\n }\n\n this.#stateStack[line + 1] = state;\n settled =\n currentChangedRangeEnd !== undefined &&\n line >= currentChangedRangeEnd &&\n previousNextState !== undefined &&\n state.equals(previousNextState);\n line++;\n if (settled) {\n changedRangeIndex++;\n const nextRange = changedLineRanges?.[changedRangeIndex];\n if (nextRange === undefined) {\n break;\n }\n currentChangedRangeEnd = nextRange[1];\n if (this.#stateStack[nextRange[0]] === undefined) {\n settled = false;\n } else {\n line = nextRange[0];\n state = this.#stateStack[line] ?? state;\n settled = false;\n continue;\n }\n }\n\n // limit the time of partial tokenize to 1ms\n if (performance.now() - t > 1) {\n break;\n }\n }\n\n this.#onDeferTokenize(lines, this.#themeType);\n if (this.#isStopped || this.#isPaused || jobId !== this.#backgroundJobId) {\n return;\n }\n\n if (settled || line >= totalLines) {\n const pendingPrebuildEndLine = this.#pendingPrebuildEndLine;\n this.stopBackgroundTokenize();\n if (pendingPrebuildEndLine >= 0) {\n this.#scheduleStatePrebuild(pendingPrebuildEndLine);\n }\n return;\n }\n\n this.#lastLine = line;\n this.#backgroundChangedRangeIndex = changedRangeIndex;\n this.#postTokenizeMessage(jobId);\n }\n}\n\nfunction tokenizeLine(\n grammar: IGrammar,\n colorMap: string[],\n lineText: string,\n stateStack: StateStack,\n timeLimit?: number,\n collectBracketIgnoredRanges = true,\n resolveTokens = true\n): {\n ruleStack: StateStack;\n resolvedTokens: Array<HighlightedToken>;\n bracketIgnoredRanges: [number, number][];\n} {\n const result = grammar.tokenizeLine2(lineText, stateStack, timeLimit);\n if (result.stoppedEarly) {\n console.warn(\n `[diffs] Time limit reached when tokenizing line: ${lineText.substring(0, 100)}`\n );\n }\n const rawTokens = result.tokens;\n const tokensLength = rawTokens.length / 2;\n const resolvedTokens: Array<HighlightedToken> = [];\n const bracketIgnoredRanges: [number, number][] = [];\n if (!resolveTokens && !collectBracketIgnoredRanges) {\n return {\n ruleStack: result.ruleStack,\n resolvedTokens,\n bracketIgnoredRanges,\n };\n }\n for (let j = 0; j < tokensLength; j++) {\n const offset = rawTokens[2 * j];\n const nextOffset =\n j + 1 < tokensLength ? rawTokens[2 * j + 2] : lineText.length;\n if (offset === nextOffset) {\n // should never reach here, skip if happens anyway\n continue;\n }\n const metadata = rawTokens[2 * j + 1];\n if (resolveTokens) {\n const fg = EncodedTokenMetadata.getForeground(metadata);\n resolvedTokens.push([\n offset,\n colorMap[fg],\n lineText.slice(offset, nextOffset),\n ]);\n }\n if (\n collectBracketIgnoredRanges &&\n EncodedTokenMetadata.getTokenType(metadata) > 0\n ) {\n bracketIgnoredRanges.push([offset, nextOffset]);\n }\n }\n return {\n ruleStack: result.ruleStack,\n resolvedTokens,\n bracketIgnoredRanges,\n };\n}\n\nexport function renderLineTokens(\n tokens: Array<HighlightedToken>\n): (HTMLElement | string)[] {\n return tokens.map(([char, fg, textContent]) => {\n if (char === 0 && fg === '') {\n if (textContent === '') {\n return h('br');\n }\n return textContent;\n }\n return h('span', {\n dataset: {\n char: char.toString(),\n },\n style: `color:${fg};`,\n textContent: textContent,\n });\n });\n}\n\n// Shiki special-cases `text` and `ansi` in codeToHast but does not expose grammars.\nfunction isGrammarlessLanguage(languageId: string): boolean {\n return languageId === 'text' || languageId === 'ansi';\n}\n"],"mappings":"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"}
@@ -89,8 +89,9 @@ declare class DiffHunksRenderer<LAnnotation = undefined> {
89
89
  * Enter edit-session mode: hunk updates preserve the current region
90
90
  * skeleton instead of recomputing hunks, and rendering happens locally
91
91
  * with the token transformer forced on (worker-pool requests/results are
92
- * suspended for this renderer). Called on every editor attach, including
93
- * a re-attach after recycle.
92
+ * suspended for this renderer). An empty additions document gets one row so
93
+ * the editor has a line for its caret. Called on every editor attach,
94
+ * including a re-attach after recycle.
94
95
  */
95
96
  beginEditSession(): void;
96
97
  /** Leave edit-session mode. The exit recompute is the host's concern. */
@@ -1 +1 @@
1
- {"version":3,"file":"DiffHunksRenderer.d.ts","names":[],"sources":["../../src/renderers/DiffHunksRenderer.ts"],"mappings":";;;;;;UAyIiB,wBAAA,SAAiC,eAAe;EAC/D,gBAAA,GAAmB,oBAAA;AAAA;AAAA,UAGJ,oCAAA,SAA6C,IAAA,CAC5D,2BAAA;EAGA,gBAAA,EAAkB,oBAAA;AAAA;AAAA,UAGH,0BAAA;EACf,IAAA;EACA,QAAA,EAAU,SAAS;EACnB,iBAAA;EACA,iBAAA;AAAA;AAAA,UAGe,wBAAA;EACf,IAAA;EACA,IAAA;EACA,SAAA;AAAA;AAAA,UAGe,cAAA;EACf,cAAA,EAAgB,SAAA;EAChB,gBAAA,GAAmB,UAAA;EACnB,iBAAA,GAAoB,UAAA;AAAA;AAAA,UAUL,mBAAA;EACf,IAAA;EACA,SAAA;EACA,SAAA;EACA,gBAAA;EACA,cAAA;EACA,YAAA,GAAe,gBAAA;EACf,YAAA,GAAe,gBAAgB;AAAA;AAAA,UAGhB,WAAA;EACf,OAAA,EAAS,OAAA;EACT,MAAA,EAAQ,OAAW;AAAA;AAAA,UAGJ,gBAAA;EACf,QAAA,EAAU,WAAA;EACV,QAAA,EAAU,WAAW;AAAA;AAAA,UAGN,2BAAA;EACf,MAAA,GAAS,WAAA;EACT,KAAA,GAAQ,WAAW;AAAA;AAAA,UAGJ,yBAAA;EACf,MAAA,GAAS,gBAAA;EACT,KAAA,GAAQ,gBAAgB;AAAA;AAAA,UAGT,iBAAA;EACf,gBAAA,EAAkB,cAAA;EAClB,iBAAA,EAAmB,cAAA;EACnB,kBAAA,EAAoB,cAAA;EACpB,mBAAA,EAAqB,cAAA;EACrB,kBAAA,EAAoB,cAAA;EACpB,mBAAA,EAAqB,cAAA;EACrB,QAAA,EAAU,QAAA;EACV,GAAA;EACA,OAAA,EAAS,OAAA;EACT,aAAA,EAAe,OAAA;EACf,UAAA;EACA,WAAA;EACA,aAAA;EACA,QAAA;EACA,YAAA;EACA,WAAA;AAAA;AAAA,cAKW,iBAAA;EAuBF,OAAA,EAAS,wBAAA;EAAA,QACR,cAAA;EAAA,QACA,aAAA;EAAA,SAxBD,IAAA;EAAA,QAED,WAAA;EAAA,QACA,IAAA;EAAA,QAEA,aAAA;EAAA,QAEA,mBAAA;EAAA,QACA,mBAAA;EAAA,QAEA,YAAA;EAAA,QACA,WAAA;EAAA,QAQA,iBAAA;EAER,WAAA,CACS,OAAA,GAAS,wBAAA,EACR,cAAA,gCACA,aAAA,GAAgB,iBAAA;EASnB,OAAA;EAOA,OAAA;EAjFP;;;;;AACmB;AAGrB;EAiGS,gBAAA;;EAKA,cAAA;EArGP;;;EA4GO,iBAAA;EA3Gc;AAAA;AAGvB;;;;;;;;EA0HS,wBAAA,IAA4B,OAAA;EAAA,QAqC3B,oBAAA;EAAA,IA0BG,SAAA,IAAa,gBAAA;EAIjB,gBAAA;EAcA,UAAA,CAAW,OAAA,EAAS,wBAAA;EAIpB,YAAA,CAAa,OAAA,EAAS,OAAA,CAAQ,wBAAA;EAI9B,UAAA,CACL,KAAA,UACA,SAAA,EAAW,mBAAA,EACX,kBAAA;EA0BK,eAAA,CAAgB,SAAA,WAAoB,mBAAA;EAIpC,mBAAA,IAAuB,GAAA,SAAY,mBAAA;EA7OlC;EAkPD,mBAAA,CACL,aAAA,EAAe,GAAA,SAAY,mBAAA;EAKtB,kBAAA,CACL,eAAA,EAAiB,kBAAA,CAAmB,WAAA;EAtPvB;;;;;;EA+QR,iBAAA,CACL,UAAA,EAAY,GAAA,SAAY,KAAA,CAAM,gBAAA,IAC9B,SAAA,oBACA,uBAAA;EAAA,QA+HM,mBAAA;EAUD,mBAAA,CAAoB,YAAA,EAAc,iBAAA;EAAA,QAwDjC,0BAAA;EAAA,QAgBA,mBAAA;EAAA,UAOE,wBAAA;IACR;EAAA,GACC,0BAAA,GAA6B,cAAA;EAAA,UAStB,sBAAA;IACR,IAAA;IACA;EAAA,GACC,wBAAA,GAA2B,cAAA;EAAA,QAetB,uBAAA;EAAA,UAKU,6BAAA,IAChB,GAAA,EAAK,mBAAA,KACF,2BAAA;EAAA,UAGa,2BAAA,IAChB,GAAA,EAAK,mBAAA,KACF,yBAAA;EAAA,UAEK,sBAAA,IAA0B,oCAAA;EAiDvB,qBAAA,IAAyB,OAAA,CAAQ,gBAAA;EAYvC,OAAA,CAAQ,IAAA,EAAM,gBAAA;EAAA,QAkCb,sBAAA;EAQD,uBAAA,IAA2B,IAAA,CAChC,eAAA;EAAA,QAeM,gBAAA;EAsCD,UAAA,CACL,IAAA,GAAM,gBAAA,cACN,WAAA,GAAa,WAAA,GACZ,iBAAA;EAuJU,WAAA,CACX,IAAA,EAAM,gBAAA,EACN,WAAA,GAAa,WAAA,GACZ,OAAA,CAAQ,iBAAA;EAAA,UAKD,gBAAA,CACR,KAAA,WACA,UAAA,UACA,gBAAA,GAAmB,mBAAA,GAClB,OAAA;EAAA,QAeW,cAAA;EAAA,QAyBN,yBAAA;EAeD,kBAAA,CACL,IAAA,EAAM,gBAAA,EACN,MAAA,EAAQ,gBAAA,EACR,OAAA,EAAS,iBAAA,EACT,WAAA;EAAA,QAQM,oBAAA;EAAA,QA+BA,4BAAA;EAAA,QAcA,yBAAA;EAaD,gBAAA,CAAiB,KAAA;EAAA,QAIhB,oBAAA;EAAA,QAIA,iBAAA;EAgjBD,aAAA,CACL,IAAA,yCACA,MAAA,EAAQ,iBAAA,GACP,cAAA;EAyBI,aAAA,CACL,MAAA,EAAQ,iBAAA,EACR,QAAA,GAAU,cAAA,KACT,OAAA;EAkDI,cAAA,CACL,MAAA,EAAQ,iBAAA,EACR,YAAA,GAAc,cAAA;EAKT,iBAAA,CACL,QAAA,EAAU,cAAA,IACV,UAAA;EAAA,QAqBM,wBAAA;EAAA,QAiEA,cAAA;EAAA,QA+DA,YAAA;AAAA"}
1
+ {"version":3,"file":"DiffHunksRenderer.d.ts","names":[],"sources":["../../src/renderers/DiffHunksRenderer.ts"],"mappings":";;;;;;UAyIiB,wBAAA,SAAiC,eAAe;EAC/D,gBAAA,GAAmB,oBAAA;AAAA;AAAA,UAGJ,oCAAA,SAA6C,IAAA,CAC5D,2BAAA;EAGA,gBAAA,EAAkB,oBAAA;AAAA;AAAA,UAGH,0BAAA;EACf,IAAA;EACA,QAAA,EAAU,SAAS;EACnB,iBAAA;EACA,iBAAA;AAAA;AAAA,UAGe,wBAAA;EACf,IAAA;EACA,IAAA;EACA,SAAA;AAAA;AAAA,UAGe,cAAA;EACf,cAAA,EAAgB,SAAA;EAChB,gBAAA,GAAmB,UAAA;EACnB,iBAAA,GAAoB,UAAA;AAAA;AAAA,UAUL,mBAAA;EACf,IAAA;EACA,SAAA;EACA,SAAA;EACA,gBAAA;EACA,cAAA;EACA,YAAA,GAAe,gBAAA;EACf,YAAA,GAAe,gBAAgB;AAAA;AAAA,UAGhB,WAAA;EACf,OAAA,EAAS,OAAA;EACT,MAAA,EAAQ,OAAW;AAAA;AAAA,UAGJ,gBAAA;EACf,QAAA,EAAU,WAAA;EACV,QAAA,EAAU,WAAW;AAAA;AAAA,UAGN,2BAAA;EACf,MAAA,GAAS,WAAA;EACT,KAAA,GAAQ,WAAW;AAAA;AAAA,UAGJ,yBAAA;EACf,MAAA,GAAS,gBAAA;EACT,KAAA,GAAQ,gBAAgB;AAAA;AAAA,UAGT,iBAAA;EACf,gBAAA,EAAkB,cAAA;EAClB,iBAAA,EAAmB,cAAA;EACnB,kBAAA,EAAoB,cAAA;EACpB,mBAAA,EAAqB,cAAA;EACrB,kBAAA,EAAoB,cAAA;EACpB,mBAAA,EAAqB,cAAA;EACrB,QAAA,EAAU,QAAA;EACV,GAAA;EACA,OAAA,EAAS,OAAA;EACT,aAAA,EAAe,OAAA;EACf,UAAA;EACA,WAAA;EACA,aAAA;EACA,QAAA;EACA,YAAA;EACA,WAAA;AAAA;AAAA,cAKW,iBAAA;EAuBF,OAAA,EAAS,wBAAA;EAAA,QACR,cAAA;EAAA,QACA,aAAA;EAAA,SAxBD,IAAA;EAAA,QAED,WAAA;EAAA,QACA,IAAA;EAAA,QAEA,aAAA;EAAA,QAEA,mBAAA;EAAA,QACA,mBAAA;EAAA,QAEA,YAAA;EAAA,QACA,WAAA;EAAA,QAQA,iBAAA;EAER,WAAA,CACS,OAAA,GAAS,wBAAA,EACR,cAAA,gCACA,aAAA,GAAgB,iBAAA;EASnB,OAAA;EAOA,OAAA;EAjFP;;;;;AACmB;AAGrB;;EAkGS,gBAAA;EAhGc;EA8Gd,cAAA;EA/GG;;;EAsHH,iBAAA;EArHc;AAGvB;;;;;;;;;EAoIS,wBAAA,IAA4B,OAAA;EAAA,QAqC3B,oBAAA;EAAA,IA0BG,SAAA,IAAa,gBAAA;EAIjB,gBAAA;EAcA,UAAA,CAAW,OAAA,EAAS,wBAAA;EAIpB,YAAA,CAAa,OAAA,EAAS,OAAA,CAAQ,wBAAA;EAI9B,UAAA,CACL,KAAA,UACA,SAAA,EAAW,mBAAA,EACX,kBAAA;EA0BK,eAAA,CAAgB,SAAA,WAAoB,mBAAA;EAIpC,mBAAA,IAAuB,GAAA,SAAY,mBAAA;EAvPlB;EA4PjB,mBAAA,CACL,aAAA,EAAe,GAAA,SAAY,mBAAA;EAKtB,kBAAA,CACL,eAAA,EAAiB,kBAAA,CAAmB,WAAA;EAhQN;;;;;;EAyRzB,iBAAA,CACL,UAAA,EAAY,GAAA,SAAY,KAAA,CAAM,gBAAA,IAC9B,SAAA,oBACA,uBAAA;EAAA,QA+HM,mBAAA;EAUD,mBAAA,CAAoB,YAAA,EAAc,iBAAA;EAAA,QAwDjC,0BAAA;EAAA,QAgBA,mBAAA;EAAA,UAOE,wBAAA;IACR;EAAA,GACC,0BAAA,GAA6B,cAAA;EAAA,UAStB,sBAAA;IACR,IAAA;IACA;EAAA,GACC,wBAAA,GAA2B,cAAA;EAAA,QAetB,uBAAA;EAAA,UAKU,6BAAA,IAChB,GAAA,EAAK,mBAAA,KACF,2BAAA;EAAA,UAGa,2BAAA,IAChB,GAAA,EAAK,mBAAA,KACF,yBAAA;EAAA,UAEK,sBAAA,IAA0B,oCAAA;EAiDvB,qBAAA,IAAyB,OAAA,CAAQ,gBAAA;EAYvC,OAAA,CAAQ,IAAA,EAAM,gBAAA;EAAA,QAkCb,sBAAA;EAQD,uBAAA,IAA2B,IAAA,CAChC,eAAA;EAAA,QAeM,gBAAA;EAsCD,UAAA,CACL,IAAA,GAAM,gBAAA,cACN,WAAA,GAAa,WAAA,GACZ,iBAAA;EAuJU,WAAA,CACX,IAAA,EAAM,gBAAA,EACN,WAAA,GAAa,WAAA,GACZ,OAAA,CAAQ,iBAAA;EAAA,UAKD,gBAAA,CACR,KAAA,WACA,UAAA,UACA,gBAAA,GAAmB,mBAAA,GAClB,OAAA;EAAA,QAeW,cAAA;EAAA,QAyBN,yBAAA;EA2CD,kBAAA,CACL,IAAA,EAAM,gBAAA,EACN,MAAA,EAAQ,gBAAA,EACR,OAAA,EAAS,iBAAA,EACT,WAAA;EAAA,QAQM,oBAAA;EAAA,QA+BA,4BAAA;EAAA,QAcA,yBAAA;EAaD,gBAAA,CAAiB,KAAA;EAAA,QAIhB,oBAAA;EAAA,QAIA,iBAAA;EAgjBD,aAAA,CACL,IAAA,yCACA,MAAA,EAAQ,iBAAA,GACP,cAAA;EAyBI,aAAA,CACL,MAAA,EAAQ,iBAAA,EACR,QAAA,GAAU,cAAA,KACT,OAAA;EAkDI,cAAA,CACL,MAAA,EAAQ,iBAAA,EACR,YAAA,GAAc,cAAA;EAKT,iBAAA,CACL,QAAA,EAAU,cAAA,IACV,UAAA;EAAA,QAqBM,wBAAA;EAAA,QAiEA,cAAA;EAAA,QA+DA,YAAA;AAAA"}
@@ -69,11 +69,18 @@ var DiffHunksRenderer = class {
69
69
  * Enter edit-session mode: hunk updates preserve the current region
70
70
  * skeleton instead of recomputing hunks, and rendering happens locally
71
71
  * with the token transformer forced on (worker-pool requests/results are
72
- * suspended for this renderer). Called on every editor attach, including
73
- * a re-attach after recycle.
72
+ * suspended for this renderer). An empty additions document gets one row so
73
+ * the editor has a line for its caret. Called on every editor attach,
74
+ * including a re-attach after recycle.
74
75
  */
75
76
  beginEditSession() {
76
77
  this.editSessionActive = true;
78
+ const diff = this.diffCache;
79
+ if (diff != null && !diff.isPartial && diff.additionLines.length === 0) {
80
+ Object.assign(diff, recomputeEmptyDocumentDiff(diff, this.options.parseDiffOptions));
81
+ this.markEditSessionPass(diff);
82
+ this.clearRenderCache();
83
+ }
77
84
  }
78
85
  /** Leave edit-session mode. The exit recompute is the host's concern. */
79
86
  endEditSession() {
@@ -269,7 +276,7 @@ var DiffHunksRenderer = class {
269
276
  result.code.additionLines = realignAdditionHastLines(previousAdditionLines, diff.additionLines, result.code.additionLines, textDocument);
270
277
  if (diff.additionLines.length <= 1 && diff.additionLines.join("") === "") {
271
278
  Object.assign(diff, recomputeEmptyDocumentDiff(diff, this.options.parseDiffOptions));
272
- result.code.additionLines[0] = createPlainAdditionLineElement(0, textDocument);
279
+ result.code.additionLines[0] = createPlainAdditionLineElement(0, textDocument.getLineText(0));
273
280
  this.markEditSessionPass(diff);
274
281
  } else if (this.editSessionActive) this.applySessionDocumentChange(diff);
275
282
  else Object.assign(diff, recomputeDiffHunksForEdit(diff, this.options.parseDiffOptions));
@@ -489,12 +496,29 @@ var DiffHunksRenderer = class {
489
496
  renderDiffWithHighlighter(diff, highlighter, forcePlainText = false) {
490
497
  const { options } = this.getRenderOptions(diff);
491
498
  const { collapsedContextThreshold } = this.getOptionsWithDefaults();
492
- return {
493
- result: renderDiffWithHighlighter(diff, highlighter, options, {
494
- forcePlainText,
499
+ const result = renderDiffWithHighlighter(diff, highlighter, options, {
500
+ forcePlainText,
501
+ expandedHunks: forcePlainText ? true : void 0,
502
+ collapsedContextThreshold
503
+ });
504
+ if (this.editSessionActive && diff.additionLines.length === 1 && diff.additionLines[0] === "" && result.code.additionLines[0] == null) {
505
+ let fallbackLine;
506
+ iterateOverDiff({
507
+ diff,
508
+ diffStyle: "both",
495
509
  expandedHunks: forcePlainText ? true : void 0,
496
- collapsedContextThreshold
497
- }),
510
+ collapsedContextThreshold,
511
+ callback: ({ additionLine }) => {
512
+ if (additionLine?.lineIndex !== 0) return;
513
+ fallbackLine = additionLine;
514
+ return true;
515
+ }
516
+ });
517
+ if (fallbackLine == null) throw new Error("DiffHunksRenderer: missing empty addition line");
518
+ result.code.additionLines[0] = createPlainAdditionLineElement(0, "", fallbackLine.unifiedLineIndex, fallbackLine.splitLineIndex);
519
+ }
520
+ return {
521
+ result,
498
522
  options
499
523
  };
500
524
  }
@@ -1120,16 +1144,16 @@ function realignAdditionHastLines(previousLines, nextLines, hastLines, textDocum
1120
1144
  for (let offset = 0; offset < suffix; offset++) realigned[nextContentLength - 1 - offset] = hastLines[previousContentLength - 1 - offset];
1121
1145
  if (previousContentLength < previousLines.length && nextContentLength < nextLines.length) realigned[nextLines.length - 1] = hastLines[previousLines.length - 1];
1122
1146
  for (let index = previousLines.length; index < nextLines.length; index++) realigned[index] ??= hastLines[index];
1123
- for (let index = prefix; index < nextLines.length; index++) realigned[index] ??= createPlainAdditionLineElement(index, textDocument);
1147
+ for (let index = prefix; index < nextLines.length; index++) realigned[index] ??= createPlainAdditionLineElement(index, textDocument.getLineText(index));
1124
1148
  return realigned;
1125
1149
  }
1126
- function createPlainAdditionLineElement(lineIndex, textDocument) {
1150
+ function createPlainAdditionLineElement(lineIndex, lineText, unifiedLineIndex = lineIndex, splitLineIndex = lineIndex) {
1127
1151
  return {
1128
1152
  type: "element",
1129
1153
  tagName: "div",
1130
1154
  properties: {
1131
1155
  "data-line": lineIndex + 1,
1132
- "data-line-index": `${lineIndex},${lineIndex}`,
1156
+ "data-line-index": `${unifiedLineIndex},${splitLineIndex}`,
1133
1157
  "data-line-type": "context"
1134
1158
  },
1135
1159
  children: [{
@@ -1138,7 +1162,7 @@ function createPlainAdditionLineElement(lineIndex, textDocument) {
1138
1162
  properties: { "data-char": 0 },
1139
1163
  children: [{
1140
1164
  type: "text",
1141
- value: textDocument.getLineText(lineIndex)
1165
+ value: lineText
1142
1166
  }]
1143
1167
  }]
1144
1168
  };