@pierre/diffs 1.3.0-beta.5 → 1.3.0-beta.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -9
- package/dist/components/CodeView.d.ts +13 -11
- package/dist/components/CodeView.d.ts.map +1 -1
- package/dist/components/CodeView.js +53 -14
- package/dist/components/CodeView.js.map +1 -1
- package/dist/components/File.d.ts +4 -5
- package/dist/components/File.d.ts.map +1 -1
- package/dist/components/File.js +37 -19
- package/dist/components/File.js.map +1 -1
- package/dist/components/FileDiff.d.ts +49 -36
- package/dist/components/FileDiff.d.ts.map +1 -1
- package/dist/components/FileDiff.js +173 -75
- package/dist/components/FileDiff.js.map +1 -1
- package/dist/components/FileStream.d.ts +0 -1
- package/dist/components/FileStream.d.ts.map +1 -1
- package/dist/components/FileStream.js +4 -4
- package/dist/components/FileStream.js.map +1 -1
- package/dist/components/UnresolvedFile.d.ts +3 -3
- package/dist/components/UnresolvedFile.d.ts.map +1 -1
- package/dist/components/UnresolvedFile.js +7 -5
- package/dist/components/UnresolvedFile.js.map +1 -1
- package/dist/components/VirtualizedFile.d.ts +0 -1
- package/dist/components/VirtualizedFile.d.ts.map +1 -1
- package/dist/components/VirtualizedFile.js +22 -25
- package/dist/components/VirtualizedFile.js.map +1 -1
- package/dist/components/VirtualizedFileDiff.d.ts +12 -7
- package/dist/components/VirtualizedFileDiff.d.ts.map +1 -1
- package/dist/components/VirtualizedFileDiff.js +192 -64
- package/dist/components/VirtualizedFileDiff.js.map +1 -1
- package/dist/components/Virtualizer.d.ts +1 -1
- package/dist/components/Virtualizer.d.ts.map +1 -1
- package/dist/components/Virtualizer.js +23 -24
- package/dist/components/Virtualizer.js.map +1 -1
- package/dist/components/VirtulizerDevelopment.d.ts.map +1 -1
- package/dist/components/web-components.d.ts.map +1 -1
- package/dist/components/web-components.js +2 -3
- package/dist/components/web-components.js.map +1 -1
- package/dist/constants.d.ts +3 -2
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +3 -2
- package/dist/constants.js.map +1 -1
- package/dist/editor/command.d.ts +2 -1
- package/dist/editor/command.d.ts.map +1 -1
- package/dist/editor/command.js +7 -3
- package/dist/editor/command.js.map +1 -1
- package/dist/editor/editStack.d.ts +7 -1
- package/dist/editor/editStack.d.ts.map +1 -1
- package/dist/editor/editStack.js +3 -3
- package/dist/editor/editStack.js.map +1 -1
- package/dist/editor/editor.d.ts +28 -4
- package/dist/editor/editor.d.ts.map +1 -1
- package/dist/editor/editor.js +669 -313
- package/dist/editor/editor.js.map +1 -1
- package/dist/editor/editor2.js +3 -3
- package/dist/editor/editor2.js.map +1 -1
- package/dist/editor/index.js +1 -2
- package/dist/editor/lineAnnotations.d.ts.map +1 -1
- package/dist/editor/lineAnnotations.js +2 -3
- package/dist/editor/lineAnnotations.js.map +1 -1
- package/dist/editor/marker.d.ts +2 -1
- package/dist/editor/marker.d.ts.map +1 -1
- package/dist/editor/marker.js +28 -11
- package/dist/editor/marker.js.map +1 -1
- package/dist/editor/pieceTable.d.ts +4 -2
- package/dist/editor/pieceTable.d.ts.map +1 -1
- package/dist/editor/pieceTable.js +138 -128
- package/dist/editor/pieceTable.js.map +1 -1
- package/dist/editor/platform.d.ts +8 -1
- package/dist/editor/platform.d.ts.map +1 -1
- package/dist/editor/platform.js +16 -5
- package/dist/editor/platform.js.map +1 -1
- package/dist/editor/searchPanel.d.ts +1 -0
- package/dist/editor/searchPanel.d.ts.map +1 -1
- package/dist/editor/searchPanel.js +75 -62
- package/dist/editor/searchPanel.js.map +1 -1
- package/dist/editor/selection.d.ts +42 -5
- package/dist/editor/selection.d.ts.map +1 -1
- package/dist/editor/selection.js +504 -114
- package/dist/editor/selection.js.map +1 -1
- package/dist/editor/selectionAction.d.ts +4 -5
- package/dist/editor/selectionAction.d.ts.map +1 -1
- package/dist/editor/selectionAction.js +14 -64
- package/dist/editor/selectionAction.js.map +1 -1
- package/dist/editor/sprite.d.ts +2 -2
- package/dist/editor/sprite.d.ts.map +1 -1
- package/dist/editor/sprite.js +7 -14
- package/dist/editor/sprite.js.map +1 -1
- package/dist/editor/textDocument.d.ts +5 -4
- package/dist/editor/textDocument.d.ts.map +1 -1
- package/dist/editor/textDocument.js +26 -15
- package/dist/editor/textDocument.js.map +1 -1
- package/dist/editor/textMeasure.d.ts +36 -3
- package/dist/editor/textMeasure.d.ts.map +1 -1
- package/dist/editor/textMeasure.js +104 -17
- package/dist/editor/textMeasure.js.map +1 -1
- package/dist/editor/tokenzier.d.ts +3 -0
- package/dist/editor/tokenzier.d.ts.map +1 -1
- package/dist/editor/tokenzier.js +27 -16
- package/dist/editor/tokenzier.js.map +1 -1
- package/dist/editor/utils.d.ts +4 -1
- package/dist/editor/utils.d.ts.map +1 -1
- package/dist/editor/utils.js +19 -3
- package/dist/editor/utils.js.map +1 -1
- package/dist/highlighter/languages/areLanguagesAttached.d.ts.map +1 -1
- package/dist/highlighter/languages/areLanguagesAttached.js +1 -2
- package/dist/highlighter/languages/areLanguagesAttached.js.map +1 -1
- package/dist/highlighter/languages/attachResolvedLanguages.d.ts +0 -2
- package/dist/highlighter/languages/attachResolvedLanguages.d.ts.map +1 -1
- package/dist/highlighter/languages/attachResolvedLanguages.js +1 -2
- package/dist/highlighter/languages/attachResolvedLanguages.js.map +1 -1
- package/dist/highlighter/languages/cleanUpResolvedLanguages.d.ts.map +1 -1
- package/dist/highlighter/languages/cleanUpResolvedLanguages.js +1 -2
- package/dist/highlighter/languages/cleanUpResolvedLanguages.js.map +1 -1
- package/dist/highlighter/languages/constants.d.ts +0 -1
- package/dist/highlighter/languages/constants.d.ts.map +1 -1
- package/dist/highlighter/languages/constants.js +1 -1
- package/dist/highlighter/languages/constants.js.map +1 -1
- package/dist/highlighter/languages/getResolvedLanguages.d.ts +0 -2
- package/dist/highlighter/languages/getResolvedLanguages.d.ts.map +1 -1
- package/dist/highlighter/languages/getResolvedLanguages.js +1 -2
- package/dist/highlighter/languages/getResolvedLanguages.js.map +1 -1
- package/dist/highlighter/languages/getResolvedOrResolveLanguage.d.ts +0 -2
- package/dist/highlighter/languages/getResolvedOrResolveLanguage.d.ts.map +1 -1
- package/dist/highlighter/languages/getResolvedOrResolveLanguage.js +1 -2
- package/dist/highlighter/languages/getResolvedOrResolveLanguage.js.map +1 -1
- package/dist/highlighter/languages/hasResolvedLanguages.d.ts.map +1 -1
- package/dist/highlighter/languages/hasResolvedLanguages.js +1 -2
- package/dist/highlighter/languages/hasResolvedLanguages.js.map +1 -1
- package/dist/highlighter/languages/registerCustomLanguage.d.ts +0 -1
- package/dist/highlighter/languages/registerCustomLanguage.d.ts.map +1 -1
- package/dist/highlighter/languages/registerCustomLanguage.js +1 -2
- package/dist/highlighter/languages/registerCustomLanguage.js.map +1 -1
- package/dist/highlighter/languages/resolveLanguage.d.ts +0 -2
- package/dist/highlighter/languages/resolveLanguage.d.ts.map +1 -1
- package/dist/highlighter/languages/resolveLanguage.js +4 -5
- package/dist/highlighter/languages/resolveLanguage.js.map +1 -1
- package/dist/highlighter/languages/resolveLanguages.d.ts +0 -2
- package/dist/highlighter/languages/resolveLanguages.d.ts.map +1 -1
- package/dist/highlighter/languages/resolveLanguages.js +1 -2
- package/dist/highlighter/languages/resolveLanguages.js.map +1 -1
- package/dist/highlighter/shared_highlighter.d.ts.map +1 -1
- package/dist/highlighter/shared_highlighter.js +3 -4
- package/dist/highlighter/shared_highlighter.js.map +1 -1
- package/dist/highlighter/themes/areThemesAttached.d.ts.map +1 -1
- package/dist/highlighter/themes/areThemesAttached.js +1 -2
- package/dist/highlighter/themes/areThemesAttached.js.map +1 -1
- package/dist/highlighter/themes/attachResolvedThemes.d.ts.map +1 -1
- package/dist/highlighter/themes/attachResolvedThemes.js +1 -2
- package/dist/highlighter/themes/attachResolvedThemes.js.map +1 -1
- package/dist/highlighter/themes/cleanUpResolvedThemes.d.ts.map +1 -1
- package/dist/highlighter/themes/cleanUpResolvedThemes.js +1 -2
- package/dist/highlighter/themes/cleanUpResolvedThemes.js.map +1 -1
- package/dist/highlighter/themes/constants.d.ts.map +1 -1
- package/dist/highlighter/themes/constants.js +1 -1
- package/dist/highlighter/themes/constants.js.map +1 -1
- package/dist/highlighter/themes/getResolvedOrResolveTheme.d.ts.map +1 -1
- package/dist/highlighter/themes/getResolvedOrResolveTheme.js +1 -2
- package/dist/highlighter/themes/getResolvedOrResolveTheme.js.map +1 -1
- package/dist/highlighter/themes/getResolvedThemes.d.ts.map +1 -1
- package/dist/highlighter/themes/getResolvedThemes.js +1 -2
- package/dist/highlighter/themes/getResolvedThemes.js.map +1 -1
- package/dist/highlighter/themes/hasResolvedThemes.d.ts.map +1 -1
- package/dist/highlighter/themes/hasResolvedThemes.js +1 -2
- package/dist/highlighter/themes/hasResolvedThemes.js.map +1 -1
- package/dist/highlighter/themes/registerCustomCSSVariableTheme.d.ts.map +1 -1
- package/dist/highlighter/themes/registerCustomCSSVariableTheme.js +1 -2
- package/dist/highlighter/themes/registerCustomCSSVariableTheme.js.map +1 -1
- package/dist/highlighter/themes/registerCustomTheme.d.ts.map +1 -1
- package/dist/highlighter/themes/registerCustomTheme.js +1 -2
- package/dist/highlighter/themes/registerCustomTheme.js.map +1 -1
- package/dist/highlighter/themes/resolveTheme.d.ts.map +1 -1
- package/dist/highlighter/themes/resolveTheme.js +1 -2
- package/dist/highlighter/themes/resolveTheme.js.map +1 -1
- package/dist/highlighter/themes/resolveThemes.d.ts.map +1 -1
- package/dist/highlighter/themes/resolveThemes.js +1 -2
- package/dist/highlighter/themes/resolveThemes.js.map +1 -1
- package/dist/highlighter/themes/themeResolution.d.ts.map +1 -1
- package/dist/highlighter/themes/themeResolution.js +1 -2
- package/dist/highlighter/themes/themeResolution.js.map +1 -1
- package/dist/highlighter/themes/themeResolver.d.ts +2 -2
- package/dist/highlighter/themes/themeResolver.d.ts.map +1 -1
- package/dist/highlighter/themes/themeResolver.js +1 -2
- package/dist/highlighter/themes/themeResolver.js.map +1 -1
- package/dist/index.d.ts +12 -10
- package/dist/index.js +4 -3
- package/dist/managers/InteractionManager.d.ts +7 -0
- package/dist/managers/InteractionManager.d.ts.map +1 -1
- package/dist/managers/InteractionManager.js +25 -4
- package/dist/managers/InteractionManager.js.map +1 -1
- package/dist/managers/ResizeManager.d.ts.map +1 -1
- package/dist/managers/ResizeManager.js +1 -1
- package/dist/managers/ResizeManager.js.map +1 -1
- package/dist/managers/ScrollSyncManager.d.ts.map +1 -1
- package/dist/managers/ScrollSyncManager.js +1 -1
- package/dist/managers/ScrollSyncManager.js.map +1 -1
- package/dist/managers/UniversalRenderingManager.d.ts.map +1 -1
- package/dist/managers/UniversalRenderingManager.js +2 -2
- package/dist/managers/UniversalRenderingManager.js.map +1 -1
- package/dist/node_modules/.pnpm/@types_hast@3.0.4/node_modules/@types/hast/index.d.ts +228 -0
- package/dist/node_modules/.pnpm/@types_hast@3.0.4/node_modules/@types/hast/index.d.ts.map +1 -0
- package/dist/node_modules/.pnpm/@types_unist@3.0.3/node_modules/@types/unist/index.d.ts +84 -0
- package/dist/node_modules/.pnpm/@types_unist@3.0.3/node_modules/@types/unist/index.d.ts.map +1 -0
- package/dist/react/CodeView.d.ts +1 -1
- package/dist/react/CodeView.d.ts.map +1 -1
- package/dist/react/CodeView.js +17 -16
- package/dist/react/CodeView.js.map +1 -1
- package/dist/react/EditorContext.d.ts +0 -1
- package/dist/react/EditorContext.d.ts.map +1 -1
- package/dist/react/EditorContext.js +2 -5
- package/dist/react/EditorContext.js.map +1 -1
- package/dist/react/File.d.ts +1 -0
- package/dist/react/File.d.ts.map +1 -1
- package/dist/react/File.js +4 -6
- package/dist/react/File.js.map +1 -1
- package/dist/react/FileDiff.d.ts +1 -0
- package/dist/react/FileDiff.d.ts.map +1 -1
- package/dist/react/FileDiff.js +4 -6
- package/dist/react/FileDiff.js.map +1 -1
- package/dist/react/MultiFileDiff.d.ts +4 -4
- package/dist/react/MultiFileDiff.d.ts.map +1 -1
- package/dist/react/MultiFileDiff.js +4 -6
- package/dist/react/MultiFileDiff.js.map +1 -1
- package/dist/react/PatchDiff.d.ts +1 -0
- package/dist/react/PatchDiff.d.ts.map +1 -1
- package/dist/react/PatchDiff.js +4 -6
- package/dist/react/PatchDiff.js.map +1 -1
- package/dist/react/UnresolvedFile.d.ts +2 -1
- package/dist/react/UnresolvedFile.d.ts.map +1 -1
- package/dist/react/UnresolvedFile.js +4 -6
- package/dist/react/UnresolvedFile.js.map +1 -1
- package/dist/react/Virtualizer.d.ts.map +1 -1
- package/dist/react/Virtualizer.js +2 -5
- package/dist/react/Virtualizer.js.map +1 -1
- package/dist/react/WorkerPoolContext.d.ts +0 -1
- package/dist/react/WorkerPoolContext.d.ts.map +1 -1
- package/dist/react/WorkerPoolContext.js +2 -5
- package/dist/react/WorkerPoolContext.js.map +1 -1
- package/dist/react/constants.d.ts.map +1 -1
- package/dist/react/constants.js +1 -1
- package/dist/react/constants.js.map +1 -1
- package/dist/react/index.d.ts +2 -2
- package/dist/react/index.js +1 -2
- package/dist/react/jsx.d.ts +0 -2
- package/dist/react/jsx.d.ts.map +1 -1
- package/dist/react/types.d.ts +2 -0
- package/dist/react/types.d.ts.map +1 -1
- package/dist/react/utils/renderDiffChildren.d.ts +2 -0
- package/dist/react/utils/renderDiffChildren.d.ts.map +1 -1
- package/dist/react/utils/renderDiffChildren.js +18 -11
- package/dist/react/utils/renderDiffChildren.js.map +1 -1
- package/dist/react/utils/renderFileChildren.d.ts +2 -0
- package/dist/react/utils/renderFileChildren.d.ts.map +1 -1
- package/dist/react/utils/renderFileChildren.js +18 -11
- package/dist/react/utils/renderFileChildren.js.map +1 -1
- package/dist/react/utils/templateRender.d.ts.map +1 -1
- package/dist/react/utils/templateRender.js +1 -2
- package/dist/react/utils/templateRender.js.map +1 -1
- package/dist/react/utils/useFileDiffInstance.d.ts.map +1 -1
- package/dist/react/utils/useFileDiffInstance.js +15 -18
- package/dist/react/utils/useFileDiffInstance.js.map +1 -1
- package/dist/react/utils/useFileInstance.d.ts.map +1 -1
- package/dist/react/utils/useFileInstance.js +1 -2
- package/dist/react/utils/useFileInstance.js.map +1 -1
- package/dist/react/utils/useStableCallback.d.ts.map +1 -1
- package/dist/react/utils/useStableCallback.js +1 -2
- package/dist/react/utils/useStableCallback.js.map +1 -1
- package/dist/react/utils/useUnresolvedFileInstance.d.ts.map +1 -1
- package/dist/react/utils/useUnresolvedFileInstance.js +10 -11
- package/dist/react/utils/useUnresolvedFileInstance.js.map +1 -1
- package/dist/renderers/DiffHunksRenderer.d.ts +2 -3
- package/dist/renderers/DiffHunksRenderer.d.ts.map +1 -1
- package/dist/renderers/DiffHunksRenderer.js +52 -33
- package/dist/renderers/DiffHunksRenderer.js.map +1 -1
- package/dist/renderers/FileRenderer.d.ts +1 -3
- package/dist/renderers/FileRenderer.d.ts.map +1 -1
- package/dist/renderers/FileRenderer.js +14 -11
- package/dist/renderers/FileRenderer.js.map +1 -1
- package/dist/renderers/UnresolvedFileHunksRenderer.d.ts +1 -2
- package/dist/renderers/UnresolvedFileHunksRenderer.d.ts.map +1 -1
- package/dist/renderers/UnresolvedFileHunksRenderer.js +1 -2
- package/dist/renderers/UnresolvedFileHunksRenderer.js.map +1 -1
- package/dist/shiki-stream/index.js +1 -2
- package/dist/shiki-stream/stream.d.ts +0 -1
- package/dist/shiki-stream/stream.d.ts.map +1 -1
- package/dist/shiki-stream/stream.js +1 -2
- package/dist/shiki-stream/stream.js.map +1 -1
- package/dist/shiki-stream/tokenizer.d.ts.map +1 -1
- package/dist/shiki-stream/tokenizer.js +1 -1
- package/dist/shiki-stream/tokenizer.js.map +1 -1
- package/dist/shiki-stream/types.d.ts +0 -1
- package/dist/shiki-stream/types.d.ts.map +1 -1
- package/dist/sprite.d.ts.map +1 -1
- package/dist/sprite.js +1 -1
- package/dist/ssr/FileDiffReact.d.ts.map +1 -1
- package/dist/ssr/FileDiffReact.js +5 -8
- package/dist/ssr/FileDiffReact.js.map +1 -1
- package/dist/ssr/index.d.ts +2 -2
- package/dist/ssr/index.js +1 -2
- package/dist/ssr/preloadDiffs.d.ts +12 -11
- package/dist/ssr/preloadDiffs.d.ts.map +1 -1
- package/dist/ssr/preloadDiffs.js +15 -8
- package/dist/ssr/preloadDiffs.js.map +1 -1
- package/dist/ssr/preloadFile.d.ts.map +1 -1
- package/dist/ssr/preloadFile.js +1 -2
- package/dist/ssr/preloadFile.js.map +1 -1
- package/dist/ssr/preloadPatchFile.d.ts.map +1 -1
- package/dist/ssr/preloadPatchFile.js +2 -3
- package/dist/ssr/preloadPatchFile.js.map +1 -1
- package/dist/ssr/renderHTML.d.ts +1 -1
- package/dist/ssr/renderHTML.d.ts.map +1 -1
- package/dist/ssr/renderHTML.js +1 -2
- package/dist/ssr/renderHTML.js.map +1 -1
- package/dist/string-import.d.ts +4 -0
- package/dist/string-import.d.ts.map +1 -1
- package/dist/style.js +3 -3
- package/dist/style.js.map +1 -1
- package/dist/types.d.ts +67 -7
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/areDiffLineAnnotationsEqual.d.ts.map +1 -1
- package/dist/utils/areDiffLineAnnotationsEqual.js +1 -1
- package/dist/utils/areDiffLineAnnotationsEqual.js.map +1 -1
- package/dist/utils/areDiffRenderOptionsEqual.d.ts.map +1 -1
- package/dist/utils/areDiffRenderOptionsEqual.js +1 -2
- package/dist/utils/areDiffRenderOptionsEqual.js.map +1 -1
- package/dist/utils/areDiffTargetsEqual.d.ts.map +1 -1
- package/dist/utils/areDiffTargetsEqual.js +1 -1
- package/dist/utils/areDiffTargetsEqual.js.map +1 -1
- package/dist/utils/areFileRenderOptionsEqual.d.ts.map +1 -1
- package/dist/utils/areFileRenderOptionsEqual.js +1 -2
- package/dist/utils/areFileRenderOptionsEqual.js.map +1 -1
- package/dist/utils/areFilesEqual.d.ts.map +1 -1
- package/dist/utils/areFilesEqual.js +1 -1
- package/dist/utils/areFilesEqual.js.map +1 -1
- package/dist/utils/areHunkDataEqual.d.ts.map +1 -1
- package/dist/utils/areHunkDataEqual.js +2 -2
- package/dist/utils/areHunkDataEqual.js.map +1 -1
- package/dist/utils/areLineAnnotationsEqual.d.ts.map +1 -1
- package/dist/utils/areLineAnnotationsEqual.js +1 -1
- package/dist/utils/areLineAnnotationsEqual.js.map +1 -1
- package/dist/utils/areManagedSnapshotsEqual.d.ts.map +1 -1
- package/dist/utils/areManagedSnapshotsEqual.js +1 -1
- package/dist/utils/areManagedSnapshotsEqual.js.map +1 -1
- package/dist/utils/areMergeConflictActionsEqual.d.ts.map +1 -1
- package/dist/utils/areMergeConflictActionsEqual.js +1 -1
- package/dist/utils/areMergeConflictActionsEqual.js.map +1 -1
- package/dist/utils/areObjectsEqual.d.ts.map +1 -1
- package/dist/utils/areObjectsEqual.js +1 -1
- package/dist/utils/areObjectsEqual.js.map +1 -1
- package/dist/utils/areOptionsEqual.d.ts +0 -2
- package/dist/utils/areOptionsEqual.d.ts.map +1 -1
- package/dist/utils/areOptionsEqual.js +1 -2
- package/dist/utils/areOptionsEqual.js.map +1 -1
- package/dist/utils/arePrePropertiesEqual.d.ts.map +1 -1
- package/dist/utils/arePrePropertiesEqual.js +1 -1
- package/dist/utils/arePrePropertiesEqual.js.map +1 -1
- package/dist/utils/areRenderRangesEqual.d.ts.map +1 -1
- package/dist/utils/areRenderRangesEqual.js +1 -1
- package/dist/utils/areRenderRangesEqual.js.map +1 -1
- package/dist/utils/areSelectionPointsEqual.d.ts.map +1 -1
- package/dist/utils/areSelectionPointsEqual.js +1 -1
- package/dist/utils/areSelectionPointsEqual.js.map +1 -1
- package/dist/utils/areSelectionsEqual.d.ts.map +1 -1
- package/dist/utils/areSelectionsEqual.js +1 -1
- package/dist/utils/areSelectionsEqual.js.map +1 -1
- package/dist/utils/areThemesEqual.d.ts.map +1 -1
- package/dist/utils/areThemesEqual.js +1 -1
- package/dist/utils/areThemesEqual.js.map +1 -1
- package/dist/utils/areVirtualWindowSpecsEqual.d.ts.map +1 -1
- package/dist/utils/areVirtualWindowSpecsEqual.js +1 -1
- package/dist/utils/areVirtualWindowSpecsEqual.js.map +1 -1
- package/dist/utils/areWorkerStatsEqual.d.ts +0 -2
- package/dist/utils/areWorkerStatsEqual.d.ts.map +1 -1
- package/dist/utils/areWorkerStatsEqual.js +1 -1
- package/dist/utils/areWorkerStatsEqual.js.map +1 -1
- package/dist/utils/awaitWithTimeout.d.ts +5 -0
- package/dist/utils/awaitWithTimeout.d.ts.map +1 -0
- package/dist/utils/awaitWithTimeout.js +15 -0
- package/dist/utils/awaitWithTimeout.js.map +1 -0
- package/dist/utils/cleanLastNewline.d.ts.map +1 -1
- package/dist/utils/cleanLastNewline.js +1 -1
- package/dist/utils/cleanLastNewline.js.map +1 -1
- package/dist/utils/cloneFileDiffMetadata.d.ts +7 -0
- package/dist/utils/cloneFileDiffMetadata.d.ts.map +1 -0
- package/dist/utils/cloneFileDiffMetadata.js +16 -0
- package/dist/utils/cloneFileDiffMetadata.js.map +1 -0
- package/dist/utils/computeEstimatedDiffHeights.d.ts +3 -1
- package/dist/utils/computeEstimatedDiffHeights.d.ts.map +1 -1
- package/dist/utils/computeEstimatedDiffHeights.js +9 -3
- package/dist/utils/computeEstimatedDiffHeights.js.map +1 -1
- package/dist/utils/computeFileOffsets.d.ts +9 -1
- package/dist/utils/computeFileOffsets.d.ts.map +1 -1
- package/dist/utils/computeFileOffsets.js +20 -2
- package/dist/utils/computeFileOffsets.js.map +1 -1
- package/dist/utils/computeVirtualFileMetrics.d.ts.map +1 -1
- package/dist/utils/computeVirtualFileMetrics.js +1 -2
- package/dist/utils/computeVirtualFileMetrics.js.map +1 -1
- package/dist/utils/createAnnotationElement.d.ts +1 -1
- package/dist/utils/createAnnotationElement.d.ts.map +1 -1
- package/dist/utils/createAnnotationElement.js +1 -2
- package/dist/utils/createAnnotationElement.js.map +1 -1
- package/dist/utils/createAnnotationWrapperNode.d.ts.map +1 -1
- package/dist/utils/createAnnotationWrapperNode.js +1 -1
- package/dist/utils/createAnnotationWrapperNode.js.map +1 -1
- package/dist/utils/createContentColumn.d.ts +1 -1
- package/dist/utils/createContentColumn.d.ts.map +1 -1
- package/dist/utils/createContentColumn.js +1 -2
- package/dist/utils/createContentColumn.js.map +1 -1
- package/dist/utils/createEmptyRowBuffer.d.ts +1 -1
- package/dist/utils/createEmptyRowBuffer.d.ts.map +1 -1
- package/dist/utils/createEmptyRowBuffer.js +1 -2
- package/dist/utils/createEmptyRowBuffer.js.map +1 -1
- package/dist/utils/createFileHeaderElement.d.ts +1 -1
- package/dist/utils/createFileHeaderElement.d.ts.map +1 -1
- package/dist/utils/createFileHeaderElement.js +6 -3
- package/dist/utils/createFileHeaderElement.js.map +1 -1
- package/dist/utils/createGutterUtilityContentNode.d.ts.map +1 -1
- package/dist/utils/createGutterUtilityContentNode.js +1 -1
- package/dist/utils/createGutterUtilityContentNode.js.map +1 -1
- package/dist/utils/createGutterUtilityElement.d.ts +1 -1
- package/dist/utils/createGutterUtilityElement.d.ts.map +1 -1
- package/dist/utils/createGutterUtilityElement.js +1 -2
- package/dist/utils/createGutterUtilityElement.js.map +1 -1
- package/dist/utils/createNoNewlineElement.d.ts +1 -1
- package/dist/utils/createNoNewlineElement.d.ts.map +1 -1
- package/dist/utils/createNoNewlineElement.js +1 -2
- package/dist/utils/createNoNewlineElement.js.map +1 -1
- package/dist/utils/createPreElement.d.ts +1 -1
- package/dist/utils/createPreElement.d.ts.map +1 -1
- package/dist/utils/createPreElement.js +1 -3
- package/dist/utils/createPreElement.js.map +1 -1
- package/dist/utils/createRowNodes.d.ts.map +1 -1
- package/dist/utils/createRowNodes.js +1 -1
- package/dist/utils/createRowNodes.js.map +1 -1
- package/dist/utils/createSeparator.d.ts +1 -1
- package/dist/utils/createSeparator.d.ts.map +1 -1
- package/dist/utils/createSeparator.js +1 -2
- package/dist/utils/createSeparator.js.map +1 -1
- package/dist/utils/createSpanNodeFromToken.d.ts.map +1 -1
- package/dist/utils/createSpanNodeFromToken.js +1 -2
- package/dist/utils/createSpanNodeFromToken.js.map +1 -1
- package/dist/utils/createStyleElement.d.ts +1 -1
- package/dist/utils/createStyleElement.d.ts.map +1 -1
- package/dist/utils/createStyleElement.js +1 -2
- package/dist/utils/createStyleElement.js.map +1 -1
- package/dist/utils/createTransformerWithState.d.ts.map +1 -1
- package/dist/utils/createTransformerWithState.js +1 -2
- package/dist/utils/createTransformerWithState.js.map +1 -1
- package/dist/utils/createUnsafeCSSStyleNode.d.ts.map +1 -1
- package/dist/utils/createUnsafeCSSStyleNode.js +1 -2
- package/dist/utils/createUnsafeCSSStyleNode.js.map +1 -1
- package/dist/utils/createWindowFromScrollPosition.d.ts.map +1 -1
- package/dist/utils/createWindowFromScrollPosition.js +5 -5
- package/dist/utils/createWindowFromScrollPosition.js.map +1 -1
- package/dist/utils/cssWrappers.d.ts.map +1 -1
- package/dist/utils/cssWrappers.js +2 -3
- package/dist/utils/cssWrappers.js.map +1 -1
- package/dist/utils/detachString.d.ts.map +1 -1
- package/dist/utils/detachString.js +1 -1
- package/dist/utils/detachString.js.map +1 -1
- package/dist/utils/diffAcceptRejectHunk.d.ts.map +1 -1
- package/dist/utils/diffAcceptRejectHunk.js +1 -2
- package/dist/utils/diffAcceptRejectHunk.js.map +1 -1
- package/dist/utils/formatCSSVariablePrefix.d.ts.map +1 -1
- package/dist/utils/formatCSSVariablePrefix.js +1 -1
- package/dist/utils/formatCSSVariablePrefix.js.map +1 -1
- package/dist/utils/getDiffFileInput.d.ts +14 -0
- package/dist/utils/getDiffFileInput.d.ts.map +1 -0
- package/dist/utils/getDiffFileInput.js +24 -0
- package/dist/utils/getDiffFileInput.js.map +1 -0
- package/dist/utils/getDiffHunksRendererOptions.d.ts.map +1 -1
- package/dist/utils/getDiffHunksRendererOptions.js +2 -1
- package/dist/utils/getDiffHunksRendererOptions.js.map +1 -1
- package/dist/utils/getFileRendererOptions.d.ts.map +1 -1
- package/dist/utils/getFileRendererOptions.js +1 -1
- package/dist/utils/getFileRendererOptions.js.map +1 -1
- package/dist/utils/getFiletypeFromFileName.d.ts.map +1 -1
- package/dist/utils/getFiletypeFromFileName.js +3 -1
- package/dist/utils/getFiletypeFromFileName.js.map +1 -1
- package/dist/utils/getHighlighterOptions.d.ts.map +1 -1
- package/dist/utils/getHighlighterOptions.js +1 -2
- package/dist/utils/getHighlighterOptions.js.map +1 -1
- package/dist/utils/getHighlighterThemeStyles.d.ts.map +1 -1
- package/dist/utils/getHighlighterThemeStyles.js +1 -2
- package/dist/utils/getHighlighterThemeStyles.js.map +1 -1
- package/dist/utils/getHunkSeparatorSlotName.d.ts.map +1 -1
- package/dist/utils/getHunkSeparatorSlotName.js +1 -1
- package/dist/utils/getHunkSeparatorSlotName.js.map +1 -1
- package/dist/utils/getIconForType.d.ts.map +1 -1
- package/dist/utils/getIconForType.js +1 -1
- package/dist/utils/getIconForType.js.map +1 -1
- package/dist/utils/getLineAnnotationName.d.ts.map +1 -1
- package/dist/utils/getLineAnnotationName.js +1 -1
- package/dist/utils/getLineAnnotationName.js.map +1 -1
- package/dist/utils/getLineEndingType.d.ts.map +1 -1
- package/dist/utils/getLineEndingType.js +1 -1
- package/dist/utils/getLineEndingType.js.map +1 -1
- package/dist/utils/getLineNodes.d.ts +1 -1
- package/dist/utils/getLineNodes.d.ts.map +1 -1
- package/dist/utils/getLineNodes.js +1 -1
- package/dist/utils/getLineNodes.js.map +1 -1
- package/dist/utils/getMergeConflictActionSlotName.d.ts.map +1 -1
- package/dist/utils/getMergeConflictActionSlotName.js +1 -1
- package/dist/utils/getMergeConflictActionSlotName.js.map +1 -1
- package/dist/utils/getMergeConflictLineTypes.d.ts.map +1 -1
- package/dist/utils/getMergeConflictLineTypes.js +1 -2
- package/dist/utils/getMergeConflictLineTypes.js.map +1 -1
- package/dist/utils/getOrCreateCodeNode.d.ts.map +1 -1
- package/dist/utils/getOrCreateCodeNode.js +1 -1
- package/dist/utils/getOrCreateCodeNode.js.map +1 -1
- package/dist/utils/getSingularPatch.d.ts.map +1 -1
- package/dist/utils/getSingularPatch.js +1 -2
- package/dist/utils/getSingularPatch.js.map +1 -1
- package/dist/utils/getThemes.d.ts.map +1 -1
- package/dist/utils/getThemes.js +1 -2
- package/dist/utils/getThemes.js.map +1 -1
- package/dist/utils/getTotalLineCountFromHunks.d.ts.map +1 -1
- package/dist/utils/getTotalLineCountFromHunks.js +1 -1
- package/dist/utils/getTotalLineCountFromHunks.js.map +1 -1
- package/dist/utils/hast_utils.d.ts +1 -1
- package/dist/utils/hast_utils.d.ts.map +1 -1
- package/dist/utils/hast_utils.js +1 -1
- package/dist/utils/hast_utils.js.map +1 -1
- package/dist/utils/hostTheme.d.ts.map +1 -1
- package/dist/utils/hostTheme.js +1 -2
- package/dist/utils/hostTheme.js.map +1 -1
- package/dist/utils/hydratePartialDiff.d.ts +10 -0
- package/dist/utils/hydratePartialDiff.d.ts.map +1 -0
- package/dist/utils/hydratePartialDiff.js +140 -0
- package/dist/utils/hydratePartialDiff.js.map +1 -0
- package/dist/utils/includesFileAnnotations.d.ts.map +1 -1
- package/dist/utils/includesFileAnnotations.js +5 -5
- package/dist/utils/includesFileAnnotations.js.map +1 -1
- package/dist/utils/isDefaultRenderRange.d.ts.map +1 -1
- package/dist/utils/isDefaultRenderRange.js +1 -1
- package/dist/utils/isDefaultRenderRange.js.map +1 -1
- package/dist/utils/isDiffPlainText.d.ts.map +1 -1
- package/dist/utils/isDiffPlainText.js +1 -2
- package/dist/utils/isDiffPlainText.js.map +1 -1
- package/dist/utils/isFilePlainText.d.ts.map +1 -1
- package/dist/utils/isFilePlainText.js +1 -2
- package/dist/utils/isFilePlainText.js.map +1 -1
- package/dist/utils/isStyleNode.d.ts.map +1 -1
- package/dist/utils/isStyleNode.js +1 -1
- package/dist/utils/isStyleNode.js.map +1 -1
- package/dist/utils/isWorkerContext.d.ts.map +1 -1
- package/dist/utils/isWorkerContext.js +1 -1
- package/dist/utils/isWorkerContext.js.map +1 -1
- package/dist/utils/iterateOverDiff.d.ts.map +1 -1
- package/dist/utils/iterateOverDiff.js +47 -48
- package/dist/utils/iterateOverDiff.js.map +1 -1
- package/dist/utils/normalizeDiffResolution.d.ts.map +1 -1
- package/dist/utils/normalizeDiffResolution.js +1 -1
- package/dist/utils/normalizeDiffResolution.js.map +1 -1
- package/dist/utils/parseDiffDecorations.d.ts.map +1 -1
- package/dist/utils/parseDiffDecorations.js +1 -2
- package/dist/utils/parseDiffDecorations.js.map +1 -1
- package/dist/utils/parseDiffFromFile.d.ts +1 -2
- package/dist/utils/parseDiffFromFile.d.ts.map +1 -1
- package/dist/utils/parseDiffFromFile.js +27 -7
- package/dist/utils/parseDiffFromFile.js.map +1 -1
- package/dist/utils/parseLineType.d.ts.map +1 -1
- package/dist/utils/parseLineType.js +1 -1
- package/dist/utils/parseLineType.js.map +1 -1
- package/dist/utils/parseMergeConflictDiffFromFile.d.ts.map +1 -1
- package/dist/utils/parseMergeConflictDiffFromFile.js +5 -5
- package/dist/utils/parseMergeConflictDiffFromFile.js.map +1 -1
- package/dist/utils/parsePatchFiles.d.ts.map +1 -1
- package/dist/utils/parsePatchFiles.js +6 -7
- package/dist/utils/parsePatchFiles.js.map +1 -1
- package/dist/utils/prefersReducedMotion.d.ts.map +1 -1
- package/dist/utils/prefersReducedMotion.js +1 -1
- package/dist/utils/prefersReducedMotion.js.map +1 -1
- package/dist/utils/prerenderHTMLIfNecessary.d.ts.map +1 -1
- package/dist/utils/prerenderHTMLIfNecessary.js +1 -1
- package/dist/utils/prerenderHTMLIfNecessary.js.map +1 -1
- package/dist/utils/processLine.d.ts +1 -1
- package/dist/utils/processLine.d.ts.map +1 -1
- package/dist/utils/processLine.js +1 -2
- package/dist/utils/processLine.js.map +1 -1
- package/dist/utils/renderDiffWithHighlighter.d.ts.map +1 -1
- package/dist/utils/renderDiffWithHighlighter.js +4 -5
- package/dist/utils/renderDiffWithHighlighter.js.map +1 -1
- package/dist/utils/renderFileWithHighlighter.d.ts.map +1 -1
- package/dist/utils/renderFileWithHighlighter.js +1 -2
- package/dist/utils/renderFileWithHighlighter.js.map +1 -1
- package/dist/utils/resolveConflict.d.ts.map +1 -1
- package/dist/utils/resolveConflict.js +1 -2
- package/dist/utils/resolveConflict.js.map +1 -1
- package/dist/utils/resolveRegion.d.ts.map +1 -1
- package/dist/utils/resolveRegion.js +1 -1
- package/dist/utils/resolveRegion.js.map +1 -1
- package/dist/utils/roundToDevicePixel.d.ts.map +1 -1
- package/dist/utils/roundToDevicePixel.js +1 -1
- package/dist/utils/roundToDevicePixel.js.map +1 -1
- package/dist/utils/scrollbarGutter.d.ts.map +1 -1
- package/dist/utils/scrollbarGutter.js +1 -2
- package/dist/utils/scrollbarGutter.js.map +1 -1
- package/dist/utils/setLanguageOverride.d.ts.map +1 -1
- package/dist/utils/setLanguageOverride.js +1 -1
- package/dist/utils/setLanguageOverride.js.map +1 -1
- package/dist/utils/setWrapperNodeProps.d.ts.map +1 -1
- package/dist/utils/setWrapperNodeProps.js +1 -2
- package/dist/utils/setWrapperNodeProps.js.map +1 -1
- package/dist/utils/shouldUseTokenTransformer.d.ts.map +1 -1
- package/dist/utils/shouldUseTokenTransformer.js +1 -1
- package/dist/utils/shouldUseTokenTransformer.js.map +1 -1
- package/dist/utils/splitFileContents.d.ts.map +1 -1
- package/dist/utils/splitFileContents.js +1 -2
- package/dist/utils/splitFileContents.js.map +1 -1
- package/dist/utils/trimPatchContext.d.ts.map +1 -1
- package/dist/utils/trimPatchContext.js +1 -2
- package/dist/utils/trimPatchContext.js.map +1 -1
- package/dist/utils/updateDiffHunks.d.ts +6 -1
- package/dist/utils/updateDiffHunks.d.ts.map +1 -1
- package/dist/utils/updateDiffHunks.js +44 -3
- package/dist/utils/updateDiffHunks.js.map +1 -1
- package/dist/utils/virtualDiffLayout.d.ts.map +1 -1
- package/dist/utils/virtualDiffLayout.js +1 -2
- package/dist/utils/virtualDiffLayout.js.map +1 -1
- package/dist/utils/wrapTokenFragments.d.ts +1 -1
- package/dist/utils/wrapTokenFragments.d.ts.map +1 -1
- package/dist/utils/wrapTokenFragments.js +1 -2
- package/dist/utils/wrapTokenFragments.js.map +1 -1
- package/dist/worker/WorkerPoolManager.d.ts +7 -2
- package/dist/worker/WorkerPoolManager.d.ts.map +1 -1
- package/dist/worker/WorkerPoolManager.js +83 -20
- package/dist/worker/WorkerPoolManager.js.map +1 -1
- package/dist/worker/getOrCreateWorkerPoolSingleton.d.ts.map +1 -1
- package/dist/worker/getOrCreateWorkerPoolSingleton.js +1 -2
- package/dist/worker/getOrCreateWorkerPoolSingleton.js.map +1 -1
- package/dist/worker/index.d.ts +2 -2
- package/dist/worker/index.js +1 -2
- package/dist/worker/types.d.ts +7 -1
- package/dist/worker/types.d.ts.map +1 -1
- package/dist/worker/wasm-B9ZqxnKj.js +8 -0
- package/dist/worker/wasm-B9ZqxnKj.js.map +1 -0
- package/dist/worker/worker-portable.js +2784 -6406
- package/dist/worker/worker-portable.js.map +1 -1
- package/dist/worker/worker.js +94 -126
- package/dist/worker/worker.js.map +1 -1
- package/package.json +13 -14
- package/dist/worker/wasm-qE0LgnY3.js +0 -10
- package/dist/worker/wasm-qE0LgnY3.js.map +0 -1
|
@@ -1,16 +1,18 @@
|
|
|
1
|
-
import { h, round } from "./utils.js";
|
|
2
|
-
|
|
1
|
+
import { getGraphemeSegmenter, h, round } from "./utils.js";
|
|
3
2
|
//#region src/editor/textMeasure.ts
|
|
3
|
+
const TEXT_WIDTH_CACHE_LIMIT = 4096;
|
|
4
4
|
var Metrics = class {
|
|
5
5
|
#root;
|
|
6
6
|
#canvasCtx;
|
|
7
7
|
#font;
|
|
8
|
+
#textWidthCache = /* @__PURE__ */ new Map();
|
|
8
9
|
/** Width of the '0' character. */
|
|
9
10
|
ch = -1;
|
|
10
11
|
/** Size of a tab(\t) character. */
|
|
11
12
|
tabSize = 2;
|
|
12
13
|
/** Height of the code line. */
|
|
13
14
|
lineHeight = 20;
|
|
15
|
+
/** Padding top of the root element. */
|
|
14
16
|
paddingTop = 0;
|
|
15
17
|
/** initialize the metrics */
|
|
16
18
|
init(root) {
|
|
@@ -31,12 +33,34 @@ var Metrics = class {
|
|
|
31
33
|
this.#font = font;
|
|
32
34
|
this.#canvasCtx.font = font;
|
|
33
35
|
this.ch = this.canvasMeasureTextWidth("0");
|
|
36
|
+
this.clearTextWidthCache();
|
|
34
37
|
}
|
|
35
|
-
|
|
38
|
+
const nextTabSize = parseInt(tabSize, 10);
|
|
39
|
+
if (!Number.isNaN(nextTabSize)) this.tabSize = nextTabSize;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Re-measure the '0' character width against the font that is loaded right
|
|
43
|
+
* now, returning true when it changed.
|
|
44
|
+
*
|
|
45
|
+
* A custom web font can finish loading after the editor first renders.
|
|
46
|
+
* Until then canvas measureText reports the fallback font's width, and
|
|
47
|
+
* getComputedStyle returns the same font-family string before and after the
|
|
48
|
+
* file arrives, so init()'s font guard never re-measures on its own. Call
|
|
49
|
+
* this once fonts have settled (e.g. on document.fonts.ready) to replace a
|
|
50
|
+
* width measured against the fallback font with the real glyph width. The
|
|
51
|
+
* boolean return lets the caller skip re-rendering when nothing changed.
|
|
52
|
+
*/
|
|
53
|
+
remeasureCharacterWidth() {
|
|
54
|
+
if (this.#canvasCtx === void 0 || this.#font === void 0) return false;
|
|
55
|
+
this.#canvasCtx.font = this.#font;
|
|
56
|
+
const ch = this.canvasMeasureTextWidth("0");
|
|
57
|
+
if (ch === this.ch) return false;
|
|
58
|
+
this.ch = ch;
|
|
59
|
+
return true;
|
|
36
60
|
}
|
|
37
61
|
/** measure the width of the text */
|
|
38
62
|
measureTextWidth(text) {
|
|
39
|
-
const textWithExpandedTabs = text
|
|
63
|
+
const textWithExpandedTabs = expandTabsToSpaces(text, this.tabSize);
|
|
40
64
|
if (needsDomTextMeasurement(textWithExpandedTabs)) return this.domMeasureTextWidth(textWithExpandedTabs);
|
|
41
65
|
return this.canvasMeasureTextWidth(textWithExpandedTabs);
|
|
42
66
|
}
|
|
@@ -47,10 +71,14 @@ var Metrics = class {
|
|
|
47
71
|
}
|
|
48
72
|
/**
|
|
49
73
|
* measure the width of the text using the DOM
|
|
50
|
-
* this is slow because it cause a reflow, use it for non-ascii text
|
|
74
|
+
* this is slow because it cause a reflow, use it for non-ascii text;
|
|
75
|
+
* results are memoized per text so repeated measurements skip the reflow
|
|
51
76
|
*/
|
|
52
77
|
domMeasureTextWidth(text) {
|
|
53
78
|
if (this.#root === void 0) throw new Error("Metrics not initialized");
|
|
79
|
+
const cacheKey = text + "|" + this.#font;
|
|
80
|
+
const cached = this.#textWidthCache.get(cacheKey);
|
|
81
|
+
if (cached !== void 0) return cached;
|
|
54
82
|
const measureEl = h("span", {
|
|
55
83
|
style: {
|
|
56
84
|
position: "absolute",
|
|
@@ -63,11 +91,26 @@ var Metrics = class {
|
|
|
63
91
|
},
|
|
64
92
|
textContent: text
|
|
65
93
|
}, this.#root);
|
|
94
|
+
let width;
|
|
66
95
|
try {
|
|
67
|
-
|
|
96
|
+
width = round(measureEl.getBoundingClientRect().width);
|
|
68
97
|
} finally {
|
|
69
98
|
measureEl.remove();
|
|
70
99
|
}
|
|
100
|
+
if (this.#textWidthCache.size >= TEXT_WIDTH_CACHE_LIMIT) {
|
|
101
|
+
const oldestKey = this.#textWidthCache.keys().next().value;
|
|
102
|
+
if (oldestKey !== void 0) this.#textWidthCache.delete(oldestKey);
|
|
103
|
+
}
|
|
104
|
+
this.#textWidthCache.set(cacheKey, width);
|
|
105
|
+
return width;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* discard memoized DOM text widths
|
|
109
|
+
* call this when the inherited font may have changed without re-running
|
|
110
|
+
* init(), e.g. on a layout reflow, so stale widths are not reused
|
|
111
|
+
*/
|
|
112
|
+
clearTextWidthCache() {
|
|
113
|
+
this.#textWidthCache.clear();
|
|
71
114
|
}
|
|
72
115
|
};
|
|
73
116
|
/** Check if the text needs DOM text measurement. */
|
|
@@ -82,12 +125,22 @@ function needsDomTextMeasurement(text) {
|
|
|
82
125
|
function snapTextOffsetToUnicodeBoundary(text, offset) {
|
|
83
126
|
const boundedOffset = Math.max(0, Math.min(offset, text.length));
|
|
84
127
|
if (boundedOffset === 0 || boundedOffset === text.length || !needsDomTextMeasurement(text)) return boundedOffset;
|
|
85
|
-
const segmenter =
|
|
86
|
-
|
|
87
|
-
const
|
|
88
|
-
|
|
128
|
+
const segmenter = getGraphemeSegmenter();
|
|
129
|
+
if (segmenter !== void 0) {
|
|
130
|
+
for (const segment of segmenter.segment(text)) {
|
|
131
|
+
const segmentStart = segment.index;
|
|
132
|
+
const segmentEnd = segmentStart + segment.segment.length;
|
|
133
|
+
if (boundedOffset > segmentStart && boundedOffset < segmentEnd) return segmentEnd;
|
|
134
|
+
if (boundedOffset <= segmentStart) break;
|
|
135
|
+
}
|
|
136
|
+
return boundedOffset;
|
|
137
|
+
}
|
|
138
|
+
let segmentStart = 0;
|
|
139
|
+
for (const codePoint of text) {
|
|
140
|
+
const segmentEnd = segmentStart + codePoint.length;
|
|
89
141
|
if (boundedOffset > segmentStart && boundedOffset < segmentEnd) return segmentEnd;
|
|
90
142
|
if (boundedOffset <= segmentStart) break;
|
|
143
|
+
segmentStart = segmentEnd;
|
|
91
144
|
}
|
|
92
145
|
return boundedOffset;
|
|
93
146
|
}
|
|
@@ -95,20 +148,54 @@ function snapTextOffsetToUnicodeBoundary(text, offset) {
|
|
|
95
148
|
function getUnicodeMeasurementOffsets(text) {
|
|
96
149
|
if (!needsDomTextMeasurement(text)) return;
|
|
97
150
|
const offsets = [0];
|
|
98
|
-
const segmenter =
|
|
99
|
-
|
|
151
|
+
const segmenter = getGraphemeSegmenter();
|
|
152
|
+
if (segmenter !== void 0) {
|
|
153
|
+
for (const segment of segmenter.segment(text)) offsets.push(segment.index + segment.segment.length);
|
|
154
|
+
return offsets;
|
|
155
|
+
}
|
|
156
|
+
let offset = 0;
|
|
157
|
+
for (const codePoint of text) {
|
|
158
|
+
offset += codePoint.length;
|
|
159
|
+
offsets.push(offset);
|
|
160
|
+
}
|
|
100
161
|
return offsets;
|
|
101
162
|
}
|
|
102
|
-
/**
|
|
163
|
+
/**
|
|
164
|
+
* Expand tab characters to spaces using fixed tab stops: each tab advances to
|
|
165
|
+
* the next multiple of tabSize from its running column, matching how the
|
|
166
|
+
* rendered text expands tabs via CSS `tab-size`. Expanding every tab to a flat
|
|
167
|
+
* tabSize would mis-measure tabs that follow other characters on the same line
|
|
168
|
+
* (e.g. an alignment tab in `foo\tbar`).
|
|
169
|
+
*/
|
|
170
|
+
function expandTabsToSpaces(text, tabSize) {
|
|
171
|
+
if (!text.includes(" ")) return text;
|
|
172
|
+
let result = "";
|
|
173
|
+
let column = 0;
|
|
174
|
+
for (let i = 0; i < text.length; i++) if (text.charCodeAt(i) === 9) {
|
|
175
|
+
const advance = tabSize - column % tabSize;
|
|
176
|
+
result += " ".repeat(advance);
|
|
177
|
+
column += advance;
|
|
178
|
+
} else {
|
|
179
|
+
result += text[i];
|
|
180
|
+
column += 1;
|
|
181
|
+
}
|
|
182
|
+
return result;
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Count the rendered columns of ASCII text, advancing each tab to the next
|
|
186
|
+
* fixed tab stop (a multiple of tabSize) to match CSS `tab-size`. Returns -1
|
|
187
|
+
* for non-ASCII text, which must be measured glyph-by-glyph instead.
|
|
188
|
+
*/
|
|
103
189
|
function getExpandedAsciiTextColumns(text, tabSize) {
|
|
104
190
|
let columns = 0;
|
|
105
191
|
for (let i = 0; i < text.length; i++) {
|
|
106
|
-
|
|
107
|
-
|
|
192
|
+
const code = text.charCodeAt(i);
|
|
193
|
+
if (code > 127) return -1;
|
|
194
|
+
columns += code === 9 ? tabSize - columns % tabSize : 1;
|
|
108
195
|
}
|
|
109
196
|
return columns;
|
|
110
197
|
}
|
|
111
|
-
|
|
112
198
|
//#endregion
|
|
113
|
-
export { Metrics, getExpandedAsciiTextColumns, getUnicodeMeasurementOffsets, needsDomTextMeasurement, snapTextOffsetToUnicodeBoundary };
|
|
199
|
+
export { Metrics, expandTabsToSpaces, getExpandedAsciiTextColumns, getUnicodeMeasurementOffsets, needsDomTextMeasurement, snapTextOffsetToUnicodeBoundary };
|
|
200
|
+
|
|
114
201
|
//# sourceMappingURL=textMeasure.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"textMeasure.js","names":["#root","#canvasCtx","#font"],"sources":["../../src/editor/textMeasure.ts"],"sourcesContent":["import { h, round } from './utils';\n\nexport class Metrics {\n #root?: HTMLElement;\n #canvasCtx?: CanvasRenderingContext2D;\n #font?: string;\n\n /** Width of the '0' character. */\n ch: number = -1;\n /** Size of a tab(\\t) character. */\n tabSize: number = 2;\n /** Height of the code line. */\n lineHeight: number = 20;\n\n paddingTop: number = 0;\n\n /** initialize the metrics */\n init(root: HTMLElement): void {\n if (\n this.#root === root &&\n this.#canvasCtx !== undefined &&\n this.ch !== -1\n ) {\n // already initialized\n return;\n }\n\n this.#root = root;\n this.#canvasCtx ??=\n document.createElement('canvas').getContext('2d') ?? undefined;\n if (this.#canvasCtx === undefined) {\n throw new Error('Could not get canvas context');\n }\n\n const parent = root.parentElement;\n if (parent !== null) {\n const { paddingTop } = getComputedStyle(parent);\n if (paddingTop.endsWith('px')) {\n this.paddingTop = parseFloat(paddingTop.slice(0, -2));\n }\n }\n\n const { fontSize, fontFamily, tabSize, lineHeight } =\n getComputedStyle(root);\n if (lineHeight.endsWith('px')) {\n this.lineHeight = parseFloat(lineHeight.slice(0, -2));\n } else if (fontSize.endsWith('px')) {\n this.lineHeight = round(\n parseFloat(fontSize.slice(0, -2)) * parseFloat(lineHeight)\n );\n }\n const font = fontSize + ' ' + fontFamily;\n if (this.#font !== font || this.ch === -1) {\n this.#font = font;\n this.#canvasCtx.font = font;\n this.ch = this.canvasMeasureTextWidth('0');\n }\n this.tabSize = parseInt(tabSize, 10);\n }\n\n /** measure the width of the text */\n measureTextWidth(text: string): number {\n const textWithExpandedTabs = text.replaceAll(\n '\\t',\n ' '.repeat(this.tabSize)\n );\n if (needsDomTextMeasurement(textWithExpandedTabs)) {\n return this.domMeasureTextWidth(textWithExpandedTabs);\n }\n return this.canvasMeasureTextWidth(textWithExpandedTabs);\n }\n\n /** measure the width of the text using the canvas measureText API */\n canvasMeasureTextWidth(text: string): number {\n if (this.#canvasCtx === undefined) {\n throw new Error('Metrics not initialized');\n }\n return round(this.#canvasCtx.measureText(text).width);\n }\n\n /**\n * measure the width of the text using the DOM\n * this is slow because it cause a reflow, use it for non-ascii text\n */\n domMeasureTextWidth(text: string): number {\n if (this.#root === undefined) {\n throw new Error('Metrics not initialized');\n }\n const measureEl = h(\n 'span',\n {\n style: {\n position: 'absolute',\n top: '0',\n left: '0',\n visibility: 'hidden',\n pointerEvents: 'none',\n whiteSpace: 'pre',\n font: 'inherit',\n },\n textContent: text,\n },\n this.#root\n );\n try {\n return measureEl.getBoundingClientRect().width;\n } finally {\n measureEl.remove();\n }\n }\n}\n\n/** Check if the text needs DOM text measurement. */\nexport function needsDomTextMeasurement(text: string): boolean {\n for (let i = 0; i < text.length; i++) {\n const code = text.charCodeAt(i);\n if (\n (code >= 0xd800 && code <= 0xdfff) ||\n code === 0x200d ||\n code === 0xfe0e ||\n code === 0xfe0f\n ) {\n return true;\n }\n }\n return false;\n}\n\n/** snap the text offset to the Unicode boundary */\nexport function snapTextOffsetToUnicodeBoundary(\n text: string,\n offset: number\n): number {\n const boundedOffset = Math.max(0, Math.min(offset, text.length));\n if (\n boundedOffset === 0 ||\n boundedOffset === text.length ||\n !needsDomTextMeasurement(text)\n ) {\n return boundedOffset;\n }\n // Avoid measuring a caret position inside one visual emoji/grapheme.\n // Browser caret movement can report offsets around UTF-16 surrogate\n // pairs and emoji joiners; measuring a partial sequence gives a\n // replacement-glyph width.\n const segmenter = new Intl.Segmenter(undefined, {\n granularity: 'grapheme',\n });\n for (const segment of segmenter.segment(text)) {\n const segmentStart = segment.index;\n const segmentEnd = segmentStart + segment.segment.length;\n if (boundedOffset > segmentStart && boundedOffset < segmentEnd) {\n return segmentEnd;\n }\n if (boundedOffset <= segmentStart) {\n break;\n }\n }\n return boundedOffset;\n}\n\n/** get the offsets of the Unicode grapheme clusters in the text */\nexport function getUnicodeMeasurementOffsets(\n text: string\n): number[] | undefined {\n if (!needsDomTextMeasurement(text)) {\n return undefined;\n }\n const offsets = [0];\n const segmenter = new Intl.Segmenter(undefined, {\n granularity: 'grapheme',\n });\n for (const segment of segmenter.segment(text)) {\n offsets.push(segment.index + segment.segment.length);\n }\n return offsets;\n}\n\n/** get the number of columns of the ASCII text */\nexport function getExpandedAsciiTextColumns(\n text: string,\n tabSize: number\n): number {\n let columns = 0;\n for (let i = 0; i < text.length; i++) {\n if (text.charCodeAt(i) > 127) {\n return -1;\n }\n columns += text.charCodeAt(i) === /* '\\t' */ 9 ? tabSize : 1;\n }\n return columns;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"textMeasure.js","names":["#root","#canvasCtx","#font","#textWidthCache"],"sources":["../../src/editor/textMeasure.ts"],"sourcesContent":["import { getGraphemeSegmenter, h, round } from './utils';\n\n// Upper bound on cached DOM text-width measurements. The cache only holds\n// non-ASCII runs (emoji, ZWJ sequences, variation selectors), so it stays\n// small for ordinary code, but capping it prevents unbounded growth on\n// emoji-heavy documents. Past the cap the oldest entry is evicted.\nconst TEXT_WIDTH_CACHE_LIMIT = 4096;\n\nexport class Metrics {\n #root?: HTMLElement;\n #canvasCtx?: CanvasRenderingContext2D;\n #font?: string;\n\n // Memoizes domMeasureTextWidth() results\n #textWidthCache = new Map<string, number>();\n\n /** Width of the '0' character. */\n ch: number = -1;\n /** Size of a tab(\\t) character. */\n tabSize: number = 2;\n /** Height of the code line. */\n lineHeight: number = 20;\n /** Padding top of the root element. */\n paddingTop: number = 0;\n\n /** initialize the metrics */\n init(root: HTMLElement): void {\n if (\n this.#root === root &&\n this.#canvasCtx !== undefined &&\n this.ch !== -1\n ) {\n // already initialized\n return;\n }\n\n this.#root = root;\n this.#canvasCtx ??=\n document.createElement('canvas').getContext('2d') ?? undefined;\n if (this.#canvasCtx === undefined) {\n throw new Error('Could not get canvas context');\n }\n\n const parent = root.parentElement;\n if (parent !== null) {\n const { paddingTop } = getComputedStyle(parent);\n if (paddingTop.endsWith('px')) {\n this.paddingTop = parseFloat(paddingTop.slice(0, -2));\n }\n }\n\n const { fontSize, fontFamily, tabSize, lineHeight } =\n getComputedStyle(root);\n if (lineHeight.endsWith('px')) {\n this.lineHeight = parseFloat(lineHeight.slice(0, -2));\n } else if (fontSize.endsWith('px')) {\n this.lineHeight = round(\n parseFloat(fontSize.slice(0, -2)) * parseFloat(lineHeight)\n );\n }\n const font = fontSize + ' ' + fontFamily;\n if (this.#font !== font || this.ch === -1) {\n this.#font = font;\n this.#canvasCtx.font = font;\n this.ch = this.canvasMeasureTextWidth('0');\n // Cached DOM widths were measured against the previous font.\n this.clearTextWidthCache();\n }\n const nextTabSize = parseInt(tabSize, 10);\n if (!Number.isNaN(nextTabSize)) {\n this.tabSize = nextTabSize;\n }\n }\n\n /**\n * Re-measure the '0' character width against the font that is loaded right\n * now, returning true when it changed.\n *\n * A custom web font can finish loading after the editor first renders.\n * Until then canvas measureText reports the fallback font's width, and\n * getComputedStyle returns the same font-family string before and after the\n * file arrives, so init()'s font guard never re-measures on its own. Call\n * this once fonts have settled (e.g. on document.fonts.ready) to replace a\n * width measured against the fallback font with the real glyph width. The\n * boolean return lets the caller skip re-rendering when nothing changed.\n */\n remeasureCharacterWidth(): boolean {\n if (this.#canvasCtx === undefined || this.#font === undefined) {\n return false;\n }\n this.#canvasCtx.font = this.#font;\n const ch = this.canvasMeasureTextWidth('0');\n if (ch === this.ch) {\n return false;\n }\n this.ch = ch;\n return true;\n }\n\n /** measure the width of the text */\n measureTextWidth(text: string): number {\n const textWithExpandedTabs = expandTabsToSpaces(text, this.tabSize);\n if (needsDomTextMeasurement(textWithExpandedTabs)) {\n return this.domMeasureTextWidth(textWithExpandedTabs);\n }\n return this.canvasMeasureTextWidth(textWithExpandedTabs);\n }\n\n /** measure the width of the text using the canvas measureText API */\n canvasMeasureTextWidth(text: string): number {\n if (this.#canvasCtx === undefined) {\n throw new Error('Metrics not initialized');\n }\n return round(this.#canvasCtx.measureText(text).width);\n }\n\n /**\n * measure the width of the text using the DOM\n * this is slow because it cause a reflow, use it for non-ascii text;\n * results are memoized per text so repeated measurements skip the reflow\n */\n domMeasureTextWidth(text: string): number {\n if (this.#root === undefined) {\n throw new Error('Metrics not initialized');\n }\n const cacheKey = text + '|' + this.#font;\n const cached = this.#textWidthCache.get(cacheKey);\n if (cached !== undefined) {\n return cached;\n }\n const measureEl = h(\n 'span',\n {\n style: {\n position: 'absolute',\n top: '0',\n left: '0',\n visibility: 'hidden',\n pointerEvents: 'none',\n whiteSpace: 'pre',\n font: 'inherit',\n },\n textContent: text,\n },\n this.#root\n );\n let width: number;\n try {\n // round() to match canvasMeasureTextWidth and ch; otherwise the DOM path\n // returns raw sub-pixel widths and caret/selection offsets drift between\n // ASCII and non-ASCII runs on the same line.\n width = round(measureEl.getBoundingClientRect().width);\n } finally {\n measureEl.remove();\n }\n if (this.#textWidthCache.size >= TEXT_WIDTH_CACHE_LIMIT) {\n const oldestKey = this.#textWidthCache.keys().next().value;\n if (oldestKey !== undefined) {\n this.#textWidthCache.delete(oldestKey);\n }\n }\n this.#textWidthCache.set(cacheKey, width);\n return width;\n }\n\n /**\n * discard memoized DOM text widths\n * call this when the inherited font may have changed without re-running\n * init(), e.g. on a layout reflow, so stale widths are not reused\n */\n clearTextWidthCache(): void {\n this.#textWidthCache.clear();\n }\n}\n\n/** Check if the text needs DOM text measurement. */\nexport function needsDomTextMeasurement(text: string): boolean {\n for (let i = 0; i < text.length; i++) {\n const code = text.charCodeAt(i);\n if (\n (code >= 0xd800 && code <= 0xdfff) ||\n code === 0x200d ||\n code === 0xfe0e ||\n code === 0xfe0f\n ) {\n return true;\n }\n }\n return false;\n}\n\n/** snap the text offset to the Unicode boundary */\nexport function snapTextOffsetToUnicodeBoundary(\n text: string,\n offset: number\n): number {\n const boundedOffset = Math.max(0, Math.min(offset, text.length));\n if (\n boundedOffset === 0 ||\n boundedOffset === text.length ||\n !needsDomTextMeasurement(text)\n ) {\n return boundedOffset;\n }\n // Avoid measuring a caret position inside one visual emoji/grapheme.\n // Browser caret movement can report offsets around UTF-16 surrogate\n // pairs and emoji joiners; measuring a partial sequence gives a\n // replacement-glyph width.\n const segmenter = getGraphemeSegmenter();\n if (segmenter !== undefined) {\n for (const segment of segmenter.segment(text)) {\n const segmentStart = segment.index;\n const segmentEnd = segmentStart + segment.segment.length;\n if (boundedOffset > segmentStart && boundedOffset < segmentEnd) {\n return segmentEnd;\n }\n if (boundedOffset <= segmentStart) {\n break;\n }\n }\n return boundedOffset;\n }\n // Degraded path for engines lacking Intl.Segmenter: snap out of a\n // surrogate pair by stepping over code points.\n let segmentStart = 0;\n for (const codePoint of text) {\n const segmentEnd = segmentStart + codePoint.length;\n if (boundedOffset > segmentStart && boundedOffset < segmentEnd) {\n return segmentEnd;\n }\n if (boundedOffset <= segmentStart) {\n break;\n }\n segmentStart = segmentEnd;\n }\n return boundedOffset;\n}\n\n/** get the offsets of the Unicode grapheme clusters in the text */\nexport function getUnicodeMeasurementOffsets(\n text: string\n): number[] | undefined {\n if (!needsDomTextMeasurement(text)) {\n return undefined;\n }\n const offsets = [0];\n const segmenter = getGraphemeSegmenter();\n if (segmenter !== undefined) {\n for (const segment of segmenter.segment(text)) {\n offsets.push(segment.index + segment.segment.length);\n }\n return offsets;\n }\n // Degraded path for engines lacking Intl.Segmenter: step by code point.\n let offset = 0;\n for (const codePoint of text) {\n offset += codePoint.length;\n offsets.push(offset);\n }\n return offsets;\n}\n\n/**\n * Expand tab characters to spaces using fixed tab stops: each tab advances to\n * the next multiple of tabSize from its running column, matching how the\n * rendered text expands tabs via CSS `tab-size`. Expanding every tab to a flat\n * tabSize would mis-measure tabs that follow other characters on the same line\n * (e.g. an alignment tab in `foo\\tbar`).\n */\nexport function expandTabsToSpaces(text: string, tabSize: number): string {\n if (!text.includes('\\t')) {\n return text;\n }\n let result = '';\n let column = 0;\n for (let i = 0; i < text.length; i++) {\n if (text.charCodeAt(i) === /* '\\t' */ 9) {\n const advance = tabSize - (column % tabSize);\n result += ' '.repeat(advance);\n column += advance;\n } else {\n result += text[i];\n column += 1;\n }\n }\n return result;\n}\n\n/**\n * Count the rendered columns of ASCII text, advancing each tab to the next\n * fixed tab stop (a multiple of tabSize) to match CSS `tab-size`. Returns -1\n * for non-ASCII text, which must be measured glyph-by-glyph instead.\n */\nexport function getExpandedAsciiTextColumns(\n text: string,\n tabSize: number\n): number {\n let columns = 0;\n for (let i = 0; i < text.length; i++) {\n const code = text.charCodeAt(i);\n if (code > 127) {\n return -1;\n }\n columns += code === /* '\\t' */ 9 ? tabSize - (columns % tabSize) : 1;\n }\n return columns;\n}\n"],"mappings":"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"}
|
|
@@ -9,6 +9,7 @@ interface EditorTokenizerProps {
|
|
|
9
9
|
codeOptions: BaseCodeOptions;
|
|
10
10
|
setStyle: (style: string) => void;
|
|
11
11
|
onDeferTokenize: (lines: Map<number, Array<HighlightedToken>>, themeType: 'dark' | 'light') => void;
|
|
12
|
+
onThemeChange?: () => void;
|
|
12
13
|
__debug?: boolean;
|
|
13
14
|
}
|
|
14
15
|
/** Stoppable code tokenizer for the editor */
|
|
@@ -22,8 +23,10 @@ declare class EditorTokenizer {
|
|
|
22
23
|
textDocument,
|
|
23
24
|
setStyle,
|
|
24
25
|
onDeferTokenize,
|
|
26
|
+
onThemeChange,
|
|
25
27
|
__debug
|
|
26
28
|
}: EditorTokenizerProps);
|
|
29
|
+
syncTheme(codeOptions: BaseCodeOptions): void;
|
|
27
30
|
cleanUp(): void;
|
|
28
31
|
tokenize(change: TextDocumentChange, renderRange?: RenderRange): Map<number, Array<HighlightedToken>>;
|
|
29
32
|
prebuildStateStack(renderRange?: RenderRange): void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tokenzier.d.ts","names":[
|
|
1
|
+
{"version":3,"file":"tokenzier.d.ts","names":[],"sources":["../../src/editor/tokenzier.ts"],"mappings":";;;;;UAiBiB,oBAAA;EACf,WAAA,EAAa,gBAAA;EACb,YAAA,EAAc,YAAA;EACd,WAAA,EAAa,eAAA;EACb,QAAA,GAAW,KAAA;EACX,eAAA,GACE,KAAA,EAAO,GAAA,SAAY,KAAA,CAAM,gBAAA,IACzB,SAAA;EAKF,aAAA;EACA,OAAA;AAAA;;cAIW,eAAA;EAAA;SACJ,mBAAA;EAAA,IAgEH,SAAA;EAIJ,WAAA;IACE,WAAA;IACA,WAAA;IACA,YAAA;IACA,QAAA;IACA,eAAA;IACA,aAAA;IACA;EAAA,GACC,oBAAA;EAgFH,SAAA,CAAU,WAAA,EAAa,eAAA;EA8CvB,OAAA;EASA,QAAA,CACE,MAAA,EAAQ,kBAAA,EACR,WAAA,GAAc,WAAA,GACb,GAAA,SAAY,KAAA,CAAM,gBAAA;EA0LrB,kBAAA,CAAmB,WAAA,GAAc,WAAA;EAmBjC,sBAAA;EAYA,uBAAA;EAYA,wBAAA;AAAA;AAAA,iBA4Nc,YAAA,CACd,OAAA,EAAS,QAAA,EACT,QAAA,YACA,QAAA,UACA,UAAA,EAAY,UAAA,EACZ,SAAA;EAEA,SAAA,EAAW,UAAA;EACX,cAAA,EAAgB,KAAA,CAAM,gBAAA;AAAA;AAAA,iBA+BR,gBAAA,CACd,MAAA,EAAQ,KAAA,CAAM,gBAAA,GACd,SAAA,sBACE,WAAA"}
|
package/dist/editor/tokenzier.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { DEFAULT_THEMES } from "../constants.js";
|
|
2
2
|
import { addEventListener, debounce, h } from "./utils.js";
|
|
3
3
|
import { EncodedTokenMetadata, INITIAL } from "shiki/textmate";
|
|
4
|
-
|
|
5
4
|
//#region src/editor/tokenzier.ts
|
|
6
5
|
/** Stoppable code tokenizer for the editor */
|
|
7
6
|
var EditorTokenizer = class EditorTokenizer {
|
|
@@ -10,11 +9,13 @@ var EditorTokenizer = class EditorTokenizer {
|
|
|
10
9
|
#grammar;
|
|
11
10
|
#mediaQueryList;
|
|
12
11
|
#themeType;
|
|
12
|
+
#themeName = "";
|
|
13
13
|
#colorMap;
|
|
14
14
|
#textDocument;
|
|
15
15
|
#tokenizeMaxLineLength;
|
|
16
16
|
#setStyle;
|
|
17
17
|
#onDeferTokenize;
|
|
18
|
+
#onThemeChange;
|
|
18
19
|
#debug;
|
|
19
20
|
#disposes;
|
|
20
21
|
#stateStack = [INITIAL];
|
|
@@ -42,24 +43,24 @@ var EditorTokenizer = class EditorTokenizer {
|
|
|
42
43
|
get themeType() {
|
|
43
44
|
return this.#themeType;
|
|
44
45
|
}
|
|
45
|
-
constructor({ codeOptions, highlighter, textDocument, setStyle, onDeferTokenize, __debug }) {
|
|
46
|
+
constructor({ codeOptions, highlighter, textDocument, setStyle, onDeferTokenize, onThemeChange, __debug }) {
|
|
46
47
|
const { themeType = "system", theme = DEFAULT_THEMES, tokenizeMaxLineLength = 1e3 } = codeOptions;
|
|
47
48
|
this.#mediaQueryList = window.matchMedia("(prefers-color-scheme: dark)");
|
|
48
49
|
if (themeType === "system") this.#themeType = this.#mediaQueryList.matches ? "dark" : "light";
|
|
49
50
|
else this.#themeType = themeType;
|
|
50
|
-
if (typeof theme !== "string") {
|
|
51
|
+
if (typeof theme !== "string" && themeType === "system") {
|
|
51
52
|
const observer = new MutationObserver((mutations) => {
|
|
52
53
|
for (const { type, attributeName } of mutations) if (type === "attributes" && attributeName !== null && (attributeName === "class" || attributeName.startsWith("data-"))) {
|
|
53
|
-
const themeType
|
|
54
|
-
this.#emitThemeChange(theme[themeType
|
|
54
|
+
const themeType = getComputedStyle(document.body).colorScheme === "dark" ? "dark" : "light";
|
|
55
|
+
this.#emitThemeChange(theme[themeType], themeType);
|
|
55
56
|
break;
|
|
56
57
|
}
|
|
57
58
|
});
|
|
58
59
|
observer.observe(document.documentElement, { attributes: true });
|
|
59
60
|
observer.observe(document.body, { attributes: true });
|
|
60
61
|
this.#disposes = [addEventListener(this.#mediaQueryList, "change", (e) => {
|
|
61
|
-
const themeType
|
|
62
|
-
this.#emitThemeChange(theme[themeType
|
|
62
|
+
const themeType = e.matches ? "dark" : "light";
|
|
63
|
+
this.#emitThemeChange(theme[themeType], themeType);
|
|
63
64
|
}), () => observer.disconnect()];
|
|
64
65
|
}
|
|
65
66
|
this.#highlighter = highlighter;
|
|
@@ -67,8 +68,9 @@ var EditorTokenizer = class EditorTokenizer {
|
|
|
67
68
|
this.#tokenizeMaxLineLength = tokenizeMaxLineLength;
|
|
68
69
|
this.#setStyle = setStyle;
|
|
69
70
|
this.#onDeferTokenize = onDeferTokenize;
|
|
71
|
+
this.#onThemeChange = onThemeChange;
|
|
70
72
|
this.#debug = __debug ?? false;
|
|
71
|
-
|
|
73
|
+
this.#ensureGrammar();
|
|
72
74
|
this.#colorMap = [];
|
|
73
75
|
this.#setTheme(typeof theme === "string" ? theme : theme[this.#themeType]);
|
|
74
76
|
}
|
|
@@ -78,14 +80,21 @@ var EditorTokenizer = class EditorTokenizer {
|
|
|
78
80
|
this.stopBackgroundTokenize();
|
|
79
81
|
this.#stateStack = [INITIAL];
|
|
80
82
|
if (this.#grammar !== void 0 && this.#textDocument.lineCount > 0) this.#scheduleBackgroundTokenize(0);
|
|
83
|
+
this.#onThemeChange?.();
|
|
84
|
+
}
|
|
85
|
+
syncTheme(codeOptions) {
|
|
86
|
+
const { themeType = "system", theme = DEFAULT_THEMES } = codeOptions;
|
|
87
|
+
const nextThemeType = themeType === "system" ? this.#mediaQueryList.matches ? "dark" : "light" : themeType;
|
|
88
|
+
const nextThemeName = typeof theme === "string" ? theme : theme[nextThemeType];
|
|
89
|
+
if (nextThemeType === this.#themeType && nextThemeName === this.#themeName) return;
|
|
90
|
+
this.#emitThemeChange(nextThemeName, nextThemeType);
|
|
81
91
|
}
|
|
82
92
|
#setTheme(themeName) {
|
|
93
|
+
this.#themeName = themeName;
|
|
83
94
|
this.#colorMap = this.#highlighter.setTheme(themeName).colorMap;
|
|
84
95
|
const { colors = {} } = this.#highlighter.getTheme(themeName);
|
|
85
96
|
const selectionBackground = colors["editor.selectionBackground"];
|
|
86
97
|
const lineHighlightBackground = colors["editor.lineHighlightBackground"];
|
|
87
|
-
const gutterForeground = colors["editorLineNumber.foreground"];
|
|
88
|
-
const gutterActiveForeground = colors["editorLineNumber.activeForeground"];
|
|
89
98
|
const cursorForeground = colors["editorCursor.foreground"];
|
|
90
99
|
const findMatchBackground = colors["editor.findMatchBackground"];
|
|
91
100
|
const findMatchHighlightBackground = colors["editor.findMatchHighlightBackground"];
|
|
@@ -96,9 +105,6 @@ var EditorTokenizer = class EditorTokenizer {
|
|
|
96
105
|
this.#setStyle(`:host {
|
|
97
106
|
--diffs-editor-selection-bg: ${selectionBackground ?? "var(--diffs-line-bg)"};
|
|
98
107
|
--diffs-editor-line-highlight-bg: ${lineHighlightBackground ?? "var(--diffs-line-bg)"};
|
|
99
|
-
--diffs-editor-line-number-fg: ${gutterForeground ?? "var(--diffs-fg-number)"};
|
|
100
|
-
--diffs-editor-line-number-active-bg: ${lineHighlightBackground ?? "var(--diffs-line-bg, var(--diffs-bg))"};
|
|
101
|
-
--diffs-editor-line-number-active-fg: ${gutterActiveForeground ?? "var(--diffs-selection-number-fg)"};
|
|
102
108
|
--diffs-editor-match-bg: ${findMatchBackground ?? "unset"};
|
|
103
109
|
--diffs-editor-match-highlight-bg: ${findMatchHighlightBackground ?? "unset"};
|
|
104
110
|
--diffs-editor-cursor-fg: ${cursorForeground ?? "unset"};
|
|
@@ -115,7 +121,8 @@ var EditorTokenizer = class EditorTokenizer {
|
|
|
115
121
|
this.#disposes = void 0;
|
|
116
122
|
}
|
|
117
123
|
tokenize(change, renderRange) {
|
|
118
|
-
|
|
124
|
+
this.#ensureGrammar();
|
|
125
|
+
if (this.#grammar === void 0 && !isGrammarlessLanguage(this.#textDocument.languageId)) throw new Error(`Grammar for language "${this.#textDocument.languageId}" not loaded`);
|
|
119
126
|
const { lineCount } = this.#textDocument;
|
|
120
127
|
const { startingLine = 0, totalLines = Infinity } = renderRange ?? {};
|
|
121
128
|
const renderRangeEndLine = totalLines === Infinity ? lineCount : Math.min(startingLine + totalLines, lineCount);
|
|
@@ -140,7 +147,6 @@ var EditorTokenizer = class EditorTokenizer {
|
|
|
140
147
|
let backgroundStartLine;
|
|
141
148
|
let backgroundChangedRangeIndex = 0;
|
|
142
149
|
let line = canReuseCachedStates ? changedLineRanges[changedRangeIndex][0] : viewStart;
|
|
143
|
-
let state = this.#stateStack[line] ?? INITIAL;
|
|
144
150
|
let settled = false;
|
|
145
151
|
const dirtyLines = /* @__PURE__ */ new Map();
|
|
146
152
|
const offscreenDirtyLines = shouldFlushOffscreenLines ? /* @__PURE__ */ new Map() : void 0;
|
|
@@ -158,6 +164,7 @@ var EditorTokenizer = class EditorTokenizer {
|
|
|
158
164
|
if (canCacheTokenizedStates) this.#stateStack[offscreenEnd] = offscreenState;
|
|
159
165
|
}
|
|
160
166
|
}
|
|
167
|
+
let state = this.#stateStack[line] ?? INITIAL;
|
|
161
168
|
for (; line < renderRangeEndLine;) {
|
|
162
169
|
const previousNextState = canReuseCachedStates ? this.#stateStack[line + 1] : void 0;
|
|
163
170
|
if (canCacheTokenizedStates) this.#stateStack[line] = state;
|
|
@@ -200,8 +207,12 @@ var EditorTokenizer = class EditorTokenizer {
|
|
|
200
207
|
return dirtyLines;
|
|
201
208
|
}
|
|
202
209
|
prebuildStateStack(renderRange) {
|
|
210
|
+
this.#ensureGrammar();
|
|
203
211
|
this.#prebuildStateStack(renderRange);
|
|
204
212
|
}
|
|
213
|
+
#ensureGrammar() {
|
|
214
|
+
if (this.#grammar === void 0 && !isGrammarlessLanguage(this.#textDocument.languageId) && this.#highlighter.getLoadedLanguages().includes(this.#textDocument.languageId)) this.#grammar = this.#highlighter.getLanguage(this.#textDocument.languageId);
|
|
215
|
+
}
|
|
205
216
|
stopBackgroundTokenize() {
|
|
206
217
|
if (this.#isStopped) return;
|
|
207
218
|
this.#isStopped = true;
|
|
@@ -395,7 +406,7 @@ function renderLineTokens(tokens, themeType) {
|
|
|
395
406
|
function isGrammarlessLanguage(languageId) {
|
|
396
407
|
return languageId === "text" || languageId === "ansi";
|
|
397
408
|
}
|
|
398
|
-
|
|
399
409
|
//#endregion
|
|
400
410
|
export { EditorTokenizer, renderLineTokens, tokenizeLine };
|
|
411
|
+
|
|
401
412
|
//# sourceMappingURL=tokenzier.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tokenzier.js","names":["#textDocument","#grammar","#highlighter","#buildStateStack","#backgroundJobId","#backgroundTokenize","#themeType","#mediaQueryList","themeType","#emitThemeChange","#disposes","#tokenizeMaxLineLength","#setStyle","#onDeferTokenize","#debug","#colorMap","#setTheme","#stateStack","#scheduleBackgroundTokenize","#detachMessageListener","changedLineRanges: readonly [number, number][]","backgroundStartLine: number | undefined","dirtyLines: Map<number, Array<HighlightedToken>>","offscreenDirtyLines:\n | Map<number, Array<HighlightedToken>>\n | undefined","#tokenizeLineAt","#prebuildStateStack","#isStopped","#isPaused","#lastLine","#backgroundChangedLineRanges","#backgroundChangedRangeIndex","#postTokenizeMessage","#isMessageListenerAttached","#onMessage","#attachMessageListener","resolvedTokens: Array<HighlightedToken>"],"sources":["../../src/editor/tokenzier.ts"],"sourcesContent":["import {\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\nexport interface EditorTokenizerProps {\n highlighter: DiffsHighlighter;\n textDocument: TextDocument<unknown>;\n codeOptions: BaseCodeOptions;\n setStyle: (style: string) => void;\n onDeferTokenize: (\n lines: Map<number, Array<HighlightedToken>>,\n themeType: 'dark' | 'light'\n ) => void;\n __debug?: boolean;\n}\n\n/** Stoppable code tokenizer for the editor */\nexport class EditorTokenizer {\n static TOKENIZE_TIME_LIMIT = 500;\n\n #highlighter: DiffsHighlighter;\n #grammar: IGrammar | undefined;\n #mediaQueryList: MediaQueryList;\n #themeType: 'light' | 'dark';\n #colorMap: string[];\n #textDocument: TextDocument<unknown>;\n #tokenizeMaxLineLength: number;\n #setStyle: EditorTokenizerProps['setStyle'];\n #onDeferTokenize: EditorTokenizerProps['onDeferTokenize'];\n #debug: boolean;\n #disposes?: (() => void)[];\n\n // state\n #stateStack: StateStack[] = [INITIAL]; // cached state stack by line index\n #lastLine: number = -1;\n #isStopped: boolean = true;\n #isPaused: boolean = false;\n #backgroundJobId: number = 0;\n #backgroundChangedLineRanges: readonly [number, number][] | undefined;\n #backgroundChangedRangeIndex: number = 0;\n #isMessageListenerAttached: boolean = false;\n\n #prebuildStateStack = debounce(async (renderRange?: RenderRange) => {\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 this.#grammar = this.#highlighter.getLanguage(\n this.#textDocument.languageId\n );\n }\n this.#buildStateStack(endLine);\n }, 500);\n\n #onMessage = ({ data }: MessageEvent<unknown>) => {\n if (typeof data !== 'object' || data === null) {\n return;\n }\n const { type, jobId } = data as {\n type?: unknown;\n jobId?: unknown;\n };\n if (\n type === 'tokenize' &&\n typeof jobId === 'number' &&\n jobId === this.#backgroundJobId\n ) {\n this.#backgroundTokenize(jobId);\n }\n };\n\n get themeType(): 'light' | 'dark' {\n return this.#themeType;\n }\n\n constructor({\n codeOptions,\n highlighter,\n textDocument,\n setStyle,\n onDeferTokenize,\n __debug,\n }: EditorTokenizerProps) {\n const {\n themeType = 'system',\n theme = DEFAULT_THEMES,\n tokenizeMaxLineLength = 1000,\n } = codeOptions;\n this.#mediaQueryList = window.matchMedia('(prefers-color-scheme: dark)');\n if (themeType === 'system') {\n this.#themeType = this.#mediaQueryList.matches ? 'dark' : 'light';\n } else {\n this.#themeType = themeType;\n }\n if (typeof theme !== 'string') {\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 =\n getComputedStyle(document.body).colorScheme === 'dark'\n ? 'dark'\n : 'light';\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', (e) => {\n const themeType = e.matches ? 'dark' : 'light';\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.#debug = __debug ?? false;\n if (\n !isGrammarlessLanguage(textDocument.languageId) &&\n highlighter.getLoadedLanguages().includes(textDocument.languageId)\n ) {\n this.#grammar = highlighter.getLanguage(textDocument.languageId);\n }\n this.#colorMap = [];\n this.#setTheme(typeof theme === 'string' ? theme : theme[this.#themeType]);\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 this.#themeType = themeType;\n this.#setTheme(themeName);\n this.stopBackgroundTokenize();\n this.#stateStack = [INITIAL];\n if (this.#grammar !== undefined && this.#textDocument.lineCount > 0) {\n this.#scheduleBackgroundTokenize(0);\n }\n }\n\n #setTheme(themeName: string) {\n this.#colorMap = this.#highlighter.setTheme(themeName).colorMap;\n const { colors = {} } = this.#highlighter.getTheme(themeName);\n const selectionBackground = colors['editor.selectionBackground'];\n const lineHighlightBackground = colors['editor.lineHighlightBackground'];\n const gutterForeground = colors['editorLineNumber.foreground'];\n const gutterActiveForeground = colors['editorLineNumber.activeForeground'];\n const cursorForeground = colors['editorCursor.foreground'];\n const findMatchBackground = colors['editor.findMatchBackground'];\n const findMatchHighlightBackground =\n colors['editor.findMatchHighlightBackground'];\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-bg: ${lineHighlightBackground ?? 'var(--diffs-line-bg)'};\n --diffs-editor-line-number-fg: ${gutterForeground ?? 'var(--diffs-fg-number)'};\n --diffs-editor-line-number-active-bg: ${lineHighlightBackground ?? 'var(--diffs-line-bg, var(--diffs-bg))'};\n --diffs-editor-line-number-active-fg: ${gutterActiveForeground ?? 'var(--diffs-selection-number-fg)'};\n --diffs-editor-match-bg: ${findMatchBackground ?? 'unset'};\n --diffs-editor-match-highlight-bg: ${findMatchHighlightBackground ?? 'unset'};\n --diffs-editor-cursor-fg: ${cursorForeground ?? 'unset'};\n --diffs-editor-hint-fg: ${hintForeground ?? 'unset'};\n --diffs-editor-info-fg: ${infoForeground ?? 'unset'};\n --diffs-editor-warning-fg: ${warningForeground ?? 'unset'};\n --diffs-editor-error-fg: ${errorForeground ?? 'unset'};\n }`);\n }\n\n cleanUp(): void {\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 if (\n this.#grammar === undefined &&\n !isGrammarlessLanguage(this.#textDocument.languageId)\n ) {\n throw new Error('Grammar not loaded');\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 = change.lineDelta === 0;\n const canCacheTokenizedStates =\n canReuseCachedStates ||\n renderRange === undefined ||\n dirtyStart >= viewStart;\n const changedLineRanges: readonly [number, number][] = canReuseCachedStates\n ? (change.changedLineRanges ?? [[dirtyStart, change.endLine]])\n : [[dirtyStart, change.endLine]];\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.#stateStack.length = Math.min(\n this.#stateStack.length,\n dirtyStart + 1\n );\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 state = this.#stateStack[line] ?? INITIAL;\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 if (canCacheTokenizedStates) {\n this.#stateStack[offscreenEnd] = offscreenState;\n }\n }\n }\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 canReuseCachedStates ? changedLineRanges : undefined,\n changedRangeIndex\n );\n }\n\n return dirtyLines;\n }\n\n prebuildStateStack(renderRange?: RenderRange): void {\n this.#prebuildStateStack(renderRange);\n }\n\n stopBackgroundTokenize(): void {\n if (this.#isStopped) {\n return;\n }\n this.#isStopped = true;\n this.#isPaused = false;\n this.#lastLine = -1;\n this.#backgroundChangedLineRanges = undefined;\n this.#backgroundChangedRangeIndex = 0;\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 #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({ type: 'tokenize', jobId });\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 this.#backgroundChangedLineRanges = changedLineRanges;\n this.#backgroundChangedRangeIndex = changedRangeIndex;\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 return { resolvedTokens: [[0, '', lineText]], state };\n }\n if (\n this.#grammar === undefined ||\n lineText === '' ||\n lineText.trim() === ''\n ) {\n return { resolvedTokens: [[0, '', lineText]], state };\n }\n const result = tokenizeLine(\n this.#grammar,\n this.#colorMap,\n lineText,\n state,\n EditorTokenizer.TOKENIZE_TIME_LIMIT\n );\n return {\n resolvedTokens: result.resolvedTokens,\n state: result.ruleStack,\n };\n }\n\n #buildStateStack(endAt: number) {\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;\n }\n let line = this.#stateStack.length - 1;\n let state = this.#stateStack[line] ?? INITIAL;\n for (; line < boundedEndAt; line++) {\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 state = this.#grammar.tokenizeLine2(\n lineText,\n state,\n EditorTokenizer.TOKENIZE_TIME_LIMIT\n ).ruleStack;\n }\n }\n this.#stateStack[line] = state;\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 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.#stateStack[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 } else if (lineText === '' || lineText.trim() === '') {\n lines.set(line, [[0, '', lineText]]);\n } else {\n const ret = tokenizeLine(\n this.#grammar,\n this.#colorMap,\n lineText,\n state,\n EditorTokenizer.TOKENIZE_TIME_LIMIT\n );\n lines.set(line, ret.resolvedTokens);\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 this.stopBackgroundTokenize();\n return;\n }\n\n this.#lastLine = line;\n this.#backgroundChangedRangeIndex = changedRangeIndex;\n this.#postTokenizeMessage(jobId);\n }\n}\n\nexport function tokenizeLine(\n grammar: IGrammar,\n colorMap: string[],\n lineText: string,\n stateStack: StateStack,\n timeLimit?: number\n): {\n ruleStack: StateStack;\n resolvedTokens: Array<HighlightedToken>;\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 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 const bg = EncodedTokenMetadata.getForeground(metadata);\n const fg = colorMap[bg];\n const tokenText = lineText.slice(offset, nextOffset);\n resolvedTokens.push([offset, fg, tokenText]);\n }\n return {\n ruleStack: result.ruleStack,\n resolvedTokens,\n };\n}\n\nexport function renderLineTokens(\n tokens: Array<HighlightedToken>,\n themeType: 'light' | 'dark'\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: `--diffs-token-${themeType}:${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":"tokenzier.js","names":["#textDocument","#grammar","#highlighter","#buildStateStack","#backgroundJobId","#backgroundTokenize","#themeType","#mediaQueryList","#emitThemeChange","#disposes","#tokenizeMaxLineLength","#setStyle","#onDeferTokenize","#onThemeChange","#debug","#ensureGrammar","#colorMap","#setTheme","#stateStack","#scheduleBackgroundTokenize","#themeName","#detachMessageListener","#tokenizeLineAt","#prebuildStateStack","#isStopped","#isPaused","#lastLine","#backgroundChangedLineRanges","#backgroundChangedRangeIndex","#postTokenizeMessage","#isMessageListenerAttached","#onMessage","#attachMessageListener"],"sources":["../../src/editor/tokenzier.ts"],"sourcesContent":["import {\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\nexport interface EditorTokenizerProps {\n highlighter: DiffsHighlighter;\n textDocument: TextDocument<unknown>;\n codeOptions: BaseCodeOptions;\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 static TOKENIZE_TIME_LIMIT = 500;\n\n #highlighter: DiffsHighlighter;\n #grammar: IGrammar | undefined;\n #mediaQueryList: MediaQueryList;\n #themeType: 'light' | '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 #debug: boolean;\n #disposes?: (() => void)[];\n\n // state\n #stateStack: StateStack[] = [INITIAL]; // cached state stack by line index\n #lastLine: number = -1;\n #isStopped: boolean = true;\n #isPaused: boolean = false;\n #backgroundJobId: number = 0;\n #backgroundChangedLineRanges: readonly [number, number][] | undefined;\n #backgroundChangedRangeIndex: number = 0;\n #isMessageListenerAttached: boolean = false;\n\n #prebuildStateStack = debounce(async (renderRange?: RenderRange) => {\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 this.#grammar = this.#highlighter.getLanguage(\n this.#textDocument.languageId\n );\n }\n this.#buildStateStack(endLine);\n }, 500);\n\n #onMessage = ({ data }: MessageEvent<unknown>) => {\n if (typeof data !== 'object' || data === null) {\n return;\n }\n const { type, jobId } = data as {\n type?: unknown;\n jobId?: unknown;\n };\n if (\n type === 'tokenize' &&\n typeof jobId === 'number' &&\n jobId === this.#backgroundJobId\n ) {\n this.#backgroundTokenize(jobId);\n }\n };\n\n get themeType(): 'light' | 'dark' {\n return this.#themeType;\n }\n\n constructor({\n codeOptions,\n highlighter,\n textDocument,\n setStyle,\n onDeferTokenize,\n onThemeChange,\n __debug,\n }: EditorTokenizerProps) {\n const {\n themeType = 'system',\n theme = DEFAULT_THEMES,\n tokenizeMaxLineLength = 1000,\n } = codeOptions;\n this.#mediaQueryList = window.matchMedia('(prefers-color-scheme: dark)');\n if (themeType === 'system') {\n this.#themeType = this.#mediaQueryList.matches ? 'dark' : 'light';\n } else {\n this.#themeType = themeType;\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' && themeType === '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 =\n getComputedStyle(document.body).colorScheme === 'dark'\n ? 'dark'\n : 'light';\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', (e) => {\n const themeType = e.matches ? 'dark' : 'light';\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.#debug = __debug ?? false;\n this.#ensureGrammar();\n this.#colorMap = [];\n this.#setTheme(typeof theme === 'string' ? theme : theme[this.#themeType]);\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 this.#themeType = themeType;\n this.#setTheme(themeName);\n this.stopBackgroundTokenize();\n this.#stateStack = [INITIAL];\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 // 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 const nextThemeType =\n themeType === 'system'\n ? this.#mediaQueryList.matches\n ? 'dark'\n : 'light'\n : themeType;\n const nextThemeName =\n typeof theme === 'string' ? theme : 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) {\n this.#themeName = themeName;\n this.#colorMap = this.#highlighter.setTheme(themeName).colorMap;\n const { colors = {} } = this.#highlighter.getTheme(themeName);\n const selectionBackground = colors['editor.selectionBackground'];\n const lineHighlightBackground = colors['editor.lineHighlightBackground'];\n const cursorForeground = colors['editorCursor.foreground'];\n const findMatchBackground = colors['editor.findMatchBackground'];\n const findMatchHighlightBackground =\n colors['editor.findMatchHighlightBackground'];\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-bg: ${lineHighlightBackground ?? 'var(--diffs-line-bg)'};\n --diffs-editor-match-bg: ${findMatchBackground ?? 'unset'};\n --diffs-editor-match-highlight-bg: ${findMatchHighlightBackground ?? 'unset'};\n --diffs-editor-cursor-fg: ${cursorForeground ?? 'unset'};\n --diffs-editor-hint-fg: ${hintForeground ?? 'unset'};\n --diffs-editor-info-fg: ${infoForeground ?? 'unset'};\n --diffs-editor-warning-fg: ${warningForeground ?? 'unset'};\n --diffs-editor-error-fg: ${errorForeground ?? 'unset'};\n }`);\n }\n\n cleanUp(): void {\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 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 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 = change.lineDelta === 0;\n const canCacheTokenizedStates =\n canReuseCachedStates ||\n renderRange === undefined ||\n dirtyStart >= viewStart;\n const changedLineRanges: readonly [number, number][] = canReuseCachedStates\n ? (change.changedLineRanges ?? [[dirtyStart, change.endLine]])\n : [[dirtyStart, change.endLine]];\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.#stateStack.length = Math.min(\n this.#stateStack.length,\n dirtyStart + 1\n );\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 if (canCacheTokenizedStates) {\n this.#stateStack[offscreenEnd] = offscreenState;\n }\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 canReuseCachedStates ? changedLineRanges : undefined,\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 #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 stopBackgroundTokenize(): void {\n if (this.#isStopped) {\n return;\n }\n this.#isStopped = true;\n this.#isPaused = false;\n this.#lastLine = -1;\n this.#backgroundChangedLineRanges = undefined;\n this.#backgroundChangedRangeIndex = 0;\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 #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({ type: 'tokenize', jobId });\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 this.#backgroundChangedLineRanges = changedLineRanges;\n this.#backgroundChangedRangeIndex = changedRangeIndex;\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 return { resolvedTokens: [[0, '', lineText]], state };\n }\n if (\n this.#grammar === undefined ||\n lineText === '' ||\n lineText.trim() === ''\n ) {\n return { resolvedTokens: [[0, '', lineText]], state };\n }\n const result = tokenizeLine(\n this.#grammar,\n this.#colorMap,\n lineText,\n state,\n EditorTokenizer.TOKENIZE_TIME_LIMIT\n );\n return {\n resolvedTokens: result.resolvedTokens,\n state: result.ruleStack,\n };\n }\n\n #buildStateStack(endAt: number) {\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;\n }\n let line = this.#stateStack.length - 1;\n let state = this.#stateStack[line] ?? INITIAL;\n for (; line < boundedEndAt; line++) {\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 state = this.#grammar.tokenizeLine2(\n lineText,\n state,\n EditorTokenizer.TOKENIZE_TIME_LIMIT\n ).ruleStack;\n }\n }\n this.#stateStack[line] = state;\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 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.#stateStack[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 } else if (lineText === '' || lineText.trim() === '') {\n lines.set(line, [[0, '', lineText]]);\n } else {\n const ret = tokenizeLine(\n this.#grammar,\n this.#colorMap,\n lineText,\n state,\n EditorTokenizer.TOKENIZE_TIME_LIMIT\n );\n lines.set(line, ret.resolvedTokens);\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 this.stopBackgroundTokenize();\n return;\n }\n\n this.#lastLine = line;\n this.#backgroundChangedRangeIndex = changedRangeIndex;\n this.#postTokenizeMessage(jobId);\n }\n}\n\nexport function tokenizeLine(\n grammar: IGrammar,\n colorMap: string[],\n lineText: string,\n stateStack: StateStack,\n timeLimit?: number\n): {\n ruleStack: StateStack;\n resolvedTokens: Array<HighlightedToken>;\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 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 const bg = EncodedTokenMetadata.getForeground(metadata);\n const fg = colorMap[bg];\n const tokenText = lineText.slice(offset, nextOffset);\n resolvedTokens.push([offset, fg, tokenText]);\n }\n return {\n ruleStack: result.ruleStack,\n resolvedTokens,\n };\n}\n\nexport function renderLineTokens(\n tokens: Array<HighlightedToken>,\n themeType: 'light' | 'dark'\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: `--diffs-token-${themeType}:${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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"}
|
package/dist/editor/utils.d.ts
CHANGED
|
@@ -13,6 +13,9 @@ declare function clampDomOffset(node: Node, offset: number): number;
|
|
|
13
13
|
declare function extend<T extends object>(obj: T, attrs: Partial<T>): T;
|
|
14
14
|
declare function debounce<T extends (...args: any[]) => void>(func: T, wait: number): (...args: Parameters<T>) => void;
|
|
15
15
|
declare function round(value: number, precision?: number): number;
|
|
16
|
+
declare function endsWithLineBreak(text: string): boolean;
|
|
17
|
+
declare function createSegmenter(options: Intl.SegmenterOptions): Intl.Segmenter | undefined;
|
|
18
|
+
declare function getGraphemeSegmenter(): Intl.Segmenter | undefined;
|
|
16
19
|
//#endregion
|
|
17
|
-
export { addEventListener, clampDomOffset, debounce, extend, getLineNumberAttr, h, round };
|
|
20
|
+
export { addEventListener, clampDomOffset, createSegmenter, debounce, endsWithLineBreak, extend, getGraphemeSegmenter, getLineNumberAttr, h, round };
|
|
18
21
|
//# sourceMappingURL=utils.d.ts.map
|