@gt-editor/markdown-editor 0.1.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/dist/index.cjs +24 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +153 -0
- package/dist/index.js +3094 -0
- package/dist/index.js.map +1 -0
- package/dist/markdown-editor.css +1 -0
- package/package.json +42 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.cjs","sources":["../src/theme.ts","../src/plugins/collapsibleFold.ts","../src/widgets/HiddenWidget.ts","../src/widgets/HorizontalRuleWidget.ts","../src/widgets/ImageWidget.ts","../src/widgets/BulletWidget.ts","../src/widgets/CollapsibleHeaderWidget.ts","../src/widgets/CollapsibleArrowWidget.ts","../src/plugins/markdownSyntax.ts","../src/plugins/imageField.ts","../src/plugins/clipboard.ts","../src/plugins/wrapSelection.ts","../src/plugins/imagePaste.ts","../src/plugins/foldState.ts","../src/widgets/IncludeLinkWidget.ts","../src/plugins/includeLink.ts","../src/plugins/contextMenu.ts","../src/plugins/hangingIndent.ts","../src/plugins/headerClick.ts","../src/plugins/gutterClick.ts","../src/plugins/collapsibleGutter.ts","../src/plugins/collapsibleArrow.ts","../src/plugins/collapsibleScopePlugin.ts","../src/plugins/fullLineSelection.ts","../src/plugins/wordSelection.ts","../src/plugins/blockMove.ts","../src/plugins/tabIndent.ts","../src/plugins/emojiHoverTooltip.ts","../src/Editor.tsx"],"sourcesContent":["import { EditorView } from '@codemirror/view'\n\n// Dark theme\nexport const createDarkTheme = (fontSize = 14, contentPaddingX = 16, contentPaddingY = 16) =>\n EditorView.theme(\n {\n '&': {\n backgroundColor: '#1e1e2e',\n color: '#e8e8e8',\n height: '100%'\n },\n '.cm-content': {\n fontFamily: '\"SF Mono\", \"Fira Code\", monospace',\n fontSize: `${fontSize}px`,\n lineHeight: '1.6',\n padding: `${contentPaddingY}px ${contentPaddingX}px`\n },\n '.cm-cursor': {\n borderLeftColor: '#f5e0dc'\n },\n // Secondary cursors (multi-cursor mode)\n '.cm-cursor-secondary': {\n borderLeftColor: '#f5e0dc'\n },\n // Secondary selection (multi-cursor mode)\n '&.cm-focused .cm-selectionBackground-secondary, .cm-selectionBackground-secondary': {\n backgroundColor: 'rgba(69, 71, 90, 0.7)'\n },\n '.cm-activeLine': {\n backgroundColor: 'rgba(255, 255, 255, 0.02)',\n boxShadow: 'inset 0 1px 0 0 rgba(255, 255, 255, 0.08), inset 0 -1px 0 0 rgba(255, 255, 255, 0.08)'\n },\n '.cm-activeLineGutter': {\n backgroundColor: 'rgba(255, 255, 255, 0.02)',\n color: '#e8e8e8',\n boxShadow: 'inset 0 1px 0 0 rgba(255, 255, 255, 0.08), inset 0 -1px 0 0 rgba(255, 255, 255, 0.08)'\n },\n '.cm-selectionBackground, &.cm-focused .cm-selectionBackground': {\n backgroundColor: 'rgba(137, 180, 250, 0.35) !important' // Синий, с !important\n },\n '.cm-selectionMatch': {\n backgroundColor: 'rgba(137, 180, 250, 0.25)',\n borderRadius: '2px'\n },\n '.cm-gutters': {\n backgroundColor: '#1e1e2e',\n color: '#6c7086',\n border: 'none',\n paddingRight: '8px',\n fontSize: `${fontSize}px`,\n fontFamily: '\"SF Mono\", \"Fira Code\", monospace',\n position: 'relative'\n },\n // foldGutter накладывается поверх контента справа от номеров\n '& .cm-foldGutter': {\n position: 'absolute',\n right: '-24px', // Выносим за пределы gutters в область контента\n top: '0',\n width: '24px',\n zIndex: '5',\n backgroundColor: 'transparent'\n },\n '.cm-hidden-markup': {\n visibility: 'hidden'\n },\n '.cm-panels': {\n backgroundColor: '#181825',\n borderBottom: '1px solid #45475a'\n },\n '.cm-panels input, .cm-panels button': {\n color: '#cdd6f4'\n },\n '.cm-searchMatch': {\n backgroundColor: 'rgba(249, 226, 175, 0.3)',\n borderRadius: '2px'\n },\n '.cm-searchMatch.cm-searchMatch-selected': {\n backgroundColor: 'rgba(249, 226, 175, 0.5)'\n },\n // Markdown styles\n '.cm-md-bold': {\n color: '#ffa348',\n fontWeight: 'bold'\n },\n '.cm-md-italic': {\n color: '#69dbdb',\n fontStyle: 'italic'\n },\n '.cm-md-strike': {\n color: '#868e96',\n textDecoration: 'line-through'\n },\n '.cm-md-code': {\n color: '#50fa7b',\n backgroundColor: 'rgba(80, 80, 80, 0.4)',\n borderRadius: '3px',\n padding: '1px 4px'\n },\n '.cm-md-link': {\n color: '#89b4fa',\n textDecoration: 'underline',\n cursor: 'pointer'\n },\n '.cm-md-heading': {\n fontWeight: 'bold'\n },\n // Color only at line level (fontSize moved to mark-level to preserve ch units)\n '.cm-md-h1': { color: '#c678dd' },\n '.cm-md-h2': { color: '#b197fc' },\n '.cm-md-h3': { color: '#a78bfa' },\n '.cm-md-h4': { color: '#9775fa' },\n '.cm-md-h5': { color: '#8b5cf6' },\n '.cm-md-h6': { color: '#7c3aed' },\n\n // Heading tags [logs], [links], [deprecated] — override heading level color\n '.cm-heading-tag-logs': { color: '#f5a3bb !important' },\n '.cm-heading-tag-links': { color: '#74c7ec !important' },\n '.cm-heading-tag-deprecated': { color: '#fab387 !important' },\n\n // Font-size on inline mark (span), not on .cm-line — keeps ch unit stable for indent guides\n '.cm-heading-size-1': { fontSize: '1.5em' },\n '.cm-heading-size-2': { fontSize: '1.3em' },\n '.cm-heading-size-3': { fontSize: '1.15em' },\n '.cm-heading-size-4': { fontSize: '1.1em' },\n '.cm-md-markup': {\n color: '#6c7086'\n },\n '.cm-md-heading-muted': {\n color: '#9595c8',\n fontWeight: 'normal'\n },\n // List styles — жёлтый\n '.cm-list-bullet': {\n color: '#f9e2af'\n },\n '.cm-md-list-marker': {\n color: '#f9e2af'\n },\n // Image styles\n '.cm-image-container': {\n display: 'block',\n marginTop: '0',\n marginBottom: '0'\n },\n '.cm-image-widget': {\n maxWidth: '100%',\n borderRadius: '4px',\n cursor: 'pointer'\n },\n // Border when image is active - use outline (doesn't affect layout)\n '.cm-image-active .cm-image-widget': {\n outline: '2px solid #89b4fa',\n outlineOffset: '2px'\n },\n // Muted markdown syntax for image (when active)\n '.cm-md-image-syntax': {\n opacity: 0.5\n },\n // Hidden markdown syntax for image (when not active) - preserves height\n '.cm-md-image-hidden': {\n visibility: 'hidden'\n },\n '.cm-md-image-line': {\n whiteSpace: 'nowrap',\n overflow: 'hidden',\n maxHeight: '1.6em'\n },\n '.cm-image-error': {\n color: '#f38ba8',\n fontStyle: 'italic',\n fontSize: '0.9em'\n },\n // Collapsible section styles (base style, can be overridden by headings/inline)\n '.cm-collapsible-header': {\n color: '#cdd6f4' // белый по умолчанию, не синий\n },\n // Headings inside collapsible override base color\n '.cm-collapsible-header.cm-md-h1': { color: '#c678dd' },\n '.cm-collapsible-header.cm-md-h2': { color: '#b197fc' },\n '.cm-collapsible-header.cm-md-h3': { color: '#a78bfa' },\n '.cm-collapsible-header.cm-md-h4': { color: '#9775fa' },\n '.cm-collapsible-header.cm-md-h5': { color: '#8b5cf6' },\n '.cm-collapsible-header.cm-md-h6': { color: '#7c3aed' },\n // Inline styles inside collapsible should override base color\n '.cm-collapsible-header .cm-md-bold': {\n color: '#ffa348'\n },\n '.cm-collapsible-header .cm-md-italic': {\n color: '#69dbdb'\n },\n '.cm-collapsible-header .cm-md-code': {\n color: '#50fa7b'\n },\n '.cm-collapsible-header .cm-md-strike': {\n color: '#868e96'\n },\n // Цвет стрелки теперь определяется в JavaScript (CollapsibleArrowWidget)\n '.cm-collapsible-marker': {\n display: 'none' // Hidden, button is now in gutter\n },\n // Fold marker - белый по умолчанию, больше\n '& .cm-fold-marker': {\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n height: '100%',\n width: '100%',\n color: '#cdd6f4',\n fontSize: '20px',\n cursor: 'pointer',\n opacity: '0.6',\n transition: 'opacity 0.15s, color 0.15s'\n },\n '& .cm-fold-marker:hover': {\n opacity: '1',\n color: '#f38ba8'\n },\n '.cm-gutterElement': {\n transition: 'color 0.15s'\n },\n // Hover на номерах строк\n '.cm-lineNumbers .cm-gutterElement': {\n cursor: 'pointer'\n },\n '.cm-lineNumbers .cm-gutterElement:hover': {\n color: '#f38ba8'\n },\n // Placeholder for folded content\n '.cm-foldPlaceholder': {\n backgroundColor: 'rgba(137, 180, 250, 0.2)',\n border: '1px solid rgba(137, 180, 250, 0.4)',\n borderRadius: '4px',\n padding: '2px 12px',\n margin: '0 8px',\n color: '#89b4fa',\n fontSize: '0.9em',\n fontWeight: '500',\n cursor: 'pointer',\n verticalAlign: 'middle',\n display: 'inline-flex',\n alignItems: 'center',\n height: '1.4em'\n },\n // Unclosed formatting markers (warning)\n '.cm-md-unclosed': {\n backgroundColor: 'rgba(243, 139, 168, 0.25)',\n borderRadius: '2px'\n }\n },\n { dark: true }\n )\n","import { foldService } from '@codemirror/language'\n\n// Count visual indent (tabs = 4 spaces)\nfunction countIndent(text: string, tabSize = 4): number {\n let n = 0\n for (let i = 0; i < text.length; i++) {\n const code = text.charCodeAt(i)\n if (code === 9) n += tabSize - (n % tabSize) // Tab\n else if (code === 32) n++ // Space\n else break // Text started\n }\n return n\n}\n\n// Fold Service for collapsible sections (indentation-based)\n// Trigger: >> (expanded) or ^^ (collapsed) at line start\n// Boundary: first line with lesser or equal indent (ignoring trailing empty lines)\nexport const collapsibleFoldService = foldService.of((state, lineStart) => {\n const line = state.doc.lineAt(lineStart)\n const lineText = line.text\n const trimmed = lineText.trim()\n\n // Check if line is a header (starts with >> or ^^)\n if (!trimmed.startsWith('>>') && !trimmed.startsWith('^^')) return null\n\n // Base indent of header\n const baseIndent = countIndent(lineText)\n\n // Find end of block\n let lastContentLine: number | null = null // Last line with actual indented content\n let pendingEmptyLines = 0 // Count of empty lines after last content\n\n for (let i = line.number + 1; i <= state.doc.lines; i++) {\n const nextLine = state.doc.line(i)\n const nextText = nextLine.text\n\n // Empty lines - count them but don't commit yet\n if (nextText.trim() === '') {\n if (lastContentLine !== null) {\n pendingEmptyLines++\n }\n continue\n }\n\n const nextIndent = countIndent(nextText)\n\n // Блок продолжается, если:\n // 1. Строка не пустая и её отступ БОЛЬШЕ базового\n // 2. ИЛИ это пустая строка, НО за ней следует строка с отступом (обрабатывается циклом дальше)\n if (nextText.trim() !== '' && nextIndent > baseIndent) {\n lastContentLine = i\n pendingEmptyLines = 0\n } else if (nextText.trim() === '') {\n pendingEmptyLines++\n } else {\n // Нашли строку с таким же или меньшим отступом — всё, блок ГАРАНТИРОВАННО кончился\n break\n }\n }\n\n // Если нашли вложенные линии, возвращаем диапазон\n if (lastContentLine !== null) {\n return {\n from: line.to,\n to: state.doc.line(lastContentLine).to\n }\n }\n\n // Пустая секция — нечего сворачивать\n return null\n})\n","import { WidgetType } from '@codemirror/view'\n\nexport class HiddenWidget extends WidgetType {\n toDOM() {\n const span = document.createElement('span')\n span.className = 'cm-hidden-markup'\n return span\n }\n}\n","import { WidgetType } from '@codemirror/view'\n\nexport class HorizontalRuleWidget extends WidgetType {\n toDOM() {\n const hr = document.createElement('div')\n hr.className = 'cm-horizontal-rule'\n return hr\n }\n}\n","import { WidgetType } from '@codemirror/view'\n\nexport class ImageWidget extends WidgetType {\n constructor(\n readonly src: string,\n readonly alt: string,\n readonly width: number | null,\n readonly resolveImageUrl?: (src: string) => string,\n readonly isActive: boolean = false\n ) {\n super()\n }\n\n eq(other: ImageWidget) {\n return (\n other.src === this.src &&\n other.width === this.width\n )\n }\n\n updateDOM(dom: HTMLElement) {\n if (this.isActive) {\n dom.classList.add('cm-image-active')\n } else {\n dom.classList.remove('cm-image-active')\n }\n return true\n }\n\n toDOM() {\n const container = document.createElement('div')\n container.className = 'cm-image-container' + (this.isActive ? ' cm-image-active' : '')\n\n const img = document.createElement('img')\n const src = this.resolveImageUrl ? this.resolveImageUrl(this.src) : this.src\n\n img.src = src\n img.alt = this.alt\n img.className = 'cm-image-widget'\n\n if (this.width) {\n img.style.width = `${this.width}px`\n }\n\n img.onerror = () => {\n container.innerHTML = `<span class=\"cm-image-error\">Image not found: ${this.src}</span>`\n }\n\n container.appendChild(img)\n return container\n }\n\n ignoreEvent() {\n return false\n }\n}\n","import { WidgetType, EditorView } from '@codemirror/view'\n\nexport class BulletWidget extends WidgetType {\n private indent: string\n private hasChildren: boolean\n private view: EditorView\n private markerStart: number // position of `-` (after indent)\n private markerEnd: number // position after `- ` (text start)\n\n constructor(indent: string, hasChildren: boolean = false, view: EditorView, markerStart: number, markerEnd: number) {\n super()\n this.indent = indent\n this.hasChildren = hasChildren\n this.view = view\n this.markerStart = markerStart\n this.markerEnd = markerEnd\n }\n\n eq(other: BulletWidget) {\n return this.indent === other.indent && this.hasChildren === other.hasChildren\n }\n\n toDOM() {\n const span = document.createElement('span')\n span.className = `cm-list-bullet ${this.hasChildren ? 'has-children' : ''}`\n\n const indentSpan = document.createElement('span')\n indentSpan.className = 'bullet-indent'\n indentSpan.textContent = this.indent\n span.appendChild(indentSpan)\n\n const iconSpan = document.createElement('span')\n iconSpan.className = 'bullet-icon'\n iconSpan.textContent = '• '\n span.appendChild(iconSpan)\n\n span.addEventListener('mousedown', (e) => {\n e.preventDefault()\n e.stopPropagation()\n\n // Determine left vs right click position relative to bullet icon center\n const iconRect = iconSpan.getBoundingClientRect()\n const iconCenter = iconRect.left + iconRect.width / 2\n const clickedLeft = e.clientX < iconCenter\n\n // Click on indent area or left of bullet → before the dash\n // Click on right of bullet → after `- ` (text start)\n const pos = clickedLeft ? this.markerStart : this.markerEnd\n this.view.dispatch({ selection: { anchor: pos } })\n this.view.focus()\n })\n\n return span\n }\n\n ignoreEvent() { return true }\n}\n","import { WidgetType } from '@codemirror/view'\n\nexport class CollapsibleHeaderWidget extends WidgetType {\n private indent: string\n\n constructor(indent: string = '') {\n super()\n this.indent = indent\n }\n\n toDOM() {\n const span = document.createElement('span')\n span.className = 'cm-collapsible-marker'\n\n // Preserve indent before the marker\n if (this.indent) {\n const indentSpan = document.createElement('span')\n indentSpan.textContent = this.indent\n span.appendChild(indentSpan)\n }\n\n return span\n }\n\n eq(other: CollapsibleHeaderWidget) {\n return this.indent === other.indent\n }\n}\n","import { WidgetType, EditorView } from '@codemirror/view'\nimport { foldedRanges, foldEffect, unfoldEffect, foldable } from '@codemirror/language'\n\n/**\n * Виджет стрелки сворачивания для collapsible секций (>>)\n * Отображается inline с учётом отступа строки\n */\n// Цвета для разных типов форматирования\nconst FORMAT_COLORS: Record<string, string> = {\n bold: '#ffa348',\n italic: '#69dbdb',\n code: '#50fa7b',\n strike: '#868e96',\n // Заголовки — фиолетовые оттенки\n h1: '#c678dd',\n h2: '#b197fc',\n h3: '#a78bfa',\n h4: '#9775fa',\n h5: '#8b5cf6',\n h6: '#7c3aed'\n}\n\nexport class CollapsibleArrowWidget extends WidgetType {\n constructor(\n readonly indent: string,\n readonly isOpen: boolean,\n readonly isEmpty: boolean,\n readonly lineFrom: number,\n readonly formatType: string | null = null, // 'bold', 'italic', 'code', 'strike'\n readonly view: EditorView | null = null\n ) {\n super()\n }\n\n toDOM() {\n const arrow = document.createElement('span')\n arrow.className = `cm-collapsible-arrow ${this.isOpen ? 'open' : 'closed'}${this.isEmpty ? ' empty' : ''}`\n arrow.textContent = this.isOpen ? '▾' : '▸'\n arrow.dataset.lineFrom = String(this.lineFrom)\n\n // Применяем цвет на основе форматирования\n if (this.formatType && FORMAT_COLORS[this.formatType]) {\n arrow.style.color = FORMAT_COLORS[this.formatType]\n }\n\n // Handle click directly in widget (events don't bubble to domEventHandlers from widgets)\n arrow.addEventListener('click', (e) => {\n e.preventDefault()\n e.stopPropagation()\n\n if (this.isEmpty || !this.view) return\n\n const line = this.view.state.doc.lineAt(this.lineFrom)\n const range = foldable(this.view.state, line.from, line.to)\n if (!range || (range.to - range.from) <= 2) return\n\n let foldedRange: { from: number; to: number } | null = null\n foldedRanges(this.view.state).between(line.from, line.to, (from, to) => {\n foldedRange = { from, to }\n })\n\n if (foldedRange) {\n const markerChange = this.createMarkerChange(line, '^^', '>>')\n this.view.dispatch({\n effects: unfoldEffect.of(foldedRange),\n changes: markerChange ? [markerChange] : undefined\n })\n } else {\n const markerChange = this.createMarkerChange(line, '>>', '^^')\n this.view.dispatch({\n effects: foldEffect.of(range),\n changes: markerChange ? [markerChange] : undefined\n })\n }\n })\n\n // FIX: Prevent selection on mousedown\n arrow.addEventListener('mousedown', (e) => {\n e.preventDefault()\n e.stopPropagation()\n })\n\n return arrow\n }\n\n eq(other: CollapsibleArrowWidget) {\n return this.indent === other.indent &&\n this.isOpen === other.isOpen &&\n this.isEmpty === other.isEmpty &&\n this.lineFrom === other.lineFrom &&\n this.formatType === other.formatType &&\n this.view === other.view\n }\n\n /**\n * Create a text change to replace marker (>> <-> ^^)\n */\n private createMarkerChange(line: { from: number; text: string }, fromMarker: string, toMarker: string) {\n const markerIndex = line.text.indexOf(fromMarker)\n if (markerIndex === -1) return null\n\n return {\n from: line.from + markerIndex,\n to: line.from + markerIndex + fromMarker.length,\n insert: toMarker\n }\n }\n\n ignoreEvent(event: Event) {\n // Игнорируем события мыши, чтобы CM не пытался ставить курсор или выделять\n // Но клики всё равно пройдут через глобальный handler, так как они всплывают\n if (event.type === 'mousedown' || event.type === 'click' || event.type === 'dblclick') {\n return true\n }\n return false\n }\n}\n","import { ViewPlugin, ViewUpdate, Decoration, DecorationSet, EditorView } from '@codemirror/view'\nimport { EditorSelection } from '@codemirror/state'\nimport {\n HiddenWidget,\n BulletWidget,\n CollapsibleHeaderWidget\n} from '../widgets'\n\nconst inlinePatterns = [\n // Bold: только ** (не __)\n { regex: /\\*\\*(.+?)\\*\\*/g, class: 'cm-md-bold', startLen: 2, endLen: 2 },\n // Italic: только * (не _)\n { regex: /(?<!\\*)\\*(.+?)\\*(?!\\*)/g, class: 'cm-md-italic', startLen: 1, endLen: 1 },\n { regex: /~~(.+?)~~/g, class: 'cm-md-strike', startLen: 2, endLen: 2 },\n { regex: /`([^`]*)`/g, class: 'cm-md-code', startLen: 1, endLen: 1 },\n]\n\nconst headingPattern = /^(\\s*)(#{1,6})\\s*(.+)$/\nconst headingTagPattern = /\\[(\\w+)\\]\\s*$/\n\n// Heading tag → CSS class mapping (case-insensitive)\nconst HEADING_TAG_MAP: Record<string, string> = {\n logs: 'cm-heading-tag-logs',\n log: 'cm-heading-tag-logs',\n data: 'cm-heading-tag-logs',\n links: 'cm-heading-tag-links',\n link: 'cm-heading-tag-links',\n sources: 'cm-heading-tag-links',\n source: 'cm-heading-tag-links',\n deprecated: 'cm-heading-tag-deprecated',\n old: 'cm-heading-tag-deprecated',\n obsolete: 'cm-heading-tag-deprecated',\n}\nconst horizontalRulePattern = /^-{3,}$/\nconst horizontalRuleWithIndentPattern = /^(\\s*)(-{3,})$/\nconst codeBlockStartPattern = /^```[\\w-]*$/\nconst codeBlockEndPattern = /^```$/\nconst unorderedListPattern = /^(\\s*)([*+-])\\s+/ \nconst orderedListPattern = /^(\\s*)(\\d+\\.)\\s+/ \n// >> = expanded, ^^ = collapsed\nconst collapsiblePattern = /^(\\s*)(>>|\\^\\^)\\s*(.*)$/\nconst linkPattern = /\\[([^\\]]+)\\]\\(([^)]+)\\)/g\n\nexport interface MarkdownSyntaxConfig {\n resolveImageUrl?: (src: string) => string\n}\n\nfunction getIndent(text: string): number {\n const match = text.match(/^(\\s*)/)\n const indentText = match ? match[0] : ''\n return Math.floor(indentText.replace(/\\t/g, ' ').length / 4)\n}\n\nexport function createMarkdownSyntaxPlugin(config: MarkdownSyntaxConfig = {}) {\n return ViewPlugin.fromClass(\n class {\n decorations: DecorationSet\n\n constructor(view: EditorView) {\n try {\n this.decorations = this.buildDecorations(view)\n } catch (e) {\n console.error('[MarkdownSyntax] constructor failed:', e instanceof Error ? e.message : e, {\n docLength: view.state.doc.length, docLines: view.state.doc.lines\n })\n this.decorations = Decoration.none\n }\n }\n\n update(update: ViewUpdate) {\n if (update.docChanged || update.viewportChanged || update.selectionSet || update.focusChanged) {\n try {\n this.decorations = this.buildDecorations(update.view)\n } catch (e) {\n console.error('[MarkdownSyntax] buildDecorations failed:', e instanceof Error ? e.message : e, {\n docChanged: update.docChanged, docLength: update.state.doc.length, docLines: update.state.doc.lines\n })\n if (update.docChanged) {\n // CRITICAL: old decorations reference old doc positions — must remap or clear\n try {\n this.decorations = this.decorations.map(update.changes)\n } catch {\n this.decorations = Decoration.none\n }\n }\n // else: doc unchanged, old positions are still valid — keep previous decorations\n }\n }\n }\n\n buildDecorations(view: EditorView): DecorationSet {\n const decorations: { from: number; to?: number; decoration: Decoration }[] = []\n const doc = view.state.doc\n let inCodeBlock = false\n // Track unclosed marker positions: position → marker length (decorations added after multiline pass)\n const unclosedPositions = new Map<number, number>()\n // All ranges matched by single-line inline patterns (protected from multiline stealing)\n const singleLineMatchedRanges: Array<{from: number, to: number}> = []\n \n // Предварительный расчет отступов для пустых строк\n const lineIndents = new Array(doc.lines + 1).fill(0)\n for (let i = 1; i <= doc.lines; i++) {\n const text = doc.line(i).text\n if (text.trim() !== '') {\n lineIndents[i] = getIndent(text)\n }\n }\n \n // Заполняем \"дыры\" (пустые строки) отступом предыдущей значимой строки\n let lastKnownIndent = 0\n for (let i = 1; i <= doc.lines; i++) {\n const text = doc.line(i).text\n if (text.trim() === '') {\n // Ищем следующий ненулевой отступ, чтобы понять, находимся ли мы внутри блока\n let nextIndent = 0\n for(let j = i + 1; j <= Math.min(i + 5, doc.lines); j++) {\n if (doc.line(j).text.trim() !== '') {\n nextIndent = lineIndents[j]\n break\n }\n }\n lineIndents[i] = Math.min(lastKnownIndent, nextIndent)\n } else {\n lastKnownIndent = lineIndents[i]\n }\n }\n\n // Get active lines only if editor has focus (preview mode when blurred)\n const activeLines = new Set<number>()\n if (view.hasFocus) {\n for (const range of view.state.selection.ranges) {\n const startLine = doc.lineAt(range.from).number\n const endLine = doc.lineAt(range.to).number\n for (let i = startLine; i <= endLine; i++) {\n activeLines.add(i)\n }\n }\n }\n\n for (let i = 1; i <= doc.lines; i++) {\n const line = doc.line(i)\n const lineText = line.text\n const isActiveLine = activeLines.has(i)\n const indentLevel = lineIndents[i]\n const clampedIndent = Math.min(indentLevel, 6)\n const indentClass = clampedIndent > 0 ? ` cm-indent-L${clampedIndent}` : ''\n\n const trimmedText = lineText.trim()\n\n // Code blocks\n if (inCodeBlock && codeBlockEndPattern.test(trimmedText)) {\n inCodeBlock = false\n decorations.push({ from: line.from, decoration: Decoration.line({ class: 'cm-code-block-line cm-code-block-end' + indentClass }) })\n continue\n }\n if (!inCodeBlock && codeBlockStartPattern.test(trimmedText)) {\n inCodeBlock = true\n decorations.push({ from: line.from, decoration: Decoration.line({ class: 'cm-code-block-line cm-code-block-start' + indentClass }) })\n continue\n }\n if (inCodeBlock) {\n decorations.push({ from: line.from, decoration: Decoration.line({ class: 'cm-code-block-line' + indentClass }) })\n continue\n }\n\n // Headings (with optional indent)\n const headingMatch = lineText.match(headingPattern)\n if (headingMatch) {\n const indentLen = headingMatch[1].length\n const level = headingMatch[2].length\n const hashStart = indentLen\n const hashLen = level + (lineText.charAt(hashStart + level) === ' ' ? 1 : 0)\n // Check for [tag] at end of heading text\n const headingText = headingMatch[3]\n const tagMatch = headingText.match(headingTagPattern)\n const tagClass = tagMatch ? HEADING_TAG_MAP[tagMatch[1].toLowerCase()] || '' : ''\n decorations.push({ from: line.from, decoration: Decoration.line({ class: `cm-md-heading cm-md-h${level}${indentClass}${tagClass ? ' ' + tagClass : ''}` }) })\n if (!isActiveLine && hashLen > 0) {\n // Hide only the hashes (and space), keep indent visible\n decorations.push({ from: line.from + hashStart, to: line.from + hashStart + hashLen, decoration: Decoration.replace({ widget: new HiddenWidget() }) })\n // Font-size mark starts AFTER hidden range to avoid overlap conflict\n if (level <= 4 && line.from + hashStart + hashLen < line.to) {\n decorations.push({ from: line.from + hashStart + hashLen, to: line.to, decoration: Decoration.mark({ class: `cm-heading-size-${level}` }) })\n }\n } else if (level <= 4) {\n // Active line: # visible, mark covers everything from # to end\n decorations.push({ from: line.from + hashStart, to: line.to, decoration: Decoration.mark({ class: `cm-heading-size-${level}` }) })\n }\n continue\n }\n\n // Horizontal rule (с учётом отступа)\n const hrMatch = lineText.match(horizontalRuleWithIndentPattern)\n if (hrMatch) {\n const hrIndentLen = hrMatch[1].length // Длина отступа\n const hrLen = hrMatch[2].length // Длина '---'\n\n decorations.push({ from: line.from, decoration: Decoration.line({ class: 'cm-hr-line' + indentClass }) })\n if (!isActiveLine) {\n // ВАЖНО: скрываем ТОЛЬКО '---', оставляя отступ видимым в DOM\n const hrStart = line.from + hrIndentLen\n const hrEnd = hrStart + hrLen\n decorations.push({ from: hrStart, to: hrEnd, decoration: Decoration.mark({ class: 'cm-hr-text-hidden' }) })\n }\n continue\n }\n\n // Lists\n const ulMatch = lineText.match(unorderedListPattern)\n const olMatch = lineText.match(orderedListPattern)\n const collapsibleMatch = lineText.match(collapsiblePattern)\n\n if (ulMatch) {\n const [fullMatch, indentStr] = ulMatch\n const markerStart = line.from + indentStr.length\n const markerEnd = line.from + indentStr.length + (fullMatch.length - indentStr.length)\n decorations.push({ from: line.from, decoration: Decoration.line({ class: 'cm-list-line' + indentClass }) })\n if (!isActiveLine) {\n decorations.push({ from: line.from, to: markerEnd, decoration: Decoration.replace({ widget: new BulletWidget(indentStr, false, view, markerStart, markerEnd) }) })\n }\n } else if (olMatch) {\n decorations.push({ from: line.from, decoration: Decoration.line({ class: 'cm-list-line' + indentClass }) })\n } else if (collapsibleMatch) {\n // collapsibleMatch: [1]=indent, [2]=marker (>> or ^^), [3]=content\n const markerPos = collapsibleMatch[1].length // position after indent\n const markerLen = 2 // >> or ^^\n const contentStart = markerPos + markerLen + (lineText.charAt(markerPos + markerLen) === ' ' ? 1 : 0)\n const collapsibleContent = collapsibleMatch[3] || ''\n\n // Проверяем есть ли заголовок внутри collapsible (>> # Header)\n const innerHeadingMatch = collapsibleContent.match(/^(#{1,6})\\s*(.+)$/)\n if (innerHeadingMatch) {\n const level = innerHeadingMatch[1].length\n const innerTagMatch = innerHeadingMatch[2].match(headingTagPattern)\n const innerTagClass = innerTagMatch ? HEADING_TAG_MAP[innerTagMatch[1].toLowerCase()] || '' : ''\n decorations.push({ from: line.from, decoration: Decoration.line({ class: `cm-collapsible-header cm-md-heading cm-md-h${level}${indentClass}${innerTagClass ? ' ' + innerTagClass : ''}` }) })\n // Скрываем хэши заголовка если строка не активна\n if (!isActiveLine) {\n const hashLen = level + (collapsibleContent.charAt(level) === ' ' ? 1 : 0)\n decorations.push({ from: line.from + contentStart, to: line.from + contentStart + hashLen, decoration: Decoration.replace({ widget: new HiddenWidget() }) })\n // Font-size mark starts AFTER hidden range to avoid overlap conflict\n if (level <= 4 && line.from + contentStart + hashLen < line.to) {\n decorations.push({ from: line.from + contentStart + hashLen, to: line.to, decoration: Decoration.mark({ class: `cm-heading-size-${level}` }) })\n }\n } else if (level <= 4) {\n // Active line: # visible, mark covers everything from # to end\n decorations.push({ from: line.from + contentStart, to: line.to, decoration: Decoration.mark({ class: `cm-heading-size-${level}` }) })\n }\n } else {\n decorations.push({ from: line.from, decoration: Decoration.line({ class: 'cm-collapsible-header' + indentClass }) })\n // НЕ скрываем >> — это делает collapsibleArrowPlugin\n }\n } else {\n // Обычная строка или пустая строка\n const finalClass = (indentClass).trim()\n if (finalClass) {\n decorations.push({ from: line.from, decoration: Decoration.line({ class: finalClass }) })\n }\n }\n\n // Inline markup (только если не заголовок и не HR)\n if (!headingMatch && !horizontalRulePattern.test(trimmedText)) {\n // Для collapsible — ищем inline только в контенте после >> или ^^\n let searchText = lineText\n let searchOffset = 0\n if (collapsibleMatch) {\n const markerPos = collapsibleMatch[1].length\n const markerEnd = markerPos + 2 // >> or ^^\n const contentStart = lineText.charAt(markerEnd) === ' ' ? markerEnd + 1 : markerEnd\n searchText = lineText.substring(contentStart)\n searchOffset = contentStart\n }\n\n // Собираем успешные диапазоны для проверки unclosed\n const matchedRanges: Array<{from: number, to: number}> = []\n\n for (const pattern of inlinePatterns) {\n const regex = new RegExp(pattern.regex.source, 'g')\n let match\n while ((match = regex.exec(searchText)) !== null) {\n const startOffset = line.from + searchOffset + match.index\n const endOffset = startOffset + match[0].length\n // Skip if this match overlaps with an already-matched range\n // (e.g. italic regex matching **bold** that was already handled by bold regex)\n if (matchedRanges.some(r => startOffset < r.to && endOffset > r.from)) continue\n const contentStart = startOffset + pattern.startLen\n const contentEnd = endOffset - pattern.endLen\n decorations.push({ from: contentStart, to: contentEnd, decoration: Decoration.mark({ class: pattern.class }) })\n matchedRanges.push({ from: startOffset, to: endOffset })\n singleLineMatchedRanges.push({ from: startOffset, to: endOffset })\n if (!isActiveLine) {\n decorations.push({ from: startOffset, to: contentStart, decoration: Decoration.replace({ widget: new HiddenWidget() }) })\n decorations.push({ from: contentEnd, to: endOffset, decoration: Decoration.replace({ widget: new HiddenWidget() }) })\n }\n }\n }\n\n // Links: [text](url)\n const linkRegex = new RegExp(linkPattern.source, 'g')\n let linkMatch\n while ((linkMatch = linkRegex.exec(searchText)) !== null) {\n const fullMatch = linkMatch[0] // [text](url)\n const linkText = linkMatch[1] // text\n const startOffset = line.from + searchOffset + linkMatch.index\n const endOffset = startOffset + fullMatch.length\n const textStart = startOffset + 1 // after [\n const textEnd = textStart + linkText.length // before ]\n\n // Style the link text\n decorations.push({ from: textStart, to: textEnd, decoration: Decoration.mark({ class: 'cm-md-link' }) })\n matchedRanges.push({ from: startOffset, to: endOffset })\n singleLineMatchedRanges.push({ from: startOffset, to: endOffset })\n\n if (!isActiveLine) {\n // Hide [ before text\n decorations.push({ from: startOffset, to: textStart, decoration: Decoration.replace({ widget: new HiddenWidget() }) })\n // Hide ](url) after text\n decorations.push({ from: textEnd, to: endOffset, decoration: Decoration.replace({ widget: new HiddenWidget() }) })\n }\n }\n\n // Ищем unclosed маркеры (сироты) — маркеры которые не вошли в успешные пары\n // _ исключён — не участвует в форматировании\n const unclosedMarkers = ['**', '~~', '*', '`']\n for (const marker of unclosedMarkers) {\n const markerRegex = new RegExp(marker.replace(/[*]/g, '\\\\*').replace(/[`]/g, '\\\\`'), 'g')\n let match\n while ((match = markerRegex.exec(searchText)) !== null) {\n const absPos = line.from + searchOffset + match.index\n // Проверяем не входит ли в успешный диапазон\n const isMatched = matchedRanges.some(r => absPos >= r.from && absPos < r.to)\n if (!isMatched) {\n // Для одиночных * и _ — проверяем что не часть ** или __\n if (marker.length === 1) {\n const nextChar = searchText[match.index + 1]\n const prevChar = match.index > 0 ? searchText[match.index - 1] : ''\n if (nextChar === marker || prevChar === marker) continue\n }\n // Проверяем \"прилипание\" — должен быть рядом с текстом\n const afterChar = searchText[match.index + marker.length]\n const beforeChar = match.index > 0 ? searchText[match.index - 1] : ' '\n const isOpening = afterChar && afterChar !== ' ' && afterChar !== '\\t'\n const isClosing = beforeChar !== ' ' && beforeChar !== '\\t'\n if (isOpening || isClosing) {\n unclosedPositions.set(absPos, marker.length)\n }\n }\n }\n }\n }\n }\n\n // ========== MULTILINE FORMATTING ==========\n // Ищем форматирование через несколько строк (до 5)\n // _ исключён — не участвует в форматировании\n const multilineMarkers = [\n { marker: '**', class: 'cm-md-bold' },\n { marker: '~~', class: 'cm-md-strike' },\n { marker: '*', class: 'cm-md-italic' },\n { marker: '`', class: 'cm-md-code' },\n ]\n\n const maxMultilineLines = 5\n const usedRanges: Array<{from: number, to: number}> = [...singleLineMatchedRanges]\n\n // Собираем строки в code blocks для пропуска\n const codeBlockLines = new Set<number>()\n let inCB = false\n for (let i = 1; i <= doc.lines; i++) {\n const text = doc.line(i).text.trim()\n if (inCB && codeBlockEndPattern.test(text)) {\n codeBlockLines.add(i)\n inCB = false\n } else if (!inCB && codeBlockStartPattern.test(text)) {\n inCB = true\n codeBlockLines.add(i)\n } else if (inCB) {\n codeBlockLines.add(i)\n }\n }\n\n for (let lineNum = 1; lineNum <= doc.lines; lineNum++) {\n const line = doc.line(lineNum)\n const text = line.text\n\n // Пропускаем code blocks, пустые, headings, HR\n if (codeBlockLines.has(lineNum)) continue\n if (text.trim() === '') continue\n if (headingPattern.test(text)) continue\n if (horizontalRulePattern.test(text.trim())) continue\n\n for (let charIdx = 0; charIdx < text.length; charIdx++) {\n const absolutePos = line.from + charIdx\n\n // Пропускаем уже обработанные диапазоны\n if (usedRanges.some(r => absolutePos >= r.from && absolutePos < r.to)) continue\n\n for (const pattern of multilineMarkers) {\n const marker = pattern.marker\n\n // Проверяем что маркер начинается здесь\n if (text.substr(charIdx, marker.length) !== marker) continue\n\n // Для одиночных маркеров - не часть двойного\n if (marker.length === 1) {\n if (charIdx + 1 < text.length && text[charIdx + 1] === marker) continue\n if (charIdx > 0 && text[charIdx - 1] === marker) continue\n }\n\n // Проверяем \"прилипание\" - после маркера не пробел\n const afterIdx = charIdx + marker.length\n if (afterIdx >= text.length) continue\n const afterChar = text[afterIdx]\n if (afterChar === ' ' || afterChar === '\\t' || afterChar === '\\n') continue\n\n // Ищем закрывающий маркер - сначала на той же строке\n let closingOnSameLine = false\n for (let searchIdx = afterIdx; searchIdx <= text.length - marker.length; searchIdx++) {\n if (text.substr(searchIdx, marker.length) !== marker) continue\n\n // Для одиночных - не часть двойного\n if (marker.length === 1) {\n if (searchIdx + 1 < text.length && text[searchIdx + 1] === marker) continue\n if (searchIdx > 0 && text[searchIdx - 1] === marker) continue\n }\n\n // Прилипание - перед маркером не пробел\n if (searchIdx > 0 && (text[searchIdx - 1] === ' ' || text[searchIdx - 1] === '\\t')) continue\n\n // Don't steal closers from complete single-line pairs\n const closeAbsPos = line.from + searchIdx\n if (singleLineMatchedRanges.some(r => closeAbsPos >= r.from && closeAbsPos < r.to)) continue\n\n closingOnSameLine = true\n // Однострочное - уже обработано inlinePatterns\n usedRanges.push({ from: absolutePos, to: line.from + searchIdx + marker.length })\n break\n }\n\n if (closingOnSameLine) break\n\n // Ищем на следующих строках\n let closingInfo: { lineNum: number, charIdx: number, absolutePos: number } | null = null\n\n for (let searchLineNum = lineNum + 1; searchLineNum <= Math.min(lineNum + maxMultilineLines, doc.lines); searchLineNum++) {\n const searchLine = doc.line(searchLineNum)\n const searchText = searchLine.text\n\n // Пустая строка или code block - прекращаем\n if (searchText.trim() === '' || codeBlockLines.has(searchLineNum)) break\n\n for (let searchIdx = 0; searchIdx <= searchText.length - marker.length; searchIdx++) {\n if (searchText.substr(searchIdx, marker.length) !== marker) continue\n\n // Для одиночных - не часть двойного\n if (marker.length === 1) {\n if (searchIdx + 1 < searchText.length && searchText[searchIdx + 1] === marker) continue\n if (searchIdx > 0 && searchText[searchIdx - 1] === marker) continue\n }\n\n // Closing marker must be right-flanking (preceded by non-space text)\n // At position 0, nothing precedes — can't be a closer\n if (searchIdx === 0 || searchText[searchIdx - 1] === ' ' || searchText[searchIdx - 1] === '\\t') continue\n\n // Don't steal closers from complete single-line pairs\n const closeAbsPos = searchLine.from + searchIdx\n if (singleLineMatchedRanges.some(r => closeAbsPos >= r.from && closeAbsPos < r.to)) continue\n\n closingInfo = { lineNum: searchLineNum, charIdx: searchIdx, absolutePos: searchLine.from + searchIdx }\n break\n }\n\n if (closingInfo) break\n }\n\n if (closingInfo) {\n // Multiline match!\n const openStart = absolutePos\n const openEnd = absolutePos + marker.length\n const closeStart = closingInfo.absolutePos\n const closeEnd = closingInfo.absolutePos + marker.length\n\n // Декорация контента\n decorations.push({\n from: openEnd,\n to: closeStart,\n decoration: Decoration.mark({ class: pattern.class })\n })\n\n // Скрываем маркеры если строки не активны\n const openLineActive = activeLines.has(lineNum)\n const closeLineActive = activeLines.has(closingInfo.lineNum)\n\n if (!openLineActive) {\n decorations.push({\n from: openStart,\n to: openEnd,\n decoration: Decoration.replace({ widget: new HiddenWidget() })\n })\n }\n\n if (!closeLineActive) {\n decorations.push({\n from: closeStart,\n to: closeEnd,\n decoration: Decoration.replace({ widget: new HiddenWidget() })\n })\n }\n\n // Помечаем как использованное\n usedRanges.push({ from: openStart, to: closeEnd })\n break\n } else if (!closingOnSameLine) {\n // Record as unclosed (decoration added after multiline pass to avoid conflicts)\n // Don't push to usedRanges — break + charIdx++ prevent re-processing,\n // and usedRanges entry would block the final unclosed decoration check at line ~485\n unclosedPositions.set(absolutePos, marker.length)\n break\n }\n }\n }\n }\n\n // Add unclosed marker decorations AFTER multiline pass to avoid conflicts\n // Only mark positions that weren't matched by any pass (single-line or multiline)\n for (const [pos, len] of unclosedPositions) {\n const isMatched = usedRanges.some(r => pos >= r.from && pos < r.to)\n if (!isMatched) {\n decorations.push({\n from: pos,\n to: pos + len,\n decoration: Decoration.mark({ class: 'cm-md-unclosed' })\n })\n }\n }\n\n // Фильтруем невалидные декорации (from >= to для mark decorations, out of bounds)\n const docLength = doc.length\n const validDecorations = decorations.filter((d) => {\n if (d.to !== undefined && d.from >= d.to) return false\n if (d.from < 0 || d.from > docLength) return false\n if (d.to !== undefined && (d.to < 0 || d.to > docLength)) return false\n return true\n })\n\n // Build ranges for Decoration.set()\n const ranges = validDecorations.map((d) => (d.to ? d.decoration.range(d.from, d.to) : d.decoration.range(d.from)))\n\n // --- Diagnostic: detect conflicts before Decoration.set() ---\n // Sort a copy to find overlapping replace decorations at the same position\n const sorted = ranges.slice().sort((a, b) => a.from - b.from || a.value.startSide - b.value.startSide)\n for (let i = 1; i < sorted.length; i++) {\n const prev = sorted[i - 1]\n const curr = sorted[i]\n // Check: two replace decorations overlapping at the same from\n if (prev.from === curr.from && prev.to !== undefined && curr.to !== undefined) {\n const prevIsReplace = (prev.value as any).widget !== undefined && prev.from !== prev.to\n const currIsReplace = (curr.value as any).widget !== undefined && curr.from !== curr.to\n if (prevIsReplace && currIsReplace) {\n const lineInfo = doc.lineAt(curr.from)\n console.warn('[MarkdownSyntax] CONFLICT: overlapping replaces at same from', {\n pos: curr.from,\n line: lineInfo.number,\n lineText: lineInfo.text.substring(0, 80),\n prev: { from: prev.from, to: prev.to, startSide: prev.value.startSide },\n curr: { from: curr.from, to: curr.to, startSide: curr.value.startSide }\n })\n }\n }\n // Check: replace that fully contains another range\n if (prev.to !== undefined && curr.from < prev.to) {\n const prevIsReplace = (prev.value as any).widget !== undefined && prev.from !== prev.to\n const currIsReplace = (curr.value as any).widget !== undefined && curr.from !== curr.to\n if (prevIsReplace || currIsReplace) {\n const lineInfo = doc.lineAt(curr.from)\n console.warn('[MarkdownSyntax] CONFLICT: overlapping ranges (one is replace)', {\n pos: curr.from,\n line: lineInfo.number,\n lineText: lineInfo.text.substring(0, 80),\n prev: { from: prev.from, to: prev.to, isReplace: prevIsReplace },\n curr: { from: curr.from, to: curr.to, isReplace: currIsReplace }\n })\n }\n }\n }\n\n // Pass true to let CodeMirror sort decorations by from/startSide\n return Decoration.set(ranges, true)\n }\n },\n { decorations: (v) => v.decorations }\n )\n}\n\n/**\n * Fix cursor placement when clicking past the visual end of a line.\n *\n * Two problems solved:\n * 1. Hidden markup: `**текс**` concealed as `текс` — clicking past \"с\" should\n * place cursor at line.to (after `**`), not at contentEnd (before `**`).\n * 2. Last character skip: clicking in empty space past `текст:` sometimes places\n * cursor before `:` instead of after it.\n *\n * Approach: capture the visual x-coordinate of line.to BEFORE the line becomes\n * active (while markup is still hidden). After CM6 processes the click, if the\n * click was at/past that visual end and cursor isn't at line.to — snap it there.\n */\nexport function createConcealClickFix() {\n return EditorView.domEventHandlers({\n mousedown(event: MouseEvent, view: EditorView) {\n if (event.button !== 0 || event.shiftKey || event.ctrlKey || event.metaKey || event.altKey) return false\n\n const clickX = event.clientX\n const clickY = event.clientY\n\n const clickPos = view.posAtCoords({ x: clickX, y: clickY })\n if (clickPos === null) return false\n\n const line = view.state.doc.lineAt(clickPos)\n\n // coordsAtPos(line.to) returns NULL when line.to is at the edge of a\n // zero-width Decoration.replace (hidden **,~~,` etc). Walk backwards\n // to find the nearest position with valid visual coordinates.\n let endCoords: {left: number, top: number, bottom: number} | null = null\n for (let p = line.to; p >= Math.max(line.from, line.to - 8); p--) {\n endCoords = view.coordsAtPos(p) || view.coordsAtPos(p, -1)\n if (endCoords) break\n }\n if (!endCoords) return false\n\n setTimeout(() => {\n const sel = view.state.selection.main\n if (!sel.empty) return\n\n const pos = sel.head\n const currentLine = view.state.doc.lineAt(pos)\n if (pos === currentLine.to) return\n\n if (clickX >= endCoords!.left - 1 &&\n clickY >= endCoords!.top && clickY <= endCoords!.bottom) {\n view.dispatch({\n selection: EditorSelection.cursor(currentLine.to)\n })\n }\n }, 0)\n\n return false\n }\n })\n}","import { Decoration, DecorationSet, EditorView } from '@codemirror/view'\nimport { StateField, EditorState } from '@codemirror/state'\nimport { ImageWidget } from '../widgets/ImageWidget'\n\n// Pattern for images:  or \nconst imagePattern = /^!\\[([^\\]|]*)?(?:\\|(\\d+))?\\]\\(([^)]+)\\)$/\n\nexport interface ImageFieldConfig {\n resolveImageUrl?: (src: string) => string\n}\n\nexport const createImageField = (config: ImageFieldConfig = {}) => {\n return StateField.define<DecorationSet>({\n create(state) {\n return buildImageDecorations(state, config)\n },\n update(decorations, tr) {\n // Update only if document or selection changed\n if (tr.docChanged || tr.selection) {\n return buildImageDecorations(tr.state, config)\n }\n return decorations\n },\n provide: (field) => EditorView.decorations.from(field)\n })\n}\n\nfunction buildImageDecorations(\n state: EditorState,\n config: ImageFieldConfig\n): DecorationSet {\n const widgets: Array<{ from: number; to?: number; decoration: Decoration }> = []\n const cursor = state.selection.main.head\n\n for (let i = 1; i <= state.doc.lines; i++) {\n const line = state.doc.line(i)\n const lineText = line.text\n\n const match = lineText.match(imagePattern)\n if (!match) continue\n\n const [, alt, widthStr, src] = match\n const width = widthStr ? parseInt(widthStr, 10) : null\n\n // Check if cursor is on this line\n const isLineActive = cursor >= line.from && cursor <= line.to\n\n // Line decoration for fixed height and no wrap\n widgets.push({\n from: line.from,\n decoration: Decoration.line({ class: 'cm-md-image-line' })\n })\n\n // ALWAYS show image as block below the line\n widgets.push({\n from: line.to,\n decoration: Decoration.widget({\n widget: new ImageWidget(src, alt || '', width, config.resolveImageUrl, isLineActive),\n block: true,\n side: 1\n })\n })\n\n if (isLineActive) {\n // Show markdown text muted when active\n widgets.push({\n from: line.from,\n to: line.to,\n decoration: Decoration.mark({ class: 'cm-md-image-syntax' })\n })\n } else {\n // Hide markdown text when not active (use mark with visibility hidden to preserve height)\n widgets.push({\n from: line.from,\n to: line.to,\n decoration: Decoration.mark({ class: 'cm-md-image-hidden' })\n })\n }\n }\n\n // Sort by position\n widgets.sort((a, b) => a.from - b.from)\n\n return Decoration.set(\n widgets.map((w) => (w.to !== undefined ? w.decoration.range(w.from, w.to) : w.decoration.range(w.from))),\n true\n )\n}\n","import { keymap, EditorView } from '@codemirror/view'\nimport { foldable, foldedRanges, foldEffect } from '@codemirror/language'\n\nexport interface ClipboardConfig {\n onImagePaste?: (base64: string) => Promise<string | null>\n onGenerateTitle?: (text: string) => Promise<string>\n}\n\n/**\n * Normalize indentation of pasted text relative to cursor position.\n *\n * Example:\n * Cursor at position with 4-space indent\n * Pasting:\n * line1 (8 spaces)\n * line2 (4 spaces - minimum)\n * line3 (8 spaces)\n *\n * Result:\n * line1 (4 + 4 = 8, relative preserved)\n * line2 (4 + 0 = 4)\n * line3 (4 + 4 = 8)\n */\nfunction normalizeIndent(text: string, currentIndent: string): string {\n const lines = text.split('\\n')\n\n // Single line - no normalization needed\n if (lines.length <= 1) return text\n\n // Find minimum indent across ALL non-empty lines (including first!)\n let minIndent = Infinity\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i]\n if (line.trim() === '') continue // Skip empty lines\n\n const indent = line.match(/^[ \\t]*/)?.[0] || ''\n const indentSize = countIndentSize(indent)\n if (indentSize < minIndent) {\n minIndent = indentSize\n }\n }\n\n // If no indented lines found, use 0\n if (minIndent === Infinity) minIndent = 0\n\n // Normalize lines:\n // - Line 0: remove minIndent, but DON'T add currentIndent (cursor is already positioned)\n // - Line 1+: remove minIndent, add currentIndent + relativeIndent\n const result: string[] = []\n\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i]\n\n if (line.trim() === '') {\n // Preserve empty lines (with currentIndent for lines after first)\n result.push(i === 0 ? '' : currentIndent)\n continue\n }\n\n // Calculate current line's indent\n const lineIndent = line.match(/^[ \\t]*/)?.[0] || ''\n const lineIndentSize = countIndentSize(lineIndent)\n\n // Calculate relative indent (how much more than minimum)\n const relativeIndent = lineIndentSize - minIndent\n\n // First line: only relative indent (cursor already has position)\n // Other lines: currentIndent + relative indent\n const newIndent = i === 0\n ? ' '.repeat(Math.max(0, relativeIndent))\n : currentIndent + ' '.repeat(Math.max(0, relativeIndent))\n\n // Replace old indent with new\n result.push(newIndent + line.slice(lineIndent.length))\n }\n\n return result.join('\\n')\n}\n\n/**\n * Count indent size (tabs = 4 spaces)\n */\nfunction countIndentSize(indent: string): number {\n let size = 0\n for (const char of indent) {\n if (char === '\\t') {\n size += 4 - (size % 4)\n } else {\n size++\n }\n }\n return size\n}\n\n/**\n * Get current line's indent at cursor position\n */\nfunction getCurrentIndent(view: EditorView): string {\n const pos = view.state.selection.main.head\n const line = view.state.doc.lineAt(pos)\n const lineText = line.text\n\n // Extract leading whitespace\n const match = lineText.match(/^[ \\t]*/)\n return match ? match[0] : ''\n}\n\n/**\n * Paste text with normalized indentation\n */\nfunction pasteWithNormalizedIndent(view: EditorView, text: string): void {\n const selection = view.state.selection.main\n const currentIndent = getCurrentIndent(view)\n const normalizedText = normalizeIndent(text, currentIndent)\n\n view.dispatch({\n changes: { from: selection.from, to: selection.to, insert: normalizedText },\n selection: { anchor: selection.from + normalizedText.length }\n })\n}\n\n/**\n * Paste clipboard as collapsed `^^ paste text [N]` block.\n *\n * Scans lines below cursor to detect max indent — if existing content\n * has deeper indent, the header must be placed at that level so the\n * fold service (indent > baseIndent) doesn't absorb existing blocks.\n */\nfunction pasteAsCollapsed(view: EditorView): boolean {\n navigator.clipboard.readText().then((text) => {\n if (!text) return\n\n // Read fresh state after async\n const sel = view.state.selection.main\n const doc = view.state.doc\n const line = doc.lineAt(sel.head)\n const currentIndent = line.text.match(/^[ \\t]*/)?.[0] || ''\n const currentIndentSize = countIndentSize(currentIndent)\n\n // Scan lines below: find max indent that fold would absorb\n let maxIndentBelow = 0\n for (let i = line.number + 1; i <= doc.lines; i++) {\n const nextLine = doc.line(i)\n if (nextLine.text.trim() === '') continue\n const nextIndentSize = countIndentSize(nextLine.text.match(/^[ \\t]*/)?.[0] || '')\n if (nextIndentSize <= currentIndentSize) break\n if (nextIndentSize > maxIndentBelow) maxIndentBelow = nextIndentSize\n }\n\n // Header indent >= maxIndentBelow so existing content won't be absorbed\n const headerIndentSize = Math.max(currentIndentSize, maxIndentBelow)\n const headerIndent = ' '.repeat(headerIndentSize)\n const bodyIndent = headerIndent + ' '\n\n const charCount = text.length\n const header = `${headerIndent}^^ paste text [${charCount}]`\n const bodyLines = text.split('\\n').map(l => bodyIndent + l)\n const block = header + '\\n' + bodyLines.join('\\n')\n\n // Replace from line.from to consume existing indent (header already has it)\n const insertFrom = line.from\n view.dispatch({\n changes: { from: insertFrom, to: sel.to, insert: block },\n selection: { anchor: insertFrom + header.length }\n })\n\n // Synchronous refold: fold ^^ immediately in the same event loop cycle\n // (before browser paint) to avoid flash of expanded content.\n // Same technique as blockMove.ts:refoldCollapsedMarkers()\n const headerLine = view.state.doc.lineAt(insertFrom)\n if (headerLine.text.trim().startsWith('^^')) {\n let isFolded = false\n foldedRanges(view.state).between(headerLine.from, headerLine.to, () => {\n isFolded = true\n })\n if (!isFolded) {\n const range = foldable(view.state, headerLine.from, headerLine.to)\n if (range && (range.to - range.from) > 2) {\n view.dispatch({ effects: foldEffect.of(range) })\n }\n }\n }\n }).catch(err => console.error('[Clipboard]', err))\n\n return true\n}\n\n/**\n * Paste clipboard as collapsed block with AI-generated title.\n * Inserts `^^ ⏳` placeholder, calls onGenerateTitle, then replaces ⏳ with the result.\n */\nfunction pasteAsCollapsedAI(view: EditorView, onGenerateTitle: (text: string) => Promise<string>): boolean {\n navigator.clipboard.readText().then((text) => {\n if (!text) return\n\n // Read fresh state after async\n const sel = view.state.selection.main\n const doc = view.state.doc\n const line = doc.lineAt(sel.head)\n const currentIndent = line.text.match(/^[ \\t]*/)?.[0] || ''\n const currentIndentSize = countIndentSize(currentIndent)\n\n // Scan lines below: find max indent that fold would absorb\n let maxIndentBelow = 0\n for (let i = line.number + 1; i <= doc.lines; i++) {\n const nextLine = doc.line(i)\n if (nextLine.text.trim() === '') continue\n const nextIndentSize = countIndentSize(nextLine.text.match(/^[ \\t]*/)?.[0] || '')\n if (nextIndentSize <= currentIndentSize) break\n if (nextIndentSize > maxIndentBelow) maxIndentBelow = nextIndentSize\n }\n\n // Header indent >= maxIndentBelow so existing content won't be absorbed\n const headerIndentSize = Math.max(currentIndentSize, maxIndentBelow)\n const headerIndent = ' '.repeat(headerIndentSize)\n const bodyIndent = headerIndent + ' '\n\n const header = `${headerIndent}^^ ⏳`\n const bodyLines = text.split('\\n').map(l => bodyIndent + l)\n const block = header + '\\n' + bodyLines.join('\\n')\n\n // Replace from line.from to consume existing indent (header already has it)\n const insertFrom = line.from\n view.dispatch({\n changes: { from: insertFrom, to: sel.to, insert: block },\n selection: { anchor: insertFrom + header.length }\n })\n\n // Synchronous refold\n const headerLine = view.state.doc.lineAt(insertFrom)\n if (headerLine.text.trim().startsWith('^^')) {\n let isFolded = false\n foldedRanges(view.state).between(headerLine.from, headerLine.to, () => {\n isFolded = true\n })\n if (!isFolded) {\n const range = foldable(view.state, headerLine.from, headerLine.to)\n if (range && (range.to - range.from) > 2) {\n view.dispatch({ effects: foldEffect.of(range) })\n }\n }\n }\n\n // Call AI to generate title, then replace ⏳ with it\n onGenerateTitle(text).then((title) => {\n const resolvedTitle = (title && title.trim()) ? title.trim() : 'paste text'\n // Re-read document state (may have changed during async AI call)\n const currentDoc = view.state.doc\n for (let i = 1; i <= currentDoc.lines; i++) {\n const ln = currentDoc.line(i)\n const match = ln.text.match(/^(\\s*)\\^\\^\\s*⏳\\s*$/)\n if (match) {\n const indent = match[1]\n const newText = `${indent}^^ ${resolvedTitle}`\n view.dispatch({\n changes: { from: ln.from, to: ln.to, insert: newText }\n })\n break\n }\n }\n }).catch((err) => {\n console.error('[Clipboard] AI title generation failed:', err)\n // Fallback: replace ⏳ with 'paste text'\n const currentDoc = view.state.doc\n for (let i = 1; i <= currentDoc.lines; i++) {\n const ln = currentDoc.line(i)\n const match = ln.text.match(/^(\\s*)\\^\\^\\s*⏳\\s*$/)\n if (match) {\n const indent = match[1]\n const newText = `${indent}^^ paste text`\n view.dispatch({\n changes: { from: ln.from, to: ln.to, insert: newText }\n })\n break\n }\n }\n })\n }).catch(err => console.error('[Clipboard]', err))\n\n return true\n}\n\n// === AI Paste Waiting Mode ===\n// When activated (from Command Palette), next Cmd+V triggers pasteAsCollapsedAI\nlet _waitingForAIPaste = false\nlet _waitingIndicator: HTMLElement | null = null\nlet _waitingView: EditorView | null = null\n\nfunction positionIndicator(view: EditorView, indicator: HTMLElement): void {\n const pos = view.state.selection.main.head\n const coords = view.coordsAtPos(pos) ?? view.coordsAtPos(pos, -1)\n if (!coords) return\n indicator.style.left = `${coords.left}px`\n indicator.style.top = `${coords.bottom + 6}px`\n // Adjust if off-screen\n requestAnimationFrame(() => {\n if (!indicator.parentElement) return\n const rect = indicator.getBoundingClientRect()\n if (rect.right > window.innerWidth) {\n indicator.style.left = `${window.innerWidth - rect.width - 10}px`\n }\n })\n}\n\nexport function activateAIPasteMode(view: EditorView): void {\n _waitingForAIPaste = true\n _waitingView = view\n\n // Show floating indicator near cursor\n cancelAIPasteIndicator()\n\n const indicator = document.createElement('div')\n indicator.className = 'cm-ai-paste-indicator'\n indicator.setAttribute('data-ai-paste-indicator', 'true')\n\n const badge = document.createElement('span')\n badge.className = 'cm-ai-paste-badge'\n badge.textContent = '📋 AI Paste'\n\n const cancelBtn = document.createElement('span')\n cancelBtn.className = 'cm-ai-paste-cancel'\n cancelBtn.textContent = '✕'\n cancelBtn.addEventListener('click', (e) => {\n e.stopPropagation()\n cancelAIPasteMode()\n })\n\n indicator.appendChild(badge)\n indicator.appendChild(cancelBtn)\n\n document.body.appendChild(indicator)\n _waitingIndicator = indicator\n positionIndicator(view, indicator)\n}\n\nfunction cancelAIPasteIndicator(): void {\n if (_waitingIndicator) {\n _waitingIndicator.remove()\n _waitingIndicator = null\n }\n}\n\nexport function cancelAIPasteMode(): void {\n _waitingForAIPaste = false\n _waitingView = null\n cancelAIPasteIndicator()\n}\n\nexport function isAIPasteModeActive(): boolean {\n return _waitingForAIPaste\n}\n\n/** Update listener that repositions the AI Paste indicator when cursor moves */\nexport const aiPasteTrackerPlugin = EditorView.updateListener.of((update) => {\n if (!_waitingForAIPaste || !_waitingIndicator) return\n if (update.selectionSet || update.geometryChanged || update.viewportChanged) {\n positionIndicator(update.view, _waitingIndicator)\n }\n})\n\n// Clipboard keymap — uses navigator.clipboard API (more reliable than event handlers in Electron 34)\nexport function createClipboardKeymap(config: ClipboardConfig = {}) {\n return keymap.of([\n {\n key: 'Mod-c',\n run: (view: EditorView) => {\n const selection = view.state.selection.main\n if (selection.empty) return false\n\n const text = view.state.sliceDoc(selection.from, selection.to)\n\n navigator.clipboard.writeText(text).catch((err) => {\n console.error('[Editor] Copy failed:', err)\n })\n return true\n }\n },\n {\n key: 'Mod-x',\n run: (view: EditorView) => {\n const selection = view.state.selection.main\n if (selection.empty) return false\n\n const text = view.state.sliceDoc(selection.from, selection.to)\n\n navigator.clipboard\n .writeText(text)\n .then(() => {\n // Read fresh selection — state may have changed during async clipboard write\n const sel = view.state.selection.main\n view.dispatch({\n changes: { from: sel.from, to: sel.to, insert: '' },\n selection: { anchor: sel.from }\n })\n })\n .catch((err) => {\n console.error('[Editor] Cut failed:', err)\n })\n return true\n }\n },\n {\n key: 'Mod-v',\n run: (view: EditorView) => {\n // Check if AI Paste waiting mode is active\n if (_waitingForAIPaste && config.onGenerateTitle) {\n cancelAIPasteIndicator()\n _waitingForAIPaste = false\n _waitingView = null\n return pasteAsCollapsedAI(view, config.onGenerateTitle)\n }\n\n // Try to read clipboard items to check for images\n navigator.clipboard.read().then(async (items) => {\n for (const item of items) {\n // Check if there's an image\n const imageType = item.types.find(t => t.startsWith('image/'))\n if (imageType && config.onImagePaste) {\n try {\n const blob = await item.getType(imageType)\n const buffer = await blob.arrayBuffer()\n const uint8Array = new Uint8Array(buffer)\n let binary = ''\n for (let i = 0; i < uint8Array.length; i++) {\n binary += String.fromCharCode(uint8Array[i])\n }\n const base64 = btoa(binary)\n\n const imagePath = await config.onImagePaste(base64)\n\n if (imagePath) {\n const markdown = `\\n`\n const pos = view.state.selection.main.head\n view.dispatch({\n changes: { from: pos, insert: markdown },\n selection: { anchor: pos + markdown.length }\n })\n }\n return // Image handled\n } catch (err) {\n console.error('[Clipboard] Image paste failed:', err)\n }\n }\n }\n\n // No image, paste text with normalized indent\n try {\n const text = await navigator.clipboard.readText()\n if (text) {\n pasteWithNormalizedIndent(view, text)\n }\n } catch (err) {\n console.error('[Clipboard] Text paste failed:', err)\n }\n }).catch((err) => {\n // Fallback to text-only paste\n console.warn('[Clipboard] read() failed, falling back to readText:', err)\n navigator.clipboard.readText().then((text) => {\n if (text) {\n pasteWithNormalizedIndent(view, text)\n }\n }).catch(err => console.error('[Clipboard]', err))\n })\n return true\n }\n },\n {\n key: 'Alt-Mod-v',\n run: pasteAsCollapsed\n },\n {\n key: 'Shift-Mod-v',\n run: (view: EditorView) => {\n if (config.onGenerateTitle) {\n return pasteAsCollapsedAI(view, config.onGenerateTitle)\n }\n return pasteAsCollapsed(view)\n }\n }\n ])\n}\n","import { EditorView } from '@codemirror/view'\n\n// Wrap selected text when typing *, `, _ etc.\nexport function createWrapSelectionHandler() {\n const wrapPairs: Record<string, string> = {\n '*': '*',\n '_': '_',\n '`': '`',\n '\"': '\"',\n \"'\": \"'\",\n '(': ')',\n '[': ']',\n '{': '}',\n '~': '~',\n // Русская раскладка: ё находится на той же клавише что и `\n 'ё': '`',\n 'Ё': '`'\n }\n\n return EditorView.domEventHandlers({\n keydown: (event, view) => {\n const char = event.key\n const closingChar = wrapPairs[char]\n\n // If character not in list — skip\n if (!closingChar) return false\n\n const selection = view.state.selection.main\n // Only if there's a selection\n if (selection.empty) return false\n\n // Prevent default behavior\n event.preventDefault()\n\n const selectedText = view.state.sliceDoc(selection.from, selection.to)\n\n // Для русской ё используем ` как оборачивающий символ\n const openChar = (char === 'ё' || char === 'Ё') ? '`' : char\n\n // Wrap text\n view.dispatch({\n changes: {\n from: selection.from,\n to: selection.to,\n insert: openChar + selectedText + closingChar\n },\n // Select text inside wrapper (without wrapper characters)\n selection: {\n anchor: selection.from + 1,\n head: selection.from + 1 + selectedText.length\n }\n })\n\n return true\n }\n })\n}\n","import { EditorView } from '@codemirror/view'\n\nexport interface ImagePasteConfig {\n onImagePaste?: (base64: string) => Promise<string | null>\n}\n\n// Paste handler only for images (domEventHandlers)\nexport function createImagePasteHandler(config: ImagePasteConfig) {\n // console.log('[ImagePaste] createImagePasteHandler called, config:', !!config.onImagePaste)\n return EditorView.domEventHandlers({\n paste: (event, view) => {\n // console.log('[ImagePaste] === PASTE EVENT ===')\n // console.log('[ImagePaste] onImagePaste exists:', !!config.onImagePaste)\n if (!config.onImagePaste) return false\n\n const items = event.clipboardData?.items\n if (!items) return false\n\n for (const item of items) {\n if (item.type.startsWith('image/')) {\n event.preventDefault()\n\n const blob = item.getAsFile()\n if (!blob) return false\n\n // Run async operation without blocking\n const handlePaste = async () => {\n try {\n const buffer = await blob.arrayBuffer()\n const uint8Array = new Uint8Array(buffer)\n let binary = ''\n for (let i = 0; i < uint8Array.length; i++) {\n binary += String.fromCharCode(uint8Array[i])\n }\n const base64 = btoa(binary)\n\n // console.log('[ImagePaste] calling onImagePaste with base64 length:', base64.length)\n const imagePath = await config.onImagePaste!(base64)\n // console.log('[ImagePaste] got imagePath:', imagePath)\n\n if (imagePath) {\n const markdown = `\\n`\n const pos = view.state.selection.main.head\n view.dispatch({\n changes: { from: pos, insert: markdown },\n selection: { anchor: pos + markdown.length }\n })\n }\n } catch (err) {\n console.error('Error pasting image:', err)\n }\n }\n\n handlePaste()\n return true\n }\n }\n return false\n }\n })\n}\n","import type { EditorView } from '@codemirror/view'\nimport { foldedRanges, foldEffect, unfoldEffect } from '@codemirror/language'\n\n// Key for localStorage\nconst getFoldStorageKey = (key: string) => `md-editor-fold:${key}`\n\n// Collapsible header pattern (>> or ^^)\nconst collapsiblePattern = /^\\s*(>>|\\^\\^)/\n\nexport interface FoldRange {\n fromLine: number\n toLine: number\n}\n\n// Save folded ranges\nexport function saveFoldState(foldStateKey: string | undefined, view: EditorView): void {\n if (!foldStateKey) return\n\n const folded = foldedRanges(view.state)\n const ranges: FoldRange[] = []\n\n folded.between(0, view.state.doc.length, (from, to) => {\n // Save line numbers (more stable than positions)\n const fromLine = view.state.doc.lineAt(from).number\n const toLine = view.state.doc.lineAt(to).number\n ranges.push({ fromLine, toLine })\n })\n\n const fileName = foldStateKey.split('/').pop()\n if (ranges.length > 0) {\n console.log('[Fold:save]', fileName, 'saving', ranges.length, 'folds:', ranges)\n localStorage.setItem(getFoldStorageKey(foldStateKey), JSON.stringify(ranges))\n } else {\n console.log('[Fold:save]', fileName, 'no folds — removing from localStorage')\n localStorage.removeItem(getFoldStorageKey(foldStateKey))\n }\n}\n\n// Load and apply folded ranges\nexport function loadFoldState(foldStateKey: string | undefined, view: EditorView): void {\n if (!foldStateKey) return\n\n try {\n const storageKey = getFoldStorageKey(foldStateKey)\n const saved = localStorage.getItem(storageKey)\n const fileName = foldStateKey.split('/').pop()\n console.log('[Fold:load]', fileName, 'localStorage entry:', saved ? saved.slice(0, 120) : 'NULL')\n if (!saved) return\n\n const ranges: FoldRange[] = JSON.parse(saved)\n const effects: ReturnType<typeof foldEffect.of>[] = []\n let skipped = 0\n\n for (const { fromLine, toLine } of ranges) {\n if (fromLine <= view.state.doc.lines && toLine <= view.state.doc.lines) {\n const headerLine = view.state.doc.line(fromLine)\n // Validate: header line must be a collapsible marker (>> or ^^)\n // Without this, stale line numbers (from changed content) create folds\n // on random lines → CM6 throws \"Invalid child in posBefore\"\n if (!collapsiblePattern.test(headerLine.text)) {\n skipped++\n continue\n }\n const from = headerLine.to\n const to = view.state.doc.line(toLine).to\n effects.push(foldEffect.of({ from, to }))\n }\n }\n\n if (skipped > 0) {\n console.warn('[Fold:load] skipped', skipped, 'stale folds (no collapsible marker at saved line)')\n }\n\n if (effects.length > 0) {\n console.log('[Fold:load]', foldStateKey?.split('/').pop(), 'restoring', effects.length, 'folds from saved:', ranges)\n view.dispatch({ effects })\n }\n } catch (e) {\n console.error('[Fold:load] Failed:', e)\n }\n}\n\n// Check if transaction has fold/unfold effects\nexport function hasFoldEffects(effects: readonly { is: (type: any) => boolean }[]): boolean {\n return effects.some((e) => e.is(foldEffect) || e.is(unfoldEffect))\n}\n\nexport { foldEffect, unfoldEffect }\n","import { WidgetType } from '@codemirror/view'\n\nexport class IncludeLinkWidget extends WidgetType {\n constructor(\n private readonly path: string,\n private readonly onOpenFile?: (path: string) => void\n ) {\n super()\n }\n\n eq(other: IncludeLinkWidget) {\n return other.path === this.path\n }\n\n toDOM() {\n const container = document.createElement('span')\n container.className = 'cm-include-link'\n\n const icon = document.createElement('span')\n icon.className = 'cm-include-link-icon'\n icon.textContent = '📎'\n container.appendChild(icon)\n\n const pathSpan = document.createElement('span')\n pathSpan.className = 'cm-include-link-path'\n pathSpan.textContent = this.path\n container.appendChild(pathSpan)\n\n if (this.onOpenFile) {\n const openBtn = document.createElement('button')\n openBtn.className = 'cm-include-link-open'\n openBtn.textContent = '↗'\n openBtn.title = 'Open file'\n openBtn.addEventListener('click', (e) => {\n e.stopPropagation()\n e.preventDefault()\n this.onOpenFile?.(this.path)\n })\n container.appendChild(openBtn)\n\n // Cmd+Click on the whole widget opens the file\n container.addEventListener('mousedown', (e) => {\n if (e.metaKey || e.ctrlKey) {\n e.stopPropagation()\n e.preventDefault()\n this.onOpenFile?.(this.path)\n }\n })\n }\n\n return container\n }\n\n ignoreEvent(event: Event) {\n // Allow click events on the open button\n return event.type === 'mousedown'\n }\n}\n","import { ViewPlugin, Decoration, DecorationSet, EditorView } from '@codemirror/view'\nimport { Prec } from '@codemirror/state'\nimport { IncludeLinkWidget } from '../widgets/IncludeLinkWidget'\n\n// Pattern: <!-- @include: ./path/to/file.md -->\nconst INCLUDE_PATTERN = /^<!--\\s*@include:\\s*(.+?)\\s*-->$/\n\nexport interface IncludeLinkConfig {\n onOpenFile?: (relativePath: string) => void\n}\n\n/**\n * Plugin to display include links as styled inline widgets\n * - Shows widget when cursor is NOT on the line (preview mode)\n * - Shows raw text when cursor IS on the line (edit mode)\n * - Cmd+Click navigates to the included file\n */\nexport function createIncludeLinkPlugin(config: IncludeLinkConfig = {}) {\n return ViewPlugin.fromClass(\n class {\n decorations: DecorationSet\n cmdPressed = false\n\n constructor(view: EditorView) {\n this.decorations = this.buildDecorations(view)\n this.setupCmdListener(view)\n }\n\n setupCmdListener(view: EditorView) {\n const onKeyDown = (e: KeyboardEvent) => {\n if (e.key === 'Meta' || e.key === 'Control') {\n this.cmdPressed = true\n view.contentDOM.classList.add('cm-include-cmd-mode')\n }\n }\n const onKeyUp = (e: KeyboardEvent) => {\n if (e.key === 'Meta' || e.key === 'Control') {\n this.cmdPressed = false\n view.contentDOM.classList.remove('cm-include-cmd-mode')\n }\n }\n const onBlur = () => {\n this.cmdPressed = false\n view.contentDOM.classList.remove('cm-include-cmd-mode')\n }\n\n document.addEventListener('keydown', onKeyDown)\n document.addEventListener('keyup', onKeyUp)\n window.addEventListener('blur', onBlur)\n\n // Store cleanup function\n ;(view as any)._includeLinkCleanup = () => {\n document.removeEventListener('keydown', onKeyDown)\n document.removeEventListener('keyup', onKeyUp)\n window.removeEventListener('blur', onBlur)\n }\n }\n\n destroy() {\n // Cleanup will be called when plugin is destroyed\n }\n\n update(update: { docChanged: boolean; selectionSet: boolean; focusChanged: boolean; view: EditorView }) {\n // Rebuild when doc changes OR when selection changes OR when focus changes (for edit mode toggle)\n if (update.docChanged || update.selectionSet || update.focusChanged) {\n this.decorations = this.buildDecorations(update.view)\n }\n }\n\n buildDecorations(view: EditorView): DecorationSet {\n const decorations: { from: number; to: number; decoration: Decoration }[] = []\n const doc = view.state.doc\n\n // Get current cursor line(s) - only if editor has focus\n const cursorLines = new Set<number>()\n if (view.hasFocus) {\n for (const range of view.state.selection.ranges) {\n const startLine = doc.lineAt(range.from).number\n const endLine = doc.lineAt(range.to).number\n for (let l = startLine; l <= endLine; l++) {\n cursorLines.add(l)\n }\n }\n }\n\n for (let i = 1; i <= doc.lines; i++) {\n const line = doc.line(i)\n const match = line.text.match(INCLUDE_PATTERN)\n\n if (match) {\n // If cursor is on this line, show raw text (edit mode)\n if (cursorLines.has(i)) {\n continue // Skip decoration - show raw markdown\n }\n\n const relativePath = match[1].trim()\n const widget = new IncludeLinkWidget(relativePath, config.onOpenFile)\n\n // Replace the entire line content with the widget\n decorations.push({\n from: line.from,\n to: line.to,\n decoration: Decoration.replace({ widget })\n })\n }\n }\n\n decorations.sort((a, b) => a.from - b.from)\n\n try {\n return Decoration.set(\n decorations.map(d => d.decoration.range(d.from, d.to)),\n true\n )\n } catch (e) {\n console.error('[IncludeLink] Error:', e)\n return Decoration.none\n }\n }\n },\n { decorations: v => v.decorations }\n )\n}\n\n/**\n * Click handler for Cmd+Click on include links\n * Uses Prec.highest to intercept before CodeMirror default handling\n */\nexport function createIncludeLinkClickHandler(config: IncludeLinkConfig = {}) {\n return Prec.highest(EditorView.domEventHandlers({\n mousedown(event: MouseEvent, view: EditorView) {\n if (!event.metaKey && !event.ctrlKey) return false\n\n const pos = view.posAtCoords({ x: event.clientX, y: event.clientY })\n if (pos === null) return false\n\n const line = view.state.doc.lineAt(pos)\n const match = line.text.match(INCLUDE_PATTERN)\n\n if (match && config.onOpenFile) {\n const relativePath = match[1].trim()\n event.preventDefault()\n event.stopPropagation()\n config.onOpenFile(relativePath)\n return true\n }\n\n return false\n }\n }))\n}\n\n/**\n * Resolve all includes in document text\n * Used for \"Copy with includes\" functionality\n */\nexport async function resolveAllIncludes(\n docText: string,\n resolveInclude: (relativePath: string) => Promise<string>\n): Promise<string> {\n const lines = docText.split('\\n')\n const result: string[] = []\n\n for (const line of lines) {\n const match = line.match(INCLUDE_PATTERN)\n if (match) {\n const relativePath = match[1].trim()\n try {\n const content = await resolveInclude(relativePath)\n result.push(content)\n } catch (e) {\n // If file not found, keep the original line\n result.push(line)\n }\n } else {\n result.push(line)\n }\n }\n\n return result.join('\\n')\n}\n\n// Export the pattern for use in context menu\nexport { INCLUDE_PATTERN }\n","import { EditorView, ViewPlugin, ViewUpdate } from '@codemirror/view'\nimport { Prec, Extension, EditorSelection } from '@codemirror/state'\nimport { foldedRanges, unfoldEffect } from '@codemirror/language'\nimport { resolveAllIncludes, INCLUDE_PATTERN } from './includeLink'\nimport { activateAIPasteMode } from './clipboard'\n\n// Track last non-empty selection for Cmd+/ palette\n// (CM6 may collapse selection before keydown handlers fire)\nlet lastNonEmptySelection: EditorSelection | null = null\n\nexport const selectionTrackerPlugin = ViewPlugin.fromClass(class {\n update(update: ViewUpdate) {\n const sel = update.state.selection\n if (!sel.main.empty) {\n lastNonEmptySelection = sel\n }\n }\n})\n\nexport interface EmojiShortcut {\n emoji: string\n name: string\n description?: string\n}\n\nexport interface ContextMenuConfig {\n /** Resolve include path to file content (for \"Copy with includes\" feature) */\n resolveInclude?: (relativePath: string) => Promise<string>\n /** Get current emoji shortcuts (getter to avoid editor recreation) */\n getEmojiShortcuts?: () => EmojiShortcut[]\n}\n\n// Get line indent (spaces/tabs at start)\nfunction getLineIndent(line: string): string {\n const match = line.match(/^[\\t ]*/)\n return match ? match[0] : ''\n}\n\n// Find where actual content starts, skipping structural prefixes:\n// indent + collapsible (>> or ^^) + heading (#{1,6}) + list marker (- * + \\d.)\nfunction getContentStart(lineText: string): number {\n let pos = 0\n\n // 1. Skip leading whitespace\n while (pos < lineText.length && (lineText[pos] === ' ' || lineText[pos] === '\\t')) {\n pos++\n }\n\n // 2. Skip collapsible marker: >> or ^^\n if (\n pos + 1 < lineText.length &&\n ((lineText[pos] === '>' && lineText[pos + 1] === '>') ||\n (lineText[pos] === '^' && lineText[pos + 1] === '^'))\n ) {\n pos += 2\n if (pos < lineText.length && lineText[pos] === ' ') pos++\n }\n\n // 3. Skip heading marker: #{1,6}\n if (pos < lineText.length && lineText[pos] === '#') {\n let hashCount = 0\n while (pos + hashCount < lineText.length && lineText[pos + hashCount] === '#' && hashCount < 6) {\n hashCount++\n }\n if (hashCount > 0 && (pos + hashCount >= lineText.length || lineText[pos + hashCount] === ' ')) {\n pos += hashCount\n if (pos < lineText.length && lineText[pos] === ' ') pos++\n }\n }\n\n // 4. Skip list marker: - * + or \\d+.\n const remaining = lineText.substring(pos)\n const listMatch = remaining.match(/^([*+\\-]|\\d+\\.)\\s+/)\n if (listMatch) {\n pos += listMatch[0].length\n }\n\n return pos\n}\n\n// Format: Add prefix after indent (e.g., \">> \" for collapsible, \"# \" for heading)\nexport function addLinePrefix(view: EditorView, prefix: string) {\n const { state } = view\n const selection = state.selection.main\n\n // Get all lines in selection (or current line if no selection)\n const fromLine = state.doc.lineAt(selection.from)\n const toLine = state.doc.lineAt(selection.to)\n\n const changes: { from: number; to: number; insert: string }[] = []\n\n for (let i = fromLine.number; i <= toLine.number; i++) {\n const line = state.doc.line(i)\n const text = line.text\n const indent = getLineIndent(text)\n const content = text.slice(indent.length)\n\n // Check if prefix already exists\n if (content.startsWith(prefix)) continue\n\n // Insert prefix after indent (works for empty lines too)\n changes.push({\n from: line.from + indent.length,\n to: line.from + indent.length,\n insert: prefix\n })\n }\n\n if (changes.length > 0) {\n view.dispatch({ changes })\n }\n}\n\n// Format: Remove prefix after indent\nexport function removeLinePrefix(view: EditorView, prefix: string) {\n const { state } = view\n const selection = state.selection.main\n\n const fromLine = state.doc.lineAt(selection.from)\n const toLine = state.doc.lineAt(selection.to)\n\n const changes: { from: number; to: number; insert: string }[] = []\n\n for (let i = fromLine.number; i <= toLine.number; i++) {\n const line = state.doc.line(i)\n const text = line.text\n const indent = getLineIndent(text)\n const content = text.slice(indent.length)\n\n // Check if prefix exists\n if (content.startsWith(prefix)) {\n changes.push({\n from: line.from + indent.length,\n to: line.from + indent.length + prefix.length,\n insert: ''\n })\n }\n }\n\n if (changes.length > 0) {\n view.dispatch({ changes })\n }\n}\n\n// Toggle prefix (add if not present, remove if present)\nexport function toggleLinePrefix(view: EditorView, prefix: string) {\n const { state } = view\n const selection = state.selection.main\n const line = state.doc.lineAt(selection.from)\n const text = line.text\n const indent = getLineIndent(text)\n const content = text.slice(indent.length)\n\n // Special case for collapsible: check both >> and ^^ (with or without trailing space)\n if (prefix === '>> ') {\n // Order matters: check with-space first to capture the full prefix\n let actualPrefix: string | null = null\n if (content.startsWith('>> ')) actualPrefix = '>> '\n else if (content.startsWith('^^ ')) actualPrefix = '^^ '\n else if (content.startsWith('>>')) actualPrefix = '>>'\n else if (content.startsWith('^^')) actualPrefix = '^^'\n\n if (actualPrefix) {\n\n // Check if this section is folded — unfold FIRST, then remove marker\n let foldedRange: { from: number; to: number } | null = null\n foldedRanges(state).between(line.from, state.doc.length, (from, to) => {\n if (from >= line.to && from <= line.to + 1 && !foldedRange) {\n foldedRange = { from, to }\n }\n })\n\n if (foldedRange) {\n // Step 1: Unfold (also change ^^ back to >> so marker is consistent)\n const markerIsCollapsed = actualPrefix.startsWith('^^')\n const markerChange = markerIsCollapsed ? {\n from: line.from + indent.length,\n to: line.from + indent.length + 2,\n insert: '>>'\n } : undefined\n\n view.dispatch({\n effects: unfoldEffect.of(foldedRange),\n ...(markerChange ? { changes: [markerChange] } : {})\n })\n\n // Step 2: Remove prefix from the now-unfolded line (re-read from fresh state)\n const newState = view.state\n const newLine = newState.doc.lineAt(selection.from)\n const newIndent = getLineIndent(newLine.text)\n const newContent = newLine.text.slice(newIndent.length)\n let newPrefix: string | null = null\n if (newContent.startsWith('>> ')) newPrefix = '>> '\n else if (newContent.startsWith('^^ ')) newPrefix = '^^ '\n else if (newContent.startsWith('>>')) newPrefix = '>>'\n else if (newContent.startsWith('^^')) newPrefix = '^^'\n\n if (newPrefix) {\n view.dispatch({\n changes: [{\n from: newLine.from + newIndent.length,\n to: newLine.from + newIndent.length + newPrefix.length,\n insert: ''\n }]\n })\n }\n } else {\n // Not folded — just remove the prefix\n view.dispatch({\n changes: [{\n from: line.from + indent.length,\n to: line.from + indent.length + actualPrefix.length,\n insert: ''\n }]\n })\n }\n } else {\n // Empty line: insert prefix + default text \"Bullet\" with cursor after it\n if (content.trim() === '') {\n const defaultText = 'Bullet'\n const insertPos = line.from + indent.length\n view.dispatch({\n changes: [{\n from: insertPos,\n to: line.to,\n insert: prefix + defaultText\n }],\n selection: { anchor: insertPos + prefix.length + defaultText.length }\n })\n } else {\n addLinePrefix(view, prefix)\n }\n }\n return\n }\n\n if (content.startsWith(prefix)) {\n removeLinePrefix(view, prefix)\n } else {\n addLinePrefix(view, prefix)\n }\n}\n\n// Format: Wrap selection or word with markers (e.g., ** for bold, * for italic)\nexport function wrapSelection(view: EditorView, marker: string, endMarker?: string) {\n const { state } = view\n const selection = state.selection.main\n const end = endMarker ?? marker\n\n let from = selection.from\n let to = selection.to\n\n // If no selection, select line content after structural prefixes\n if (selection.empty) {\n const line = state.doc.lineAt(from)\n const lineText = line.text\n if (lineText.trim() === '') return // empty line\n const contentStart = getContentStart(lineText)\n const contentEnd = lineText.trimEnd().length\n if (contentStart >= contentEnd) return // only prefixes, no content\n\n from = line.from + contentStart\n to = line.from + contentEnd\n }\n\n // Trim whitespace then narrow if text includes markers at boundaries\n const rawText = state.sliceDoc(from, to)\n const lwsW = rawText.length - rawText.trimStart().length\n const twsW = rawText.length - rawText.trimEnd().length\n const trimTextW = rawText.trim()\n const ml = marker.length\n const el = end.length\n if (trimTextW.length >= ml + el + 1 && trimTextW.startsWith(marker) && trimTextW.endsWith(end)) {\n from = from + lwsW + ml\n to = to - twsW - el\n }\n\n const selectedText = state.sliceDoc(from, to)\n\n // Check if already wrapped - unwrap\n const beforeStart = from >= marker.length ? state.sliceDoc(from - marker.length, from) : ''\n const afterEnd = to + end.length <= state.doc.length ? state.sliceDoc(to, to + end.length) : ''\n\n if (beforeStart === marker && afterEnd === end) {\n // Unwrap\n view.dispatch({\n changes: [\n { from: from - marker.length, to: from, insert: '' },\n { from: to, to: to + end.length, insert: '' }\n ],\n selection: { anchor: from - marker.length, head: to - marker.length }\n })\n } else {\n // Wrap\n view.dispatch({\n changes: [\n { from, to, insert: marker + selectedText + end }\n ],\n selection: { anchor: from + marker.length, head: from + marker.length + selectedText.length }\n })\n }\n}\n\n// Heading levels\nexport function setHeadingLevel(view: EditorView, level: number) {\n const { state } = view\n const selection = state.selection.main\n\n const fromLine = state.doc.lineAt(selection.from)\n const toLine = state.doc.lineAt(selection.to)\n\n const changes: { from: number; to: number; insert: string }[] = []\n\n for (let i = fromLine.number; i <= toLine.number; i++) {\n const line = state.doc.line(i)\n const text = line.text\n const indent = getLineIndent(text)\n let offset = indent.length\n let afterPrefix = text.slice(offset)\n\n // Skip collapsible marker: >> or ^^ (heading goes AFTER collapsible)\n const collapsibleMatch = afterPrefix.match(/^(>>|\\^\\^)\\s?/)\n if (collapsibleMatch) {\n offset += collapsibleMatch[0].length\n afterPrefix = text.slice(offset)\n }\n\n // Remove existing heading markers\n const existingHeading = afterPrefix.match(/^#{1,6}\\s*/)\n\n // New prefix\n const newPrefix = level > 0 ? '#'.repeat(level) + ' ' : ''\n\n changes.push({\n from: line.from + offset,\n to: line.from + offset + (existingHeading ? existingHeading[0].length : 0),\n insert: newPrefix\n })\n }\n\n if (changes.length > 0) {\n view.dispatch({ changes })\n }\n}\n\n// Menu item types\nexport interface MenuItem {\n label: string\n action?: (view: EditorView) => void\n submenu?: MenuItem[]\n divider?: boolean\n /** Description shown as tooltip on Cmd+hover (for emoji shortcuts) */\n _emojiDescription?: string\n}\n\n// Find inline code at cursor position\nfunction findInlineCodeAtCursor(view: EditorView): { content: string; from: number; to: number } | null {\n const { state } = view\n const pos = state.selection.main.head\n const line = state.doc.lineAt(pos)\n const lineText = line.text\n const posInLine = pos - line.from\n\n // Find all backtick pairs in line (including empty)\n const regex = /`([^`]*)`/g\n let match\n while ((match = regex.exec(lineText)) !== null) {\n const start = match.index\n const end = start + match[0].length\n // Check if cursor is inside this code block (including backticks)\n if (posInLine >= start && posInLine <= end) {\n return {\n content: match[1], // Content without backticks\n from: line.from + start,\n to: line.from + end\n }\n }\n }\n return null\n}\n\n// Copy text to clipboard\nasync function copyToClipboard(text: string) {\n try {\n await navigator.clipboard.writeText(text)\n } catch (err) {\n // Fallback\n const textarea = document.createElement('textarea')\n textarea.value = text\n document.body.appendChild(textarea)\n textarea.select()\n document.execCommand('copy')\n document.body.removeChild(textarea)\n }\n}\n\n// Check if selection/word is wrapped with marker\nfunction isWrappedWith(view: EditorView, marker: string): boolean {\n const { state } = view\n const selection = state.selection.main\n\n let from = selection.from\n let to = selection.to\n\n // If no selection, select line content after structural prefixes\n if (selection.empty) {\n const line = state.doc.lineAt(from)\n const lineText = line.text\n if (lineText.trim() === '') return false\n const contentStart = getContentStart(lineText)\n const contentEnd = lineText.trimEnd().length\n if (contentStart >= contentEnd) return false\n\n from = line.from + contentStart\n to = line.from + contentEnd\n }\n\n // Trim whitespace from boundaries before marker detection\n // (user may select \"**text** \" with trailing space)\n const rawText = state.sliceDoc(from, to)\n const leadingWs = rawText.length - rawText.trimStart().length\n const trailingWs = rawText.length - rawText.trimEnd().length\n const trimmedFrom = from + leadingWs\n const trimmedTo = to - trailingWs\n const trimmedText = rawText.trim()\n\n // If text starts/ends with marker, narrow range inward so the\n // \"check outside\" logic below naturally finds the markers.\n // Example: selected \"**zsf** \" → trim → \"**zsf**\" → narrow to \"zsf\" → beforeStart=\"**\" ✓\n const ml = marker.length\n if (trimmedText.length >= ml * 2 + 1 && trimmedText.startsWith(marker) && trimmedText.endsWith(marker)) {\n from = trimmedFrom + ml\n to = trimmedTo - ml\n }\n\n const beforeStart = from >= marker.length ? state.sliceDoc(from - marker.length, from) : ''\n const afterEnd = to + marker.length <= state.doc.length ? state.sliceDoc(to, to + marker.length) : ''\n\n return beforeStart === marker && afterEnd === marker\n}\n\n// Check if line has prefix\nfunction hasLinePrefix(view: EditorView, prefix: string): boolean {\n const { state } = view\n const selection = state.selection.main\n const line = state.doc.lineAt(selection.from)\n const text = line.text\n const indent = getLineIndent(text)\n const content = text.slice(indent.length)\n return content.startsWith(prefix)\n}\n\n// Get current heading level (0 if no heading)\nfunction getCurrentHeadingLevel(view: EditorView): number {\n const { state } = view\n const selection = state.selection.main\n const line = state.doc.lineAt(selection.from)\n const text = line.text\n const indent = getLineIndent(text)\n let content = text.slice(indent.length)\n\n // Skip collapsible marker: >> or ^^ (heading sits after it)\n const collapsibleMatch = content.match(/^(>>|\\^\\^)\\s?/)\n if (collapsibleMatch) {\n content = content.slice(collapsibleMatch[0].length)\n }\n\n const match = content.match(/^(#{1,6})\\s/)\n return match ? match[1].length : 0\n}\n\n// Check if document has any includes\nfunction hasIncludes(doc: string): boolean {\n return INCLUDE_PATTERN.test(doc)\n}\n\n// Default menu items\nexport function getDefaultMenuItems(view?: EditorView, config?: ContextMenuConfig): MenuItem[] {\n const items: MenuItem[] = []\n\n // Check formatting state\n const isBold = view ? isWrappedWith(view, '**') : false\n const isItalic = view ? isWrappedWith(view, '*') && !isBold : false\n const isCode = view ? isWrappedWith(view, '`') : false\n const isStrike = view ? isWrappedWith(view, '~~') : false\n const isCollapsible = view ? (hasLinePrefix(view, '>> ') || hasLinePrefix(view, '^^ ')) : false\n const headingLevel = view ? getCurrentHeadingLevel(view) : 0\n\n // Check if cursor is inside inline code\n if (view) {\n const inlineCode = findInlineCodeAtCursor(view)\n if (inlineCode) {\n items.push({\n label: 'Copy block',\n action: () => {\n copyToClipboard(inlineCode.content)\n }\n })\n items.push({ divider: true, label: '' })\n }\n }\n\n // Add \"Copy with includes\" if document has includes and resolver is available\n if (view && config?.resolveInclude) {\n const docText = view.state.doc.toString()\n if (hasIncludes(docText)) {\n items.push({\n label: 'Copy with includes',\n action: async () => {\n try {\n const resolved = await resolveAllIncludes(docText, config.resolveInclude!)\n await copyToClipboard(resolved)\n } catch (e) {\n console.error('[ContextMenu] Failed to resolve includes:', e)\n }\n }\n })\n items.push({ divider: true, label: '' })\n }\n }\n\n items.push({\n label: 'Transform',\n submenu: [\n {\n label: isCollapsible ? '✓ Collapsible Section' : 'Collapsible Section',\n action: (view) => toggleLinePrefix(view, '>> ')\n },\n { divider: true, label: '' },\n {\n label: headingLevel === 1 ? '✓ Heading 1' : 'Heading 1',\n action: (view) => setHeadingLevel(view, headingLevel === 1 ? 0 : 1)\n },\n {\n label: headingLevel === 2 ? '✓ Heading 2' : 'Heading 2',\n action: (view) => setHeadingLevel(view, headingLevel === 2 ? 0 : 2)\n },\n {\n label: headingLevel === 3 ? '✓ Heading 3' : 'Heading 3',\n action: (view) => setHeadingLevel(view, headingLevel === 3 ? 0 : 3)\n },\n { divider: true, label: '' },\n {\n label: isBold ? '✓ Bold' : 'Bold',\n action: (view) => wrapSelection(view, '**')\n },\n {\n label: isItalic ? '✓ Italic' : 'Italic',\n action: (view) => wrapSelection(view, '*')\n },\n {\n label: isCode ? '✓ Code' : 'Code',\n action: (view) => wrapSelection(view, '`')\n },\n {\n label: isStrike ? '✓ Strikethrough' : 'Strikethrough',\n action: (view) => wrapSelection(view, '~~')\n }\n ]\n })\n\n // Emoji shortcuts submenu\n const emojiShortcuts = config?.getEmojiShortcuts?.() ?? []\n if (emojiShortcuts.length > 0) {\n items.push({ divider: true, label: '' })\n items.push({\n label: 'Emoji',\n submenu: emojiShortcuts.map((shortcut) => ({\n label: `${shortcut.emoji} ${shortcut.name || shortcut.emoji}`,\n _emojiDescription: shortcut.description,\n action: (view: EditorView) => {\n const pos = view.state.selection.main.head\n view.dispatch({\n changes: { from: pos, insert: shortcut.emoji }\n })\n }\n } as MenuItem))\n })\n }\n\n return items\n}\n\n// Create and show context menu\nexport function showContextMenu(\n view: EditorView,\n x: number,\n y: number,\n items?: MenuItem[],\n config?: ContextMenuConfig\n) {\n const menuItems = items ?? getDefaultMenuItems(view, config)\n // Remove existing menu\n hideContextMenu()\n\n const menu = document.createElement('div') as HTMLDivElement & { _emojiCleanup?: () => void }\n menu.className = 'cm-context-menu'\n menu.style.left = `${x}px`\n menu.style.top = `${y}px`\n menu.setAttribute('data-context-menu', 'true')\n\n // Track active tooltip for Cmd+hover on emoji items\n let activeTooltip: HTMLElement | null = null\n let hoveredEmojiItem: { el: HTMLElement; desc: string } | null = null\n\n function showEmojiTooltip(el: HTMLElement, description: string) {\n hideEmojiTooltip()\n const tooltip = document.createElement('div')\n tooltip.className = 'cm-emoji-tooltip'\n tooltip.textContent = description\n document.body.appendChild(tooltip)\n\n const rect = el.getBoundingClientRect()\n tooltip.style.left = `${rect.right + 8}px`\n tooltip.style.top = `${rect.top}px`\n\n // Adjust if off-screen\n requestAnimationFrame(() => {\n const tRect = tooltip.getBoundingClientRect()\n if (tRect.right > window.innerWidth) {\n tooltip.style.left = `${rect.left - tRect.width - 8}px`\n }\n if (tRect.bottom > window.innerHeight) {\n tooltip.style.top = `${window.innerHeight - tRect.height - 8}px`\n }\n })\n\n activeTooltip = tooltip\n }\n\n function hideEmojiTooltip() {\n if (activeTooltip) {\n activeTooltip.remove()\n activeTooltip = null\n }\n }\n\n // Cmd key listener for emoji tooltips\n const cmdKeyDown = (e: KeyboardEvent) => {\n if (e.key === 'Meta' && hoveredEmojiItem) {\n showEmojiTooltip(hoveredEmojiItem.el, hoveredEmojiItem.desc)\n }\n }\n const cmdKeyUp = (e: KeyboardEvent) => {\n if (e.key === 'Meta') {\n hideEmojiTooltip()\n }\n }\n document.addEventListener('keydown', cmdKeyDown)\n document.addEventListener('keyup', cmdKeyUp)\n\n // Store cleanup so hideContextMenu can remove listeners\n menu._emojiCleanup = () => {\n document.removeEventListener('keydown', cmdKeyDown)\n document.removeEventListener('keyup', cmdKeyUp)\n hideEmojiTooltip()\n hoveredEmojiItem = null\n }\n\n function renderItems(container: HTMLElement, menuItems: MenuItem[], isSubmenu = false) {\n menuItems.forEach((item) => {\n if (item.divider) {\n const divider = document.createElement('div')\n divider.className = 'cm-context-menu-divider'\n container.appendChild(divider)\n return\n }\n\n const menuItem = document.createElement('div')\n menuItem.className = 'cm-context-menu-item'\n\n if (item.submenu) {\n menuItem.classList.add('has-submenu')\n menuItem.innerHTML = `<span>${item.label}</span><span class=\"submenu-arrow\">▸</span>`\n\n const submenu = document.createElement('div')\n submenu.className = 'cm-context-submenu'\n\n // Emoji tooltip delegation: mousemove on submenu container\n // (mouseenter on individual items doesn't fire when submenu appears under cursor)\n let currentHoveredEl: HTMLElement | null = null\n submenu.addEventListener('mousemove', (e) => {\n // Find which direct child item is under the cursor\n let target: HTMLElement | null = null\n for (const child of submenu.children) {\n const rect = (child as HTMLElement).getBoundingClientRect()\n if (e.clientY >= rect.top && e.clientY <= rect.bottom) {\n target = child as HTMLElement\n break\n }\n }\n \n if (target) {\n // console.log('[EmojiTooltip] Mousemove hit target:', target.textContent, 'data:', target.dataset)\n }\n\n if (target === currentHoveredEl) return\n currentHoveredEl = target\n \n const desc = target?.dataset.emojiDesc\n console.log('[EmojiTooltip] Hover changed. Target:', target?.textContent?.trim(), 'Desc:', desc, 'Meta:', e.metaKey)\n \n if (target && desc) {\n hoveredEmojiItem = { el: target, desc }\n if (e.metaKey) {\n showEmojiTooltip(target, desc)\n }\n } else {\n hoveredEmojiItem = null\n hideEmojiTooltip()\n }\n })\n submenu.addEventListener('mouseleave', () => {\n currentHoveredEl = null\n hoveredEmojiItem = null\n hideEmojiTooltip()\n })\n\n renderItems(submenu, item.submenu, true)\n menuItem.appendChild(submenu)\n } else {\n menuItem.textContent = item.label\n menuItem.addEventListener('click', (e) => {\n e.stopPropagation()\n hideContextMenu()\n item.action?.(view)\n view.focus()\n })\n\n // Store description as data attribute for mousemove delegation\n if (item._emojiDescription) {\n menuItem.dataset.emojiDesc = item._emojiDescription\n console.log('[EmojiTooltip] Set data-emoji-desc on item:', item.label, 'desc:', item._emojiDescription)\n }\n }\n\n container.appendChild(menuItem)\n })\n }\n\n renderItems(menu, menuItems)\n console.log('[EmojiTooltip] Menu rendered. HTML:', menu.innerHTML)\n document.body.appendChild(menu)\n // console.log('[ContextMenu] Menu appended to body, element:', menu)\n\n // Adjust position if menu goes off screen\n requestAnimationFrame(() => {\n const rect = menu.getBoundingClientRect()\n let newLeft = x\n let newTop = y\n\n // Горизонтальная корректировка\n if (rect.right > window.innerWidth) {\n newLeft = window.innerWidth - rect.width - 10\n }\n\n // Вертикальная корректировка: если не хватает места снизу - открываем вверх\n const spaceBelow = window.innerHeight - y\n const spaceAbove = y\n\n if (rect.height > spaceBelow && spaceAbove > spaceBelow) {\n // Открываем вверх от курсора\n newTop = y - rect.height\n // console.log('[ContextMenu] Открываем вверх: spaceBelow=', spaceBelow, 'spaceAbove=', spaceAbove, 'menuHeight=', rect.height)\n } else if (rect.bottom > window.innerHeight) {\n // Сдвигаем вверх чтобы поместилось\n newTop = window.innerHeight - rect.height - 10\n }\n\n // Не допускаем отрицательные значения\n menu.style.left = `${Math.max(10, newLeft)}px`\n menu.style.top = `${Math.max(10, newTop)}px`\n })\n\n // Close on click outside\n const closeHandler = (e: MouseEvent) => {\n if (!(e.target as HTMLElement).closest('[data-context-menu]')) {\n hideContextMenu()\n document.removeEventListener('click', closeHandler)\n }\n }\n\n // Close on Escape\n const escHandler = (e: KeyboardEvent) => {\n if (e.key === 'Escape') {\n hideContextMenu()\n document.removeEventListener('keydown', escHandler)\n }\n }\n\n setTimeout(() => {\n document.addEventListener('click', closeHandler)\n document.addEventListener('keydown', escHandler)\n }, 0)\n}\n\nexport function hideContextMenu() {\n const existing = document.querySelector('[data-context-menu]') as any\n if (existing) {\n existing._emojiCleanup?.()\n existing.remove()\n }\n}\n\n// ============================================================================\n// Command Palette (Cmd+/)\n// ============================================================================\n\ninterface PaletteItem {\n label: string\n color: string\n action: (view: EditorView) => void\n}\n\nfunction getPaletteItems(view: EditorView): PaletteItem[] {\n const headingLevel = getCurrentHeadingLevel(view)\n const isBold = isWrappedWith(view, '**')\n const isItalic = isWrappedWith(view, '*') && !isBold\n const isCode = isWrappedWith(view, '`')\n const isCollapsible = hasLinePrefix(view, '>>') || hasLinePrefix(view, '^^')\n return [\n { label: isCollapsible ? '✓ Collapsible' : 'Collapsible', color: '#868e96', action: (v) => toggleLinePrefix(v, '>> ') },\n { label: isBold ? '✓ Bold' : 'Bold', color: '#ffa348', action: (v) => wrapSelection(v, '**') },\n { label: isItalic ? '✓ Italic' : 'Italic', color: '#69dbdb', action: (v) => wrapSelection(v, '*') },\n { label: isCode ? '✓ Code' : 'Code', color: '#50fa7b', action: (v) => wrapSelection(v, '`') },\n { label: headingLevel === 1 ? '✓ H1' : 'H1', color: '#c678dd', action: (v) => setHeadingLevel(v, headingLevel === 1 ? 0 : 1) },\n { label: headingLevel === 2 ? '✓ H2' : 'H2', color: '#b197fc', action: (v) => setHeadingLevel(v, headingLevel === 2 ? 0 : 2) },\n { label: headingLevel === 3 ? '✓ H3' : 'H3', color: '#a78bfa', action: (v) => setHeadingLevel(v, headingLevel === 3 ? 0 : 3) },\n { label: '📋 AI Paste', color: '#4ecdc4', action: (v) => activateAIPasteMode(v) },\n ]\n}\n\nlet paletteKeydownHandler: ((e: KeyboardEvent) => void) | null = null\nlet paletteClickHandler: ((e: MouseEvent) => void) | null = null\n\nexport function hideCommandPalette() {\n const existing = document.querySelector('[data-command-palette]')\n if (existing) {\n existing.remove()\n }\n if (paletteKeydownHandler) {\n document.removeEventListener('keydown', paletteKeydownHandler, true)\n paletteKeydownHandler = null\n }\n if (paletteClickHandler) {\n document.removeEventListener('click', paletteClickHandler)\n paletteClickHandler = null\n }\n}\n\nexport function showCommandPalette(view: EditorView, capturedSelection?: EditorSelection) {\n hideCommandPalette()\n\n // Priority: capturedSelection > current view selection > lastNonEmptySelection\n // When capturedSelection is provided (from Cmd+/ keydown at Prec.highest),\n // trust it — if it's empty, user genuinely has no selection.\n // Only fallback to lastNonEmptySelection when NO capturedSelection was provided.\n let sel = capturedSelection ?? view.state.selection\n if (!capturedSelection && sel.main.empty && lastNonEmptySelection && !lastNonEmptySelection.main.empty) {\n sel = lastNonEmptySelection\n }\n const selMain = sel.main\n\n // Restore selection into the view so getPaletteItems/isWrappedWith see it\n if (!selMain.empty) {\n view.dispatch({ selection: sel })\n }\n\n const pos = selMain.head\n // coordsAtPos returns null at fold boundaries (cursor at end of folded ^^ line).\n // Fallback: side=-1 gets coords from the left (visible) side of the boundary.\n const coords = view.coordsAtPos(pos) ?? view.coordsAtPos(pos, -1)\n if (!coords) return\n\n const items = getPaletteItems(view)\n\n const palette = document.createElement('div')\n palette.className = 'cm-command-palette'\n palette.setAttribute('data-command-palette', 'true')\n palette.style.left = `${coords.left}px`\n palette.style.top = `${coords.bottom + 4}px`\n\n // Show selected text preview if there's a selection\n if (!selMain.empty) {\n const selectedText = view.state.sliceDoc(selMain.from, selMain.to)\n\n const preview = document.createElement('div')\n preview.className = 'cm-command-palette-preview'\n const truncated = selectedText.length > 30 ? selectedText.slice(0, 30) + '...' : selectedText\n preview.textContent = truncated\n palette.appendChild(preview)\n }\n\n // Items container (so renderItems doesn't destroy preview)\n const itemsContainer = document.createElement('div')\n palette.appendChild(itemsContainer)\n\n let activeIndex = 0\n\n function renderItems() {\n itemsContainer.innerHTML = ''\n items.forEach((item, i) => {\n const el = document.createElement('div')\n el.className = 'cm-command-palette-item' + (i === activeIndex ? ' active' : '')\n\n const colorBar = document.createElement('span')\n colorBar.className = 'palette-color'\n colorBar.style.backgroundColor = item.color\n\n const label = document.createElement('span')\n label.textContent = item.label\n\n el.appendChild(colorBar)\n el.appendChild(label)\n\n el.addEventListener('click', (e) => {\n e.stopPropagation()\n hideCommandPalette()\n item.action(view)\n view.focus()\n })\n\n itemsContainer.appendChild(el)\n })\n }\n\n renderItems()\n document.body.appendChild(palette)\n\n // Adjust position if off-screen\n requestAnimationFrame(() => {\n const rect = palette.getBoundingClientRect()\n if (rect.right > window.innerWidth) {\n palette.style.left = `${window.innerWidth - rect.width - 10}px`\n }\n if (rect.bottom > window.innerHeight) {\n palette.style.top = `${coords.top - rect.height - 4}px`\n }\n palette.style.left = `${Math.max(10, parseInt(palette.style.left))}px`\n palette.style.top = `${Math.max(10, parseInt(palette.style.top))}px`\n })\n\n // Save selection to restore after action\n const savedSelection = sel\n\n paletteKeydownHandler = (e: KeyboardEvent) => {\n if (e.key === 'ArrowDown' || e.key === 'ArrowUp' || e.key === 'Enter' || e.key === 'Escape') {\n // Stop event from reaching CodeMirror\n e.preventDefault()\n e.stopPropagation()\n e.stopImmediatePropagation()\n }\n\n if (e.key === 'ArrowDown') {\n activeIndex = (activeIndex + 1) % items.length\n renderItems()\n } else if (e.key === 'ArrowUp') {\n activeIndex = (activeIndex - 1 + items.length) % items.length\n renderItems()\n } else if (e.key === 'Enter') {\n const action = items[activeIndex].action\n hideCommandPalette()\n // Restore cursor position before applying action (in case arrows moved it)\n view.dispatch({ selection: savedSelection })\n action(view)\n view.focus()\n } else if (e.key === 'Escape') {\n hideCommandPalette()\n // Restore cursor position\n view.dispatch({ selection: savedSelection })\n view.focus()\n }\n }\n\n paletteClickHandler = (e: MouseEvent) => {\n if (!(e.target as HTMLElement).closest('[data-command-palette]')) {\n hideCommandPalette()\n }\n }\n\n setTimeout(() => {\n document.addEventListener('keydown', paletteKeydownHandler!, true)\n document.addEventListener('click', paletteClickHandler!)\n }, 0)\n}\n\n// Create context menu handler for EditorView\nexport function createContextMenuHandler(config?: ContextMenuConfig): Extension {\n return Prec.highest(EditorView.domEventHandlers({\n contextmenu: (event, view) => {\n // console.log('[ContextMenu] Right click at', event.clientX, event.clientY)\n event.preventDefault()\n\n const selection = view.state.selection.main\n const clickPos = view.posAtCoords({ x: event.clientX, y: event.clientY })\n\n // Только перемещать курсор если НЕТ выделения или клик ВНЕ выделения\n if (clickPos !== null) {\n const hasSelection = !selection.empty\n const clickInsideSelection = hasSelection && clickPos >= selection.from && clickPos <= selection.to\n\n if (!clickInsideSelection) {\n // Клик вне выделения — перемещаем курсор\n view.dispatch({\n selection: { anchor: clickPos }\n })\n }\n // Если клик внутри выделения — оставляем выделение как есть\n }\n\n showContextMenu(view, event.clientX, event.clientY, undefined, config)\n return true\n },\n }))\n}\n","import { EditorView, Decoration, DecorationSet, ViewPlugin, ViewUpdate } from '@codemirror/view'\nimport { RangeSetBuilder } from '@codemirror/state'\n\n/**\n * Plugin that adds hanging indent for wrapped lines.\n * When a line starts with whitespace and wraps, continuation lines\n * will be indented to match the first non-whitespace character.\n */\nfunction computeHangingIndent(view: EditorView): DecorationSet {\n const builder = new RangeSetBuilder<Decoration>()\n\n for (const { from, to } of view.visibleRanges) {\n for (let pos = from; pos <= to; ) {\n const line = view.state.doc.lineAt(pos)\n const text = line.text\n\n // Count leading whitespace\n let indent = 0\n for (let i = 0; i < text.length; i++) {\n if (text[i] === ' ') {\n indent++\n } else if (text[i] === '\\t') {\n // Tab = 4 spaces (matches indentUnit in Editor.tsx)\n indent += 4\n } else {\n break\n }\n }\n\n // Only add decoration if there's indent\n if (indent > 0) {\n const deco = Decoration.line({\n attributes: {\n // FIX: Add 6px (base padding) to padding-left to compensate for negative text-indent.\n // This ensures the first character stays at the 6px mark instead of jumping to 0px.\n style: `padding-left: calc(${indent}ch + 6px); text-indent: -${indent}ch;`\n }\n })\n builder.add(line.from, line.from, deco)\n }\n\n pos = line.to + 1\n }\n }\n\n return builder.finish()\n}\n\nexport const hangingIndentPlugin = ViewPlugin.fromClass(\n class {\n decorations: DecorationSet\n\n constructor(view: EditorView) {\n this.decorations = computeHangingIndent(view)\n }\n\n update(update: ViewUpdate) {\n if (update.docChanged || update.viewportChanged) {\n this.decorations = computeHangingIndent(update.view)\n }\n }\n },\n {\n decorations: (v) => v.decorations\n }\n)\n","import { EditorView } from '@codemirror/view'\nimport { foldedRanges, foldEffect, unfoldEffect, foldable } from '@codemirror/language'\n\nexport const headerClickPlugin = EditorView.domEventHandlers({\n mousedown(event, view) {\n const target = event.target as HTMLElement\n\n // Ищем .cm-line родителя\n const lineEl = target.closest('.cm-line')\n if (!lineEl) return\n\n // Используем posAtDOM — надёжнее для виджетов\n const pos = view.posAtDOM(lineEl)\n const line = view.state.doc.lineAt(pos)\n const text = line.text.trim()\n\n // Если строка начинается с >> или ^^ — переключаем fold\n if (text.startsWith('>>') || text.startsWith('^^')) {\n let isFolded = false\n let foldedRange: { from: number; to: number } | null = null\n\n foldedRanges(view.state).between(line.from, line.to, (from, to) => {\n isFolded = true\n foldedRange = { from, to }\n })\n\n if (isFolded && foldedRange) {\n view.dispatch({ effects: unfoldEffect.of(foldedRange) })\n } else {\n const range = foldable(view.state, line.from, line.to)\n if (range) {\n view.dispatch({ effects: foldEffect.of(range) })\n }\n }\n\n // Предотвращаем стандартное поведение\n event.preventDefault()\n return true\n }\n\n return false\n }\n})\n","import { lineNumbers, GutterMarker } from '@codemirror/view'\nimport { foldedRanges, foldEffect, unfoldEffect, foldable } from '@codemirror/language'\n\nexport interface IncludeOffset {\n editorLine: number // 1-based line number in editor\n diskLines: number // how many lines this block takes on disk\n}\n\n/**\n * Create lineNumbers gutter with:\n * - Virtual line numbers (accounting for transclusion)\n * - Fold/unfold on click for collapsible headers\n */\nexport function createLineNumbersWithVirtual(offsets: IncludeOffset[] = []) {\n return lineNumbers({\n formatNumber: (editorLine: number) => {\n let diskLine = editorLine\n for (const offset of offsets) {\n if (editorLine > offset.editorLine) {\n diskLine += offset.diskLines // hidden block lines (BEGIN+content+END) not visible in editor\n }\n }\n return String(diskLine)\n },\n domEventHandlers: {\n // mousedown to prevent text selection\n mousedown(view, line, event) {\n const lineObj = view.state.doc.lineAt(line.from)\n const text = lineObj.text.trim()\n\n // Fold/unfold logic for >> (expanded) or ^^ (collapsed) headers\n if (text.startsWith('>>') || text.startsWith('^^')) {\n let isFolded = false\n let foldedRange: { from: number; to: number } | null = null\n\n foldedRanges(view.state).between(line.from, line.to, (from, to) => {\n isFolded = true\n foldedRange = { from, to }\n })\n\n // Find marker position for replacement\n const lineText = lineObj.text\n const createMarkerChange = (fromMarker: string, toMarker: string) => {\n const idx = lineText.indexOf(fromMarker)\n if (idx === -1) return null\n return { from: lineObj.from + idx, to: lineObj.from + idx + 2, insert: toMarker }\n }\n\n if (isFolded && foldedRange) {\n // Unfold: ^^ -> >>\n const change = createMarkerChange('^^', '>>')\n view.dispatch({\n effects: unfoldEffect.of(foldedRange),\n changes: change ? [change] : undefined\n })\n } else {\n const range = foldable(view.state, line.from, line.to)\n if (range && (range.to - range.from) > 2) {\n // Fold: >> -> ^^\n const change = createMarkerChange('>>', '^^')\n view.dispatch({\n effects: foldEffect.of(range),\n changes: change ? [change] : undefined\n })\n }\n }\n\n event.preventDefault()\n event.stopPropagation()\n return true\n }\n\n return false\n }\n }\n })\n}\n\n// Legacy export for backwards compatibility (no virtual line numbers)\nexport const lineNumbersWithFold = createLineNumbersWithVirtual([])","import { gutter, GutterMarker } from '@codemirror/view'\nimport { EditorView } from '@codemirror/view'\nimport { foldedRanges, foldEffect, unfoldEffect, foldable } from '@codemirror/language'\nimport { RangeSet } from '@codemirror/state'\n\n// Маркер для collapsible секций\nclass CollapsibleMarker extends GutterMarker {\n constructor(readonly isOpen: boolean, readonly isEmpty: boolean) {\n super()\n }\n\n toDOM() {\n const el = document.createElement('div')\n el.className = `cm-fold-marker ${this.isOpen ? 'open' : 'closed'}${this.isEmpty ? ' empty' : ''}`\n el.textContent = this.isOpen ? '▾' : '▸'\n return el\n }\n}\n\nconst openMarker = new CollapsibleMarker(true, false)\nconst closedMarker = new CollapsibleMarker(false, false)\nconst emptyMarker = new CollapsibleMarker(false, true) // пустая секция - всегда \"свёрнута\" (декоративно)\n\n// Проверяет есть ли контент для сворачивания\nfunction hasContent(view: EditorView, lineFrom: number, lineTo: number): boolean {\n const range = foldable(view.state, lineFrom, lineTo)\n // Если range больше 2 символов - есть контент\n return range !== null && (range.to - range.from) > 2\n}\n\n// Проверяет свёрнута ли строка\nfunction isFolded(view: EditorView, lineFrom: number, lineTo: number): boolean {\n let folded = false\n foldedRanges(view.state).between(lineFrom, lineTo, () => {\n folded = true\n })\n return folded\n}\n\nexport const collapsibleGutter = gutter({\n class: 'cm-foldGutter',\n\n markers: (view) => {\n const markers: { from: number; marker: GutterMarker }[] = []\n\n for (let i = 1; i <= view.state.doc.lines; i++) {\n const line = view.state.doc.line(i)\n const text = line.text.trim()\n\n if (text.startsWith('>>') || text.startsWith('^^')) {\n const hasContentToFold = hasContent(view, line.from, line.to)\n\n if (!hasContentToFold) {\n // Пустая секция - декоративный маркер\n markers.push({ from: line.from, marker: emptyMarker })\n } else if (isFolded(view, line.from, line.to)) {\n markers.push({ from: line.from, marker: closedMarker })\n } else {\n markers.push({ from: line.from, marker: openMarker })\n }\n }\n }\n\n return RangeSet.of(markers.map(m => m.marker.range(m.from)))\n },\n\n domEventHandlers: {\n mousedown(view, line, event) {\n const lineObj = view.state.doc.lineAt(line.from)\n const text = lineObj.text.trim()\n\n if (!text.startsWith('>>') && !text.startsWith('^^')) return false\n\n // Проверяем есть ли контент\n const hasContentToFold = hasContent(view, line.from, line.to)\n if (!hasContentToFold) {\n // Пустая секция - ничего не делаем\n event.preventDefault()\n return true\n }\n\n // Проверяем свёрнуто ли\n let foldedRange: { from: number; to: number } | null = null\n foldedRanges(view.state).between(line.from, line.to, (from, to) => {\n foldedRange = { from, to }\n })\n\n if (foldedRange) {\n view.dispatch({ effects: unfoldEffect.of(foldedRange) })\n } else {\n const range = foldable(view.state, line.from, line.to)\n if (range) {\n view.dispatch({ effects: foldEffect.of(range) })\n }\n }\n\n event.preventDefault()\n return true\n }\n }\n})\n","import { ViewPlugin, Decoration, DecorationSet, EditorView, keymap } from '@codemirror/view'\nimport { Prec } from '@codemirror/state'\nimport { foldedRanges, foldEffect, unfoldEffect, foldable } from '@codemirror/language'\nimport { CollapsibleArrowWidget } from '../widgets'\n\n// >> = expanded (open), ^^ = collapsed (folded)\nconst collapsiblePattern = /^(\\s*)(>>|\\^\\^)/\n\n// Diagnostic: track pending async fold operations\nconst _foldDiag = { pendingFold: 0, pendingUnfold: 0 }\n;(window as any).__foldDiag = _foldDiag\n\n/**\n * Плагин для отображения inline стрелок сворачивания\n * Стрелки отображаются с учётом отступа строки (не в gutter)\n */\nexport const collapsibleArrowPlugin = ViewPlugin.fromClass(\n class {\n decorations: DecorationSet\n\n constructor(view: EditorView) {\n this.decorations = this.buildDecorations(view)\n }\n\n update(update: { docChanged: boolean; selectionSet: boolean; view: EditorView; state: any }) {\n // Обновляем при изменении документа, selection или состояния fold\n if (update.docChanged || update.selectionSet || this.foldStateChanged(update)) {\n this.decorations = this.buildDecorations(update.view)\n }\n\n // Auto-unfold stale folds BEFORE auto-folding (order matters for setTimeout queue)\n if (update.docChanged) {\n this.autoUnfoldStaleFolds(update.view)\n this.autoFoldCollapsedMarkers(update.view)\n }\n }\n\n /**\n * Automatically fold blocks marked with ^^ (collapsed marker)\n * This ensures pasted ^^ blocks get folded\n */\n autoFoldCollapsedMarkers(view: EditorView) {\n const doc = view.state.doc\n const foldEffects: any[] = []\n\n for (let i = 1; i <= doc.lines; i++) {\n const line = doc.line(i)\n const trimmed = line.text.trim()\n\n // Check for ^^ marker (collapsed state)\n if (trimmed.startsWith('^^')) {\n // Check if already folded\n let isFolded = false\n foldedRanges(view.state).between(line.from, line.to, () => {\n isFolded = true\n })\n\n // If not folded, fold it\n if (!isFolded) {\n const range = foldable(view.state, line.from, line.to)\n if (range && (range.to - range.from) > 2) {\n foldEffects.push(foldEffect.of(range))\n }\n }\n }\n }\n\n // Count total ^^ blocks for diagnostic\n let totalCollapsed = 0\n for (let i = 1; i <= doc.lines; i++) {\n if (doc.line(i).text.trim().startsWith('^^')) totalCollapsed++\n }\n\n // Apply all fold effects in one dispatch\n if (foldEffects.length === 0) {\n if (totalCollapsed > 0) {\n console.log('[Fold:autoFold] ran: 0 to fold, all', totalCollapsed, '^^ blocks already folded')\n }\n return\n }\n {\n console.log('[Fold:autoFold]', foldEffects.length, '/', totalCollapsed, 'unfolded ^^ blocks found, scheduling fold')\n _foldDiag.pendingFold++\n const count = foldEffects.length\n setTimeout(() => {\n _foldDiag.pendingFold--\n view.dispatch({ effects: foldEffects })\n }, 0)\n }\n }\n\n /**\n * Auto-unfold stale folds.\n * When content after a folded section gets indented (Tab) or moved (Alt+Up/Down),\n * the fold range becomes stale — foldable() returns a different range than stored.\n * Detect this and unfold + swap ^^ → >> to keep state consistent.\n */\n autoUnfoldStaleFolds(view: EditorView) {\n const doc = view.state.doc\n const unfoldEffects: any[] = []\n const markerChanges: { from: number; to: number; insert: string }[] = []\n\n foldedRanges(view.state).between(0, doc.length, (foldFrom, foldTo) => {\n // foldFrom is headerLine.to (fold starts at end of header line)\n const headerLine = doc.lineAt(foldFrom)\n const match = headerLine.text.match(collapsiblePattern)\n if (!match) return // Not a collapsible fold\n\n // Compute what the fold range SHOULD be based on current content\n const expectedRange = foldable(view.state, headerLine.from, headerLine.to)\n\n // Stale if: no foldable range anymore, or range endpoint changed\n if (!expectedRange || expectedRange.to !== foldTo) {\n unfoldEffects.push(unfoldEffect.of({ from: foldFrom, to: foldTo }))\n // Swap ^^ → >> to prevent autoFoldCollapsedMarkers from re-folding\n if (match[2] === '^^') {\n const markerStart = headerLine.from + match[1].length\n markerChanges.push({ from: markerStart, to: markerStart + 2, insert: '>>' })\n }\n }\n })\n\n if (unfoldEffects.length > 0) {\n _foldDiag.pendingUnfold++\n // Use setTimeout to avoid dispatch during update\n // ^^ → >> is same length (2 chars), so positions stay stable\n setTimeout(() => {\n _foldDiag.pendingUnfold--\n view.dispatch({\n ...(markerChanges.length > 0 ? { changes: markerChanges } : {}),\n effects: unfoldEffects\n })\n }, 0)\n }\n }\n\n foldStateChanged(update: any): boolean {\n // Проверяем изменилось ли состояние fold\n for (const tr of update.transactions || []) {\n for (const effect of tr.effects) {\n if (effect.is(foldEffect) || effect.is(unfoldEffect)) {\n return true\n }\n }\n }\n return false\n }\n\n buildDecorations(view: EditorView): DecorationSet {\n const decorations: { from: number; to: number; decoration: Decoration }[] = []\n const doc = view.state.doc\n\n // Стрелка отображается ВСЕГДА (даже на активной строке)\n // Это позволяет кликать для fold/unfold в любой момент\n\n for (let i = 1; i <= doc.lines; i++) {\n const line = doc.line(i)\n const match = line.text.match(collapsiblePattern)\n\n if (match) {\n const indentLen = match[1].length // Длина отступа\n const markerLen = match[2].length // Длина '>>' (всегда 2)\n\n // ВАЖНО: заменяем ТОЛЬКО '>>', оставляя отступ в DOM\n const decoStart = line.from + indentLen\n const decoEnd = decoStart + markerLen\n\n // Определяем состояние fold\n const hasContent = this.hasContent(view, line.from, line.to)\n const isFolded = this.isFolded(view, line.from, line.to)\n\n // Определяем тип форматирования в заголовке\n const formatType = this.detectFormatting(line.text)\n\n // Создаём виджет со стрелкой\n const widget = new CollapsibleArrowWidget(\n '', // Отступ не нужен — CodeMirror отрисует его как обычный текст\n !isFolded, // isOpen (empty sections show ▾ with .empty styling)\n !hasContent, // isEmpty\n line.from,\n formatType, // Тип форматирования для цвета\n view // EditorView для обработки кликов\n )\n\n // Заменяем ТОЛЬКО '>>' на стрелку (отступ остаётся в DOM!)\n decorations.push({\n from: decoStart,\n to: decoEnd,\n decoration: Decoration.replace({ widget })\n })\n }\n }\n\n decorations.sort((a, b) => a.from - b.from)\n\n try {\n return Decoration.set(\n decorations.map(d => d.decoration.range(d.from, d.to)),\n true\n )\n } catch (e) {\n console.error('[CollapsibleArrow] Error:', e)\n return Decoration.none\n }\n }\n\n hasContent(view: EditorView, lineFrom: number, lineTo: number): boolean {\n const range = foldable(view.state, lineFrom, lineTo)\n return range !== null && (range.to - range.from) > 2\n }\n\n isFolded(view: EditorView, lineFrom: number, lineTo: number): boolean {\n let folded = false\n foldedRanges(view.state).between(lineFrom, lineTo, () => {\n folded = true\n })\n return folded\n }\n\n /**\n * Определяет тип форматирования в тексте заголовка (после >> или ^^)\n * Приоритет: h1-h6 > bold > italic > code > strike\n */\n detectFormatting(lineText: string): string | null {\n // Убираем >> или ^^ и отступ в начале\n const content = lineText.replace(/^\\s*(>>|\\^\\^)\\s*/, '')\n\n // Проверяем заголовки (# Header) — высший приоритет\n const headingMatch = content.match(/^(#{1,6})\\s/)\n if (headingMatch) {\n const level = headingMatch[1].length\n return `h${level}`\n }\n\n // Проверяем форматирование в порядке приоритета\n // Bold: только ** (не __)\n if (/\\*\\*[^*]+\\*\\*/.test(content)) {\n return 'bold'\n }\n // Italic: только * (не _)\n if (/(?<!\\*)\\*[^*]+\\*(?!\\*)/.test(content)) {\n return 'italic'\n }\n if (/`[^`]+`/.test(content)) {\n return 'code'\n }\n if (/~~[^~]+~~/.test(content)) {\n return 'strike'\n }\n\n return null\n }\n },\n { decorations: v => v.decorations }\n)\n\n/**\n * Обработчик кликов на стрелки сворачивания\n */\nexport function createCollapsibleArrowClickHandler() {\n return EditorView.domEventHandlers({\n click(event, view) {\n const target = event.target as HTMLElement\n\n // Проверяем клик на стрелку\n if (!target.classList.contains('cm-collapsible-arrow')) {\n return false\n }\n\n const lineFromStr = target.dataset.lineFrom\n if (!lineFromStr) return false\n\n const lineFrom = parseInt(lineFromStr, 10)\n const line = view.state.doc.lineAt(lineFrom)\n\n // Проверяем есть ли контент для сворачивания\n const range = foldable(view.state, line.from, line.to)\n if (!range || (range.to - range.from) <= 2) {\n // Пустая секция — ничего не делаем\n event.preventDefault()\n return true\n }\n\n // Проверяем свёрнуто ли\n let foldedRange: { from: number; to: number } | null = null\n foldedRanges(view.state).between(line.from, line.to, (from, to) => {\n foldedRange = { from, to }\n })\n\n if (foldedRange) {\n view.dispatch({ effects: unfoldEffect.of(foldedRange) })\n } else {\n view.dispatch({ effects: foldEffect.of(range) })\n }\n\n event.preventDefault()\n return true\n }\n })\n}\n\n/**\n * Custom Enter handler (Prec.high).\n *\n * Two responsibilities:\n *\n * 1. FOLDED SECTIONS: cursor on a folded ^^ header can be at fold.from\n * (headerLine.to) or fold.to (lastContentLine.to). Insert \\n after fold,\n * outside the inclusive boundary, so fold is not broken.\n * Only matches when cursor is exactly at a fold boundary of a collapsible header.\n *\n * 2. INDENT PRESERVATION: for all other Enter-at-line-end presses, copy\n * the current line's leading whitespace. This replaces CM6's\n * insertNewlineAndIndent which may not preserve indent without a Language.\n */\nexport function createCollapsibleEnterHandler() {\n return Prec.high(keymap.of([\n {\n key: 'Enter',\n run: (view: EditorView) => {\n const { state } = view\n const sel = state.selection.main\n if (!sel.empty) return false\n\n const pos = sel.head\n const line = state.doc.lineAt(pos)\n\n // Only intercept when cursor is at line end\n if (pos !== line.to) return false\n\n // --- Case 1: Folded collapsible section ---\n // Cursor can be at fold.from (headerLine.to) or fold.to (lastContentLine.to).\n let targetFold: { from: number; to: number } | null = null\n foldedRanges(state).between(pos, pos, (from, to) => {\n const headerLine = state.doc.lineAt(from)\n if (headerLine.text.match(collapsiblePattern) && (pos === headerLine.to || pos === to)) {\n targetFold = { from, to }\n }\n })\n\n if (targetFold) {\n const fold = targetFold as { from: number; to: number }\n // Insert \\n AFTER the fold's trailing \\n (= start of next line).\n // This avoids fold absorption since codeFolding decorations use inclusive: true.\n // Preserve header indent so the new line matches the folded section's level.\n const headerLine = state.doc.lineAt(fold.from)\n const headerIndent = headerLine.text.match(/^\\s*/)?.[0] ?? ''\n const foldEndLine = state.doc.lineAt(fold.to)\n if (foldEndLine.number < state.doc.lines) {\n const nextLineFrom = state.doc.line(foldEndLine.number + 1).from\n const insert = headerIndent + '\\n'\n view.dispatch({\n changes: { from: nextLineFrom, insert },\n selection: { anchor: nextLineFrom + headerIndent.length }\n })\n } else {\n const insert = '\\n' + headerIndent\n view.dispatch({\n changes: { from: state.doc.length, insert },\n selection: { anchor: state.doc.length + insert.length }\n })\n }\n return true\n }\n\n // --- Case 1.5: Expanded collapsible header (>>) — indent +1 tab ---\n const collapsibleMatch = line.text.match(/^(\\s*)(>>)\\s/)\n if (collapsibleMatch) {\n const currentIndent = collapsibleMatch[1]\n const insert = '\\n' + currentIndent + ' '\n view.dispatch(\n state.replaceSelection(insert),\n { scrollIntoView: true, userEvent: 'input' }\n )\n return true\n }\n\n // --- Case 2: Normal line — preserve indentation ---\n // Use current line's leading whitespace.\n // If current line has no indent, check the immediately next line only.\n let leading = /^\\s*/.exec(line.text)?.[0] ?? ''\n if (line.number < state.doc.lines) {\n const nextLine = state.doc.line(line.number + 1)\n const nextLeading = /^\\s*/.exec(nextLine.text)?.[0] ?? ''\n if (nextLeading.length > leading.length) {\n leading = nextLeading\n }\n }\n const insert = '\\n' + leading\n view.dispatch(\n state.replaceSelection(insert),\n { scrollIntoView: true, userEvent: 'input' }\n )\n return true\n }\n },\n {\n key: 'Mod-Enter',\n run: (view: EditorView) => {\n const { state } = view\n const sel = state.selection.main\n if (!sel.empty) return false\n\n const line = state.doc.lineAt(sel.head)\n\n // --- Folded collapsible section ---\n let targetFold: { from: number; to: number } | null = null\n foldedRanges(state).between(line.from, line.to, (from, to) => {\n const headerLine = state.doc.lineAt(from)\n if (headerLine.text.match(collapsiblePattern)) {\n targetFold = { from, to }\n }\n })\n\n if (targetFold) {\n const fold = targetFold as { from: number; to: number }\n // Preserve header indent so the new line matches the folded section's level.\n const headerLine = state.doc.lineAt(fold.from)\n const headerIndent = headerLine.text.match(/^\\s*/)?.[0] ?? ''\n const foldEndLine = state.doc.lineAt(fold.to)\n if (foldEndLine.number < state.doc.lines) {\n const nextLineFrom = state.doc.line(foldEndLine.number + 1).from\n const insert = headerIndent + '\\n'\n view.dispatch({\n changes: { from: nextLineFrom, insert },\n selection: { anchor: nextLineFrom + headerIndent.length },\n scrollIntoView: true\n })\n } else {\n const insert = '\\n' + headerIndent\n view.dispatch({\n changes: { from: state.doc.length, insert },\n selection: { anchor: state.doc.length + insert.length },\n scrollIntoView: true\n })\n }\n return true\n }\n\n // --- Expanded collapsible header (>>) — indent +1 tab ---\n const collapsibleMatch = line.text.match(/^(\\s*)(>>)\\s/)\n if (collapsibleMatch) {\n const currentIndent = collapsibleMatch[1]\n const insert = '\\n' + currentIndent + ' '\n view.dispatch({\n changes: { from: line.to, insert },\n selection: { anchor: line.to + insert.length },\n scrollIntoView: true,\n userEvent: 'input'\n })\n return true\n }\n\n // --- Normal line — insert after line end with look-ahead indent ---\n let leading = /^\\s*/.exec(line.text)?.[0] ?? ''\n if (line.number < state.doc.lines) {\n const nextLine = state.doc.line(line.number + 1)\n const nextLeading = /^\\s*/.exec(nextLine.text)?.[0] ?? ''\n if (nextLeading.length > leading.length) {\n leading = nextLeading\n }\n }\n const insert = '\\n' + leading\n view.dispatch({\n changes: { from: line.to, insert },\n selection: { anchor: line.to + insert.length },\n scrollIntoView: true,\n userEvent: 'input'\n })\n return true\n }\n }\n ]))\n}\n\n/**\n * Custom Backspace handler to prevent cursor from disappearing into folded sections.\n *\n * When cursor is at the start of a line and the previous position (pos-1)\n * is inside a folded collapsible range, default deleteCharBackward would\n * merge the line into the invisible fold. Instead, move cursor to the\n * visible end of the fold's header line.\n */\nexport function createCollapsibleBackspaceHandler() {\n return Prec.high(keymap.of([{\n key: 'Backspace',\n run: (view: EditorView) => {\n const { state } = view\n const sel = state.selection.main\n if (!sel.empty) return false\n\n const pos = sel.head\n if (pos === 0) return false\n const line = state.doc.lineAt(pos)\n if (pos !== line.from) return false\n\n // Check if pos-1 is inside a folded collapsible range\n let targetFold: { from: number; to: number } | null = null\n foldedRanges(state).between(pos - 1, pos - 1, (from, to) => {\n const headerLine = state.doc.lineAt(from)\n if (headerLine.text.match(collapsiblePattern)) {\n targetFold = { from, to }\n }\n })\n\n if (targetFold) {\n const fold = targetFold as { from: number; to: number }\n const headerLine = state.doc.lineAt(fold.from)\n // Place cursor 1 pos before fold.from to avoid inclusive fold boundary\n // (codeFolding uses inclusive: true → cursor at fold.from is \"inside\" invisible content)\n const targetPos = Math.max(headerLine.from, fold.from - 1)\n view.dispatch({ selection: { anchor: targetPos }, scrollIntoView: true })\n return true\n }\n return false\n }\n }]))\n}\n\n/**\n * Swap >> ↔ ^^ marker on a given line.\n * Returns the transaction change spec, or null if no marker found.\n */\nfunction createMarkerChange(line: { text: string; from: number }, fromMarker: string, toMarker: string) {\n const match = line.text.match(collapsiblePattern)\n if (!match || match[2] !== fromMarker) return null\n const markerStart = line.from + match[1].length\n return { from: markerStart, to: markerStart + fromMarker.length, insert: toMarker }\n}\n\n/**\n * Toggle fold/unfold on a collapsible header line.\n * Swaps >> ↔ ^^ and applies fold/unfold effect.\n * Optional `selection` moves cursor in the same dispatch (atomic).\n */\nfunction toggleFoldOnLine(\n view: EditorView,\n line: { from: number; to: number; text: string },\n selection?: { anchor: number }\n) {\n // Check if currently folded\n let foldedRange: { from: number; to: number } | null = null\n foldedRanges(view.state).between(line.from, line.to, (from, to) => {\n foldedRange = { from, to }\n })\n\n if (foldedRange) {\n // Unfold: ^^ → >>\n const markerChange = createMarkerChange(line, '^^', '>>')\n const effects = [unfoldEffect.of(foldedRange!)]\n view.dispatch({\n ...(markerChange ? { changes: markerChange } : {}),\n effects,\n ...(selection ? { selection } : {})\n })\n } else {\n // Fold: >> → ^^\n const range = foldable(view.state, line.from, line.to)\n if (!range || (range.to - range.from) <= 2) return // Empty section\n const markerChange = createMarkerChange(line, '>>', '^^')\n const effects = [foldEffect.of(range)]\n view.dispatch({\n ...(markerChange ? { changes: markerChange } : {}),\n effects,\n ...(selection ? { selection } : {})\n })\n }\n}\n\n/**\n * Scan upward from `pos` to find the nearest parent collapsible header\n * whose foldable range contains `pos`.\n */\nfunction findNearestParentHeader(state: EditorView['state'], pos: number) {\n const currentLine = state.doc.lineAt(pos)\n\n // Scan upward from current line\n for (let i = currentLine.number - 1; i >= 1; i--) {\n const line = state.doc.line(i)\n const match = line.text.match(collapsiblePattern)\n if (!match) continue\n\n // Check if this header's foldable range contains our position\n const range = foldable(state, line.from, line.to)\n if (range && range.to >= pos) {\n return line\n }\n\n // Also check if it's already folded and the fold range contains pos\n let foldedRange: { from: number; to: number } | null = null\n foldedRanges(state).between(line.from, line.to, (from, to) => {\n foldedRange = { from, to }\n })\n if (foldedRange && (foldedRange as { from: number; to: number }).to >= pos) {\n return line\n }\n }\n return null\n}\n\n/**\n * Cmd+. handler: fold/unfold nearest parent collapsible section.\n * If cursor is on a collapsible header — toggles that header.\n * Otherwise scans upward for the nearest parent header.\n *\n * Cursor always moves to end of header line (same dispatch, atomic).\n * Scroll is preserved so header appears at cursor's old screen position.\n */\nexport function createCollapsibleFoldParentHandler() {\n return Prec.high(keymap.of([\n {\n key: 'Mod-.',\n run: (view: EditorView) => {\n const { state } = view\n const pos = state.selection.main.head\n const currentLine = state.doc.lineAt(pos)\n\n // Case 1: cursor is on a collapsible header line\n if (collapsiblePattern.test(currentLine.text)) {\n toggleFoldOnLine(view, currentLine, { anchor: currentLine.to })\n return true\n }\n\n // Case 2: cursor inside section → fold nearest parent\n const parentLine = findNearestParentHeader(state, pos)\n if (parentLine) {\n // Capture cursor screen Y using lineBlockAt (document coordinates).\n // Must use lineBlockAt (not coordsAtPos) to stay in the same coordinate\n // space as scrollTop — coordsAtPos includes contentPaddingY offset.\n const cursorDocY = view.lineBlockAt(pos).top\n const headerDocY = view.lineBlockAt(parentLine.from).top\n const savedScrollTop = view.scrollDOM.scrollTop\n\n // Fold + move cursor to end of parent header (atomic dispatch)\n // >> → ^^ is same length, so parentLine.to is valid in new state\n toggleFoldOnLine(view, parentLine, { anchor: parentLine.to })\n\n // Adjust scroll: cursor moved from cursorDocY to headerDocY,\n // shift scrollTop by the same delta to keep screen position stable.\n // Browser auto-clamps scrollTop if document became too short.\n view.scrollDOM.scrollTop = savedScrollTop + (headerDocY - cursorDocY)\n\n return true\n }\n\n return true // Always consume the key\n }\n }\n ]))\n}\n","import { ViewPlugin, Decoration, DecorationSet, EditorView } from '@codemirror/view'\nimport { RangeSetBuilder } from '@codemirror/state'\n\nconst collapsiblePattern = /^(\\s*)(>>|\\^\\^)/\n\n/**\n * Определяет тип форматирования в тексте заголовка (после >>)\n * Приоритет: h1-h6 > bold > italic > code > strike\n * ВАЖНО: _ (нижнее подчёркивание) не учитывается — только *\n */\nfunction detectFormatting(lineText: string): string | null {\n // Убираем >> и отступ в начале\n const content = lineText.replace(/^\\s*(>>|\\^\\^)\\s*/, '')\n\n // Проверяем заголовки (# Header) — высший приоритет\n const headingMatch = content.match(/^(#{1,6})\\s/)\n if (headingMatch) {\n const level = headingMatch[1].length\n return `h${level}`\n }\n\n // Проверяем форматирование в порядке приоритета\n // Bold: только ** (не __)\n if (/\\*\\*[^*]+\\*\\*/.test(content)) {\n return 'bold'\n }\n // Italic: только * (не _)\n if (/(?<!\\*)\\*[^*]+\\*(?!\\*)/.test(content)) {\n return 'italic'\n }\n if (/`[^`]+`/.test(content)) {\n return 'code'\n }\n if (/~~[^~]+~~/.test(content)) {\n return 'strike'\n }\n\n return null\n}\n\n/**\n * Вычисляет уровень отступа строки (количество табов или групп по 4 пробела)\n */\nfunction getIndentLevel(lineText: string): number {\n const match = lineText.match(/^(\\s*)/)\n if (!match) return 0\n const indentStr = match[1]\n // Считаем табы как 1 уровень, 4 пробела как 1 уровень\n let level = 0\n let spaces = 0\n for (const char of indentStr) {\n if (char === '\\t') {\n level++\n spaces = 0\n } else if (char === ' ') {\n spaces++\n if (spaces >= 4) {\n level++\n spaces = 0\n }\n }\n }\n return level\n}\n\ninterface ActiveScope {\n headerLine: number\n headerIndentLevel: number // Уровень отступа заголовка\n formatType: string\n ownsLevel: number // Какой уровень indent принадлежит этой секции (headerIndentLevel + 1)\n}\n\n/**\n * Плагин для добавления классов cm-scope-L{level}-{formatType} к строкам\n * Поддерживает вложенные collapsible секции с разными цветами на разных уровнях\n */\nexport const collapsibleScopePlugin = ViewPlugin.fromClass(\n class {\n decorations: DecorationSet\n\n constructor(view: EditorView) {\n this.decorations = this.buildDecorations(view)\n }\n\n update(update: { docChanged: boolean; view: EditorView }) {\n if (update.docChanged) {\n this.decorations = this.buildDecorations(update.view)\n }\n }\n\n buildDecorations(view: EditorView): DecorationSet {\n const doc = view.state.doc\n const builder = new RangeSetBuilder<Decoration>()\n\n // Стек активных секций\n const activeScopes: ActiveScope[] = []\n\n // Собираем все декорации\n const lineDecorations: Map<number, Set<string>> = new Map()\n\n for (let lineNum = 1; lineNum <= doc.lines; lineNum++) {\n const line = doc.line(lineNum)\n const lineText = line.text\n const currentIndentLevel = getIndentLevel(lineText)\n const isEmptyLine = lineText.trim() === ''\n\n // Очищаем стек от секций, которые уже закончились\n // Секция заканчивается когда мы встречаем НЕпустую строку с indent <= headerIndent\n if (!isEmptyLine) {\n while (activeScopes.length > 0) {\n const topScope = activeScopes[activeScopes.length - 1]\n if (currentIndentLevel <= topScope.headerIndentLevel) {\n activeScopes.pop()\n } else {\n break\n }\n }\n }\n\n // Проверяем, является ли строка заголовком collapsible\n const match = lineText.match(collapsiblePattern)\n if (match) {\n const formatType = detectFormatting(lineText)\n if (formatType) {\n // Добавляем новую секцию в стек\n activeScopes.push({\n headerLine: lineNum,\n headerIndentLevel: currentIndentLevel,\n formatType,\n ownsLevel: currentIndentLevel + 1\n })\n }\n }\n\n // Для текущей строки определяем классы на основе активных секций\n // Но не для строк-заголовков (они сами не внутри своего scope)\n if (!isEmptyLine && currentIndentLevel > 0) {\n const classes = new Set<string>()\n\n for (const scope of activeScopes) {\n // Секция влияет на линию своего уровня (ownsLevel)\n // Если текущая строка имеет indent >= ownsLevel, то линия на уровне ownsLevel принадлежит этой секции\n if (currentIndentLevel >= scope.ownsLevel) {\n classes.add(`cm-scope-L${scope.ownsLevel}-${scope.formatType}`)\n }\n }\n\n if (classes.size > 0) {\n lineDecorations.set(lineNum, classes)\n }\n }\n\n // Для пустых строк — копируем классы от предыдущей непустой строки\n // чтобы линии не прерывались\n if (isEmptyLine && activeScopes.length > 0) {\n const classes = new Set<string>()\n for (const scope of activeScopes) {\n // Для пустых строк добавляем все активные scope\n classes.add(`cm-scope-L${scope.ownsLevel}-${scope.formatType}`)\n }\n if (classes.size > 0) {\n lineDecorations.set(lineNum, classes)\n }\n }\n }\n\n // Конвертируем в декорации (сортированные по позиции)\n const sortedLineNums = Array.from(lineDecorations.keys()).sort((a, b) => a - b)\n\n for (const lineNum of sortedLineNums) {\n const classes = lineDecorations.get(lineNum)!\n const line = doc.line(lineNum)\n const classString = Array.from(classes).join(' ')\n builder.add(line.from, line.from, Decoration.line({ class: classString }))\n }\n\n return builder.finish()\n }\n },\n { decorations: v => v.decorations }\n)\n","import { EditorView, ViewPlugin, ViewUpdate } from '@codemirror/view'\n\n/**\n * Manual Layer Selection Plugin\n * Replaces native drawSelection with a custom layer to allow:\n * 1. Full-width background for selected lines (VS Code style).\n * 2. Precise text selection for partial ranges.\n */\n\ninterface SelectionRect {\n type: 'full' | 'partial'\n top: number\n height: number\n left: number\n width: number\n}\n\nexport const fullLineSelectionPlugin = ViewPlugin.fromClass(\n class {\n layer: HTMLElement\n view: EditorView\n \n constructor(view: EditorView) {\n this.view = view\n this.layer = document.createElement('div')\n this.layer.className = 'cm-custom-selection-layer'\n this.layer.setAttribute('aria-hidden', 'true')\n view.scrollDOM.appendChild(this.layer)\n this.measureAndDraw()\n }\n\n update(update: ViewUpdate) {\n if (update.docChanged || update.selectionSet || update.viewportChanged || update.geometryChanged) {\n this.measureAndDraw()\n }\n }\n\n destroy() {\n this.layer.remove()\n }\n\n measureAndDraw() {\n this.view.requestMeasure({\n read: (view) => this.readSelections(view),\n write: (rects) => {\n if (rects && rects.length > 0) {\n this.drawSelections(rects)\n } else {\n this.layer.textContent = ''\n }\n }\n })\n }\n\n readSelections(view: EditorView): SelectionRect[] {\n const { selection, doc } = view.state\n\n if (selection.main.empty) return []\n\n const rects: SelectionRect[] = []\n\n try {\n const parentRect = view.scrollDOM.getBoundingClientRect()\n const scrollLeft = view.scrollDOM.scrollLeft\n const scrollTop = view.scrollDOM.scrollTop\n\n const toRelative = (r: DOMRect) => {\n return {\n left: r.left - parentRect.left + scrollLeft,\n top: r.top - parentRect.top + scrollTop,\n width: r.width,\n height: r.height\n }\n }\n\n for (const range of selection.ranges) {\n if (range.empty) continue\n\n const startLine = doc.lineAt(range.from)\n const endLine = doc.lineAt(range.to)\n\n for (let lineNum = startLine.number; lineNum <= endLine.number; lineNum++) {\n const line = doc.line(lineNum)\n if (lineNum === endLine.number && range.to === line.from) continue\n\n const coversStart = range.from <= line.from\n const isLastLine = (line.from + line.length) === doc.length\n const coversEnd = isLastLine ? range.to >= line.to : range.to > line.to\n\n if (coversStart && coversEnd) {\n try {\n const domInfo = view.domAtPos(line.from)\n let lineEl = domInfo.node\n while (lineEl && lineEl !== view.contentDOM) {\n if (lineEl.nodeType === 1 && (lineEl as HTMLElement).classList.contains('cm-line')) break\n lineEl = lineEl.parentElement!\n }\n\n if (lineEl && (lineEl as HTMLElement).classList.contains('cm-line')) {\n const el = lineEl as HTMLElement\n const lineRect = el.getBoundingClientRect()\n\n const style = window.getComputedStyle(el)\n const pLeft = parseFloat(style.paddingLeft) || 0\n const tIndent = parseFloat(style.textIndent) || 0\n const visualOffset = pLeft + tIndent\n\n const left = lineRect.left + visualOffset - parentRect.left + scrollLeft\n const top = lineRect.top - parentRect.top + scrollTop\n const height = lineRect.height\n\n rects.push({\n type: 'full',\n top,\n height,\n left,\n width: 0\n })\n }\n } catch (e) {}\n } else {\n try {\n const from = Math.max(range.from, line.from)\n const to = Math.min(range.to, line.to)\n const start = view.domAtPos(from)\n const end = view.domAtPos(to)\n const domRange = document.createRange()\n domRange.setStart(start.node, start.offset)\n domRange.setEnd(end.node, end.offset)\n const clientRects = domRange.getClientRects()\n for (let i = 0; i < clientRects.length; i++) {\n const rel = toRelative(clientRects[i])\n rects.push({ type: 'partial', top: rel.top, height: rel.height, left: rel.left, width: rel.width })\n }\n } catch (e) {}\n }\n }\n }\n } catch (e) {\n console.error('[FullLineSelection] readSelections failed:', {\n error: e instanceof Error ? e.message : e,\n selectionRanges: selection.ranges.length,\n mainRange: { from: selection.main.from, to: selection.main.to },\n docLength: doc.length\n })\n return []\n }\n return rects\n }\n\n drawSelections(rects: SelectionRect[]) {\n this.layer.textContent = ''\n for (const r of rects) {\n const el = document.createElement('div')\n el.className = 'cm-custom-selection-rect'\n if (r.type === 'full') {\n el.classList.add('cm-full-line-selection') \n el.style.top = `${r.top}px`\n el.style.height = `${r.height}px`\n el.style.left = `${r.left}px`\n el.style.right = '0'\n } else {\n el.classList.add('cm-partial-selection')\n el.style.top = `${r.top}px`\n el.style.height = `${r.height}px`\n el.style.left = `${r.left}px`\n el.style.width = `${r.width}px`\n }\n this.layer.appendChild(el)\n }\n }\n }\n)\n\nexport function customFullLineSelection() {\n return [fullLineSelectionPlugin]\n}\n","import { EditorView } from '@codemirror/view'\nimport { EditorSelection, Extension } from '@codemirror/state'\n\n/**\n * Stable Word Selection via mouseSelectionStyle\n *\n * Problem: CM6's default word-selection flips anchor/head when mouse crosses\n * the midpoint of the selected word during drag. This causes visual cursor jumping.\n *\n * Solution: Override mouseSelectionStyle to lock anchor during word-selection drag.\n * Uses event.detail === 2 to detect double-click (browser-native, no timers needed).\n *\n * Note: When extending selection beyond the original word, direction changes\n * are allowed - this is expected behavior (cursor at start when dragging up/left).\n */\n\ninterface WordBoundaries {\n start: number\n end: number\n}\n\n// Word character pattern (including Russian letters and hyphens)\nconst WORD_CHAR = /[\\w\\-а-яёА-ЯЁ_]/\n\nfunction getWordAt(view: EditorView, pos: number): WordBoundaries {\n const doc = view.state.doc\n const line = doc.lineAt(pos)\n const lineText = line.text\n const posInLine = Math.max(0, Math.min(pos - line.from, line.length))\n\n let start = posInLine\n let end = posInLine\n\n while (start > 0 && WORD_CHAR.test(lineText[start - 1])) start--\n while (end < lineText.length && WORD_CHAR.test(lineText[end])) end++\n\n return {\n start: line.from + start,\n end: line.from + end\n }\n}\n\nfunction snapToWordBoundary(view: EditorView, pos: number, direction: 'left' | 'right'): number {\n const word = getWordAt(view, pos)\n return direction === 'left' ? word.start : word.end\n}\n\n/**\n * Custom mouseSelectionStyle that locks anchor during word-selection drag.\n */\nexport const stableWordSelection: Extension = EditorView.mouseSelectionStyle.of((view, event) => {\n // Only activate for double-click (word selection)\n if (event.detail !== 2) return null\n\n const startPos = view.posAtCoords({ x: event.clientX, y: event.clientY })\n if (startPos === null) return null\n\n const originalWord = getWordAt(view, startPos)\n\n // If clicked on whitespace (no word), don't activate\n if (originalWord.start === originalWord.end) return null\n\n // Lock anchor at word start (forward selection by default)\n const lockedAnchor = originalWord.start\n\n // Capture existing ranges for Cmd+double-click multi-cursor\n const isMulti = event.metaKey || event.ctrlKey\n const existingRanges = isMulti ? view.state.selection.ranges.slice() : []\n\n return {\n get(curEvent: MouseEvent, _extend: boolean, _multiple: boolean) {\n const curPos = view.posAtCoords({ x: curEvent.clientX, y: curEvent.clientY })\n\n let newRange: import('@codemirror/state').SelectionRange\n\n if (curPos === null) {\n newRange = EditorSelection.range(lockedAnchor, originalWord.end)\n } else if (curPos < originalWord.start) {\n // Dragging left - extend to word boundary, anchor stays at word end\n const newHead = snapToWordBoundary(view, curPos, 'left')\n newRange = EditorSelection.range(originalWord.end, newHead)\n } else if (curPos > originalWord.end) {\n // Dragging right - extend to word boundary, anchor stays at word start\n const newHead = snapToWordBoundary(view, curPos, 'right')\n newRange = EditorSelection.range(lockedAnchor, newHead)\n } else {\n // Still within original word - keep stable forward selection\n newRange = EditorSelection.range(lockedAnchor, originalWord.end)\n }\n\n if (existingRanges.length > 0) {\n return EditorSelection.create([...existingRanges, newRange])\n }\n return EditorSelection.create([newRange])\n },\n\n update(_update: import('@codemirror/view').ViewUpdate) {\n return false\n }\n }\n})\n\n// Export as function for consistency with other plugins\nexport function createStableWordSelection(): Extension {\n return stableWordSelection\n}\n","import { EditorView } from '@codemirror/view'\nimport { EditorSelection, type Text } from '@codemirror/state'\nimport { foldedRanges, foldEffect, foldable } from '@codemirror/language'\n\n/**\n * Block-aware move: Alt+Up/Down moves the entire block (line + deeper-indented children)\n * instead of a single line.\n *\n * Algorithm:\n * 1. Find the block under cursor: cursorLine + all lines below with deeper indent\n * 2. Determine target to swap with:\n * - Empty line above/below → swap block with single line\n * - Line with indent < baseIndent (parent) → swap block with single line (exits parent)\n * - Line with indent >= baseIndent → find sibling block, swap entire blocks\n */\n\n// ─── Indent helper (same logic as collapsibleFold.ts) ───────────────────────\n\n/** Count visual indent columns. Tabs expand to tabSize (default 4). */\nfunction countIndent(text: string, tabSize: number): number {\n let n = 0\n for (let i = 0; i < text.length; i++) {\n const code = text.charCodeAt(i)\n if (code === 9) n += tabSize - (n % tabSize) // Tab\n else if (code === 32) n++ // Space\n else break\n }\n return n\n}\n\n// ─── Block detection ────────────────────────────────────────────────────────\n\nexport interface BlockRange {\n startLine: number\n endLine: number\n}\n\n/**\n * Find the block starting at `lineNumber`.\n * Block = the line itself + all subsequent lines with deeper indentation.\n * Trailing empty lines are NOT included.\n * Internal empty lines (followed by deeper content) ARE included.\n */\nexport function findBlock(doc: Text, lineNumber: number, tabSize: number): BlockRange {\n const line = doc.line(lineNumber)\n const baseIndent = countIndent(line.text, tabSize)\n\n let lastContentLine = lineNumber\n\n for (let i = lineNumber + 1; i <= doc.lines; i++) {\n const nextText = doc.line(i).text\n\n // Empty line: keep scanning (don't commit as block end)\n if (nextText.trim() === '') continue\n\n const nextIndent = countIndent(nextText, tabSize)\n\n if (nextIndent > baseIndent) {\n // Deeper indentation → part of this block\n lastContentLine = i\n } else {\n // Same or less indentation → block ended\n break\n }\n }\n\n return { startLine: lineNumber, endLine: lastContentLine }\n}\n\n// ─── Sibling detection ──────────────────────────────────────────────────────\n\n/**\n * Scan upward from `blockStartLine - 1` to find the previous sibling block.\n * A sibling is a non-empty line with indent == baseIndent.\n * Lines with indent > baseIndent are children of the sibling.\n * Empty lines are skipped.\n *\n * Returns { startLine, endLine } of the sibling block, or null if no sibling\n * (hit a parent line with indent < baseIndent, or start of document).\n *\n * Note: endLine = blockStartLine - 1 (everything between sibling header and our block).\n */\nfunction findPreviousSibling(\n doc: Text, blockStartLine: number, baseIndent: number, tabSize: number\n): BlockRange | null {\n if (blockStartLine <= 1) return null\n\n const siblingEnd = blockStartLine - 1\n\n for (let i = blockStartLine - 1; i >= 1; i--) {\n const text = doc.line(i).text\n\n if (text.trim() === '') continue // skip empty lines\n\n const indent = countIndent(text, tabSize)\n\n if (indent === baseIndent) {\n // Found sibling header\n return { startLine: i, endLine: siblingEnd }\n } else if (indent > baseIndent) {\n // Child of the sibling — keep scanning up\n continue\n } else {\n // indent < baseIndent → hit parent boundary\n return null\n }\n }\n\n return null // reached start of document\n}\n\n// ─── Swap helper ────────────────────────────────────────────────────────────\n\n/**\n * Swap two adjacent text ranges in the document.\n * `upper` is above `lower` in the document. They must be adjacent\n * (upper.endLine + 1 == lower.startLine is guaranteed by the algorithm).\n */\nfunction swapBlocks(\n view: EditorView,\n upper: BlockRange,\n lower: BlockRange,\n cursor: number,\n /** Which block the cursor belongs to: 'upper' or 'lower' */\n cursorBlock: 'upper' | 'lower'\n): void {\n const doc = view.state.doc\n\n const upperFrom = doc.line(upper.startLine).from\n const upperTo = doc.line(upper.endLine).to\n const lowerFrom = doc.line(lower.startLine).from\n const lowerTo = doc.line(lower.endLine).to\n\n const upperText = doc.sliceString(upperFrom, upperTo)\n const lowerText = doc.sliceString(lowerFrom, lowerTo)\n\n // New text: lower first, then upper\n const newText = lowerText + '\\n' + upperText\n\n // Calculate new cursor position\n let newCursorPos: number\n if (cursorBlock === 'lower') {\n // Block moved UP: it now starts at upperFrom\n const cursorOffset = cursor - lowerFrom\n newCursorPos = upperFrom + cursorOffset\n } else {\n // Block moved DOWN: it now starts after lowerText + \\n\n const lowerTextLen = lowerTo - lowerFrom\n const cursorOffset = cursor - upperFrom\n newCursorPos = upperFrom + lowerTextLen + 1 + cursorOffset\n }\n\n // Clamp cursor to valid range\n const newDocLen = view.state.doc.length - (lowerTo - upperFrom) + newText.length\n newCursorPos = Math.max(0, Math.min(newCursorPos, newDocLen - 1))\n\n // Calculate block visual heights BEFORE dispatch (fold states intact).\n // Post-dispatch lineBlockAt is unreliable: text replacement destroys fold ranges,\n // temporarily inflating heights until autoFoldCollapsedMarkers re-folds in setTimeout(0).\n // Instead, compute scroll offset from pre-dispatch heights only:\n // Move DOWN → cursor shifts down by lowerVisualH → scrollTop += lowerVisualH\n // Move UP → cursor shifts up by upperVisualH → scrollTop -= upperVisualH\n const savedScrollTop = view.scrollDOM.scrollTop\n const upperVisualTop = view.lineBlockAt(doc.line(upper.startLine).from).top\n const lowerVisualTop = view.lineBlockAt(doc.line(lower.startLine).from).top\n const upperVisualH = lowerVisualTop - upperVisualTop\n\n let lowerVisualH: number\n if (lower.endLine < doc.lines) {\n lowerVisualH = view.lineBlockAt(doc.line(lower.endLine + 1).from).top - lowerVisualTop\n } else {\n const lastBlock = view.lineBlockAt(doc.line(lower.endLine).from)\n lowerVisualH = lastBlock.top + lastBlock.height - lowerVisualTop\n }\n\n view.dispatch({\n changes: { from: upperFrom, to: lowerTo, insert: newText },\n selection: EditorSelection.cursor(newCursorPos)\n })\n\n // Re-fold ^^ markers synchronously to prevent visual flash of expanded content.\n // The swap dispatch destroys fold ranges (CM remaps them to zero-length).\n // autoFoldCollapsedMarkers would re-fold via setTimeout(0), but that allows\n // a paint frame with expanded content between dispatches.\n // Two synchronous dispatches → one paint → no flash.\n refoldCollapsedMarkers(view, upperFrom, lowerTo)\n\n // Restore scroll using pre-dispatch visual heights (fold-accurate).\n // Browser auto-clamps scrollTop if block moved to very top of document.\n if (cursorBlock === 'lower') {\n // Moving UP: cursor's block shifted up by upperVisualH\n view.scrollDOM.scrollTop = savedScrollTop - upperVisualH\n } else {\n // Moving DOWN: cursor's block shifted down by lowerVisualH\n view.scrollDOM.scrollTop = savedScrollTop + lowerVisualH\n }\n}\n\n// ─── Re-fold helper ─────────────────────────────────────────────────────────\n\n/**\n * Synchronously re-fold ^^ markers in the affected range after a swap dispatch.\n *\n * The swap replaces the entire [from..to] range, which destroys CM6 fold ranges\n * (ChangeDesc.mapPos collapses positions inside the replaced range to a single point).\n * collapsibleArrowPlugin.autoFoldCollapsedMarkers would re-fold via setTimeout(0),\n * but between the dispatch and the setTimeout callback the browser paints a frame\n * with expanded content — causing the visual flash.\n *\n * By dispatching fold effects synchronously here (after the swap dispatch but\n * before returning to the event loop), the browser only paints ONCE with folds\n * already restored. No flash.\n */\nfunction refoldCollapsedMarkers(view: EditorView, from: number, to: number): void {\n const doc = view.state.doc\n const startLine = doc.lineAt(from).number\n const endLine = doc.lineAt(Math.min(to, doc.length)).number\n const effects: any[] = []\n\n for (let i = startLine; i <= endLine; i++) {\n const line = doc.line(i)\n if (!line.text.trim().startsWith('^^')) continue\n\n // Check if already folded (shouldn't be after full-range swap, but be safe)\n let isFolded = false\n foldedRanges(view.state).between(line.from, line.to, () => {\n isFolded = true\n })\n\n if (!isFolded) {\n const range = foldable(view.state, line.from, line.to)\n if (range && (range.to - range.from) > 2) {\n effects.push(foldEffect.of(range))\n }\n }\n }\n\n if (effects.length > 0) {\n view.dispatch({ effects })\n }\n}\n\n// ─── Commands ───────────────────────────────────────────────────────────────\n\n/** Move the block under cursor UP (Alt+ArrowUp). */\nexport function moveBlockUp(view: EditorView): boolean {\n const { state } = view\n const doc = state.doc\n const tabSize = state.tabSize\n const cursor = state.selection.main.head\n const curLine = doc.lineAt(cursor)\n\n const block = findBlock(doc, curLine.number, tabSize)\n const baseIndent = countIndent(curLine.text, tabSize)\n\n // Can't move past start of document\n if (block.startLine <= 1) {\n return false\n }\n\n const aboveLine = doc.line(block.startLine - 1)\n\n // Case 1: Empty line above → single line swap\n if (aboveLine.text.trim() === '') {\n swapBlocks(view,\n { startLine: aboveLine.number, endLine: aboveLine.number },\n block,\n cursor,\n 'lower'\n )\n return true\n }\n\n const aboveIndent = countIndent(aboveLine.text, tabSize)\n\n // Case 2: Parent line above (less indent) → single line swap, block exits parent\n if (aboveIndent < baseIndent) {\n swapBlocks(view,\n { startLine: aboveLine.number, endLine: aboveLine.number },\n block,\n cursor,\n 'lower'\n )\n return true\n }\n\n // Case 3: Sibling or child of sibling above → find sibling block\n const sibling = findPreviousSibling(doc, block.startLine, baseIndent, tabSize)\n\n if (sibling) {\n swapBlocks(view, sibling, block, cursor, 'lower')\n return true\n }\n\n // No sibling found (e.g. orphan deeper line above) → single line swap\n swapBlocks(view,\n { startLine: aboveLine.number, endLine: aboveLine.number },\n block,\n cursor,\n 'lower'\n )\n return true\n}\n\n/** Move the block under cursor DOWN (Alt+ArrowDown). */\nexport function moveBlockDown(view: EditorView): boolean {\n const { state } = view\n const doc = state.doc\n const tabSize = state.tabSize\n const cursor = state.selection.main.head\n const curLine = doc.lineAt(cursor)\n\n const block = findBlock(doc, curLine.number, tabSize)\n const baseIndent = countIndent(curLine.text, tabSize)\n\n // Can't move past end of document\n if (block.endLine >= doc.lines) {\n return false\n }\n\n const belowLine = doc.line(block.endLine + 1)\n\n // Case 1: Empty line below → single line swap\n if (belowLine.text.trim() === '') {\n swapBlocks(view,\n block,\n { startLine: belowLine.number, endLine: belowLine.number },\n cursor,\n 'upper'\n )\n return true\n }\n\n const belowIndent = countIndent(belowLine.text, tabSize)\n\n // Case 2: Parent boundary below (less indent) → single line swap\n if (belowIndent < baseIndent) {\n swapBlocks(view,\n block,\n { startLine: belowLine.number, endLine: belowLine.number },\n cursor,\n 'upper'\n )\n return true\n }\n\n // Case 3: Sibling below (same indent) → find its full block, swap\n if (belowIndent === baseIndent) {\n const siblingBlock = findBlock(doc, belowLine.number, tabSize)\n swapBlocks(view, block, siblingBlock, cursor, 'upper')\n return true\n }\n\n // Case 4: Deeper indent below (shouldn't happen — would be in our block)\n // Fallback: single line swap\n swapBlocks(view,\n block,\n { startLine: belowLine.number, endLine: belowLine.number },\n cursor,\n 'upper'\n )\n return true\n}\n","import { EditorView, type KeyBinding } from '@codemirror/view'\nimport { EditorState, EditorSelection } from '@codemirror/state'\nimport { indentUnit } from '@codemirror/language'\nimport { findBlock } from './blockMove'\n\n/**\n * Count leading whitespace columns (tabs expand to tabSize).\n */\nfunction countIndentColumns(text: string, tabSize: number): number {\n let col = 0\n for (let i = 0; i < text.length; i++) {\n if (text.charCodeAt(i) === 9) col += tabSize - (col % tabSize)\n else if (text.charCodeAt(i) === 32) col++\n else break\n }\n return col\n}\n\n/**\n * Get tab stop step size from indentUnit facet.\n */\nfunction getTabStep(state: EditorState): number {\n const unit = state.facet(indentUnit)\n return unit === '\\t' ? state.tabSize : unit.length\n}\n\n/**\n * Generate indent string (spaces only, matching indentUnit convention).\n */\nfunction makeIndent(cols: number): string {\n return ' '.repeat(cols)\n}\n\n/**\n * VS Code-style Tab / Shift-Tab with tab stop snapping.\n *\n * Instead of blindly adding 4 spaces (indentMore), snaps the line's\n * leading whitespace to the next/previous multiple of indentUnit size.\n *\n * Examples (step=4):\n * Tab: 0→4, 1→4, 3→4, 4→8, 5→8, 8→12\n * Shift-Tab: 4→0, 5→4, 8→4, 1→0, 0→0\n *\n * Uses state.changeByRange() for correct multi-cursor support\n * (same pattern as CM6's built-in indentMore/indentLess).\n */\nconst collapsiblePattern = /^\\s*(>>|\\^\\^)/\n\nexport const tabStopIndent: KeyBinding = {\n key: 'Tab',\n run: (view: EditorView): boolean => {\n const { state } = view\n const step = getTabStep(state)\n\n // Collapsible header: block-aware indent (like Cmd+])\n const sel = state.selection.main\n if (sel.empty) {\n const line = state.doc.lineAt(sel.head)\n if (collapsiblePattern.test(line.text)) {\n return blockIndent(view)\n }\n }\n\n const spec = state.changeByRange(range => {\n const changes: { from: number; to: number; insert: string }[] = []\n let atLine = -1\n\n for (let pos = range.from; pos <= range.to;) {\n const line = state.doc.lineAt(pos)\n if (line.number > atLine && (range.empty || range.to > line.from)) {\n atLine = line.number\n const ws = /^\\s*/.exec(line.text)![0]\n const cols = countIndentColumns(ws, state.tabSize)\n const newCols = (Math.floor(cols / step) + 1) * step\n changes.push({\n from: line.from,\n to: line.from + ws.length,\n insert: makeIndent(newCols)\n })\n }\n pos = line.to + 1\n }\n\n const changeSet = state.changes(changes)\n return {\n changes,\n range: EditorSelection.range(\n changeSet.mapPos(range.anchor, 1),\n changeSet.mapPos(range.head, 1)\n )\n }\n })\n\n view.dispatch(spec, { scrollIntoView: true, userEvent: 'input.indent' })\n return true\n },\n shift: (view: EditorView): boolean => {\n const { state } = view\n const step = getTabStep(state)\n\n // Collapsible header: block-aware outdent (like Cmd+[)\n const sel = state.selection.main\n if (sel.empty) {\n const line = state.doc.lineAt(sel.head)\n if (collapsiblePattern.test(line.text)) {\n return blockOutdent(view)\n }\n }\n\n const spec = state.changeByRange(range => {\n const changes: { from: number; to: number; insert: string }[] = []\n let atLine = -1\n\n for (let pos = range.from; pos <= range.to;) {\n const line = state.doc.lineAt(pos)\n if (line.number > atLine && (range.empty || range.to > line.from)) {\n atLine = line.number\n const ws = /^\\s*/.exec(line.text)![0]\n const cols = countIndentColumns(ws, state.tabSize)\n if (cols > 0) {\n const newCols = Math.max(0, Math.floor((cols - 1) / step) * step)\n changes.push({\n from: line.from,\n to: line.from + ws.length,\n insert: makeIndent(newCols)\n })\n }\n }\n pos = line.to + 1\n }\n\n const changeSet = state.changes(changes)\n return {\n changes,\n range: EditorSelection.range(\n changeSet.mapPos(range.anchor, 1),\n changeSet.mapPos(range.head, 1)\n )\n }\n })\n\n view.dispatch(spec, { scrollIntoView: true, userEvent: 'input.indent' })\n return true\n },\n preventDefault: true\n}\n\n/**\n * Block-aware Cmd+] — indent current line + all deeper children.\n *\n * Empty cursor: finds block (cursor line + deeper children via findBlock),\n * computes delta from cursor line's tab stop snap, applies SAME delta\n * to all lines. Preserves relative indentation within the block.\n *\n * Selection: indent each selected line independently (tab stop snapping per line).\n */\nexport function blockIndent(view: EditorView): boolean {\n const { state } = view\n const step = getTabStep(state)\n const tabSize = state.tabSize\n const sel = state.selection.main\n\n if (sel.empty) {\n // Block-aware: uniform delta from cursor line\n const curLine = state.doc.lineAt(sel.head)\n const block = findBlock(state.doc, curLine.number, tabSize)\n\n const curWs = /^\\s*/.exec(curLine.text)![0]\n const curCols = countIndentColumns(curWs, tabSize)\n const newCurCols = (Math.floor(curCols / step) + 1) * step\n const delta = newCurCols - curCols\n\n const changes: { from: number; to: number; insert: string }[] = []\n for (let i = block.startLine; i <= block.endLine; i++) {\n const line = state.doc.line(i)\n if (line.text.trim() === '') continue\n const ws = /^\\s*/.exec(line.text)![0]\n const cols = countIndentColumns(ws, tabSize)\n changes.push({\n from: line.from,\n to: line.from + ws.length,\n insert: makeIndent(cols + delta)\n })\n }\n\n if (changes.length === 0) return true\n\n const changeSet = state.changes(changes)\n view.dispatch({\n changes,\n selection: EditorSelection.cursor(changeSet.mapPos(sel.head, 1)),\n scrollIntoView: true,\n userEvent: 'input.indent'\n })\n return true\n }\n\n // Selection: indent each line independently (tab stop snapping)\n const startLine = state.doc.lineAt(sel.from).number\n const endLine = state.doc.lineAt(sel.to).number\n\n const changes: { from: number; to: number; insert: string }[] = []\n for (let i = startLine; i <= endLine; i++) {\n const line = state.doc.line(i)\n if (line.text.trim() === '') continue\n const ws = /^\\s*/.exec(line.text)![0]\n const cols = countIndentColumns(ws, tabSize)\n const newCols = (Math.floor(cols / step) + 1) * step\n changes.push({\n from: line.from,\n to: line.from + ws.length,\n insert: makeIndent(newCols)\n })\n }\n\n if (changes.length === 0) return true\n\n const changeSet = state.changes(changes)\n view.dispatch({\n changes,\n selection: EditorSelection.range(changeSet.mapPos(sel.anchor, 1), changeSet.mapPos(sel.head, 1)),\n scrollIntoView: true,\n userEvent: 'input.indent'\n })\n return true\n}\n\n/**\n * Block-aware Cmd+[ — outdent current line + all deeper children.\n *\n * Empty cursor: computes delta from cursor line's tab stop snap.\n * If cursor line is already at indent 0 → delta=0 → nothing moves (block stays intact).\n * Otherwise applies SAME delta to all lines, clamping at 0.\n *\n * Selection: outdent each selected line independently (tab stop snapping per line).\n */\nexport function blockOutdent(view: EditorView): boolean {\n const { state } = view\n const step = getTabStep(state)\n const tabSize = state.tabSize\n const sel = state.selection.main\n\n if (sel.empty) {\n // Block-aware: uniform delta from cursor line\n const curLine = state.doc.lineAt(sel.head)\n const block = findBlock(state.doc, curLine.number, tabSize)\n\n const curWs = /^\\s*/.exec(curLine.text)![0]\n const curCols = countIndentColumns(curWs, tabSize)\n\n // Can't outdent: cursor line at indent 0 → nothing moves\n if (curCols === 0) return true\n\n const newCurCols = Math.max(0, Math.floor((curCols - 1) / step) * step)\n const delta = newCurCols - curCols // negative\n\n const changes: { from: number; to: number; insert: string }[] = []\n for (let i = block.startLine; i <= block.endLine; i++) {\n const line = state.doc.line(i)\n if (line.text.trim() === '') continue\n const ws = /^\\s*/.exec(line.text)![0]\n const cols = countIndentColumns(ws, tabSize)\n const newCols = Math.max(0, cols + delta)\n if (newCols !== cols) {\n changes.push({\n from: line.from,\n to: line.from + ws.length,\n insert: makeIndent(newCols)\n })\n }\n }\n\n if (changes.length === 0) return true\n\n const changeSet = state.changes(changes)\n view.dispatch({\n changes,\n selection: EditorSelection.cursor(changeSet.mapPos(sel.head, 1)),\n scrollIntoView: true,\n userEvent: 'input.indent'\n })\n return true\n }\n\n // Selection: outdent each line independently (tab stop snapping)\n const startLine = state.doc.lineAt(sel.from).number\n const endLine = state.doc.lineAt(sel.to).number\n\n const changes: { from: number; to: number; insert: string }[] = []\n for (let i = startLine; i <= endLine; i++) {\n const line = state.doc.line(i)\n if (line.text.trim() === '') continue\n const ws = /^\\s*/.exec(line.text)![0]\n const cols = countIndentColumns(ws, tabSize)\n if (cols > 0) {\n const newCols = Math.max(0, Math.floor((cols - 1) / step) * step)\n changes.push({\n from: line.from,\n to: line.from + ws.length,\n insert: makeIndent(newCols)\n })\n }\n }\n\n if (changes.length === 0) return true\n\n const changeSet = state.changes(changes)\n view.dispatch({\n changes,\n selection: EditorSelection.range(changeSet.mapPos(sel.anchor, 1), changeSet.mapPos(sel.head, 1)),\n scrollIntoView: true,\n userEvent: 'input.indent'\n })\n return true\n}\n","import { EditorView, ViewPlugin } from '@codemirror/view'\nimport { Extension } from '@codemirror/state'\nimport type { EmojiShortcut } from './contextMenu'\n\nexport interface EmojiHoverTooltipConfig {\n getEmojiShortcuts: () => EmojiShortcut[]\n}\n\n// Intl.Segmenter is available in Electron/Chrome but not in older TS lib types\ndeclare namespace Intl {\n class Segmenter {\n constructor(locale?: string, options?: { granularity: 'grapheme' | 'word' | 'sentence' })\n segment(input: string): Iterable<{ segment: string; index: number }>\n }\n}\n\n/**\n * ViewPlugin: Cmd+Hover on emoji in editor text → show tooltip with description.\n * Reuses `.cm-emoji-tooltip` CSS class from editor.css.\n *\n * Cursor change uses CSS class `.cm-emoji-hover` on `.cm-editor` wrapper\n * (not inline style on `.cm-content`) because CM6 resets contentDOM styles on update.\n *\n * Meta key is tracked at document level to work regardless of contentDOM focus.\n */\nexport function createEmojiHoverTooltip(config: EmojiHoverTooltipConfig): Extension {\n // Segmenter for correct grapheme cluster extraction (emoji can be multi-codepoint)\n const segmenter = new Intl.Segmenter(undefined, { granularity: 'grapheme' })\n\n return ViewPlugin.fromClass(class {\n tooltip: HTMLElement | null = null\n currentEmoji: string | null = null\n lastMouseX = 0\n lastMouseY = 0\n // Dynamic <style> tag for cursor override (CM6 resets both .cm-content inline styles\n // AND .cm-editor className on every update cycle, so neither approach survives)\n cursorStyleEl: HTMLStyleElement | null = null\n // Track Meta key at document level (contentDOM keydown requires focus)\n metaDown = false\n private _onKeyDown: (e: KeyboardEvent) => void\n private _onKeyUp: (e: KeyboardEvent) => void\n // Cache: emoji → description (rebuilt when shortcuts change)\n emojiMap: Map<string, string> = new Map()\n lastShortcutsRef: EmojiShortcut[] | null = null\n\n constructor(private view: EditorView) {\n this._onKeyDown = (e: KeyboardEvent) => {\n if (e.key === 'Meta') {\n this.metaDown = true\n this.onMetaPress()\n }\n }\n this._onKeyUp = (e: KeyboardEvent) => {\n if (e.key === 'Meta') {\n this.metaDown = false\n this.hideTooltip()\n }\n }\n document.addEventListener('keydown', this._onKeyDown)\n document.addEventListener('keyup', this._onKeyUp)\n }\n\n getEmojiMap(): Map<string, string> {\n const shortcuts = config.getEmojiShortcuts()\n if (shortcuts !== this.lastShortcutsRef) {\n this.lastShortcutsRef = shortcuts\n this.emojiMap = new Map()\n for (const s of shortcuts) {\n if (s.description) {\n this.emojiMap.set(s.emoji, s.description)\n }\n }\n }\n return this.emojiMap\n }\n\n /** Called when Meta is pressed — show tooltip if mouse is already over an emoji */\n onMetaPress() {\n const pos = this.view.posAtCoords({ x: this.lastMouseX, y: this.lastMouseY })\n if (pos === null) return\n const match = this.matchEmojiAt(this.view, pos, this.lastMouseX)\n if (match) {\n this.currentEmoji = match.emoji\n this.showTooltip(match.description, this.lastMouseX, this.lastMouseY)\n }\n }\n\n showTooltip(description: string, x: number, y: number) {\n this.hideTooltip()\n const el = document.createElement('div')\n el.className = 'cm-emoji-tooltip'\n el.textContent = description\n el.style.left = `${x + 12}px`\n el.style.top = `${y + 12}px`\n document.body.appendChild(el)\n\n // Adjust if off-screen\n requestAnimationFrame(() => {\n if (!el.isConnected) return\n const rect = el.getBoundingClientRect()\n if (rect.right > window.innerWidth) {\n el.style.left = `${x - rect.width - 4}px`\n }\n if (rect.bottom > window.innerHeight) {\n el.style.top = `${y - rect.height - 4}px`\n }\n })\n\n this.tooltip = el\n }\n\n hideTooltip() {\n if (this.tooltip) {\n this.tooltip.remove()\n this.tooltip = null\n }\n this.currentEmoji = null\n }\n\n setCursorHover(isEmoji: boolean) {\n if (isEmoji) {\n if (!this.cursorStyleEl) {\n this.cursorStyleEl = document.createElement('style')\n this.cursorStyleEl.textContent = '.cm-content { cursor: default !important; }'\n document.head.appendChild(this.cursorStyleEl)\n }\n } else {\n if (this.cursorStyleEl) {\n this.cursorStyleEl.remove()\n this.cursorStyleEl = null\n }\n }\n }\n\n /**\n * Extract the grapheme cluster at document position `pos` and check if it's an emoji\n * from the shortcuts map. Returns the description or null.\n */\n matchEmojiAt(view: EditorView, pos: number, mouseX: number): { emoji: string; description: string } | null {\n const map = this.getEmojiMap()\n if (map.size === 0) return null\n\n const doc = view.state.doc\n const from = Math.max(0, pos - 8)\n const to = Math.min(doc.length, pos + 12)\n const slice = doc.sliceString(from, to)\n\n for (const { segment, index } of segmenter.segment(slice)) {\n const segStart = from + index\n const segEnd = segStart + segment.length\n if (pos >= segStart && pos <= segEnd) {\n const desc = map.get(segment)\n if (desc) {\n // Verify mouse X is within emoji's visual bounds\n const left = view.coordsAtPos(segStart)\n const right = view.coordsAtPos(segEnd, -1)\n if (left && right && mouseX >= left.left && mouseX <= right.right) {\n return { emoji: segment, description: desc }\n }\n }\n }\n }\n return null\n }\n\n destroy() {\n if (this.cursorStyleEl) {\n this.cursorStyleEl.remove()\n this.cursorStyleEl = null\n }\n this.hideTooltip()\n document.removeEventListener('keydown', this._onKeyDown)\n document.removeEventListener('keyup', this._onKeyUp)\n }\n }, {\n eventHandlers: {\n mousemove(e: MouseEvent, view: EditorView) {\n this.lastMouseX = e.clientX\n this.lastMouseY = e.clientY\n\n const pos = view.posAtCoords({ x: e.clientX, y: e.clientY })\n if (pos === null) {\n this.setCursorHover(false)\n this.hideTooltip()\n return\n }\n\n const match = this.matchEmojiAt(view, pos, this.lastMouseX)\n\n // Cursor: always default when over emoji, text otherwise\n this.setCursorHover(!!match)\n\n // Tooltip: only with Cmd (check both event flag and tracked state)\n const metaActive = e.metaKey || this.metaDown\n if (!metaActive) {\n if (this.tooltip) this.hideTooltip()\n return\n }\n\n if (match) {\n if (this.currentEmoji !== match.emoji) {\n this.currentEmoji = match.emoji\n this.showTooltip(match.description, e.clientX, e.clientY)\n }\n } else {\n this.hideTooltip()\n }\n },\n mouseleave() {\n this.setCursorHover(false)\n this.hideTooltip()\n }\n }\n })\n}\n","import React, { useEffect, useRef, useMemo } from 'react'\nimport {\n EditorView,\n keymap,\n highlightActiveLine,\n highlightActiveLineGutter,\n drawSelection\n} from '@codemirror/view'\nimport { EditorState, Prec, EditorSelection } from '@codemirror/state'\nimport { defaultKeymap, history, historyKeymap, redo, addCursorAbove, addCursorBelow, copyLineUp, copyLineDown } from '@codemirror/commands'\nimport { highlightSelectionMatches, selectNextOccurrence, selectSelectionMatches } from '@codemirror/search'\nimport { foldKeymap, codeFolding, indentUnit, foldedRanges } from '@codemirror/language'\n\nimport { createDarkTheme } from './theme'\nimport {\n collapsibleFoldService,\n collapsibleGutter,\n collapsibleArrowPlugin,\n createCollapsibleArrowClickHandler,\n createCollapsibleEnterHandler,\n createCollapsibleFoldParentHandler,\n createCollapsibleBackspaceHandler,\n collapsibleScopePlugin,\n fullLineSelectionPlugin,\n createMarkdownSyntaxPlugin,\n createImageField,\n createClipboardKeymap,\n createWrapSelectionHandler,\n createImagePasteHandler,\n createContextMenuHandler,\n showCommandPalette,\n hideCommandPalette,\n selectionTrackerPlugin,\n wrapSelection,\n stableWordSelection,\n saveFoldState,\n loadFoldState,\n hasFoldEffects,\n hangingIndentPlugin,\n createLineNumbersWithVirtual,\n toggleLinePrefix,\n createIncludeLinkPlugin,\n createIncludeLinkClickHandler,\n tabStopIndent,\n blockIndent,\n blockOutdent,\n moveBlockUp,\n moveBlockDown,\n type IncludeOffset,\n aiPasteTrackerPlugin,\n createConcealClickFix,\n createEmojiHoverTooltip\n} from './plugins'\n\nimport './styles/editor.css'\n\nexport interface MarkdownEditorProps {\n /** Markdown content */\n content: string\n /** Called when content changes */\n onChange: (content: string) => void\n\n /** Font size in pixels (default: 14) */\n fontSize?: number\n /** Enable word wrap (default: true) */\n wordWrap?: boolean\n\n /** Called when user pastes an image. Should return the path to save or null to cancel */\n onImagePaste?: (base64: string) => Promise<string | null>\n /** Transform image src before loading (e.g., add protocol) */\n resolveImageUrl?: (src: string) => string\n\n /** Key for persisting fold state in localStorage. Set to undefined to disable */\n foldStateKey?: string\n\n /** Callback to receive the EditorView instance */\n onEditorView?: (view: EditorView | null) => void\n\n /** Initial scroll position */\n initialScrollTop?: number\n\n /** Resolve include path to file content (for \"Copy with includes\" feature) */\n resolveInclude?: (relativePath: string) => Promise<string>\n\n /** Called when user clicks \"open file\" on an include link */\n onOpenInclude?: (relativePath: string) => void\n\n /** Called when editor loses focus (for auto-save) */\n onBlur?: () => void\n\n /** Show line numbers gutter (default: true) */\n showLineNumbers?: boolean\n\n /** Disable overscroll padding (default: false). Use for compact/sidebar editors */\n compact?: boolean\n\n /** Read-only mode — not editable but widgets (collapsible, links) stay interactive (default: false) */\n readOnly?: boolean\n\n /** Horizontal content padding in pixels (default: 16) */\n contentPaddingX?: number\n\n /** Vertical content padding in pixels (default: 16) */\n contentPaddingY?: number\n\n /** Line offsets for virtual line numbers (transclusion support) */\n includeOffsets?: IncludeOffset[]\n\n /** Called to generate AI title for Shift+Cmd+V paste */\n onGenerateTitle?: (text: string) => Promise<string>\n\n /** Emoji shortcuts for context menu quick-insert */\n emojiShortcuts?: {emoji: string, name: string, description?: string}[]\n}\n\n// Stable empty array to avoid recreating editor on every render\nconst EMPTY_OFFSETS: IncludeOffset[] = []\n\nexport function MarkdownEditor({\n content,\n onChange,\n fontSize = 14,\n wordWrap = true,\n onImagePaste,\n resolveImageUrl,\n foldStateKey,\n onEditorView,\n initialScrollTop = 0,\n resolveInclude,\n onOpenInclude,\n onBlur,\n showLineNumbers = true,\n compact = false,\n readOnly = false,\n contentPaddingX = 16,\n contentPaddingY = 16,\n includeOffsets,\n onGenerateTitle,\n emojiShortcuts\n}: MarkdownEditorProps) {\n // Use stable reference for includeOffsets to prevent editor recreation\n const stableIncludeOffsets = includeOffsets ?? EMPTY_OFFSETS\n const editorRef = useRef<HTMLDivElement>(null)\n const viewRef = useRef<EditorView | null>(null)\n\n // Store callbacks in refs to avoid recreating editor on every render\n const onChangeRef = useRef(onChange)\n const onImagePasteRef = useRef(onImagePaste)\n const resolveImageUrlRef = useRef(resolveImageUrl)\n const onEditorViewRef = useRef(onEditorView)\n const resolveIncludeRef = useRef(resolveInclude)\n const onOpenIncludeRef = useRef(onOpenInclude)\n const onBlurRef = useRef(onBlur)\n const onGenerateTitleRef = useRef(onGenerateTitle)\n const emojiShortcutsRef = useRef(emojiShortcuts)\n const initialScrollTopRef = useRef(initialScrollTop)\n\n // Update refs when props change\n useEffect(() => {\n onChangeRef.current = onChange\n }, [onChange])\n\n useEffect(() => {\n onImagePasteRef.current = onImagePaste\n }, [onImagePaste])\n\n useEffect(() => {\n resolveImageUrlRef.current = resolveImageUrl\n }, [resolveImageUrl])\n\n useEffect(() => {\n onEditorViewRef.current = onEditorView\n }, [onEditorView])\n\n useEffect(() => {\n resolveIncludeRef.current = resolveInclude\n }, [resolveInclude])\n\n useEffect(() => {\n onOpenIncludeRef.current = onOpenInclude\n }, [onOpenInclude])\n\n useEffect(() => {\n onBlurRef.current = onBlur\n }, [onBlur])\n\n useEffect(() => {\n onGenerateTitleRef.current = onGenerateTitle\n }, [onGenerateTitle])\n\n useEffect(() => {\n emojiShortcutsRef.current = emojiShortcuts\n }, [emojiShortcuts])\n\n useEffect(() => {\n initialScrollTopRef.current = initialScrollTop\n }, [initialScrollTop])\n\n useEffect(() => {\n if (!editorRef.current) return\n\n const vscodeKeymap = [\n { key: 'Mod-d', run: selectNextOccurrence, preventDefault: true },\n { key: 'Mod-Shift-l', run: selectSelectionMatches, preventDefault: true },\n // Multi-cursor: Ctrl+Shift+Up/Down (VS Code style)\n { key: 'Ctrl-Shift-ArrowUp', run: addCursorAbove, preventDefault: true },\n { key: 'Ctrl-Shift-ArrowDown', run: addCursorBelow, preventDefault: true },\n // Also Cmd+Alt+Up/Down (default CodeMirror binding)\n { key: 'Mod-Alt-ArrowUp', run: addCursorAbove, preventDefault: true },\n { key: 'Mod-Alt-ArrowDown', run: addCursorBelow, preventDefault: true },\n // Move block up/down: Cmd+Up/Down (block-aware, moves line + deeper children)\n { key: 'Mod-ArrowUp', run: moveBlockUp, preventDefault: true },\n { key: 'Mod-ArrowDown', run: moveBlockDown, preventDefault: true },\n // Copy line up/down: Alt+Shift+Up/Down (VS Code style)\n { key: 'Alt-Shift-ArrowUp', run: copyLineUp, preventDefault: true },\n { key: 'Alt-Shift-ArrowDown', run: copyLineDown, preventDefault: true },\n // Block-aware indent/outdent: Cmd+]/[ (line + deeper children)\n { key: 'Mod-]', run: blockIndent, preventDefault: true },\n { key: 'Mod-[', run: blockOutdent, preventDefault: true }\n ]\n\n // DOM event handlers: blur for auto-save, focus/blur logging, mousedown diagnostics\n const domHandlers = EditorView.domEventHandlers({\n mousedown(event, view) {\n const diag = (window as any).__foldDiag || {}\n if (diag.pendingFold > 0 || diag.pendingUnfold > 0) {\n const folds: { from: number; to: number }[] = []\n foldedRanges(view.state).between(0, view.state.doc.length, (from, to) => {\n folds.push({ from, to })\n })\n console.warn('[Fold:mousedown] PENDING OPS AT CLICK', {\n x: event.clientX, y: event.clientY,\n folds: folds.length,\n foldRanges: folds.slice(0, 5),\n pending: { ...diag },\n docLen: view.state.doc.length\n })\n }\n },\n blur(event, view) {\n console.log('[Editor] blur', { scrollTop: view.scrollDOM.scrollTop, foldStateKey })\n onBlurRef.current?.()\n },\n focus(event, view) {\n console.log('[Editor] focus', { scrollTop: view.scrollDOM.scrollTop, foldStateKey })\n }\n })\n\n // Cmd+. для fold/unfold nearest parent collapsible section\n const collapsibleFoldKeymap = createCollapsibleFoldParentHandler()\n\n // Cmd+^ для toggle >> prefix на текущей строке\n const collapsibleToggleKeymap = Prec.high(keymap.of([\n {\n key: 'Mod-^',\n run: (view: EditorView) => {\n toggleLinePrefix(view, '>> ')\n return true\n }\n }\n ]))\n\n // Cmd+/ для command palette (toggle)\n // IMPORTANT: capture selection BEFORE CM keymap processing may collapse it\n const commandPaletteKeymap = Prec.highest(EditorView.domEventHandlers({\n keydown(event, view) {\n const isMod = event.metaKey || event.ctrlKey\n if (!isMod || event.key !== '/') return false\n\n event.preventDefault()\n event.stopPropagation()\n\n const sel = view.state.selection\n\n const existing = document.querySelector('[data-command-palette]')\n if (existing) {\n hideCommandPalette()\n view.focus()\n return true\n }\n showCommandPalette(view, sel)\n return true\n }\n }))\n\n // Cmd+8 — wrap with * (additive, pressing again adds more stars)\n const starWrapHandler = Prec.highest(EditorView.domEventHandlers({\n keydown(event, view) {\n if ((event.metaKey || event.ctrlKey) && !event.shiftKey && (event.key === '8' || event.code === 'Digit8')) {\n event.preventDefault()\n // Collapse selection to cursor so wrapSelection uses full-line mode\n // This prevents unwrap: existing *markers* end up INSIDE selectedText\n const cursor = view.state.selection.main.head\n view.dispatch({ selection: { anchor: cursor } })\n wrapSelection(view, '*')\n return true\n }\n return false\n }\n }))\n\n const extensions = [\n // Track selection for Cmd+/ palette (before any handlers)\n selectionTrackerPlugin,\n // DOM event handlers (blur для автосохранения)\n domHandlers,\n // Cmd+. fold/unfold parent, Cmd+^ toggle prefix\n collapsibleFoldKeymap,\n collapsibleToggleKeymap,\n // Cmd+/ для command palette\n commandPaletteKeymap,\n // Cmd+* для wrap with stars\n starWrapHandler,\n history(),\n // Enable multiple cursors (Cmd+Click, Ctrl+Shift+Up/Down)\n EditorState.allowMultipleSelections.of(true),\n // Draw cursors and selections (required for multi-cursor visibility)\n drawSelection(),\n // 4 spaces for indent\n indentUnit.of(' '),\n // Clipboard keymap BEFORE defaultKeymap to intercept Mod-c/v/x\n createClipboardKeymap({\n onImagePaste: (base64) => onImagePasteRef.current?.(base64) ?? Promise.resolve(null),\n onGenerateTitle: (text) => onGenerateTitleRef.current ? onGenerateTitleRef.current(text) : Promise.resolve('paste text')\n }),\n // Track cursor movement for AI Paste indicator\n aiPasteTrackerPlugin,\n // Tab/Shift+Tab with VS Code-style tab stop snapping\n keymap.of([tabStopIndent, ...foldKeymap, ...vscodeKeymap, ...defaultKeymap, ...historyKeymap, { key: 'Mod-y', run: redo, preventDefault: true }]),\n createDarkTheme(fontSize, contentPaddingX, contentPaddingY),\n // Collapsible sections & Highlighting\n collapsibleFoldService,\n // headerClickPlugin убран — сворачивание только через gutter\n codeFolding({\n placeholderDOM: () => {\n const span = document.createElement('span')\n span.style.display = 'none'\n return span\n }\n }),\n // collapsibleGutter убран — используем inline стрелки вместо gutter\n // Inline стрелки с учётом отступа\n collapsibleArrowPlugin,\n createCollapsibleArrowClickHandler(),\n // Enter at end of folded section → insert after fold\n createCollapsibleEnterHandler(),\n // Backspace at line start after folded section → move to header end\n createCollapsibleBackspaceHandler(),\n // Цветные indent guides для collapsible секций\n collapsibleScopePlugin,\n // Selection на всю ширину строки\n fullLineSelectionPlugin,\n createMarkdownSyntaxPlugin({\n resolveImageUrl: (src) => resolveImageUrlRef.current?.(src) ?? src\n }),\n // Fix: click at visual line end with hidden markup → snap to actual line.to\n createConcealClickFix(),\n // StateField for images (supports block widgets)\n createImageField({\n resolveImageUrl: (src) => resolveImageUrlRef.current?.(src) ?? src\n }),\n ...(showLineNumbers ? [createLineNumbersWithVirtual(stableIncludeOffsets), highlightActiveLineGutter()] : []),\n highlightActiveLine(),\n highlightSelectionMatches(),\n EditorView.updateListener.of((update) => {\n if (update.docChanged) {\n onChangeRef.current(update.state.doc.toString())\n }\n // Save fold state on fold/unfold\n if (update.transactions.some((tr) => hasFoldEffects(tr.effects))) {\n saveFoldState(foldStateKey, update.view)\n }\n }),\n ...(readOnly ? [EditorState.readOnly.of(true), EditorView.editable.of(false)] : []),\n ...(compact ? [] : [EditorView.contentAttributes.of({ style: 'padding-bottom: calc(100vh - 80px)' })]),\n // Wrap selected text when typing * ` _ etc.\n createWrapSelectionHandler(),\n // Image paste handler\n createImagePasteHandler({\n onImagePaste: (base64) => {\n // console.log('[Editor] onImagePaste wrapper called, ref exists:', !!onImagePasteRef.current)\n return onImagePasteRef.current?.(base64) ?? Promise.resolve(null)\n }\n }),\n // Include links (file transclusion)\n createIncludeLinkPlugin({\n onOpenFile: (path) => onOpenIncludeRef.current?.(path)\n }),\n // Cmd+Click handler for include links\n createIncludeLinkClickHandler({\n onOpenFile: (path) => onOpenIncludeRef.current?.(path)\n }),\n // Context menu\n createContextMenuHandler({\n resolveInclude: (path) => resolveIncludeRef.current?.(path) ?? Promise.reject('No resolver'),\n getEmojiShortcuts: () => emojiShortcutsRef.current ?? []\n }),\n // Cmd+Hover on emoji in text → show tooltip with description\n createEmojiHoverTooltip({\n getEmojiShortcuts: () => emojiShortcutsRef.current ?? []\n }),\n // Stable word selection (fix anchor/head flipping on dblclick + drag)\n stableWordSelection\n ]\n\n if (wordWrap) {\n extensions.push(EditorView.lineWrapping)\n extensions.push(hangingIndentPlugin)\n }\n\n const state = EditorState.create({\n doc: content,\n extensions\n })\n\n const view = new EditorView({\n state,\n parent: editorRef.current\n })\n\n viewRef.current = view\n onEditorViewRef.current?.(view)\n\n // Catch posBefore errors and dump fold state for diagnostics\n const errorHandler = (event: ErrorEvent) => {\n if (event.message?.includes('posBefore') || event.message?.includes('Invalid child')) {\n const folds: { from: number; to: number; headerText: string }[] = []\n try {\n foldedRanges(view.state).between(0, view.state.doc.length, (from, to) => {\n const headerLine = view.state.doc.lineAt(from)\n folds.push({ from, to, headerText: headerLine.text.slice(0, 50) })\n })\n } catch {}\n console.error('[Fold:ERROR] posBefore — active folds:', folds, 'docLen:', view.state.doc.length)\n }\n }\n window.addEventListener('error', errorHandler)\n\n // Restore fold state first, then scroll after folds settle layout\n requestAnimationFrame(() => {\n loadFoldState(foldStateKey, view)\n\n // Second rAF: scroll after fold operations have changed layout height\n requestAnimationFrame(() => {\n const scrollTarget = initialScrollTopRef.current\n if (scrollTarget > 0) {\n view.scrollDOM.scrollTop = scrollTarget\n const actualScroll = view.scrollDOM.scrollTop\n console.log('[Editor] scroll restored:', { requested: scrollTarget, actual: actualScroll, scrollHeight: view.scrollDOM.scrollHeight, foldStateKey })\n }\n })\n })\n\n return () => {\n window.removeEventListener('error', errorHandler)\n console.log('[Editor] DESTROYING editor', { foldStateKey, scrollTop: view.scrollDOM.scrollTop })\n view.destroy()\n onEditorViewRef.current?.(null)\n }\n }, [wordWrap, fontSize, foldStateKey, stableIncludeOffsets, showLineNumbers, compact, readOnly, contentPaddingX, contentPaddingY])\n\n // Sync content from props (only when external change detected)\n useEffect(() => {\n if (viewRef.current) {\n const currentContent = viewRef.current.state.doc.toString()\n if (currentContent !== content) {\n console.warn('[MarkdownEditor] External content sync:', {\n currentLength: currentContent.length,\n newLength: content.length,\n foldStateKey\n })\n viewRef.current.dispatch({\n changes: {\n from: 0,\n to: currentContent.length,\n insert: content\n }\n })\n }\n }\n }, [content])\n\n return <div ref={editorRef} className=\"markdown-editor\" />\n}\n\nexport default MarkdownEditor\n"],"names":["createDarkTheme","fontSize","contentPaddingX","contentPaddingY","EditorView","countIndent","text","tabSize","i","code","collapsibleFoldService","foldService","state","lineStart","line","lineText","trimmed","baseIndent","lastContentLine","nextText","nextIndent","HiddenWidget","WidgetType","span","HorizontalRuleWidget","hr","ImageWidget","src","alt","width","resolveImageUrl","isActive","other","dom","container","img","BulletWidget","indent","hasChildren","view","markerStart","markerEnd","__publicField","indentSpan","iconSpan","e","iconRect","iconCenter","pos","CollapsibleHeaderWidget","FORMAT_COLORS","CollapsibleArrowWidget","isOpen","isEmpty","lineFrom","formatType","arrow","range","foldable","foldedRange","foldedRanges","from","to","markerChange","unfoldEffect","foldEffect","fromMarker","toMarker","markerIndex","event","inlinePatterns","headingPattern","headingTagPattern","HEADING_TAG_MAP","horizontalRulePattern","horizontalRuleWithIndentPattern","codeBlockStartPattern","codeBlockEndPattern","unorderedListPattern","orderedListPattern","collapsiblePattern","linkPattern","getIndent","match","indentText","createMarkdownSyntaxPlugin","config","ViewPlugin","Decoration","update","decorations","doc","inCodeBlock","unclosedPositions","singleLineMatchedRanges","lineIndents","lastKnownIndent","j","activeLines","startLine","endLine","isActiveLine","indentLevel","clampedIndent","indentClass","trimmedText","headingMatch","indentLen","level","hashStart","hashLen","tagMatch","tagClass","hrMatch","hrIndentLen","hrLen","hrStart","hrEnd","ulMatch","olMatch","collapsibleMatch","fullMatch","indentStr","markerPos","markerLen","contentStart","collapsibleContent","innerHeadingMatch","innerTagMatch","innerTagClass","finalClass","searchText","searchOffset","matchedRanges","pattern","regex","startOffset","endOffset","r","contentEnd","linkRegex","linkMatch","linkText","textStart","textEnd","unclosedMarkers","marker","markerRegex","absPos","nextChar","prevChar","afterChar","beforeChar","multilineMarkers","maxMultilineLines","usedRanges","codeBlockLines","inCB","lineNum","charIdx","absolutePos","afterIdx","closingOnSameLine","searchIdx","closeAbsPos","closingInfo","searchLineNum","searchLine","openStart","openEnd","closeStart","closeEnd","openLineActive","closeLineActive","len","docLength","ranges","d","sorted","a","b","prev","curr","prevIsReplace","currIsReplace","lineInfo","v","createConcealClickFix","clickX","clickY","clickPos","endCoords","p","sel","currentLine","EditorSelection","imagePattern","createImageField","StateField","buildImageDecorations","tr","field","widgets","cursor","widthStr","isLineActive","w","normalizeIndent","currentIndent","lines","minIndent","_a","indentSize","countIndentSize","result","lineIndent","_b","relativeIndent","newIndent","size","char","getCurrentIndent","pasteWithNormalizedIndent","selection","normalizedText","pasteAsCollapsed","currentIndentSize","maxIndentBelow","nextLine","nextIndentSize","headerIndentSize","headerIndent","bodyIndent","charCount","header","bodyLines","l","block","insertFrom","headerLine","isFolded","err","pasteAsCollapsedAI","onGenerateTitle","title","resolvedTitle","currentDoc","ln","newText","_waitingForAIPaste","_waitingIndicator","positionIndicator","indicator","coords","rect","activateAIPasteMode","cancelAIPasteIndicator","badge","cancelBtn","cancelAIPasteMode","aiPasteTrackerPlugin","createClipboardKeymap","keymap","items","item","imageType","t","buffer","uint8Array","binary","base64","imagePath","markdown","createWrapSelectionHandler","wrapPairs","closingChar","selectedText","openChar","createImagePasteHandler","blob","getFoldStorageKey","key","saveFoldState","foldStateKey","folded","fromLine","toLine","fileName","loadFoldState","storageKey","saved","effects","skipped","hasFoldEffects","IncludeLinkWidget","path","onOpenFile","icon","pathSpan","openBtn","INCLUDE_PATTERN","createIncludeLinkPlugin","onKeyDown","onKeyUp","onBlur","cursorLines","relativePath","widget","createIncludeLinkClickHandler","Prec","resolveAllIncludes","docText","resolveInclude","content","lastNonEmptySelection","selectionTrackerPlugin","getLineIndent","getContentStart","hashCount","listMatch","addLinePrefix","prefix","changes","toggleLinePrefix","actualPrefix","newLine","newContent","newPrefix","defaultText","insertPos","wrapSelection","endMarker","end","rawText","lwsW","twsW","trimTextW","ml","el","beforeStart","afterEnd","setHeadingLevel","offset","afterPrefix","existingHeading","findInlineCodeAtCursor","posInLine","start","copyToClipboard","textarea","isWrappedWith","leadingWs","trailingWs","trimmedFrom","trimmedTo","hasLinePrefix","getCurrentHeadingLevel","hasIncludes","getDefaultMenuItems","isBold","isItalic","isCode","isStrike","isCollapsible","headingLevel","inlineCode","resolved","emojiShortcuts","shortcut","showContextMenu","x","y","menuItems","hideContextMenu","menu","activeTooltip","hoveredEmojiItem","showEmojiTooltip","description","hideEmojiTooltip","tooltip","tRect","cmdKeyDown","cmdKeyUp","renderItems","isSubmenu","divider","menuItem","submenu","currentHoveredEl","target","child","desc","newLeft","newTop","spaceBelow","spaceAbove","closeHandler","escHandler","existing","getPaletteItems","paletteKeydownHandler","paletteClickHandler","hideCommandPalette","showCommandPalette","capturedSelection","selMain","palette","preview","truncated","itemsContainer","activeIndex","colorBar","label","savedSelection","action","createContextMenuHandler","computeHangingIndent","builder","RangeSetBuilder","deco","hangingIndentPlugin","lineEl","createLineNumbersWithVirtual","offsets","lineNumbers","editorLine","diskLine","lineObj","createMarkerChange","idx","change","CollapsibleMarker","GutterMarker","openMarker","closedMarker","emptyMarker","hasContent","lineTo","gutter","markers","RangeSet","m","_foldDiag","collapsibleArrowPlugin","foldEffects","totalCollapsed","unfoldEffects","markerChanges","foldFrom","foldTo","expectedRange","effect","decoStart","decoEnd","createCollapsibleArrowClickHandler","lineFromStr","createCollapsibleEnterHandler","targetFold","fold","foldEndLine","nextLineFrom","insert","leading","nextLeading","_c","createCollapsibleBackspaceHandler","targetPos","toggleFoldOnLine","findNearestParentHeader","createCollapsibleFoldParentHandler","parentLine","cursorDocY","headerDocY","savedScrollTop","detectFormatting","getIndentLevel","spaces","collapsibleScopePlugin","activeScopes","lineDecorations","currentIndentLevel","isEmptyLine","topScope","classes","scope","sortedLineNums","classString","fullLineSelectionPlugin","rects","parentRect","scrollLeft","scrollTop","toRelative","coversStart","coversEnd","lineRect","style","pLeft","tIndent","visualOffset","left","top","height","domRange","clientRects","rel","WORD_CHAR","getWordAt","snapToWordBoundary","direction","word","stableWordSelection","startPos","originalWord","lockedAnchor","existingRanges","curEvent","_extend","_multiple","curPos","newRange","newHead","_update","findBlock","lineNumber","findPreviousSibling","blockStartLine","siblingEnd","swapBlocks","upper","lower","cursorBlock","upperFrom","upperTo","lowerFrom","lowerTo","upperText","newCursorPos","cursorOffset","lowerTextLen","newDocLen","upperVisualTop","lowerVisualTop","upperVisualH","lowerVisualH","lastBlock","refoldCollapsedMarkers","moveBlockUp","curLine","aboveLine","sibling","moveBlockDown","belowLine","belowIndent","siblingBlock","countIndentColumns","col","getTabStep","unit","indentUnit","makeIndent","cols","tabStopIndent","step","blockIndent","spec","atLine","ws","newCols","changeSet","blockOutdent","curWs","curCols","delta","createEmojiHoverTooltip","segmenter","shortcuts","s","isEmoji","mouseX","map","slice","segment","index","segStart","segEnd","right","EMPTY_OFFSETS","MarkdownEditor","onChange","wordWrap","onImagePaste","onEditorView","initialScrollTop","onOpenInclude","showLineNumbers","compact","readOnly","includeOffsets","stableIncludeOffsets","editorRef","useRef","viewRef","onChangeRef","onImagePasteRef","resolveImageUrlRef","onEditorViewRef","resolveIncludeRef","onOpenIncludeRef","onBlurRef","onGenerateTitleRef","emojiShortcutsRef","initialScrollTopRef","useEffect","vscodeKeymap","selectNextOccurrence","selectSelectionMatches","addCursorAbove","addCursorBelow","copyLineUp","copyLineDown","domHandlers","diag","folds","collapsibleFoldKeymap","collapsibleToggleKeymap","commandPaletteKeymap","starWrapHandler","extensions","history","EditorState","drawSelection","foldKeymap","defaultKeymap","historyKeymap","redo","codeFolding","highlightActiveLineGutter","highlightActiveLine","highlightSelectionMatches","errorHandler","scrollTarget","actualScroll","currentContent","jsx"],"mappings":"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"}
|