@latentic/live-markdown 0.3.1 → 0.4.0
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/CHANGELOG.md +27 -0
- package/README.md +2 -2
- package/dist/chunk-V6TY7KAL.js +8 -0
- package/dist/chunk-V6TY7KAL.js.map +1 -0
- package/dist/codemirror/CodeMirrorMarkdownEditor.d.ts +106 -0
- package/dist/codemirror/CodeMirrorMarkdownEditor.js +482 -0
- package/dist/codemirror/CodeMirrorMarkdownEditor.js.map +1 -0
- package/dist/codemirror/byteOffset.d.ts +17 -0
- package/dist/codemirror/byteOffset.js +19 -0
- package/dist/codemirror/byteOffset.js.map +1 -0
- package/dist/codemirror/caretLayer.d.ts +19 -0
- package/dist/codemirror/caretLayer.js +44 -0
- package/dist/codemirror/caretLayer.js.map +1 -0
- package/dist/codemirror/clipboard/copyRich.d.ts +37 -0
- package/dist/codemirror/clipboard/copyRich.js +72 -0
- package/dist/codemirror/clipboard/copyRich.js.map +1 -0
- package/dist/codemirror/clipboard/htmlToMarkdown.d.ts +20 -0
- package/dist/codemirror/clipboard/htmlToMarkdown.js +91 -0
- package/dist/codemirror/clipboard/htmlToMarkdown.js.map +1 -0
- package/dist/codemirror/clipboard/pasteMarkdown.d.ts +18 -0
- package/dist/codemirror/clipboard/pasteMarkdown.js +41 -0
- package/dist/codemirror/clipboard/pasteMarkdown.js.map +1 -0
- package/dist/codemirror/code/codeHighlight.d.ts +13 -0
- package/dist/codemirror/code/codeHighlight.js +15 -0
- package/dist/codemirror/code/codeHighlight.js.map +1 -0
- package/dist/codemirror/code/codeLangAffordance.d.ts +17 -0
- package/dist/codemirror/code/codeLangAffordance.js +80 -0
- package/dist/codemirror/code/codeLangAffordance.js.map +1 -0
- package/dist/codemirror/code/codeLanguageMenu.d.ts +40 -0
- package/dist/codemirror/code/codeLanguageMenu.js +184 -0
- package/dist/codemirror/code/codeLanguageMenu.js.map +1 -0
- package/dist/codemirror/code/codePalette.d.ts +39 -0
- package/dist/codemirror/code/codePalette.js +53 -0
- package/dist/codemirror/code/codePalette.js.map +1 -0
- package/dist/codemirror/code/fenceAutoClose.d.ts +30 -0
- package/dist/codemirror/code/fenceAutoClose.js +171 -0
- package/dist/codemirror/code/fenceAutoClose.js.map +1 -0
- package/dist/codemirror/code/fenceCaretGuard.d.ts +28 -0
- package/dist/codemirror/code/fenceCaretGuard.js +66 -0
- package/dist/codemirror/code/fenceCaretGuard.js.map +1 -0
- package/dist/codemirror/code/fenceDeleteGuards.d.ts +22 -0
- package/dist/codemirror/code/fenceDeleteGuards.js +105 -0
- package/dist/codemirror/code/fenceDeleteGuards.js.map +1 -0
- package/dist/codemirror/code/fenceTabIndent.d.ts +8 -0
- package/dist/codemirror/code/fenceTabIndent.js +50 -0
- package/dist/codemirror/code/fenceTabIndent.js.map +1 -0
- package/dist/codemirror/code/highlightFence.d.ts +25 -0
- package/dist/codemirror/code/highlightFence.js +45 -0
- package/dist/codemirror/code/highlightFence.js.map +1 -0
- package/dist/codemirror/code/index.d.ts +9 -0
- package/dist/codemirror/code/index.js +8 -0
- package/dist/codemirror/code/index.js.map +1 -0
- package/dist/codemirror/core/codeContext.d.ts +32 -0
- package/dist/codemirror/core/codeContext.js +22 -0
- package/dist/codemirror/core/codeContext.js.map +1 -0
- package/dist/codemirror/core/editorTestHarness.d.ts +31 -0
- package/dist/codemirror/core/editorTestHarness.js +69 -0
- package/dist/codemirror/core/editorTestHarness.js.map +1 -0
- package/dist/codemirror/core/editorTheme.d.ts +39 -0
- package/dist/codemirror/core/editorTheme.js +498 -0
- package/dist/codemirror/core/editorTheme.js.map +1 -0
- package/dist/codemirror/core/hostFacets.d.ts +58 -0
- package/dist/codemirror/core/hostFacets.js +27 -0
- package/dist/codemirror/core/hostFacets.js.map +1 -0
- package/dist/codemirror/core/hrWidget.d.ts +22 -0
- package/dist/codemirror/core/hrWidget.js +22 -0
- package/dist/codemirror/core/hrWidget.js.map +1 -0
- package/dist/codemirror/core/htmlEscape.d.ts +6 -0
- package/dist/codemirror/core/htmlEscape.js +12 -0
- package/dist/codemirror/core/htmlEscape.js.map +1 -0
- package/dist/codemirror/core/index.d.ts +13 -0
- package/dist/codemirror/core/index.js +9 -0
- package/dist/codemirror/core/index.js.map +1 -0
- package/dist/codemirror/core/inlineScan.d.ts +49 -0
- package/dist/codemirror/core/inlineScan.js +31 -0
- package/dist/codemirror/core/inlineScan.js.map +1 -0
- package/dist/codemirror/core/lineStructure.d.ts +47 -0
- package/dist/codemirror/core/lineStructure.js +64 -0
- package/dist/codemirror/core/lineStructure.js.map +1 -0
- package/dist/codemirror/core/linkResolution.d.ts +36 -0
- package/dist/codemirror/core/linkResolution.js +58 -0
- package/dist/codemirror/core/linkResolution.js.map +1 -0
- package/dist/codemirror/core/paint.d.ts +118 -0
- package/dist/codemirror/core/paint.js +42 -0
- package/dist/codemirror/core/paint.js.map +1 -0
- package/dist/codemirror/core/parseToEnd.d.ts +24 -0
- package/dist/codemirror/core/parseToEnd.js +38 -0
- package/dist/codemirror/core/parseToEnd.js.map +1 -0
- package/dist/codemirror/core/plugin.d.ts +32 -0
- package/dist/codemirror/core/plugin.js +161 -0
- package/dist/codemirror/core/plugin.js.map +1 -0
- package/dist/codemirror/core/registry.d.ts +38 -0
- package/dist/codemirror/core/registry.js +133 -0
- package/dist/codemirror/core/registry.js.map +1 -0
- package/dist/codemirror/core/testKeys.d.ts +17 -0
- package/dist/codemirror/core/testKeys.js +11 -0
- package/dist/codemirror/core/testKeys.js.map +1 -0
- package/dist/codemirror/core/treeAt.d.ts +31 -0
- package/dist/codemirror/core/treeAt.js +10 -0
- package/dist/codemirror/core/treeAt.js.map +1 -0
- package/dist/codemirror/extensions/footnoteExtension.d.ts +9 -0
- package/dist/codemirror/extensions/footnoteExtension.js +14 -0
- package/dist/codemirror/extensions/footnoteExtension.js.map +1 -0
- package/dist/codemirror/extensions/highlightExtension.d.ts +9 -0
- package/dist/codemirror/extensions/highlightExtension.js +14 -0
- package/dist/codemirror/extensions/highlightExtension.js.map +1 -0
- package/dist/codemirror/extensions/index.d.ts +12 -0
- package/dist/codemirror/extensions/index.js +19 -0
- package/dist/codemirror/extensions/index.js.map +1 -0
- package/dist/codemirror/extensions/loader.d.ts +24 -0
- package/dist/codemirror/extensions/loader.js +33 -0
- package/dist/codemirror/extensions/loader.js.map +1 -0
- package/dist/codemirror/extensions/mathExtension.d.ts +9 -0
- package/dist/codemirror/extensions/mathExtension.js +14 -0
- package/dist/codemirror/extensions/mathExtension.js.map +1 -0
- package/dist/codemirror/extensions/mermaidExtension.d.ts +9 -0
- package/dist/codemirror/extensions/mermaidExtension.js +12 -0
- package/dist/codemirror/extensions/mermaidExtension.js.map +1 -0
- package/dist/codemirror/extensions/tableExtension.d.ts +13 -0
- package/dist/codemirror/extensions/tableExtension.js +39 -0
- package/dist/codemirror/extensions/tableExtension.js.map +1 -0
- package/dist/codemirror/extensions/types.d.ts +39 -0
- package/dist/codemirror/extensions/types.js +1 -0
- package/dist/codemirror/extensions/types.js.map +1 -0
- package/dist/codemirror/extensions/wikilinkExtension.d.ts +9 -0
- package/dist/codemirror/extensions/wikilinkExtension.js +14 -0
- package/dist/codemirror/extensions/wikilinkExtension.js.map +1 -0
- package/dist/codemirror/features/blockCommandSteps.d.ts +20 -0
- package/dist/codemirror/features/blockCommandSteps.js +83 -0
- package/dist/codemirror/features/blockCommandSteps.js.map +1 -0
- package/dist/codemirror/footnote/footnotePlugin.d.ts +10 -0
- package/dist/codemirror/footnote/footnotePlugin.js +78 -0
- package/dist/codemirror/footnote/footnotePlugin.js.map +1 -0
- package/dist/codemirror/footnote/footnoteScanRule.d.ts +9 -0
- package/dist/codemirror/footnote/footnoteScanRule.js +12 -0
- package/dist/codemirror/footnote/footnoteScanRule.js.map +1 -0
- package/dist/codemirror/footnote/index.d.ts +2 -0
- package/dist/codemirror/footnote/index.js +2 -0
- package/dist/codemirror/footnote/index.js.map +1 -0
- package/dist/codemirror/format/blockCommands.d.ts +17 -0
- package/dist/codemirror/format/blockCommands.js +176 -0
- package/dist/codemirror/format/blockCommands.js.map +1 -0
- package/dist/codemirror/format/formatCommands.d.ts +11 -0
- package/dist/codemirror/format/formatCommands.js +132 -0
- package/dist/codemirror/format/formatCommands.js.map +1 -0
- package/dist/codemirror/format/index.d.ts +4 -0
- package/dist/codemirror/format/index.js +3 -0
- package/dist/codemirror/format/index.js.map +1 -0
- package/dist/codemirror/highlight/highlightPlugin.d.ts +10 -0
- package/dist/codemirror/highlight/highlightPlugin.js +66 -0
- package/dist/codemirror/highlight/highlightPlugin.js.map +1 -0
- package/dist/codemirror/highlight/highlightScanRule.d.ts +8 -0
- package/dist/codemirror/highlight/highlightScanRule.js +12 -0
- package/dist/codemirror/highlight/highlightScanRule.js.map +1 -0
- package/dist/codemirror/highlight/index.d.ts +2 -0
- package/dist/codemirror/highlight/index.js +2 -0
- package/dist/codemirror/highlight/index.js.map +1 -0
- package/dist/codemirror/html/htmlWidget.d.ts +23 -0
- package/dist/codemirror/html/htmlWidget.js +67 -0
- package/dist/codemirror/html/htmlWidget.js.map +1 -0
- package/dist/codemirror/html/index.d.ts +4 -0
- package/dist/codemirror/html/index.js +2 -0
- package/dist/codemirror/html/index.js.map +1 -0
- package/dist/codemirror/image/imageActionMenu.d.ts +14 -0
- package/dist/codemirror/image/imageActionMenu.js +112 -0
- package/dist/codemirror/image/imageActionMenu.js.map +1 -0
- package/dist/codemirror/image/imageEditEvent.d.ts +20 -0
- package/dist/codemirror/image/imageEditEvent.js +6 -0
- package/dist/codemirror/image/imageEditEvent.js.map +1 -0
- package/dist/codemirror/image/imageInsertHandlers.d.ts +13 -0
- package/dist/codemirror/image/imageInsertHandlers.js +64 -0
- package/dist/codemirror/image/imageInsertHandlers.js.map +1 -0
- package/dist/codemirror/image/imageWidget.d.ts +49 -0
- package/dist/codemirror/image/imageWidget.js +83 -0
- package/dist/codemirror/image/imageWidget.js.map +1 -0
- package/dist/codemirror/image/index.d.ts +8 -0
- package/dist/codemirror/image/index.js +5 -0
- package/dist/codemirror/image/index.js.map +1 -0
- package/dist/codemirror/interaction/clickModel.d.ts +43 -0
- package/dist/codemirror/interaction/clickModel.js +99 -0
- package/dist/codemirror/interaction/clickModel.js.map +1 -0
- package/dist/codemirror/interaction/cursorModel.d.ts +10 -0
- package/dist/codemirror/interaction/cursorModel.js +58 -0
- package/dist/codemirror/interaction/cursorModel.js.map +1 -0
- package/dist/codemirror/interaction/deleteNormalizer.d.ts +18 -0
- package/dist/codemirror/interaction/deleteNormalizer.js +157 -0
- package/dist/codemirror/interaction/deleteNormalizer.js.map +1 -0
- package/dist/codemirror/interaction/flankingGuard.d.ts +20 -0
- package/dist/codemirror/interaction/flankingGuard.js +48 -0
- package/dist/codemirror/interaction/flankingGuard.js.map +1 -0
- package/dist/codemirror/interaction/index.d.ts +7 -0
- package/dist/codemirror/interaction/index.js +6 -0
- package/dist/codemirror/interaction/index.js.map +1 -0
- package/dist/codemirror/interaction/visiblePosition.d.ts +43 -0
- package/dist/codemirror/interaction/visiblePosition.js +98 -0
- package/dist/codemirror/interaction/visiblePosition.js.map +1 -0
- package/dist/codemirror/list/bulletWidget.d.ts +61 -0
- package/dist/codemirror/list/bulletWidget.js +84 -0
- package/dist/codemirror/list/bulletWidget.js.map +1 -0
- package/dist/codemirror/list/index.d.ts +4 -0
- package/dist/codemirror/list/index.js +3 -0
- package/dist/codemirror/list/index.js.map +1 -0
- package/dist/codemirror/list/listContinuation.d.ts +28 -0
- package/dist/codemirror/list/listContinuation.js +61 -0
- package/dist/codemirror/list/listContinuation.js.map +1 -0
- package/dist/codemirror/list/listIndent.d.ts +8 -0
- package/dist/codemirror/list/listIndent.js +95 -0
- package/dist/codemirror/list/listIndent.js.map +1 -0
- package/dist/codemirror/list/taskCheckboxWidget.d.ts +42 -0
- package/dist/codemirror/list/taskCheckboxWidget.js +47 -0
- package/dist/codemirror/list/taskCheckboxWidget.js.map +1 -0
- package/dist/codemirror/math/index.d.ts +3 -0
- package/dist/codemirror/math/index.js +2 -0
- package/dist/codemirror/math/index.js.map +1 -0
- package/dist/codemirror/math/mathPlugin.d.ts +10 -0
- package/dist/codemirror/math/mathPlugin.js +73 -0
- package/dist/codemirror/math/mathPlugin.js.map +1 -0
- package/dist/codemirror/math/mathScanRule.d.ts +16 -0
- package/dist/codemirror/math/mathScanRule.js +18 -0
- package/dist/codemirror/math/mathScanRule.js.map +1 -0
- package/dist/codemirror/math/mathWidget.d.ts +15 -0
- package/dist/codemirror/math/mathWidget.js +36 -0
- package/dist/codemirror/math/mathWidget.js.map +1 -0
- package/dist/codemirror/mermaid/index.d.ts +4 -0
- package/dist/codemirror/mermaid/index.js +3 -0
- package/dist/codemirror/mermaid/index.js.map +1 -0
- package/dist/codemirror/mermaid/mermaidPlugin.d.ts +25 -0
- package/dist/codemirror/mermaid/mermaidPlugin.js +78 -0
- package/dist/codemirror/mermaid/mermaidPlugin.js.map +1 -0
- package/dist/codemirror/mermaid/mermaidRender.d.ts +42 -0
- package/dist/codemirror/mermaid/mermaidRender.js +136 -0
- package/dist/codemirror/mermaid/mermaidRender.js.map +1 -0
- package/dist/codemirror/mermaid/mermaidWidget.d.ts +42 -0
- package/dist/codemirror/mermaid/mermaidWidget.js +142 -0
- package/dist/codemirror/mermaid/mermaidWidget.js.map +1 -0
- package/dist/codemirror/selectionLayer.d.ts +43 -0
- package/dist/codemirror/selectionLayer.js +135 -0
- package/dist/codemirror/selectionLayer.js.map +1 -0
- package/dist/codemirror/table/cellDividerWidget.d.ts +9 -0
- package/dist/codemirror/table/cellDividerWidget.js +19 -0
- package/dist/codemirror/table/cellDividerWidget.js.map +1 -0
- package/dist/codemirror/table/index.d.ts +5 -0
- package/dist/codemirror/table/index.js +4 -0
- package/dist/codemirror/table/index.js.map +1 -0
- package/dist/codemirror/table/tableArmed.d.ts +27 -0
- package/dist/codemirror/table/tableArmed.js +43 -0
- package/dist/codemirror/table/tableArmed.js.map +1 -0
- package/dist/codemirror/table/tableCell.d.ts +19 -0
- package/dist/codemirror/table/tableCell.js +15 -0
- package/dist/codemirror/table/tableCell.js.map +1 -0
- package/dist/codemirror/table/tableCellNav.d.ts +51 -0
- package/dist/codemirror/table/tableCellNav.js +47 -0
- package/dist/codemirror/table/tableCellNav.js.map +1 -0
- package/dist/codemirror/table/tableContextMenu.d.ts +22 -0
- package/dist/codemirror/table/tableContextMenu.js +139 -0
- package/dist/codemirror/table/tableContextMenu.js.map +1 -0
- package/dist/codemirror/table/tableEditCommands.d.ts +29 -0
- package/dist/codemirror/table/tableEditCommands.js +86 -0
- package/dist/codemirror/table/tableEditCommands.js.map +1 -0
- package/dist/codemirror/table/tableExcerpt.d.ts +29 -0
- package/dist/codemirror/table/tableExcerpt.js +34 -0
- package/dist/codemirror/table/tableExcerpt.js.map +1 -0
- package/dist/codemirror/table/tableField.d.ts +6 -0
- package/dist/codemirror/table/tableField.js +37 -0
- package/dist/codemirror/table/tableField.js.map +1 -0
- package/dist/codemirror/table/tableGeometry.d.ts +33 -0
- package/dist/codemirror/table/tableGeometry.js +28 -0
- package/dist/codemirror/table/tableGeometry.js.map +1 -0
- package/dist/codemirror/table/tableInline.d.ts +37 -0
- package/dist/codemirror/table/tableInline.js +105 -0
- package/dist/codemirror/table/tableInline.js.map +1 -0
- package/dist/codemirror/table/tableModel.d.ts +45 -0
- package/dist/codemirror/table/tableModel.js +98 -0
- package/dist/codemirror/table/tableModel.js.map +1 -0
- package/dist/codemirror/tablev2/bridgeRules.d.ts +48 -0
- package/dist/codemirror/tablev2/bridgeRules.js +42 -0
- package/dist/codemirror/tablev2/bridgeRules.js.map +1 -0
- package/dist/codemirror/tablev2/cellEditingSurface.d.ts +79 -0
- package/dist/codemirror/tablev2/cellEditingSurface.js +70 -0
- package/dist/codemirror/tablev2/cellEditingSurface.js.map +1 -0
- package/dist/codemirror/tablev2/cellText.d.ts +11 -0
- package/dist/codemirror/tablev2/cellText.js +12 -0
- package/dist/codemirror/tablev2/cellText.js.map +1 -0
- package/dist/codemirror/tablev2/inlineCellSurface.d.ts +38 -0
- package/dist/codemirror/tablev2/inlineCellSurface.js +162 -0
- package/dist/codemirror/tablev2/inlineCellSurface.js.map +1 -0
- package/dist/codemirror/tablev2/overlayCellSurface.d.ts +36 -0
- package/dist/codemirror/tablev2/overlayCellSurface.js +150 -0
- package/dist/codemirror/tablev2/overlayCellSurface.js.map +1 -0
- package/dist/codemirror/tablev2/tableEditingSteps.d.ts +12 -0
- package/dist/codemirror/tablev2/tableEditingSteps.js +518 -0
- package/dist/codemirror/tablev2/tableEditingSteps.js.map +1 -0
- package/dist/codemirror/tablev2/tableV2HoverControls.d.ts +23 -0
- package/dist/codemirror/tablev2/tableV2HoverControls.js +89 -0
- package/dist/codemirror/tablev2/tableV2HoverControls.js.map +1 -0
- package/dist/codemirror/tablev2/tableV2Interaction.d.ts +29 -0
- package/dist/codemirror/tablev2/tableV2Interaction.js +224 -0
- package/dist/codemirror/tablev2/tableV2Interaction.js.map +1 -0
- package/dist/codemirror/tablev2/tableV2Selection.d.ts +45 -0
- package/dist/codemirror/tablev2/tableV2Selection.js +81 -0
- package/dist/codemirror/tablev2/tableV2Selection.js.map +1 -0
- package/dist/codemirror/tablev2/tableV2Sync.d.ts +13 -0
- package/dist/codemirror/tablev2/tableV2Sync.js +13 -0
- package/dist/codemirror/tablev2/tableV2Sync.js.map +1 -0
- package/dist/codemirror/tablev2/tableWidgetV2.d.ts +46 -0
- package/dist/codemirror/tablev2/tableWidgetV2.js +139 -0
- package/dist/codemirror/tablev2/tableWidgetV2.js.map +1 -0
- package/dist/codemirror/updateBus.d.ts +29 -0
- package/dist/codemirror/updateBus.js +26 -0
- package/dist/codemirror/updateBus.js.map +1 -0
- package/dist/codemirror/wikilink/index.d.ts +3 -0
- package/dist/codemirror/wikilink/index.js +2 -0
- package/dist/codemirror/wikilink/index.js.map +1 -0
- package/dist/codemirror/wikilink/wikilinkPlugin.d.ts +40 -0
- package/dist/codemirror/wikilink/wikilinkPlugin.js +89 -0
- package/dist/codemirror/wikilink/wikilinkPlugin.js.map +1 -0
- package/dist/codemirror/wikilink/wikilinkScanRule.d.ts +9 -0
- package/dist/codemirror/wikilink/wikilinkScanRule.js +13 -0
- package/dist/codemirror/wikilink/wikilinkScanRule.js.map +1 -0
- package/dist/frontmatter.d.ts +79 -0
- package/dist/frontmatter.js +58 -0
- package/dist/frontmatter.js.map +1 -0
- package/dist/imageInsert.d.ts +66 -0
- package/dist/imageInsert.js +111 -0
- package/dist/imageInsert.js.map +1 -0
- package/dist/imageSrcResolver.d.ts +55 -0
- package/dist/imageSrcResolver.js +49 -0
- package/dist/imageSrcResolver.js.map +1 -0
- package/dist/index.d.ts +35 -880
- package/dist/index.js +128 -5996
- package/dist/index.js.map +1 -1
- package/dist/links/wikilink.d.ts +26 -0
- package/dist/links/wikilink.js +54 -0
- package/dist/links/wikilink.js.map +1 -0
- package/dist/links/workspaceLink.d.ts +34 -0
- package/dist/links/workspaceLink.js +60 -0
- package/dist/links/workspaceLink.js.map +1 -0
- package/dist/types.d.ts +20 -0
- package/dist/types.js +1 -0
- package/dist/types.js.map +1 -0
- package/package.json +7 -3
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import "../../chunk-V6TY7KAL.js";
|
|
2
|
+
import { EditorSelection, Facet } from "@codemirror/state";
|
|
3
|
+
import { EditorView } from "@codemirror/view";
|
|
4
|
+
import { parseWikilinkBody, resolveWikilinkTarget } from "../../links/wikilink.js";
|
|
5
|
+
import { resolveWorkspaceLink } from "../../links/workspaceLink.js";
|
|
6
|
+
import { inCode } from "../core/codeContext.js";
|
|
7
|
+
import { openExternalUrlFacet } from "../core/hostFacets.js";
|
|
8
|
+
import { wikilinkFromPathFacet, wikilinkTargetsFacet } from "../wikilink/wikilinkPlugin.js";
|
|
9
|
+
import { treeAt } from "../core/treeAt.js";
|
|
10
|
+
const navigateToFacet = Facet.define({
|
|
11
|
+
combine: (vals) => vals[0] ?? null
|
|
12
|
+
});
|
|
13
|
+
function linkUrlAt(view, pos) {
|
|
14
|
+
const node = treeAt(view.state, pos).resolveInner(pos, 1);
|
|
15
|
+
let n = node;
|
|
16
|
+
while (n && n.name !== "Link") n = n.parent;
|
|
17
|
+
if (!n) return null;
|
|
18
|
+
const urlNode = n.node.getChild("URL");
|
|
19
|
+
if (!urlNode) return null;
|
|
20
|
+
return view.state.sliceDoc(urlNode.from, urlNode.to);
|
|
21
|
+
}
|
|
22
|
+
function wikilinkTargetAt(view, pos) {
|
|
23
|
+
const line = view.state.doc.lineAt(pos);
|
|
24
|
+
const text = line.text;
|
|
25
|
+
const re = /\[\[([^\]\n]+?)\]\]/g;
|
|
26
|
+
const tree = treeAt(view.state, line.to);
|
|
27
|
+
let m;
|
|
28
|
+
while ((m = re.exec(text)) !== null) {
|
|
29
|
+
const matchStart = line.from + m.index;
|
|
30
|
+
const matchEnd = matchStart + m[0].length;
|
|
31
|
+
if (pos < matchStart || pos > matchEnd) continue;
|
|
32
|
+
if (inCode(tree, matchStart) || inCode(tree, matchEnd - 2)) continue;
|
|
33
|
+
const { target } = parseWikilinkBody(m[1] ?? "");
|
|
34
|
+
if (!target) return null;
|
|
35
|
+
const fromPath = view.state.facet(wikilinkFromPathFacet);
|
|
36
|
+
const knownPaths = view.state.facet(wikilinkTargetsFacet);
|
|
37
|
+
return resolveWikilinkTarget(target, { fromPath, knownPaths });
|
|
38
|
+
}
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
function linkActionAt(view, pos) {
|
|
42
|
+
const url = linkUrlAt(view, pos);
|
|
43
|
+
if (url) {
|
|
44
|
+
const fromPath = view.state.facet(wikilinkFromPathFacet);
|
|
45
|
+
const knownPaths = view.state.facet(wikilinkTargetsFacet);
|
|
46
|
+
const resolved = resolveWorkspaceLink(url, { fromPath, knownPaths });
|
|
47
|
+
if (resolved?.kind === "internal") return { kind: "navigate", path: resolved.path };
|
|
48
|
+
if (resolved?.kind === "external") return { kind: "open", href: resolved.href };
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
51
|
+
const target = wikilinkTargetAt(view, pos);
|
|
52
|
+
return target ? { kind: "navigate", path: target } : null;
|
|
53
|
+
}
|
|
54
|
+
const clickModel = EditorView.domEventHandlers({
|
|
55
|
+
mousedown(event, view) {
|
|
56
|
+
if (event.button !== 0) return false;
|
|
57
|
+
if (!(event.metaKey || event.ctrlKey)) return false;
|
|
58
|
+
const pos = view.posAtCoords({ x: event.clientX, y: event.clientY });
|
|
59
|
+
if (pos == null) return false;
|
|
60
|
+
const action = linkActionAt(view, pos);
|
|
61
|
+
if (action?.kind === "navigate") {
|
|
62
|
+
const navigate = view.state.facet(navigateToFacet);
|
|
63
|
+
if (navigate) {
|
|
64
|
+
event.preventDefault();
|
|
65
|
+
navigate(action.path);
|
|
66
|
+
return true;
|
|
67
|
+
}
|
|
68
|
+
} else if (action?.kind === "open") {
|
|
69
|
+
event.preventDefault();
|
|
70
|
+
view.state.facet(openExternalUrlFacet)(action.href);
|
|
71
|
+
return true;
|
|
72
|
+
}
|
|
73
|
+
return false;
|
|
74
|
+
},
|
|
75
|
+
contextmenu(event, view) {
|
|
76
|
+
const pos = view.posAtCoords({ x: event.clientX, y: event.clientY });
|
|
77
|
+
if (pos == null) return false;
|
|
78
|
+
const current = view.state.selection.main;
|
|
79
|
+
if (!current.empty && pos >= current.from && pos <= current.to) {
|
|
80
|
+
return false;
|
|
81
|
+
}
|
|
82
|
+
const wordRange = view.state.wordAt(pos);
|
|
83
|
+
if (!wordRange || wordRange.from === wordRange.to) return false;
|
|
84
|
+
event.preventDefault();
|
|
85
|
+
view.dispatch({
|
|
86
|
+
selection: EditorSelection.range(wordRange.from, wordRange.to),
|
|
87
|
+
userEvent: "select.pointer"
|
|
88
|
+
});
|
|
89
|
+
return true;
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
export {
|
|
93
|
+
clickModel,
|
|
94
|
+
linkActionAt,
|
|
95
|
+
linkUrlAt,
|
|
96
|
+
navigateToFacet,
|
|
97
|
+
wikilinkTargetAt
|
|
98
|
+
};
|
|
99
|
+
//# sourceMappingURL=clickModel.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/codemirror/interaction/clickModel.ts"],"sourcesContent":["/**\n * Click model — handles the mouse interactions spec 7 requires that\n * CM6 doesn't already do natively.\n *\n * The default CM6 click path is *good* for normal text clicks: it\n * computes a byte position via `posAtCoords`, handles padding past\n * EOL by snapping to line end, supports drag-select, double-click\n * to select word, triple-click to select line. We do **not** want\n * to fight any of that — every previous attempt to intercept\n * mousedown ate the first click in some case (lost focus, blocked\n * drag start, etc).\n *\n * So this handler narrows to the single interaction CM6 can't infer\n * for us: **Cmd / Ctrl-click on a link → follow it** (spec 7.4). A\n * link to a known workspace file opens that note in a tab; a link\n * with a URI scheme opens in the browser. Plain click on a link\n * still places the caret in the link text via CM6's default.\n *\n * Checkbox toggles (7.5), image selection (7.6), and table cell\n * editing (7.8) are widget-driven — they handle their own clicks\n * via the widget DOM, so they don't appear here.\n *\n * Caret-never-inside-hidden-marker (spec 6.3) is enforced by the\n * decoration plugin's atomic ranges; the click handler doesn't need\n * a snap-to-content fallback because hidden ranges are rendered\n * width-0 by `Decoration.replace`, so clicks visually can't land on\n * them. Trust the rendering.\n */\n\nimport { EditorSelection, Facet } from \"@codemirror/state\";\nimport { EditorView } from \"@codemirror/view\";\n\nimport { parseWikilinkBody, resolveWikilinkTarget } from \"../../links/wikilink\";\nimport { resolveWorkspaceLink } from \"../../links/workspaceLink\";\nimport { inCode } from \"../core/codeContext\";\nimport { openExternalUrlFacet } from \"../core/hostFacets\";\nimport { wikilinkFromPathFacet, wikilinkTargetsFacet } from \"../wikilink/wikilinkPlugin\";\nimport { treeAt } from \"../core/treeAt\";\n\n/**\n * Navigation callback registered by the editor's React shell. Routes a\n * clicked workspace-relative path back through `selectFile`.\n */\nexport const navigateToFacet = Facet.define<\n (path: string) => void,\n ((path: string) => void) | null\n>({\n combine: (vals) => vals[0] ?? null,\n});\n\n/**\n * Walk up from a syntax node to find a `Link` ancestor and return\n * its URL — or `null` if the click wasn't on a link.\n */\nexport function linkUrlAt(view: EditorView, pos: number): string | null {\n const node = treeAt(view.state, pos).resolveInner(pos, 1);\n let n: typeof node | null = node;\n while (n && n.name !== \"Link\") n = n.parent;\n if (!n) return null;\n const urlNode = n.node.getChild(\"URL\");\n if (!urlNode) return null;\n return view.state.sliceDoc(urlNode.from, urlNode.to);\n}\n\n/**\n * If `pos` falls inside a `[[…]]` wikilink, return the workspace\n * file path it resolves to (or null if unresolved). Wikilinks are\n * detected via the same regex + code-context guard `wikilinkPlugin`\n * uses; we re-scan the current line at click time because the plugin\n * doesn't expose its matches.\n */\nexport function wikilinkTargetAt(view: EditorView, pos: number): string | null {\n const line = view.state.doc.lineAt(pos);\n const text = line.text;\n const re = /\\[\\[([^\\]\\n]+?)\\]\\]/g;\n const tree = treeAt(view.state, line.to);\n let m: RegExpExecArray | null;\n while ((m = re.exec(text)) !== null) {\n const matchStart = line.from + m.index;\n const matchEnd = matchStart + m[0].length;\n if (pos < matchStart || pos > matchEnd) continue;\n if (inCode(tree, matchStart) || inCode(tree, matchEnd - 2)) continue;\n const { target } = parseWikilinkBody(m[1] ?? \"\");\n if (!target) return null;\n const fromPath = view.state.facet(wikilinkFromPathFacet);\n const knownPaths = view.state.facet(wikilinkTargetsFacet);\n return resolveWikilinkTarget(target, { fromPath, knownPaths });\n }\n return null;\n}\n\n/** What a Cmd/Ctrl-clicked link resolves to. */\nexport type LinkAction =\n | { kind: \"navigate\"; path: string }\n | { kind: \"open\"; href: string };\n\n/**\n * Resolve the link under `pos` to an action. A markdown link `[t](href)` or a\n * `[[wikilink]]` that names a known workspace file → navigate in-app; a markdown\n * link with a URI scheme (`https:`, `mailto:`, …) → open in the browser; plain\n * text, a broken internal link, or an in-page `#anchor` → null, leaving the\n * click to CM6's default. Pure over editor state, so it's unit-testable with an\n * explicit pos — the DOM click path can't run under jsdom's layout-less\n * `posAtCoords`.\n */\nexport function linkActionAt(view: EditorView, pos: number): LinkAction | null {\n const url = linkUrlAt(view, pos);\n if (url) {\n const fromPath = view.state.facet(wikilinkFromPathFacet);\n const knownPaths = view.state.facet(wikilinkTargetsFacet);\n const resolved = resolveWorkspaceLink(url, { fromPath, knownPaths });\n if (resolved?.kind === \"internal\") return { kind: \"navigate\", path: resolved.path };\n if (resolved?.kind === \"external\") return { kind: \"open\", href: resolved.href };\n return null;\n }\n const target = wikilinkTargetAt(view, pos);\n return target ? { kind: \"navigate\", path: target } : null;\n}\n\nexport const clickModel = EditorView.domEventHandlers({\n mousedown(event, view) {\n // Only intervene on Cmd/Ctrl-click — everything else stays\n // with CM6's default click path so focus + drag-select + EOL\n // snapping all keep working.\n if (event.button !== 0) return false;\n if (!(event.metaKey || event.ctrlKey)) return false;\n const pos = view.posAtCoords({ x: event.clientX, y: event.clientY });\n if (pos == null) return false;\n const action = linkActionAt(view, pos);\n if (action?.kind === \"navigate\") {\n const navigate = view.state.facet(navigateToFacet);\n if (navigate) {\n event.preventDefault();\n navigate(action.path);\n return true;\n }\n } else if (action?.kind === \"open\") {\n event.preventDefault();\n view.state.facet(openExternalUrlFacet)(action.href);\n return true;\n }\n return false;\n },\n contextmenu(event, view) {\n // Right-click → select the word under the pointer and let the\n // selection comment bubble surface its menu. Spec section 7.4\n // (comment context menu on highlight) is the same UX whether\n // the user dragged a selection or right-clicked — both produce\n // a non-empty selection so the bubble appears.\n //\n // If the user has an existing selection that covers the click,\n // leave it as-is; otherwise expand the click position to the\n // word boundary.\n const pos = view.posAtCoords({ x: event.clientX, y: event.clientY });\n if (pos == null) return false;\n const current = view.state.selection.main;\n if (!current.empty && pos >= current.from && pos <= current.to) {\n // Existing selection covers the click — no need to re-select.\n return false;\n }\n const wordRange = view.state.wordAt(pos);\n if (!wordRange || wordRange.from === wordRange.to) return false;\n event.preventDefault();\n view.dispatch({\n selection: EditorSelection.range(wordRange.from, wordRange.to),\n userEvent: \"select.pointer\",\n });\n return true;\n },\n});\n"],"mappings":";AA6BA,SAAS,iBAAiB,aAAa;AACvC,SAAS,kBAAkB;AAE3B,SAAS,mBAAmB,6BAA6B;AACzD,SAAS,4BAA4B;AACrC,SAAS,cAAc;AACvB,SAAS,4BAA4B;AACrC,SAAS,uBAAuB,4BAA4B;AAC5D,SAAS,cAAc;AAMhB,MAAM,kBAAkB,MAAM,OAGnC;AAAA,EACA,SAAS,CAAC,SAAS,KAAK,CAAC,KAAK;AAChC,CAAC;AAMM,SAAS,UAAU,MAAkB,KAA4B;AACtE,QAAM,OAAO,OAAO,KAAK,OAAO,GAAG,EAAE,aAAa,KAAK,CAAC;AACxD,MAAI,IAAwB;AAC5B,SAAO,KAAK,EAAE,SAAS,OAAQ,KAAI,EAAE;AACrC,MAAI,CAAC,EAAG,QAAO;AACf,QAAM,UAAU,EAAE,KAAK,SAAS,KAAK;AACrC,MAAI,CAAC,QAAS,QAAO;AACrB,SAAO,KAAK,MAAM,SAAS,QAAQ,MAAM,QAAQ,EAAE;AACrD;AASO,SAAS,iBAAiB,MAAkB,KAA4B;AAC7E,QAAM,OAAO,KAAK,MAAM,IAAI,OAAO,GAAG;AACtC,QAAM,OAAO,KAAK;AAClB,QAAM,KAAK;AACX,QAAM,OAAO,OAAO,KAAK,OAAO,KAAK,EAAE;AACvC,MAAI;AACJ,UAAQ,IAAI,GAAG,KAAK,IAAI,OAAO,MAAM;AACnC,UAAM,aAAa,KAAK,OAAO,EAAE;AACjC,UAAM,WAAW,aAAa,EAAE,CAAC,EAAE;AACnC,QAAI,MAAM,cAAc,MAAM,SAAU;AACxC,QAAI,OAAO,MAAM,UAAU,KAAK,OAAO,MAAM,WAAW,CAAC,EAAG;AAC5D,UAAM,EAAE,OAAO,IAAI,kBAAkB,EAAE,CAAC,KAAK,EAAE;AAC/C,QAAI,CAAC,OAAQ,QAAO;AACpB,UAAM,WAAW,KAAK,MAAM,MAAM,qBAAqB;AACvD,UAAM,aAAa,KAAK,MAAM,MAAM,oBAAoB;AACxD,WAAO,sBAAsB,QAAQ,EAAE,UAAU,WAAW,CAAC;AAAA,EAC/D;AACA,SAAO;AACT;AAgBO,SAAS,aAAa,MAAkB,KAAgC;AAC7E,QAAM,MAAM,UAAU,MAAM,GAAG;AAC/B,MAAI,KAAK;AACP,UAAM,WAAW,KAAK,MAAM,MAAM,qBAAqB;AACvD,UAAM,aAAa,KAAK,MAAM,MAAM,oBAAoB;AACxD,UAAM,WAAW,qBAAqB,KAAK,EAAE,UAAU,WAAW,CAAC;AACnE,QAAI,UAAU,SAAS,WAAY,QAAO,EAAE,MAAM,YAAY,MAAM,SAAS,KAAK;AAClF,QAAI,UAAU,SAAS,WAAY,QAAO,EAAE,MAAM,QAAQ,MAAM,SAAS,KAAK;AAC9E,WAAO;AAAA,EACT;AACA,QAAM,SAAS,iBAAiB,MAAM,GAAG;AACzC,SAAO,SAAS,EAAE,MAAM,YAAY,MAAM,OAAO,IAAI;AACvD;AAEO,MAAM,aAAa,WAAW,iBAAiB;AAAA,EACpD,UAAU,OAAO,MAAM;AAIrB,QAAI,MAAM,WAAW,EAAG,QAAO;AAC/B,QAAI,EAAE,MAAM,WAAW,MAAM,SAAU,QAAO;AAC9C,UAAM,MAAM,KAAK,YAAY,EAAE,GAAG,MAAM,SAAS,GAAG,MAAM,QAAQ,CAAC;AACnE,QAAI,OAAO,KAAM,QAAO;AACxB,UAAM,SAAS,aAAa,MAAM,GAAG;AACrC,QAAI,QAAQ,SAAS,YAAY;AAC/B,YAAM,WAAW,KAAK,MAAM,MAAM,eAAe;AACjD,UAAI,UAAU;AACZ,cAAM,eAAe;AACrB,iBAAS,OAAO,IAAI;AACpB,eAAO;AAAA,MACT;AAAA,IACF,WAAW,QAAQ,SAAS,QAAQ;AAClC,YAAM,eAAe;AACrB,WAAK,MAAM,MAAM,oBAAoB,EAAE,OAAO,IAAI;AAClD,aAAO;AAAA,IACT;AACA,WAAO;AAAA,EACT;AAAA,EACA,YAAY,OAAO,MAAM;AAUvB,UAAM,MAAM,KAAK,YAAY,EAAE,GAAG,MAAM,SAAS,GAAG,MAAM,QAAQ,CAAC;AACnE,QAAI,OAAO,KAAM,QAAO;AACxB,UAAM,UAAU,KAAK,MAAM,UAAU;AACrC,QAAI,CAAC,QAAQ,SAAS,OAAO,QAAQ,QAAQ,OAAO,QAAQ,IAAI;AAE9D,aAAO;AAAA,IACT;AACA,UAAM,YAAY,KAAK,MAAM,OAAO,GAAG;AACvC,QAAI,CAAC,aAAa,UAAU,SAAS,UAAU,GAAI,QAAO;AAC1D,UAAM,eAAe;AACrB,SAAK,SAAS;AAAA,MACZ,WAAW,gBAAgB,MAAM,UAAU,MAAM,UAAU,EAAE;AAAA,MAC7D,WAAW;AAAA,IACb,CAAC;AACD,WAAO;AAAA,EACT;AACF,CAAC;","names":[]}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import * as _codemirror_state from '@codemirror/state';
|
|
2
|
+
import { Command } from '@codemirror/view';
|
|
3
|
+
|
|
4
|
+
declare const cursorVisibleCharLeft: Command;
|
|
5
|
+
declare const cursorVisibleCharRight: Command;
|
|
6
|
+
declare const selectVisibleCharLeft: Command;
|
|
7
|
+
declare const selectVisibleCharRight: Command;
|
|
8
|
+
declare const cursorModelKeymap: _codemirror_state.Extension;
|
|
9
|
+
|
|
10
|
+
export { cursorModelKeymap, cursorVisibleCharLeft, cursorVisibleCharRight, selectVisibleCharLeft, selectVisibleCharRight };
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import "../../chunk-V6TY7KAL.js";
|
|
2
|
+
import { EditorSelection, Prec } from "@codemirror/state";
|
|
3
|
+
import { keymap } from "@codemirror/view";
|
|
4
|
+
import { nextVisiblePosition, previousVisiblePosition } from "./visiblePosition.js";
|
|
5
|
+
const cursorVisibleCharLeft = (view) => {
|
|
6
|
+
const main = view.state.selection.main;
|
|
7
|
+
const newPos = main.empty ? previousVisiblePosition(view, main.head) : Math.min(main.from, main.to);
|
|
8
|
+
view.dispatch({
|
|
9
|
+
selection: EditorSelection.cursor(newPos),
|
|
10
|
+
userEvent: "select.move",
|
|
11
|
+
scrollIntoView: true
|
|
12
|
+
});
|
|
13
|
+
return true;
|
|
14
|
+
};
|
|
15
|
+
const cursorVisibleCharRight = (view) => {
|
|
16
|
+
const main = view.state.selection.main;
|
|
17
|
+
const newPos = main.empty ? nextVisiblePosition(view, main.head) : Math.max(main.from, main.to);
|
|
18
|
+
view.dispatch({
|
|
19
|
+
selection: EditorSelection.cursor(newPos),
|
|
20
|
+
userEvent: "select.move",
|
|
21
|
+
scrollIntoView: true
|
|
22
|
+
});
|
|
23
|
+
return true;
|
|
24
|
+
};
|
|
25
|
+
const selectVisibleCharLeft = (view) => {
|
|
26
|
+
const main = view.state.selection.main;
|
|
27
|
+
view.dispatch({
|
|
28
|
+
selection: EditorSelection.range(main.anchor, previousVisiblePosition(view, main.head)),
|
|
29
|
+
userEvent: "select.extend",
|
|
30
|
+
scrollIntoView: true
|
|
31
|
+
});
|
|
32
|
+
return true;
|
|
33
|
+
};
|
|
34
|
+
const selectVisibleCharRight = (view) => {
|
|
35
|
+
const main = view.state.selection.main;
|
|
36
|
+
view.dispatch({
|
|
37
|
+
selection: EditorSelection.range(main.anchor, nextVisiblePosition(view, main.head)),
|
|
38
|
+
userEvent: "select.extend",
|
|
39
|
+
scrollIntoView: true
|
|
40
|
+
});
|
|
41
|
+
return true;
|
|
42
|
+
};
|
|
43
|
+
const cursorModelKeymap = Prec.high(
|
|
44
|
+
keymap.of([
|
|
45
|
+
{ key: "ArrowLeft", run: cursorVisibleCharLeft },
|
|
46
|
+
{ key: "ArrowRight", run: cursorVisibleCharRight },
|
|
47
|
+
{ key: "Shift-ArrowLeft", run: selectVisibleCharLeft },
|
|
48
|
+
{ key: "Shift-ArrowRight", run: selectVisibleCharRight }
|
|
49
|
+
])
|
|
50
|
+
);
|
|
51
|
+
export {
|
|
52
|
+
cursorModelKeymap,
|
|
53
|
+
cursorVisibleCharLeft,
|
|
54
|
+
cursorVisibleCharRight,
|
|
55
|
+
selectVisibleCharLeft,
|
|
56
|
+
selectVisibleCharRight
|
|
57
|
+
};
|
|
58
|
+
//# sourceMappingURL=cursorModel.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/codemirror/interaction/cursorModel.ts"],"sourcesContent":["/**\n * Cursor model — visible-position navigation across hidden markdown\n * syntax.\n *\n * Per spec section 6.3, in Rich Edit Mode the caret may never land\n * inside a hidden marker. The natural CM6 atomic-ranges behaviour\n * snaps the caret to the nearest *boundary* of a hidden region —\n * but boundaries of a hidden region look the same visually (the\n * `**` between them is hidden), so left-arrow from \"end of bold\"\n * appears to do nothing on the first press and only moves on the\n * second.\n *\n * This module replaces those motions with commands that compute\n * the **next visible source position** in one step:\n *\n * 1. Step one source character in the desired direction.\n * 2. If that step landed strictly inside an atomic range, jump\n * past the range entirely (one character beyond its far edge).\n * 3. Repeat until the position is outside every atomic range or\n * at the document boundary.\n *\n * The output is the position the user expects: one visible char\n * to the left or right of where they were. Hidden markers cease to\n * exist as cursor stops.\n *\n * Wired at `Prec.high` so the bindings beat `defaultKeymap`.\n */\n\nimport { EditorSelection, Prec } from \"@codemirror/state\";\nimport { type Command, keymap } from \"@codemirror/view\";\n\nimport { nextVisiblePosition, previousVisiblePosition } from \"./visiblePosition\";\n\nexport const cursorVisibleCharLeft: Command = (view) => {\n const main = view.state.selection.main;\n const newPos = main.empty\n ? previousVisiblePosition(view, main.head)\n : Math.min(main.from, main.to);\n view.dispatch({\n selection: EditorSelection.cursor(newPos),\n userEvent: \"select.move\",\n scrollIntoView: true,\n });\n return true;\n};\n\nexport const cursorVisibleCharRight: Command = (view) => {\n const main = view.state.selection.main;\n const newPos = main.empty\n ? nextVisiblePosition(view, main.head)\n : Math.max(main.from, main.to);\n view.dispatch({\n selection: EditorSelection.cursor(newPos),\n userEvent: \"select.move\",\n scrollIntoView: true,\n });\n return true;\n};\n\nexport const selectVisibleCharLeft: Command = (view) => {\n const main = view.state.selection.main;\n view.dispatch({\n selection: EditorSelection.range(main.anchor, previousVisiblePosition(view, main.head)),\n userEvent: \"select.extend\",\n scrollIntoView: true,\n });\n return true;\n};\n\nexport const selectVisibleCharRight: Command = (view) => {\n const main = view.state.selection.main;\n view.dispatch({\n selection: EditorSelection.range(main.anchor, nextVisiblePosition(view, main.head)),\n userEvent: \"select.extend\",\n scrollIntoView: true,\n });\n return true;\n};\n\nexport const cursorModelKeymap = Prec.high(\n keymap.of([\n { key: \"ArrowLeft\", run: cursorVisibleCharLeft },\n { key: \"ArrowRight\", run: cursorVisibleCharRight },\n { key: \"Shift-ArrowLeft\", run: selectVisibleCharLeft },\n { key: \"Shift-ArrowRight\", run: selectVisibleCharRight },\n ]),\n);\n"],"mappings":";AA4BA,SAAS,iBAAiB,YAAY;AACtC,SAAuB,cAAc;AAErC,SAAS,qBAAqB,+BAA+B;AAEtD,MAAM,wBAAiC,CAAC,SAAS;AACtD,QAAM,OAAO,KAAK,MAAM,UAAU;AAClC,QAAM,SAAS,KAAK,QAChB,wBAAwB,MAAM,KAAK,IAAI,IACvC,KAAK,IAAI,KAAK,MAAM,KAAK,EAAE;AAC/B,OAAK,SAAS;AAAA,IACZ,WAAW,gBAAgB,OAAO,MAAM;AAAA,IACxC,WAAW;AAAA,IACX,gBAAgB;AAAA,EAClB,CAAC;AACD,SAAO;AACT;AAEO,MAAM,yBAAkC,CAAC,SAAS;AACvD,QAAM,OAAO,KAAK,MAAM,UAAU;AAClC,QAAM,SAAS,KAAK,QAChB,oBAAoB,MAAM,KAAK,IAAI,IACnC,KAAK,IAAI,KAAK,MAAM,KAAK,EAAE;AAC/B,OAAK,SAAS;AAAA,IACZ,WAAW,gBAAgB,OAAO,MAAM;AAAA,IACxC,WAAW;AAAA,IACX,gBAAgB;AAAA,EAClB,CAAC;AACD,SAAO;AACT;AAEO,MAAM,wBAAiC,CAAC,SAAS;AACtD,QAAM,OAAO,KAAK,MAAM,UAAU;AAClC,OAAK,SAAS;AAAA,IACZ,WAAW,gBAAgB,MAAM,KAAK,QAAQ,wBAAwB,MAAM,KAAK,IAAI,CAAC;AAAA,IACtF,WAAW;AAAA,IACX,gBAAgB;AAAA,EAClB,CAAC;AACD,SAAO;AACT;AAEO,MAAM,yBAAkC,CAAC,SAAS;AACvD,QAAM,OAAO,KAAK,MAAM,UAAU;AAClC,OAAK,SAAS;AAAA,IACZ,WAAW,gBAAgB,MAAM,KAAK,QAAQ,oBAAoB,MAAM,KAAK,IAAI,CAAC;AAAA,IAClF,WAAW;AAAA,IACX,gBAAgB;AAAA,EAClB,CAAC;AACD,SAAO;AACT;AAEO,MAAM,oBAAoB,KAAK;AAAA,EACpC,OAAO,GAAG;AAAA,IACR,EAAE,KAAK,aAAa,KAAK,sBAAsB;AAAA,IAC/C,EAAE,KAAK,cAAc,KAAK,uBAAuB;AAAA,IACjD,EAAE,KAAK,mBAAmB,KAAK,sBAAsB;AAAA,IACrD,EAAE,KAAK,oBAAoB,KAAK,uBAAuB;AAAA,EACzD,CAAC;AACH;","names":[]}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import * as _codemirror_state from '@codemirror/state';
|
|
2
|
+
import { Command } from '@codemirror/view';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Length of a line's leading **block** prefix — the list marker (`- `, `* `,
|
|
6
|
+
* `1. `), ATX heading marker (`## `), and/or blockquote marker (`> `), including
|
|
7
|
+
* nesting/indentation. Everything after is **inline** content (which may begin
|
|
8
|
+
* with hidden inline markers like `**`). Used to line-join without eating inline
|
|
9
|
+
* markers: backspacing at the visible start of `- **B**` deletes the newline +
|
|
10
|
+
* `- ` but keeps `**B**`. Pure (operates on the line text) so it's unit-testable
|
|
11
|
+
* without an `EditorView`.
|
|
12
|
+
*/
|
|
13
|
+
declare function blockPrefixLength(lineText: string): number;
|
|
14
|
+
declare const visibleBackspace: Command;
|
|
15
|
+
declare const visibleDeleteForward: Command;
|
|
16
|
+
declare const deleteNormalizerKeymap: _codemirror_state.Extension;
|
|
17
|
+
|
|
18
|
+
export { blockPrefixLength, deleteNormalizerKeymap, visibleBackspace, visibleDeleteForward };
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import "../../chunk-V6TY7KAL.js";
|
|
2
|
+
import { EditorSelection, Prec } from "@codemirror/state";
|
|
3
|
+
import { keymap } from "@codemirror/view";
|
|
4
|
+
import { fenceBackspaceGuard, fenceDeleteGuard } from "../code/fenceDeleteGuards.js";
|
|
5
|
+
import { lineStructure } from "../core/lineStructure.js";
|
|
6
|
+
import { setArmedTable } from "../table/tableArmed.js";
|
|
7
|
+
import { tableField } from "../table/tableField.js";
|
|
8
|
+
import { visibleCharAfter, visibleCharBefore } from "./visiblePosition.js";
|
|
9
|
+
import { treeAt } from "../core/treeAt.js";
|
|
10
|
+
const COLLAPSIBLE_SPAN_NAMES = /* @__PURE__ */ new Set([
|
|
11
|
+
"StrongEmphasis",
|
|
12
|
+
"Emphasis",
|
|
13
|
+
"InlineCode",
|
|
14
|
+
"Link",
|
|
15
|
+
"Strikethrough"
|
|
16
|
+
]);
|
|
17
|
+
function blockPrefixLength(lineText) {
|
|
18
|
+
const match = lineText.match(/^(?:\s*(?:[-*+]|\d+[.)])\s+|#{1,6}\s+|>\s?)+/);
|
|
19
|
+
return match ? match[0].length : 0;
|
|
20
|
+
}
|
|
21
|
+
function findCollapsibleSpan(view, from, to) {
|
|
22
|
+
const tree = treeAt(view.state, to);
|
|
23
|
+
let node = tree.resolveInner(from, 1);
|
|
24
|
+
while (node) {
|
|
25
|
+
if (COLLAPSIBLE_SPAN_NAMES.has(node.name)) {
|
|
26
|
+
const first = node.firstChild;
|
|
27
|
+
const last = node.lastChild;
|
|
28
|
+
if (first && last && first !== last) {
|
|
29
|
+
const contentStart = first.to;
|
|
30
|
+
const contentEnd = last.from;
|
|
31
|
+
const leftKept = Math.max(0, from - contentStart);
|
|
32
|
+
const rightKept = Math.max(0, contentEnd - to);
|
|
33
|
+
if (leftKept === 0 && rightKept === 0) {
|
|
34
|
+
return { from: node.from, to: node.to };
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
break;
|
|
38
|
+
}
|
|
39
|
+
node = node.parent;
|
|
40
|
+
}
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
function applyDeletion(view, from, to) {
|
|
44
|
+
if (from === to) return true;
|
|
45
|
+
const span = findCollapsibleSpan(view, from, to);
|
|
46
|
+
let changes;
|
|
47
|
+
let caret;
|
|
48
|
+
if (span) {
|
|
49
|
+
changes = { from: span.from, to: span.to, insert: "" };
|
|
50
|
+
caret = span.from;
|
|
51
|
+
} else {
|
|
52
|
+
changes = { from, to, insert: "" };
|
|
53
|
+
caret = from;
|
|
54
|
+
}
|
|
55
|
+
view.dispatch({
|
|
56
|
+
changes,
|
|
57
|
+
selection: EditorSelection.cursor(caret),
|
|
58
|
+
userEvent: from < view.state.selection.main.head ? "delete.backward" : "delete.forward",
|
|
59
|
+
scrollIntoView: true
|
|
60
|
+
});
|
|
61
|
+
return true;
|
|
62
|
+
}
|
|
63
|
+
function tableBefore(view, pos) {
|
|
64
|
+
let p = pos;
|
|
65
|
+
while (p > 0 && /\s/.test(view.state.doc.sliceString(p - 1, p))) p--;
|
|
66
|
+
let found = null;
|
|
67
|
+
view.state.field(tableField, false)?.between(p, p, (from, to) => {
|
|
68
|
+
if (to === p) {
|
|
69
|
+
found = { from, to };
|
|
70
|
+
return false;
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
return found;
|
|
74
|
+
}
|
|
75
|
+
function tableAfter(view, pos) {
|
|
76
|
+
const docLen = view.state.doc.length;
|
|
77
|
+
let p = pos;
|
|
78
|
+
while (p < docLen && /\s/.test(view.state.doc.sliceString(p, p + 1))) p++;
|
|
79
|
+
let found = null;
|
|
80
|
+
view.state.field(tableField, false)?.between(p, p, (from, to) => {
|
|
81
|
+
if (from === p) {
|
|
82
|
+
found = { from, to };
|
|
83
|
+
return false;
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
return found;
|
|
87
|
+
}
|
|
88
|
+
function tableDeleteStep(view, table, pos, edge) {
|
|
89
|
+
if (pos === edge) {
|
|
90
|
+
return applyDeletion(view, table.from, table.to);
|
|
91
|
+
}
|
|
92
|
+
view.dispatch({
|
|
93
|
+
selection: EditorSelection.cursor(edge),
|
|
94
|
+
effects: setArmedTable.of({ from: table.from, edge: edge === table.to ? "end" : "start" }),
|
|
95
|
+
userEvent: "select",
|
|
96
|
+
scrollIntoView: true
|
|
97
|
+
});
|
|
98
|
+
return true;
|
|
99
|
+
}
|
|
100
|
+
const visibleBackspace = (view) => {
|
|
101
|
+
const sel = view.state.selection.main;
|
|
102
|
+
if (!sel.empty) {
|
|
103
|
+
return applyDeletion(view, sel.from, sel.to);
|
|
104
|
+
}
|
|
105
|
+
const pos = sel.head;
|
|
106
|
+
if (pos === 0) return true;
|
|
107
|
+
const before = tableBefore(view, pos);
|
|
108
|
+
if (before) return tableDeleteStep(view, before, pos, before.to);
|
|
109
|
+
const ch = visibleCharBefore(view, pos);
|
|
110
|
+
const line = view.state.doc.lineAt(pos);
|
|
111
|
+
const structure = lineStructure(view.state, line);
|
|
112
|
+
const lineMark = structure.list ?? structure.heading;
|
|
113
|
+
if (lineMark && (!ch || ch.to <= lineMark.markTo)) {
|
|
114
|
+
return applyDeletion(view, lineMark.markFrom, lineMark.markTo);
|
|
115
|
+
}
|
|
116
|
+
if (!ch) return true;
|
|
117
|
+
if (ch.from < line.from && line.from > 0) {
|
|
118
|
+
if (fenceBackspaceGuard(view, pos)) return true;
|
|
119
|
+
const prefixLen = blockPrefixLength(view.state.doc.sliceString(line.from, line.to));
|
|
120
|
+
return applyDeletion(view, line.from - 1, line.from + prefixLen);
|
|
121
|
+
}
|
|
122
|
+
return applyDeletion(view, ch.from, ch.to);
|
|
123
|
+
};
|
|
124
|
+
const visibleDeleteForward = (view) => {
|
|
125
|
+
const sel = view.state.selection.main;
|
|
126
|
+
if (!sel.empty) {
|
|
127
|
+
return applyDeletion(view, sel.from, sel.to);
|
|
128
|
+
}
|
|
129
|
+
const pos = sel.head;
|
|
130
|
+
const docLen = view.state.doc.length;
|
|
131
|
+
if (pos >= docLen) return true;
|
|
132
|
+
const after = tableAfter(view, pos);
|
|
133
|
+
if (after) return tableDeleteStep(view, after, pos, after.from);
|
|
134
|
+
const ch = visibleCharAfter(view, pos);
|
|
135
|
+
if (!ch) return true;
|
|
136
|
+
const line = view.state.doc.lineAt(pos);
|
|
137
|
+
if (ch.from >= line.to && line.to < docLen) {
|
|
138
|
+
if (fenceDeleteGuard(view, pos)) return true;
|
|
139
|
+
const next = view.state.doc.lineAt(line.to + 1);
|
|
140
|
+
const prefixLen = blockPrefixLength(view.state.doc.sliceString(next.from, next.to));
|
|
141
|
+
return applyDeletion(view, line.to, next.from + prefixLen);
|
|
142
|
+
}
|
|
143
|
+
return applyDeletion(view, ch.from, ch.to);
|
|
144
|
+
};
|
|
145
|
+
const deleteNormalizerKeymap = Prec.high(
|
|
146
|
+
keymap.of([
|
|
147
|
+
{ key: "Backspace", run: visibleBackspace },
|
|
148
|
+
{ key: "Delete", run: visibleDeleteForward }
|
|
149
|
+
])
|
|
150
|
+
);
|
|
151
|
+
export {
|
|
152
|
+
blockPrefixLength,
|
|
153
|
+
deleteNormalizerKeymap,
|
|
154
|
+
visibleBackspace,
|
|
155
|
+
visibleDeleteForward
|
|
156
|
+
};
|
|
157
|
+
//# sourceMappingURL=deleteNormalizer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/codemirror/interaction/deleteNormalizer.ts"],"sourcesContent":["/**\n * Backspace / Delete normalizer — spec section 8.2 and 8.3.\n *\n * Two invariants this enforces:\n *\n * 1. **Backspace deletes visible content first.** Hidden markdown\n * markers are never the unit of deletion in Rich Edit Mode.\n * So pressing backspace at the end of `**bold**` removes the\n * `d` (turning the source into `**bol**`), not the closing `**`.\n *\n * 2. **Empty styled spans collapse entirely.** If a backspace\n * would leave a span with no content (e.g. backspace inside\n * `**X**` where `X` is the only char), we delete the entire\n * construct — markers and all — instead of leaving dangling\n * `****` / `[]()` / ` `` ` behind.\n *\n * The same rules apply forward for Delete.\n *\n * Constructs we normalise:\n *\n * * `StrongEmphasis` (`**…**`)\n * * `Emphasis` (`*…*` / `_…_`)\n * * `InlineCode` (`` `…` ``)\n * * `Link` (`[…](…)`)\n * * `Strikethrough` (`~~…~~`)\n *\n * Each is identified by Lezer's node name; the content range is\n * `firstChild.to .. lastChild.from`.\n */\n\nimport { EditorSelection, Prec, type ChangeSpec } from \"@codemirror/state\";\nimport { type Command, EditorView, keymap } from \"@codemirror/view\";\n\nimport { fenceBackspaceGuard, fenceDeleteGuard } from \"../code/fenceDeleteGuards\";\nimport { lineStructure } from \"../core/lineStructure\";\nimport { setArmedTable } from \"../table/tableArmed\";\nimport { tableField } from \"../table/tableField\";\nimport { visibleCharAfter, visibleCharBefore } from \"./visiblePosition\";\nimport { treeAt } from \"../core/treeAt\";\n\n// Lezer's SyntaxNode type isn't directly exposed via @codemirror/language's\n// public types and `@lezer/common` is a transitive dep. The structural\n// shape we use is small enough to inline rather than pull a new direct\n// dependency just for the type.\ntype SyntaxNodeLike = {\n readonly name: string;\n readonly from: number;\n readonly to: number;\n readonly parent: SyntaxNodeLike | null;\n readonly firstChild: SyntaxNodeLike | null;\n readonly lastChild: SyntaxNodeLike | null;\n};\n\nconst COLLAPSIBLE_SPAN_NAMES = new Set([\n \"StrongEmphasis\",\n \"Emphasis\",\n \"InlineCode\",\n \"Link\",\n \"Strikethrough\",\n]);\n\n/**\n * Length of a line's leading **block** prefix — the list marker (`- `, `* `,\n * `1. `), ATX heading marker (`## `), and/or blockquote marker (`> `), including\n * nesting/indentation. Everything after is **inline** content (which may begin\n * with hidden inline markers like `**`). Used to line-join without eating inline\n * markers: backspacing at the visible start of `- **B**` deletes the newline +\n * `- ` but keeps `**B**`. Pure (operates on the line text) so it's unit-testable\n * without an `EditorView`.\n */\nexport function blockPrefixLength(lineText: string): number {\n const match = lineText.match(/^(?:\\s*(?:[-*+]|\\d+[.)])\\s+|#{1,6}\\s+|>\\s?)+/);\n return match ? match[0].length : 0;\n}\n\n/**\n * If the planned deletion `[from, to]` would empty (or already empties)\n * a collapsible styled span, return the span's full source range\n * (markers included). Otherwise return `null`.\n */\nfunction findCollapsibleSpan(\n view: EditorView,\n from: number,\n to: number,\n): { from: number; to: number } | null {\n const tree = treeAt(view.state, to);\n // Walk up from the deletion's left edge.\n let node: SyntaxNodeLike | null = tree.resolveInner(from, 1) as unknown as SyntaxNodeLike;\n while (node) {\n if (COLLAPSIBLE_SPAN_NAMES.has(node.name)) {\n const first = node.firstChild;\n const last = node.lastChild;\n if (first && last && first !== last) {\n const contentStart = first.to;\n const contentEnd = last.from;\n // Remaining content after deletion =\n // [contentStart, from) ∪ [to, contentEnd)\n // span collapses if both halves are empty.\n const leftKept = Math.max(0, from - contentStart);\n const rightKept = Math.max(0, contentEnd - to);\n if (leftKept === 0 && rightKept === 0) {\n return { from: node.from, to: node.to };\n }\n }\n // Stop at the first collapsible match — outer spans aren't\n // affected by inner-content deletes.\n break;\n }\n node = node.parent;\n }\n return null;\n}\n\nfunction applyDeletion(view: EditorView, from: number, to: number): boolean {\n if (from === to) return true;\n const span = findCollapsibleSpan(view, from, to);\n let changes: ChangeSpec;\n let caret: number;\n if (span) {\n changes = { from: span.from, to: span.to, insert: \"\" };\n caret = span.from;\n } else {\n changes = { from, to, insert: \"\" };\n caret = from;\n }\n view.dispatch({\n changes,\n selection: EditorSelection.cursor(caret),\n userEvent: from < view.state.selection.main.head ? \"delete.backward\" : \"delete.forward\",\n scrollIntoView: true,\n });\n return true;\n}\n\n/** The table whose source ends just before `pos` (only whitespace between), or\n * null — so Backspace can treat a table as one atomic block rather than edit\n * its hidden `| … |` source. */\nfunction tableBefore(view: EditorView, pos: number): { from: number; to: number } | null {\n let p = pos;\n while (p > 0 && /\\s/.test(view.state.doc.sliceString(p - 1, p))) p--;\n let found: { from: number; to: number } | null = null;\n view.state.field(tableField, false)?.between(p, p, (from, to) => {\n if (to === p) {\n found = { from, to };\n return false;\n }\n });\n return found;\n}\n\n/** The table whose source starts just after `pos` (only whitespace between). */\nfunction tableAfter(view: EditorView, pos: number): { from: number; to: number } | null {\n const docLen = view.state.doc.length;\n let p = pos;\n while (p < docLen && /\\s/.test(view.state.doc.sliceString(p, p + 1))) p++;\n let found: { from: number; to: number } | null = null;\n view.state.field(tableField, false)?.between(p, p, (from, to) => {\n if (from === p) {\n found = { from, to };\n return false;\n }\n });\n return found;\n}\n\n/**\n * Two-press table delete (Zettlr-style). When the caret reaches a table from\n * the line below/above, the first press parks the caret at the table's `edge`\n * — a visible caret sitting just past the table, NOT a selection — and the\n * second press (caret now AT that edge) removes the whole table. Never edits\n * the hidden `| … |` source.\n */\nfunction tableDeleteStep(\n view: EditorView,\n table: { from: number; to: number },\n pos: number,\n edge: number,\n): boolean {\n if (pos === edge) {\n return applyDeletion(view, table.from, table.to);\n }\n view.dispatch({\n selection: EditorSelection.cursor(edge),\n effects: setArmedTable.of({ from: table.from, edge: edge === table.to ? \"end\" : \"start\" }),\n userEvent: \"select\",\n scrollIntoView: true,\n });\n return true;\n}\n\nexport const visibleBackspace: Command = (view) => {\n const sel = view.state.selection.main;\n if (!sel.empty) {\n // Non-empty selection: delete it as a whole. Default backspace\n // works fine here; we explicitly mirror that to keep the userEvent\n // tagged consistently.\n return applyDeletion(view, sel.from, sel.to);\n }\n const pos = sel.head;\n if (pos === 0) return true;\n // A table just before the caret → park the caret at its end (first press); a\n // second press, caret now at that end, removes it. Never edits hidden source.\n const before = tableBefore(view, pos);\n if (before) return tableDeleteStep(view, before, pos, before.to);\n // The unit of deletion is the visible grapheme left of the caret — never a\n // hidden marker, and never marker + char folded together (the caret can rest\n // on either side of a hidden closing `**`; both must delete just the char).\n const ch = visibleCharBefore(view, pos);\n const line = view.state.doc.lineAt(pos);\n // §8.2a — nothing VISIBLE stands between the caret and the line's own\n // marker (the walked-back char ends at/inside the marker range, or there is\n // none at all) — wherever the caret sits among hidden ranges, I2. The\n // marker dies first: checkbox, bullet, number, or hashes are removed in\n // place and the line becomes plain text where it stands. Joining up is the\n // NEXT press.\n const structure = lineStructure(view.state, line);\n const lineMark = structure.list ?? structure.heading;\n if (lineMark && (!ch || ch.to <= lineMark.markTo)) {\n return applyDeletion(view, lineMark.markFrom, lineMark.markTo);\n }\n if (!ch) return true; // nothing visible before the caret (doc/line 1 start)\n // The previous visible char is on an earlier line. This is a line-join, not\n // an inline delete: delete only the preceding newline + this line's block\n // prefix (a quote's `> `), leaving inline content and its hidden leading\n // markers (`**B**`) intact. List/heading markers were §8.2a's press.\n if (ch.from < line.from && line.from > 0) {\n // Fence lines are structure: crossing one walls, parks, or collapses the\n // block instead of merging text into a fence (§12.1–.2).\n if (fenceBackspaceGuard(view, pos)) return true;\n const prefixLen = blockPrefixLength(view.state.doc.sliceString(line.from, line.to));\n return applyDeletion(view, line.from - 1, line.from + prefixLen);\n }\n return applyDeletion(view, ch.from, ch.to);\n};\n\nexport const visibleDeleteForward: Command = (view) => {\n const sel = view.state.selection.main;\n if (!sel.empty) {\n return applyDeletion(view, sel.from, sel.to);\n }\n const pos = sel.head;\n const docLen = view.state.doc.length;\n if (pos >= docLen) return true;\n // Mirror of Backspace: a table just after the caret → park the caret at its\n // start (first press), then a second press removes it.\n const after = tableAfter(view, pos);\n if (after) return tableDeleteStep(view, after, pos, after.from);\n // The unit of deletion is the visible grapheme right of the caret — from a\n // line start this skips a hidden opening `**` and deletes the first letter,\n // never carving `**C` out of `**Compose**`.\n const ch = visibleCharAfter(view, pos);\n if (!ch) return true; // nothing visible after the caret\n const line = view.state.doc.lineAt(pos);\n // Forward-join — the mirror of backspace's line-join. The next visible char\n // is on a later line; delete only the newline + the next line's block\n // prefix, keeping inline markers on both sides.\n if (ch.from >= line.to && line.to < docLen) {\n if (fenceDeleteGuard(view, pos)) return true;\n const next = view.state.doc.lineAt(line.to + 1);\n const prefixLen = blockPrefixLength(view.state.doc.sliceString(next.from, next.to));\n return applyDeletion(view, line.to, next.from + prefixLen);\n }\n return applyDeletion(view, ch.from, ch.to);\n};\n\nexport const deleteNormalizerKeymap = Prec.high(\n keymap.of([\n { key: \"Backspace\", run: visibleBackspace },\n { key: \"Delete\", run: visibleDeleteForward },\n ]),\n);\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import * as _codemirror_state from '@codemirror/state';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Keep typed whitespace from dissolving emphasis (#94).
|
|
5
|
+
*
|
|
6
|
+
* CommonMark's flanking rules make a closing `**`/`*`/`~~` delimiter literal
|
|
7
|
+
* when preceded by whitespace (and an opening one when followed by it). The
|
|
8
|
+
* caret's resting position at a bold word's end is INSIDE the construct —
|
|
9
|
+
* before the hidden closing marker — so typing a space there writes
|
|
10
|
+
* `**Compose **`, the delimiters stop parsing, and the raw markers appear in
|
|
11
|
+
* rich mode.
|
|
12
|
+
*
|
|
13
|
+
* Whitespace typed at a flanking-sensitive construct's content edge belongs
|
|
14
|
+
* OUTSIDE its markers: `**Compose** ` / ` **Compose**`. This filter re-sites
|
|
15
|
+
* such insertions; everything else passes through untouched. Inline code is
|
|
16
|
+
* exempt — code spans have no flanking rule and edge spaces are meaningful.
|
|
17
|
+
*/
|
|
18
|
+
declare const flankingGuard: _codemirror_state.Extension;
|
|
19
|
+
|
|
20
|
+
export { flankingGuard };
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import "../../chunk-V6TY7KAL.js";
|
|
2
|
+
import { EditorSelection, EditorState } from "@codemirror/state";
|
|
3
|
+
import { treeAt } from "../core/treeAt.js";
|
|
4
|
+
const FLANKING_SENSITIVE = /* @__PURE__ */ new Set(["StrongEmphasis", "Emphasis", "Strikethrough"]);
|
|
5
|
+
function siteOutsideFlanking(state, pos, side) {
|
|
6
|
+
for (; ; ) {
|
|
7
|
+
const tree = treeAt(state, pos);
|
|
8
|
+
let node = tree.resolveInner(pos, side === "end" ? -1 : 1);
|
|
9
|
+
let moved = false;
|
|
10
|
+
for (; node; node = node.parent) {
|
|
11
|
+
if (!FLANKING_SENSITIVE.has(node.name)) continue;
|
|
12
|
+
const mark = side === "end" ? node.lastChild : node.firstChild;
|
|
13
|
+
const boundary = side === "end" ? mark?.from : mark?.to;
|
|
14
|
+
if (boundary === pos) {
|
|
15
|
+
pos = side === "end" ? node.to : node.from;
|
|
16
|
+
moved = true;
|
|
17
|
+
break;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
if (!moved) return pos;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
const flankingGuard = EditorState.transactionFilter.of((tr) => {
|
|
24
|
+
if (!tr.docChanged || !tr.isUserEvent("input.type") || tr.isUserEvent("input.type.compose")) {
|
|
25
|
+
return tr;
|
|
26
|
+
}
|
|
27
|
+
let insertion = null;
|
|
28
|
+
let eligible = true;
|
|
29
|
+
tr.changes.iterChanges((fromA, toA, _fromB, _toB, inserted) => {
|
|
30
|
+
if (insertion || fromA !== toA || !/^\s+$/.test(inserted.toString())) eligible = false;
|
|
31
|
+
else insertion = { from: fromA, text: inserted.toString() };
|
|
32
|
+
});
|
|
33
|
+
if (!eligible || !insertion) return tr;
|
|
34
|
+
const { from, text } = insertion;
|
|
35
|
+
const end = siteOutsideFlanking(tr.startState, from, "end");
|
|
36
|
+
const resited = end !== from ? end : siteOutsideFlanking(tr.startState, from, "start");
|
|
37
|
+
if (resited === from) return tr;
|
|
38
|
+
return {
|
|
39
|
+
changes: { from: resited, insert: text },
|
|
40
|
+
selection: EditorSelection.cursor(resited + text.length),
|
|
41
|
+
userEvent: "input.type",
|
|
42
|
+
scrollIntoView: true
|
|
43
|
+
};
|
|
44
|
+
});
|
|
45
|
+
export {
|
|
46
|
+
flankingGuard
|
|
47
|
+
};
|
|
48
|
+
//# sourceMappingURL=flankingGuard.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/codemirror/interaction/flankingGuard.ts"],"sourcesContent":["/**\n * Keep typed whitespace from dissolving emphasis (#94).\n *\n * CommonMark's flanking rules make a closing `**`/`*`/`~~` delimiter literal\n * when preceded by whitespace (and an opening one when followed by it). The\n * caret's resting position at a bold word's end is INSIDE the construct —\n * before the hidden closing marker — so typing a space there writes\n * `**Compose **`, the delimiters stop parsing, and the raw markers appear in\n * rich mode.\n *\n * Whitespace typed at a flanking-sensitive construct's content edge belongs\n * OUTSIDE its markers: `**Compose** ` / ` **Compose**`. This filter re-sites\n * such insertions; everything else passes through untouched. Inline code is\n * exempt — code spans have no flanking rule and edge spaces are meaningful.\n */\n\nimport { EditorSelection, EditorState, type Transaction } from \"@codemirror/state\";\nimport { treeAt } from \"../core/treeAt\";\n\nconst FLANKING_SENSITIVE = new Set([\"StrongEmphasis\", \"Emphasis\", \"Strikethrough\"]);\n\ntype NodeLike = {\n readonly name: string;\n readonly from: number;\n readonly to: number;\n readonly parent: NodeLike | null;\n readonly firstChild: NodeLike | null;\n readonly lastChild: NodeLike | null;\n};\n\n/** Where a whitespace insertion at `pos` must land so no construct's\n * delimiter is invalidated — hopping outward through nested constructs\n * (`***x***` needs two hops). Returns `pos` itself when it isn't at a\n * flanking-sensitive content edge. */\nfunction siteOutsideFlanking(state: EditorState, pos: number, side: \"end\" | \"start\"): number {\n for (;;) {\n // Re-acquired each hop: `pos` moves outward to an enclosing node's edge,\n // which can sit past what the previous round parsed.\n const tree = treeAt(state, pos);\n let node = tree.resolveInner(pos, side === \"end\" ? -1 : 1) as unknown as NodeLike | null;\n let moved = false;\n for (; node; node = node.parent) {\n if (!FLANKING_SENSITIVE.has(node.name)) continue;\n const mark = side === \"end\" ? node.lastChild : node.firstChild;\n const boundary = side === \"end\" ? mark?.from : mark?.to;\n if (boundary === pos) {\n pos = side === \"end\" ? node.to : node.from;\n moved = true;\n break;\n }\n }\n if (!moved) return pos;\n }\n}\n\nexport const flankingGuard = EditorState.transactionFilter.of((tr: Transaction) => {\n if (!tr.docChanged || !tr.isUserEvent(\"input.type\") || tr.isUserEvent(\"input.type.compose\")) {\n return tr;\n }\n // Exactly one pure insertion of whitespace — a keystroke, not a wrap/paste.\n let insertion: { from: number; text: string } | null = null;\n let eligible = true;\n tr.changes.iterChanges((fromA, toA, _fromB, _toB, inserted) => {\n if (insertion || fromA !== toA || !/^\\s+$/.test(inserted.toString())) eligible = false;\n else insertion = { from: fromA, text: inserted.toString() };\n });\n if (!eligible || !insertion) return tr;\n const { from, text } = insertion as { from: number; text: string };\n\n const end = siteOutsideFlanking(tr.startState, from, \"end\");\n const resited = end !== from ? end : siteOutsideFlanking(tr.startState, from, \"start\");\n if (resited === from) return tr;\n\n return {\n changes: { from: resited, insert: text },\n selection: EditorSelection.cursor(resited + text.length),\n userEvent: \"input.type\",\n scrollIntoView: true,\n };\n});\n"],"mappings":";AAgBA,SAAS,iBAAiB,mBAAqC;AAC/D,SAAS,cAAc;AAEvB,MAAM,qBAAqB,oBAAI,IAAI,CAAC,kBAAkB,YAAY,eAAe,CAAC;AAelF,SAAS,oBAAoB,OAAoB,KAAa,MAA+B;AAC3F,aAAS;AAGP,UAAM,OAAO,OAAO,OAAO,GAAG;AAC9B,QAAI,OAAO,KAAK,aAAa,KAAK,SAAS,QAAQ,KAAK,CAAC;AACzD,QAAI,QAAQ;AACZ,WAAO,MAAM,OAAO,KAAK,QAAQ;AAC/B,UAAI,CAAC,mBAAmB,IAAI,KAAK,IAAI,EAAG;AACxC,YAAM,OAAO,SAAS,QAAQ,KAAK,YAAY,KAAK;AACpD,YAAM,WAAW,SAAS,QAAQ,MAAM,OAAO,MAAM;AACrD,UAAI,aAAa,KAAK;AACpB,cAAM,SAAS,QAAQ,KAAK,KAAK,KAAK;AACtC,gBAAQ;AACR;AAAA,MACF;AAAA,IACF;AACA,QAAI,CAAC,MAAO,QAAO;AAAA,EACrB;AACF;AAEO,MAAM,gBAAgB,YAAY,kBAAkB,GAAG,CAAC,OAAoB;AACjF,MAAI,CAAC,GAAG,cAAc,CAAC,GAAG,YAAY,YAAY,KAAK,GAAG,YAAY,oBAAoB,GAAG;AAC3F,WAAO;AAAA,EACT;AAEA,MAAI,YAAmD;AACvD,MAAI,WAAW;AACf,KAAG,QAAQ,YAAY,CAAC,OAAO,KAAK,QAAQ,MAAM,aAAa;AAC7D,QAAI,aAAa,UAAU,OAAO,CAAC,QAAQ,KAAK,SAAS,SAAS,CAAC,EAAG,YAAW;AAAA,QAC5E,aAAY,EAAE,MAAM,OAAO,MAAM,SAAS,SAAS,EAAE;AAAA,EAC5D,CAAC;AACD,MAAI,CAAC,YAAY,CAAC,UAAW,QAAO;AACpC,QAAM,EAAE,MAAM,KAAK,IAAI;AAEvB,QAAM,MAAM,oBAAoB,GAAG,YAAY,MAAM,KAAK;AAC1D,QAAM,UAAU,QAAQ,OAAO,MAAM,oBAAoB,GAAG,YAAY,MAAM,OAAO;AACrF,MAAI,YAAY,KAAM,QAAO;AAE7B,SAAO;AAAA,IACL,SAAS,EAAE,MAAM,SAAS,QAAQ,KAAK;AAAA,IACvC,WAAW,gBAAgB,OAAO,UAAU,KAAK,MAAM;AAAA,IACvD,WAAW;AAAA,IACX,gBAAgB;AAAA,EAClB;AACF,CAAC;","names":[]}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { LinkAction, clickModel, linkActionAt, linkUrlAt, navigateToFacet, wikilinkTargetAt } from './clickModel.js';
|
|
2
|
+
export { cursorModelKeymap, cursorVisibleCharLeft, cursorVisibleCharRight, selectVisibleCharLeft, selectVisibleCharRight } from './cursorModel.js';
|
|
3
|
+
export { blockPrefixLength, deleteNormalizerKeymap, visibleBackspace, visibleDeleteForward } from './deleteNormalizer.js';
|
|
4
|
+
export { flankingGuard } from './flankingGuard.js';
|
|
5
|
+
export { nextVisiblePosition, previousVisiblePosition, visibleCharAfter, visibleCharBefore } from './visiblePosition.js';
|
|
6
|
+
import '@codemirror/state';
|
|
7
|
+
import '@codemirror/view';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/codemirror/interaction/index.ts"],"sourcesContent":["/**\n * Caret, click, and delete invariants of Rich Edit Mode (the interaction\n * spec): the caret never lands inside hidden markup, backspace deletes\n * visible content first, clicks resolve to visible positions, and typed\n * whitespace can't dissolve emphasis.\n */\nexport * from \"./clickModel\";\nexport * from \"./cursorModel\";\nexport * from \"./deleteNormalizer\";\nexport * from \"./flankingGuard\";\nexport * from \"./visiblePosition\";\n"],"mappings":"AAMA,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;","names":[]}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { EditorView } from '@codemirror/view';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Visible-position navigation across hidden, atomic ranges.
|
|
5
|
+
*
|
|
6
|
+
* In Rich Edit Mode the caret may never land *inside* an atomic range — a
|
|
7
|
+
* hidden inline marker (`**`, `[`, `` ` ``, …) or a whole table's `| … |` block
|
|
8
|
+
* source. These helpers return the next / previous position that sits outside
|
|
9
|
+
* every atomic range, so the arrow keys and the delete normalizer step *over* a
|
|
10
|
+
* table the same way they step over an inline marker instead of walking into
|
|
11
|
+
* its hidden source.
|
|
12
|
+
*
|
|
13
|
+
* Two atomic sources are consulted together: the decoration plugin's inline
|
|
14
|
+
* ranges and the table field's block ranges. (The table also registers with
|
|
15
|
+
* CM6's `EditorView.atomicRanges` facet, but that only governs CM6's *default*
|
|
16
|
+
* commands — our `Prec.high` arrow/delete handlers run instead, so they have to
|
|
17
|
+
* consult the table themselves or they march straight through the grid source.)
|
|
18
|
+
*
|
|
19
|
+
* "Inside" is strict: a position at a range's `from` or `to` is a boundary the
|
|
20
|
+
* caret may rest on, not inside it.
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* The visible grapheme immediately before/after `pos` as a deletable source
|
|
25
|
+
* range, skipping any hidden markers between it and the caret — or null at the
|
|
26
|
+
* document edge. Unlike {@link previousVisiblePosition} (a caret MOTION stop),
|
|
27
|
+
* this never folds a marker into the range: deleting it removes exactly one
|
|
28
|
+
* visible character, so `**Compose**` backspaced from either side of its
|
|
29
|
+
* hidden closing `**` becomes `**Compos**`, never raw `**Compos`. A newline
|
|
30
|
+
* counts as the adjacent char — callers treat that as a line-join.
|
|
31
|
+
*/
|
|
32
|
+
declare function visibleCharBefore(view: EditorView, pos: number): {
|
|
33
|
+
from: number;
|
|
34
|
+
to: number;
|
|
35
|
+
} | null;
|
|
36
|
+
declare function visibleCharAfter(view: EditorView, pos: number): {
|
|
37
|
+
from: number;
|
|
38
|
+
to: number;
|
|
39
|
+
} | null;
|
|
40
|
+
declare function previousVisiblePosition(view: EditorView, pos: number): number;
|
|
41
|
+
declare function nextVisiblePosition(view: EditorView, pos: number): number;
|
|
42
|
+
|
|
43
|
+
export { nextVisiblePosition, previousVisiblePosition, visibleCharAfter, visibleCharBefore };
|