diff --git a/README.md b/README.md index 79aa494..ec3e02f 100644 --- a/README.md +++ b/README.md @@ -51,6 +51,16 @@ A powerful cross-platform Markdown editor and document converter powered by Pand - **ASCII Art Generator** - Create text banners and diagrams - **Word templates** - Use custom Word templates for enhanced exports - **Import documents** - Import from 30+ formats (DOCX, PDF, HTML, etc.) +- **Excel export** - Markdown tables to native .xlsx workbooks (one sheet per table) +- **AI Assistant** - Multi-provider AI help (OpenAI/Anthropic/Ollama/LM Studio): chat panel, summarize/improve/translate commands, grammar proofreading +- **Inline comments** - Anchor-based document comments in `.comments/` sidecars with F8 navigation +- **Wiki-links & Backlinks** - `[[Note]]` links with click-to-create and a "what links here?" panel (local knowledge base) +- **Crash recovery** - Session restore of open tabs and unsaved buffers after a crash +- **Version history** - Automatic pre-save snapshots with restore/diff/delete from the History panel +- **Vim mode & snippet expansion** - Vim keybindings toggle; Tab expands saved snippets +- **Quick Note** - Global scratchpad (Ctrl+Alt+Q) that appends to `notes/quick-notes.md` +- **Real PDF encryption** - Password protection, removal, and permissions actually work +- **Offline math & diagrams** - KaTeX bundled locally; PlantUML renders locally when the CLI is installed ## Installation @@ -96,9 +106,18 @@ npm run build:linux | Redo | Ctrl+Shift+Z | | New Tab | Ctrl+T | | Close Tab | Ctrl+W | -| Toggle Preview | Ctrl+Shift+P | +| Toggle Preview | Ctrl+Shift+V | | Zoom In | Ctrl+Shift++ | | Zoom Out | Ctrl+Shift+- | +| Command Palette | Ctrl+Shift+P | +| Zen Mode | F11 | +| Writing Analytics | Ctrl+Shift+A | +| Quick Note | Ctrl+Alt+Q | +| Universal Converter | Ctrl+Shift+C | +| Table Generator | Ctrl+Shift+T | +| ASCII Art Generator | Ctrl+Shift+A | +| Next Comment | F8 | +| Add Comment at Cursor | Ctrl+Alt+M | ## Themes @@ -162,4 +181,4 @@ Amit Haridas (amit.wh@gmail.com) ## Version -v4.5.0 +v4.6.0 diff --git a/UPDATES.md b/UPDATES.md index d08b05c..d96e396 100644 --- a/UPDATES.md +++ b/UPDATES.md @@ -1,5 +1,73 @@ # PanConverter - Updates & Changelog +## Version 4.6.0 (2026-09-05) + +### New Features + +#### AI Assistant Plugin (multi-provider) +- Chat sidebar panel with rolling conversation history and insert-reply-into-document +- Providers: OpenAI, Anthropic, Ollama, LM Studio, and any OpenAI-compatible endpoint +- All provider traffic proxied through the main process — API keys never enter the renderer and the CSP stays closed to AI endpoints +- Commands: AI Summarize / Improve / Explain / Translate selection +- Answers the writing-studio `ai:analyze` contract, finally enabling the Proofread panel + +#### Collaboration Plugin (inline comments) +- Anchor-based comments stored in `.comments/` sidecar files (never exported, never committed) +- Comments sidebar panel: add at cursor, list, resolve, delete, jump to anchor +- Drift detection flags moved/edited anchors; F8 navigates to the next open comment + +#### Local Knowledge Base (wiki-links + backlinks) +- `[[Note]]`, `[[Note|alias]]`, `[[Note#section]]` render as links in the preview (code blocks excluded) +- Clicking a wiki-link opens the note or offers to create it +- Backlinks sidebar panel scans the folder (bounded BFS) for documents linking to the current one + +#### Crash Recovery / Session Restore +- Open tabs (paths + unsaved buffer content) snapshotted to localStorage, debounced on edits, on tab changes, on unload, and once a minute +- Restore prompt on launch with per-tab restore, clean-fresh option, and 2MB content budget + +#### Document Version History +- Every save snapshots the previous on-disk content to `/versions/` +- History sidebar panel: list, restore (with safety snapshot), unified diff vs. current, delete, manual "save version now" +- Per-document pruning (20 versions), path-hash storage, id-validated reads + +#### Editor +- Vim keybindings (View → Vim Mode, persisted, live toggle via CodeMirror Compartment) +- Snippet Tab-expansion: type a snippet name and press Tab to insert it +- Zen Mode word-goal setter (the HUD progress bar finally has UI) + +#### Export / Conversion +- **Real PDF encryption**: pdf-lib swapped for @cantoo/pdf-lib — encrypt/decrypt/permissions now actually work (UI auto-enables via the capability probe) +- **XLSX export**: markdown tables → native Excel workbook, one sheet per table (no Pandoc needed) +- **ODT headers/footers + page size**: real ODF styles.xml patching replaces the empty stub +- **Local PlantUML rendering**: diagrams render on-machine via the `plantuml` CLI when installed; plantuml.com stays as fallback +- **KaTeX bundled locally** (CSS + fonts): math renders offline, no CDN calls +- Writing heatmap (GitHub-style 30-day grid) in the writing-studio Goals panel + +#### Platform +- Quick Note global scratchpad (Ctrl+Alt+Q, works when unfocused; appends to `notes/quick-notes.md`) +- Deep link protocol `markdownconverter://open?path=…` +- REPL confirmation dialog before first code execution per language per session (unsandboxed-execution guard rail) +- Writing-studio's four sidebar panels (Manuscript/Goals/Snapshots/Proofread) are now actually wired with rail icons +- Plugin sidebar panels get automatic rail icons via `registerPanel({icon})` + +### Bug Fixes +- `Ctrl+Shift+P` collision: PDF (Enhanced) export now `Ctrl+Alt+Shift+P`; Command Palette keeps `Ctrl+Shift+P` +- Universal Converter's Pandoc tool no longer always reports "not installed" (`checkConverterAvailable` gained a pandoc case with bundled-binary check) +- CLI headless export: removed dangling `--css` / `--reference-doc` flags that made pandoc exit with an error; `--self-contained` replaced with `--standalone` (Pandoc 3.x) +- Removed dead "Open Export Options Dialog…" button from the converter dialog +- Removed duplicate `styles-zen.css` include + +### Security +- AI provider requests carry size caps (200KB prompt), timeouts (120s), and user-safe error surfaces +- Version-history reads validate ids against traversal; history listing requires a valid document path +- PlantUML local rendering removes the diagram-text exfiltration path when a local CLI exists (CVE-MC-007 follow-up) + +### Tests +- New suites: OdtStyling, AiProviders, ai-assistant prompts, collaboration comment-store, wiki-links/backlinks, session-store, XlsxExporter, VersionHistory +- PDFOperations encryption tests rewritten for the real-encryption reality + +--- + ## Version 4.0.0 (2026-03-04) ### Major Changes diff --git a/assets/katex/fonts/KaTeX_AMS-Regular.ttf b/assets/katex/fonts/KaTeX_AMS-Regular.ttf new file mode 100644 index 0000000..c6f9a5e Binary files /dev/null and b/assets/katex/fonts/KaTeX_AMS-Regular.ttf differ diff --git a/assets/katex/fonts/KaTeX_AMS-Regular.woff b/assets/katex/fonts/KaTeX_AMS-Regular.woff new file mode 100644 index 0000000..b804d7b Binary files /dev/null and b/assets/katex/fonts/KaTeX_AMS-Regular.woff differ diff --git a/assets/katex/fonts/KaTeX_AMS-Regular.woff2 b/assets/katex/fonts/KaTeX_AMS-Regular.woff2 new file mode 100644 index 0000000..0acaaff Binary files /dev/null and b/assets/katex/fonts/KaTeX_AMS-Regular.woff2 differ diff --git a/assets/katex/fonts/KaTeX_Caligraphic-Bold.ttf b/assets/katex/fonts/KaTeX_Caligraphic-Bold.ttf new file mode 100644 index 0000000..9ff4a5e Binary files /dev/null and b/assets/katex/fonts/KaTeX_Caligraphic-Bold.ttf differ diff --git a/assets/katex/fonts/KaTeX_Caligraphic-Bold.woff b/assets/katex/fonts/KaTeX_Caligraphic-Bold.woff new file mode 100644 index 0000000..9759710 Binary files /dev/null and b/assets/katex/fonts/KaTeX_Caligraphic-Bold.woff differ diff --git a/assets/katex/fonts/KaTeX_Caligraphic-Bold.woff2 b/assets/katex/fonts/KaTeX_Caligraphic-Bold.woff2 new file mode 100644 index 0000000..f390922 Binary files /dev/null and b/assets/katex/fonts/KaTeX_Caligraphic-Bold.woff2 differ diff --git a/assets/katex/fonts/KaTeX_Caligraphic-Regular.ttf b/assets/katex/fonts/KaTeX_Caligraphic-Regular.ttf new file mode 100644 index 0000000..f522294 Binary files /dev/null and b/assets/katex/fonts/KaTeX_Caligraphic-Regular.ttf differ diff --git a/assets/katex/fonts/KaTeX_Caligraphic-Regular.woff b/assets/katex/fonts/KaTeX_Caligraphic-Regular.woff new file mode 100644 index 0000000..9bdd534 Binary files /dev/null and b/assets/katex/fonts/KaTeX_Caligraphic-Regular.woff differ diff --git a/assets/katex/fonts/KaTeX_Caligraphic-Regular.woff2 b/assets/katex/fonts/KaTeX_Caligraphic-Regular.woff2 new file mode 100644 index 0000000..75344a1 Binary files /dev/null and b/assets/katex/fonts/KaTeX_Caligraphic-Regular.woff2 differ diff --git a/assets/katex/fonts/KaTeX_Fraktur-Bold.ttf b/assets/katex/fonts/KaTeX_Fraktur-Bold.ttf new file mode 100644 index 0000000..4e98259 Binary files /dev/null and b/assets/katex/fonts/KaTeX_Fraktur-Bold.ttf differ diff --git a/assets/katex/fonts/KaTeX_Fraktur-Bold.woff b/assets/katex/fonts/KaTeX_Fraktur-Bold.woff new file mode 100644 index 0000000..e7730f6 Binary files /dev/null and b/assets/katex/fonts/KaTeX_Fraktur-Bold.woff differ diff --git a/assets/katex/fonts/KaTeX_Fraktur-Bold.woff2 b/assets/katex/fonts/KaTeX_Fraktur-Bold.woff2 new file mode 100644 index 0000000..395f28b Binary files /dev/null and b/assets/katex/fonts/KaTeX_Fraktur-Bold.woff2 differ diff --git a/assets/katex/fonts/KaTeX_Fraktur-Regular.ttf b/assets/katex/fonts/KaTeX_Fraktur-Regular.ttf new file mode 100644 index 0000000..b8461b2 Binary files /dev/null and b/assets/katex/fonts/KaTeX_Fraktur-Regular.ttf differ diff --git a/assets/katex/fonts/KaTeX_Fraktur-Regular.woff b/assets/katex/fonts/KaTeX_Fraktur-Regular.woff new file mode 100644 index 0000000..acab069 Binary files /dev/null and b/assets/katex/fonts/KaTeX_Fraktur-Regular.woff differ diff --git a/assets/katex/fonts/KaTeX_Fraktur-Regular.woff2 b/assets/katex/fonts/KaTeX_Fraktur-Regular.woff2 new file mode 100644 index 0000000..735f694 Binary files /dev/null and b/assets/katex/fonts/KaTeX_Fraktur-Regular.woff2 differ diff --git a/assets/katex/fonts/KaTeX_Main-Bold.ttf b/assets/katex/fonts/KaTeX_Main-Bold.ttf new file mode 100644 index 0000000..4060e62 Binary files /dev/null and b/assets/katex/fonts/KaTeX_Main-Bold.ttf differ diff --git a/assets/katex/fonts/KaTeX_Main-Bold.woff b/assets/katex/fonts/KaTeX_Main-Bold.woff new file mode 100644 index 0000000..f38136a Binary files /dev/null and b/assets/katex/fonts/KaTeX_Main-Bold.woff differ diff --git a/assets/katex/fonts/KaTeX_Main-Bold.woff2 b/assets/katex/fonts/KaTeX_Main-Bold.woff2 new file mode 100644 index 0000000..ab2ad21 Binary files /dev/null and b/assets/katex/fonts/KaTeX_Main-Bold.woff2 differ diff --git a/assets/katex/fonts/KaTeX_Main-BoldItalic.ttf b/assets/katex/fonts/KaTeX_Main-BoldItalic.ttf new file mode 100644 index 0000000..dc00797 Binary files /dev/null and b/assets/katex/fonts/KaTeX_Main-BoldItalic.ttf differ diff --git a/assets/katex/fonts/KaTeX_Main-BoldItalic.woff b/assets/katex/fonts/KaTeX_Main-BoldItalic.woff new file mode 100644 index 0000000..67807b0 Binary files /dev/null and b/assets/katex/fonts/KaTeX_Main-BoldItalic.woff differ diff --git a/assets/katex/fonts/KaTeX_Main-BoldItalic.woff2 b/assets/katex/fonts/KaTeX_Main-BoldItalic.woff2 new file mode 100644 index 0000000..5931794 Binary files /dev/null and b/assets/katex/fonts/KaTeX_Main-BoldItalic.woff2 differ diff --git a/assets/katex/fonts/KaTeX_Main-Italic.ttf b/assets/katex/fonts/KaTeX_Main-Italic.ttf new file mode 100644 index 0000000..0e9b0f3 Binary files /dev/null and b/assets/katex/fonts/KaTeX_Main-Italic.ttf differ diff --git a/assets/katex/fonts/KaTeX_Main-Italic.woff b/assets/katex/fonts/KaTeX_Main-Italic.woff new file mode 100644 index 0000000..6f43b59 Binary files /dev/null and b/assets/katex/fonts/KaTeX_Main-Italic.woff differ diff --git a/assets/katex/fonts/KaTeX_Main-Italic.woff2 b/assets/katex/fonts/KaTeX_Main-Italic.woff2 new file mode 100644 index 0000000..b50920e Binary files /dev/null and b/assets/katex/fonts/KaTeX_Main-Italic.woff2 differ diff --git a/assets/katex/fonts/KaTeX_Main-Regular.ttf b/assets/katex/fonts/KaTeX_Main-Regular.ttf new file mode 100644 index 0000000..dd45e1e Binary files /dev/null and b/assets/katex/fonts/KaTeX_Main-Regular.ttf differ diff --git a/assets/katex/fonts/KaTeX_Main-Regular.woff b/assets/katex/fonts/KaTeX_Main-Regular.woff new file mode 100644 index 0000000..21f5812 Binary files /dev/null and b/assets/katex/fonts/KaTeX_Main-Regular.woff differ diff --git a/assets/katex/fonts/KaTeX_Main-Regular.woff2 b/assets/katex/fonts/KaTeX_Main-Regular.woff2 new file mode 100644 index 0000000..eb24a7b Binary files /dev/null and b/assets/katex/fonts/KaTeX_Main-Regular.woff2 differ diff --git a/assets/katex/fonts/KaTeX_Math-BoldItalic.ttf b/assets/katex/fonts/KaTeX_Math-BoldItalic.ttf new file mode 100644 index 0000000..728ce7a Binary files /dev/null and b/assets/katex/fonts/KaTeX_Math-BoldItalic.ttf differ diff --git a/assets/katex/fonts/KaTeX_Math-BoldItalic.woff b/assets/katex/fonts/KaTeX_Math-BoldItalic.woff new file mode 100644 index 0000000..0ae390d Binary files /dev/null and b/assets/katex/fonts/KaTeX_Math-BoldItalic.woff differ diff --git a/assets/katex/fonts/KaTeX_Math-BoldItalic.woff2 b/assets/katex/fonts/KaTeX_Math-BoldItalic.woff2 new file mode 100644 index 0000000..2965702 Binary files /dev/null and b/assets/katex/fonts/KaTeX_Math-BoldItalic.woff2 differ diff --git a/assets/katex/fonts/KaTeX_Math-Italic.ttf b/assets/katex/fonts/KaTeX_Math-Italic.ttf new file mode 100644 index 0000000..70d559b Binary files /dev/null and b/assets/katex/fonts/KaTeX_Math-Italic.ttf differ diff --git a/assets/katex/fonts/KaTeX_Math-Italic.woff b/assets/katex/fonts/KaTeX_Math-Italic.woff new file mode 100644 index 0000000..eb5159d Binary files /dev/null and b/assets/katex/fonts/KaTeX_Math-Italic.woff differ diff --git a/assets/katex/fonts/KaTeX_Math-Italic.woff2 b/assets/katex/fonts/KaTeX_Math-Italic.woff2 new file mode 100644 index 0000000..215c143 Binary files /dev/null and b/assets/katex/fonts/KaTeX_Math-Italic.woff2 differ diff --git a/assets/katex/fonts/KaTeX_SansSerif-Bold.ttf b/assets/katex/fonts/KaTeX_SansSerif-Bold.ttf new file mode 100644 index 0000000..2f65a8a Binary files /dev/null and b/assets/katex/fonts/KaTeX_SansSerif-Bold.ttf differ diff --git a/assets/katex/fonts/KaTeX_SansSerif-Bold.woff b/assets/katex/fonts/KaTeX_SansSerif-Bold.woff new file mode 100644 index 0000000..8d47c02 Binary files /dev/null and b/assets/katex/fonts/KaTeX_SansSerif-Bold.woff differ diff --git a/assets/katex/fonts/KaTeX_SansSerif-Bold.woff2 b/assets/katex/fonts/KaTeX_SansSerif-Bold.woff2 new file mode 100644 index 0000000..cfaa3bd Binary files /dev/null and b/assets/katex/fonts/KaTeX_SansSerif-Bold.woff2 differ diff --git a/assets/katex/fonts/KaTeX_SansSerif-Italic.ttf b/assets/katex/fonts/KaTeX_SansSerif-Italic.ttf new file mode 100644 index 0000000..d5850df Binary files /dev/null and b/assets/katex/fonts/KaTeX_SansSerif-Italic.ttf differ diff --git a/assets/katex/fonts/KaTeX_SansSerif-Italic.woff b/assets/katex/fonts/KaTeX_SansSerif-Italic.woff new file mode 100644 index 0000000..7e02df9 Binary files /dev/null and b/assets/katex/fonts/KaTeX_SansSerif-Italic.woff differ diff --git a/assets/katex/fonts/KaTeX_SansSerif-Italic.woff2 b/assets/katex/fonts/KaTeX_SansSerif-Italic.woff2 new file mode 100644 index 0000000..349c06d Binary files /dev/null and b/assets/katex/fonts/KaTeX_SansSerif-Italic.woff2 differ diff --git a/assets/katex/fonts/KaTeX_SansSerif-Regular.ttf b/assets/katex/fonts/KaTeX_SansSerif-Regular.ttf new file mode 100644 index 0000000..537279f Binary files /dev/null and b/assets/katex/fonts/KaTeX_SansSerif-Regular.ttf differ diff --git a/assets/katex/fonts/KaTeX_SansSerif-Regular.woff b/assets/katex/fonts/KaTeX_SansSerif-Regular.woff new file mode 100644 index 0000000..31b8482 Binary files /dev/null and b/assets/katex/fonts/KaTeX_SansSerif-Regular.woff differ diff --git a/assets/katex/fonts/KaTeX_SansSerif-Regular.woff2 b/assets/katex/fonts/KaTeX_SansSerif-Regular.woff2 new file mode 100644 index 0000000..a90eea8 Binary files /dev/null and b/assets/katex/fonts/KaTeX_SansSerif-Regular.woff2 differ diff --git a/assets/katex/fonts/KaTeX_Script-Regular.ttf b/assets/katex/fonts/KaTeX_Script-Regular.ttf new file mode 100644 index 0000000..fd679bf Binary files /dev/null and b/assets/katex/fonts/KaTeX_Script-Regular.ttf differ diff --git a/assets/katex/fonts/KaTeX_Script-Regular.woff b/assets/katex/fonts/KaTeX_Script-Regular.woff new file mode 100644 index 0000000..0e7da82 Binary files /dev/null and b/assets/katex/fonts/KaTeX_Script-Regular.woff differ diff --git a/assets/katex/fonts/KaTeX_Script-Regular.woff2 b/assets/katex/fonts/KaTeX_Script-Regular.woff2 new file mode 100644 index 0000000..b3048fc Binary files /dev/null and b/assets/katex/fonts/KaTeX_Script-Regular.woff2 differ diff --git a/assets/katex/fonts/KaTeX_Size1-Regular.ttf b/assets/katex/fonts/KaTeX_Size1-Regular.ttf new file mode 100644 index 0000000..871fd7d Binary files /dev/null and b/assets/katex/fonts/KaTeX_Size1-Regular.ttf differ diff --git a/assets/katex/fonts/KaTeX_Size1-Regular.woff b/assets/katex/fonts/KaTeX_Size1-Regular.woff new file mode 100644 index 0000000..7f292d9 Binary files /dev/null and b/assets/katex/fonts/KaTeX_Size1-Regular.woff differ diff --git a/assets/katex/fonts/KaTeX_Size1-Regular.woff2 b/assets/katex/fonts/KaTeX_Size1-Regular.woff2 new file mode 100644 index 0000000..c5a8462 Binary files /dev/null and b/assets/katex/fonts/KaTeX_Size1-Regular.woff2 differ diff --git a/assets/katex/fonts/KaTeX_Size2-Regular.ttf b/assets/katex/fonts/KaTeX_Size2-Regular.ttf new file mode 100644 index 0000000..7a212ca Binary files /dev/null and b/assets/katex/fonts/KaTeX_Size2-Regular.ttf differ diff --git a/assets/katex/fonts/KaTeX_Size2-Regular.woff b/assets/katex/fonts/KaTeX_Size2-Regular.woff new file mode 100644 index 0000000..d241d9b Binary files /dev/null and b/assets/katex/fonts/KaTeX_Size2-Regular.woff differ diff --git a/assets/katex/fonts/KaTeX_Size2-Regular.woff2 b/assets/katex/fonts/KaTeX_Size2-Regular.woff2 new file mode 100644 index 0000000..e1bccfe Binary files /dev/null and b/assets/katex/fonts/KaTeX_Size2-Regular.woff2 differ diff --git a/assets/katex/fonts/KaTeX_Size3-Regular.ttf b/assets/katex/fonts/KaTeX_Size3-Regular.ttf new file mode 100644 index 0000000..00bff34 Binary files /dev/null and b/assets/katex/fonts/KaTeX_Size3-Regular.ttf differ diff --git a/assets/katex/fonts/KaTeX_Size3-Regular.woff b/assets/katex/fonts/KaTeX_Size3-Regular.woff new file mode 100644 index 0000000..e6e9b65 Binary files /dev/null and b/assets/katex/fonts/KaTeX_Size3-Regular.woff differ diff --git a/assets/katex/fonts/KaTeX_Size3-Regular.woff2 b/assets/katex/fonts/KaTeX_Size3-Regular.woff2 new file mode 100644 index 0000000..249a286 Binary files /dev/null and b/assets/katex/fonts/KaTeX_Size3-Regular.woff2 differ diff --git a/assets/katex/fonts/KaTeX_Size4-Regular.ttf b/assets/katex/fonts/KaTeX_Size4-Regular.ttf new file mode 100644 index 0000000..74f0892 Binary files /dev/null and b/assets/katex/fonts/KaTeX_Size4-Regular.ttf differ diff --git a/assets/katex/fonts/KaTeX_Size4-Regular.woff b/assets/katex/fonts/KaTeX_Size4-Regular.woff new file mode 100644 index 0000000..e1ec545 Binary files /dev/null and b/assets/katex/fonts/KaTeX_Size4-Regular.woff differ diff --git a/assets/katex/fonts/KaTeX_Size4-Regular.woff2 b/assets/katex/fonts/KaTeX_Size4-Regular.woff2 new file mode 100644 index 0000000..680c130 Binary files /dev/null and b/assets/katex/fonts/KaTeX_Size4-Regular.woff2 differ diff --git a/assets/katex/fonts/KaTeX_Typewriter-Regular.ttf b/assets/katex/fonts/KaTeX_Typewriter-Regular.ttf new file mode 100644 index 0000000..c83252c Binary files /dev/null and b/assets/katex/fonts/KaTeX_Typewriter-Regular.ttf differ diff --git a/assets/katex/fonts/KaTeX_Typewriter-Regular.woff b/assets/katex/fonts/KaTeX_Typewriter-Regular.woff new file mode 100644 index 0000000..2432419 Binary files /dev/null and b/assets/katex/fonts/KaTeX_Typewriter-Regular.woff differ diff --git a/assets/katex/fonts/KaTeX_Typewriter-Regular.woff2 b/assets/katex/fonts/KaTeX_Typewriter-Regular.woff2 new file mode 100644 index 0000000..771f1af Binary files /dev/null and b/assets/katex/fonts/KaTeX_Typewriter-Regular.woff2 differ diff --git a/assets/katex/katex.min.css b/assets/katex/katex.min.css new file mode 100644 index 0000000..9061690 --- /dev/null +++ b/assets/katex/katex.min.css @@ -0,0 +1 @@ +@font-face{font-display:block;font-family:KaTeX_AMS;font-style:normal;font-weight:400;src:url(fonts/KaTeX_AMS-Regular.woff2) format("woff2"),url(fonts/KaTeX_AMS-Regular.woff) format("woff"),url(fonts/KaTeX_AMS-Regular.ttf) format("truetype")}@font-face{font-display:block;font-family:KaTeX_Caligraphic;font-style:normal;font-weight:700;src:url(fonts/KaTeX_Caligraphic-Bold.woff2) format("woff2"),url(fonts/KaTeX_Caligraphic-Bold.woff) format("woff"),url(fonts/KaTeX_Caligraphic-Bold.ttf) format("truetype")}@font-face{font-display:block;font-family:KaTeX_Caligraphic;font-style:normal;font-weight:400;src:url(fonts/KaTeX_Caligraphic-Regular.woff2) format("woff2"),url(fonts/KaTeX_Caligraphic-Regular.woff) format("woff"),url(fonts/KaTeX_Caligraphic-Regular.ttf) format("truetype")}@font-face{font-display:block;font-family:KaTeX_Fraktur;font-style:normal;font-weight:700;src:url(fonts/KaTeX_Fraktur-Bold.woff2) format("woff2"),url(fonts/KaTeX_Fraktur-Bold.woff) format("woff"),url(fonts/KaTeX_Fraktur-Bold.ttf) format("truetype")}@font-face{font-display:block;font-family:KaTeX_Fraktur;font-style:normal;font-weight:400;src:url(fonts/KaTeX_Fraktur-Regular.woff2) format("woff2"),url(fonts/KaTeX_Fraktur-Regular.woff) format("woff"),url(fonts/KaTeX_Fraktur-Regular.ttf) format("truetype")}@font-face{font-display:block;font-family:KaTeX_Main;font-style:normal;font-weight:700;src:url(fonts/KaTeX_Main-Bold.woff2) format("woff2"),url(fonts/KaTeX_Main-Bold.woff) format("woff"),url(fonts/KaTeX_Main-Bold.ttf) format("truetype")}@font-face{font-display:block;font-family:KaTeX_Main;font-style:italic;font-weight:700;src:url(fonts/KaTeX_Main-BoldItalic.woff2) format("woff2"),url(fonts/KaTeX_Main-BoldItalic.woff) format("woff"),url(fonts/KaTeX_Main-BoldItalic.ttf) format("truetype")}@font-face{font-display:block;font-family:KaTeX_Main;font-style:italic;font-weight:400;src:url(fonts/KaTeX_Main-Italic.woff2) format("woff2"),url(fonts/KaTeX_Main-Italic.woff) format("woff"),url(fonts/KaTeX_Main-Italic.ttf) format("truetype")}@font-face{font-display:block;font-family:KaTeX_Main;font-style:normal;font-weight:400;src:url(fonts/KaTeX_Main-Regular.woff2) format("woff2"),url(fonts/KaTeX_Main-Regular.woff) format("woff"),url(fonts/KaTeX_Main-Regular.ttf) format("truetype")}@font-face{font-display:block;font-family:KaTeX_Math;font-style:italic;font-weight:700;src:url(fonts/KaTeX_Math-BoldItalic.woff2) format("woff2"),url(fonts/KaTeX_Math-BoldItalic.woff) format("woff"),url(fonts/KaTeX_Math-BoldItalic.ttf) format("truetype")}@font-face{font-display:block;font-family:KaTeX_Math;font-style:italic;font-weight:400;src:url(fonts/KaTeX_Math-Italic.woff2) format("woff2"),url(fonts/KaTeX_Math-Italic.woff) format("woff"),url(fonts/KaTeX_Math-Italic.ttf) format("truetype")}@font-face{font-display:block;font-family:"KaTeX_SansSerif";font-style:normal;font-weight:700;src:url(fonts/KaTeX_SansSerif-Bold.woff2) format("woff2"),url(fonts/KaTeX_SansSerif-Bold.woff) format("woff"),url(fonts/KaTeX_SansSerif-Bold.ttf) format("truetype")}@font-face{font-display:block;font-family:"KaTeX_SansSerif";font-style:italic;font-weight:400;src:url(fonts/KaTeX_SansSerif-Italic.woff2) format("woff2"),url(fonts/KaTeX_SansSerif-Italic.woff) format("woff"),url(fonts/KaTeX_SansSerif-Italic.ttf) format("truetype")}@font-face{font-display:block;font-family:"KaTeX_SansSerif";font-style:normal;font-weight:400;src:url(fonts/KaTeX_SansSerif-Regular.woff2) format("woff2"),url(fonts/KaTeX_SansSerif-Regular.woff) format("woff"),url(fonts/KaTeX_SansSerif-Regular.ttf) format("truetype")}@font-face{font-display:block;font-family:KaTeX_Script;font-style:normal;font-weight:400;src:url(fonts/KaTeX_Script-Regular.woff2) format("woff2"),url(fonts/KaTeX_Script-Regular.woff) format("woff"),url(fonts/KaTeX_Script-Regular.ttf) format("truetype")}@font-face{font-display:block;font-family:KaTeX_Size1;font-style:normal;font-weight:400;src:url(fonts/KaTeX_Size1-Regular.woff2) format("woff2"),url(fonts/KaTeX_Size1-Regular.woff) format("woff"),url(fonts/KaTeX_Size1-Regular.ttf) format("truetype")}@font-face{font-display:block;font-family:KaTeX_Size2;font-style:normal;font-weight:400;src:url(fonts/KaTeX_Size2-Regular.woff2) format("woff2"),url(fonts/KaTeX_Size2-Regular.woff) format("woff"),url(fonts/KaTeX_Size2-Regular.ttf) format("truetype")}@font-face{font-display:block;font-family:KaTeX_Size3;font-style:normal;font-weight:400;src:url(fonts/KaTeX_Size3-Regular.woff2) format("woff2"),url(fonts/KaTeX_Size3-Regular.woff) format("woff"),url(fonts/KaTeX_Size3-Regular.ttf) format("truetype")}@font-face{font-display:block;font-family:KaTeX_Size4;font-style:normal;font-weight:400;src:url(fonts/KaTeX_Size4-Regular.woff2) format("woff2"),url(fonts/KaTeX_Size4-Regular.woff) format("woff"),url(fonts/KaTeX_Size4-Regular.ttf) format("truetype")}@font-face{font-display:block;font-family:KaTeX_Typewriter;font-style:normal;font-weight:400;src:url(fonts/KaTeX_Typewriter-Regular.woff2) format("woff2"),url(fonts/KaTeX_Typewriter-Regular.woff) format("woff"),url(fonts/KaTeX_Typewriter-Regular.ttf) format("truetype")}.katex{font:normal 1.21em KaTeX_Main,Times New Roman,serif;line-height:1.2;position:relative;text-indent:0;text-rendering:auto}.katex *{-ms-high-contrast-adjust:none!important;border-color:currentColor}.katex .katex-version:after{content:"0.18.5"}.katex .katex-mathml{border:0;-webkit-clip-path:inset(50%);clip-path:inset(50%);height:1px;overflow:hidden;padding:0;position:absolute;width:1px}.katex .katex-html>.katex-newline{display:block}.katex .katex-base{position:relative;white-space:nowrap;width:-webkit-min-content;width:-moz-min-content;width:min-content}.katex .katex-base,.katex .katex-strut{display:inline-block}.katex .textbf{font-weight:700}.katex .textit{font-style:italic}.katex .textrm{font-family:KaTeX_Main}.katex .textsf{font-family:KaTeX_SansSerif}.katex .texttt{font-family:KaTeX_Typewriter}.katex .mathnormal{font-family:KaTeX_Math;font-style:italic}.katex .mathit{font-family:KaTeX_Main;font-style:italic}.katex .mathrm{font-style:normal}.katex .mathbf{font-family:KaTeX_Main;font-weight:700}.katex .boldsymbol{font-family:KaTeX_Math;font-style:italic;font-weight:700}.katex .amsrm,.katex .mathbb,.katex .textbb{font-family:KaTeX_AMS}.katex .mathcal{font-family:KaTeX_Caligraphic}.katex .mathfrak,.katex .textfrak{font-family:KaTeX_Fraktur}.katex .mathboldfrak,.katex .textboldfrak{font-family:KaTeX_Fraktur;font-weight:700}.katex .mathtt{font-family:KaTeX_Typewriter}.katex .mathscr,.katex .textscr{font-family:KaTeX_Script}.katex .mathsf,.katex .textsf{font-family:KaTeX_SansSerif}.katex .mathboldsf,.katex .textboldsf{font-family:KaTeX_SansSerif;font-weight:700}.katex .mathitsf,.katex .mathsfit,.katex .textitsf{font-family:KaTeX_SansSerif;font-style:italic}.katex .mainrm{font-family:KaTeX_Main;font-style:normal}.katex .vlist-t{border-collapse:collapse;display:inline-table;table-layout:fixed}.katex .vlist-r{display:table-row}.katex .vlist{display:table-cell;position:relative;vertical-align:bottom}.katex .vlist>span{display:block;height:0;position:relative}.katex .vlist>span>span{display:inline-block}.katex .vlist>span>.pstrut{overflow:hidden;width:0}.katex .vlist-t2{margin-right:-2px}.katex .vlist-s{display:table-cell;font-size:1px;min-width:2px;vertical-align:bottom;width:2px}.katex .katex-vbox{align-items:baseline;display:inline-flex;flex-direction:column}.katex .katex-thinbox{display:inline-flex;flex-direction:row;max-width:0;width:0}.katex .msupsub{text-align:left}.katex .mfrac>span>span{text-align:center}.katex .mfrac .frac-line{border-bottom-style:solid;display:inline-block;width:100%}.katex .katex-hdashline,.katex .katex-hline,.katex .katex-overline .overline-line,.katex .katex-rule,.katex .katex-underline .underline-line,.katex .mfrac .frac-line{min-height:1px}.katex .mspace{display:inline-block}.katex .katex-smash{display:inline;line-height:0}.katex .clap,.katex .llap,.katex .rlap{position:relative;width:0}.katex .clap>.katex-inner,.katex .llap>.katex-inner,.katex .rlap>.katex-inner{position:absolute}.katex .clap>.katex-fix,.katex .llap>.katex-fix,.katex .rlap>.katex-fix{display:inline-block}.katex .llap>.katex-inner{right:0}.katex .clap>.katex-inner,.katex .rlap>.katex-inner{left:0}.katex .clap>.katex-inner>span{margin-left:-50%;margin-right:50%}.katex .katex-rule{border:0 solid;display:inline-block;position:relative}.katex .katex-hline,.katex .katex-overline .overline-line,.katex .katex-underline .underline-line{border-bottom-style:solid;display:inline-block;width:100%}.katex .katex-hdashline{border-bottom-style:dashed;display:inline-block;width:100%}.katex .sqrt>.katex-root{margin-left:.2777777778em;margin-right:-.5555555556em}.katex .fontsize-ensurer.reset-size1.size1,.katex .katex-sizing.reset-size1.size1{font-size:1em}.katex .fontsize-ensurer.reset-size1.size2,.katex .katex-sizing.reset-size1.size2{font-size:1.2em}.katex .fontsize-ensurer.reset-size1.size3,.katex .katex-sizing.reset-size1.size3{font-size:1.4em}.katex .fontsize-ensurer.reset-size1.size4,.katex .katex-sizing.reset-size1.size4{font-size:1.6em}.katex .fontsize-ensurer.reset-size1.size5,.katex .katex-sizing.reset-size1.size5{font-size:1.8em}.katex .fontsize-ensurer.reset-size1.size6,.katex .katex-sizing.reset-size1.size6{font-size:2em}.katex .fontsize-ensurer.reset-size1.size7,.katex .katex-sizing.reset-size1.size7{font-size:2.4em}.katex .fontsize-ensurer.reset-size1.size8,.katex .katex-sizing.reset-size1.size8{font-size:2.88em}.katex .fontsize-ensurer.reset-size1.size9,.katex .katex-sizing.reset-size1.size9{font-size:3.456em}.katex .fontsize-ensurer.reset-size1.size10,.katex .katex-sizing.reset-size1.size10{font-size:4.148em}.katex .fontsize-ensurer.reset-size1.size11,.katex .katex-sizing.reset-size1.size11{font-size:4.976em}.katex .fontsize-ensurer.reset-size2.size1,.katex .katex-sizing.reset-size2.size1{font-size:.8333333333em}.katex .fontsize-ensurer.reset-size2.size2,.katex .katex-sizing.reset-size2.size2{font-size:1em}.katex .fontsize-ensurer.reset-size2.size3,.katex .katex-sizing.reset-size2.size3{font-size:1.1666666667em}.katex .fontsize-ensurer.reset-size2.size4,.katex .katex-sizing.reset-size2.size4{font-size:1.3333333333em}.katex .fontsize-ensurer.reset-size2.size5,.katex .katex-sizing.reset-size2.size5{font-size:1.5em}.katex .fontsize-ensurer.reset-size2.size6,.katex .katex-sizing.reset-size2.size6{font-size:1.6666666667em}.katex .fontsize-ensurer.reset-size2.size7,.katex .katex-sizing.reset-size2.size7{font-size:2em}.katex .fontsize-ensurer.reset-size2.size8,.katex .katex-sizing.reset-size2.size8{font-size:2.4em}.katex .fontsize-ensurer.reset-size2.size9,.katex .katex-sizing.reset-size2.size9{font-size:2.88em}.katex .fontsize-ensurer.reset-size2.size10,.katex .katex-sizing.reset-size2.size10{font-size:3.4566666667em}.katex .fontsize-ensurer.reset-size2.size11,.katex .katex-sizing.reset-size2.size11{font-size:4.1466666667em}.katex .fontsize-ensurer.reset-size3.size1,.katex .katex-sizing.reset-size3.size1{font-size:.7142857143em}.katex .fontsize-ensurer.reset-size3.size2,.katex .katex-sizing.reset-size3.size2{font-size:.8571428571em}.katex .fontsize-ensurer.reset-size3.size3,.katex .katex-sizing.reset-size3.size3{font-size:1em}.katex .fontsize-ensurer.reset-size3.size4,.katex .katex-sizing.reset-size3.size4{font-size:1.1428571429em}.katex .fontsize-ensurer.reset-size3.size5,.katex .katex-sizing.reset-size3.size5{font-size:1.2857142857em}.katex .fontsize-ensurer.reset-size3.size6,.katex .katex-sizing.reset-size3.size6{font-size:1.4285714286em}.katex .fontsize-ensurer.reset-size3.size7,.katex .katex-sizing.reset-size3.size7{font-size:1.7142857143em}.katex .fontsize-ensurer.reset-size3.size8,.katex .katex-sizing.reset-size3.size8{font-size:2.0571428571em}.katex .fontsize-ensurer.reset-size3.size9,.katex .katex-sizing.reset-size3.size9{font-size:2.4685714286em}.katex .fontsize-ensurer.reset-size3.size10,.katex .katex-sizing.reset-size3.size10{font-size:2.9628571429em}.katex .fontsize-ensurer.reset-size3.size11,.katex .katex-sizing.reset-size3.size11{font-size:3.5542857143em}.katex .fontsize-ensurer.reset-size4.size1,.katex .katex-sizing.reset-size4.size1{font-size:.625em}.katex .fontsize-ensurer.reset-size4.size2,.katex .katex-sizing.reset-size4.size2{font-size:.75em}.katex .fontsize-ensurer.reset-size4.size3,.katex .katex-sizing.reset-size4.size3{font-size:.875em}.katex .fontsize-ensurer.reset-size4.size4,.katex .katex-sizing.reset-size4.size4{font-size:1em}.katex .fontsize-ensurer.reset-size4.size5,.katex .katex-sizing.reset-size4.size5{font-size:1.125em}.katex .fontsize-ensurer.reset-size4.size6,.katex .katex-sizing.reset-size4.size6{font-size:1.25em}.katex .fontsize-ensurer.reset-size4.size7,.katex .katex-sizing.reset-size4.size7{font-size:1.5em}.katex .fontsize-ensurer.reset-size4.size8,.katex .katex-sizing.reset-size4.size8{font-size:1.8em}.katex .fontsize-ensurer.reset-size4.size9,.katex .katex-sizing.reset-size4.size9{font-size:2.16em}.katex .fontsize-ensurer.reset-size4.size10,.katex .katex-sizing.reset-size4.size10{font-size:2.5925em}.katex .fontsize-ensurer.reset-size4.size11,.katex .katex-sizing.reset-size4.size11{font-size:3.11em}.katex .fontsize-ensurer.reset-size5.size1,.katex .katex-sizing.reset-size5.size1{font-size:.5555555556em}.katex .fontsize-ensurer.reset-size5.size2,.katex .katex-sizing.reset-size5.size2{font-size:.6666666667em}.katex .fontsize-ensurer.reset-size5.size3,.katex .katex-sizing.reset-size5.size3{font-size:.7777777778em}.katex .fontsize-ensurer.reset-size5.size4,.katex .katex-sizing.reset-size5.size4{font-size:.8888888889em}.katex .fontsize-ensurer.reset-size5.size5,.katex .katex-sizing.reset-size5.size5{font-size:1em}.katex .fontsize-ensurer.reset-size5.size6,.katex .katex-sizing.reset-size5.size6{font-size:1.1111111111em}.katex .fontsize-ensurer.reset-size5.size7,.katex .katex-sizing.reset-size5.size7{font-size:1.3333333333em}.katex .fontsize-ensurer.reset-size5.size8,.katex .katex-sizing.reset-size5.size8{font-size:1.6em}.katex .fontsize-ensurer.reset-size5.size9,.katex .katex-sizing.reset-size5.size9{font-size:1.92em}.katex .fontsize-ensurer.reset-size5.size10,.katex .katex-sizing.reset-size5.size10{font-size:2.3044444444em}.katex .fontsize-ensurer.reset-size5.size11,.katex .katex-sizing.reset-size5.size11{font-size:2.7644444444em}.katex .fontsize-ensurer.reset-size6.size1,.katex .katex-sizing.reset-size6.size1{font-size:.5em}.katex .fontsize-ensurer.reset-size6.size2,.katex .katex-sizing.reset-size6.size2{font-size:.6em}.katex .fontsize-ensurer.reset-size6.size3,.katex .katex-sizing.reset-size6.size3{font-size:.7em}.katex .fontsize-ensurer.reset-size6.size4,.katex .katex-sizing.reset-size6.size4{font-size:.8em}.katex .fontsize-ensurer.reset-size6.size5,.katex .katex-sizing.reset-size6.size5{font-size:.9em}.katex .fontsize-ensurer.reset-size6.size6,.katex .katex-sizing.reset-size6.size6{font-size:1em}.katex .fontsize-ensurer.reset-size6.size7,.katex .katex-sizing.reset-size6.size7{font-size:1.2em}.katex .fontsize-ensurer.reset-size6.size8,.katex .katex-sizing.reset-size6.size8{font-size:1.44em}.katex .fontsize-ensurer.reset-size6.size9,.katex .katex-sizing.reset-size6.size9{font-size:1.728em}.katex .fontsize-ensurer.reset-size6.size10,.katex .katex-sizing.reset-size6.size10{font-size:2.074em}.katex .fontsize-ensurer.reset-size6.size11,.katex .katex-sizing.reset-size6.size11{font-size:2.488em}.katex .fontsize-ensurer.reset-size7.size1,.katex .katex-sizing.reset-size7.size1{font-size:.4166666667em}.katex .fontsize-ensurer.reset-size7.size2,.katex .katex-sizing.reset-size7.size2{font-size:.5em}.katex .fontsize-ensurer.reset-size7.size3,.katex .katex-sizing.reset-size7.size3{font-size:.5833333333em}.katex .fontsize-ensurer.reset-size7.size4,.katex .katex-sizing.reset-size7.size4{font-size:.6666666667em}.katex .fontsize-ensurer.reset-size7.size5,.katex .katex-sizing.reset-size7.size5{font-size:.75em}.katex .fontsize-ensurer.reset-size7.size6,.katex .katex-sizing.reset-size7.size6{font-size:.8333333333em}.katex .fontsize-ensurer.reset-size7.size7,.katex .katex-sizing.reset-size7.size7{font-size:1em}.katex .fontsize-ensurer.reset-size7.size8,.katex .katex-sizing.reset-size7.size8{font-size:1.2em}.katex .fontsize-ensurer.reset-size7.size9,.katex .katex-sizing.reset-size7.size9{font-size:1.44em}.katex .fontsize-ensurer.reset-size7.size10,.katex .katex-sizing.reset-size7.size10{font-size:1.7283333333em}.katex .fontsize-ensurer.reset-size7.size11,.katex .katex-sizing.reset-size7.size11{font-size:2.0733333333em}.katex .fontsize-ensurer.reset-size8.size1,.katex .katex-sizing.reset-size8.size1{font-size:.3472222222em}.katex .fontsize-ensurer.reset-size8.size2,.katex .katex-sizing.reset-size8.size2{font-size:.4166666667em}.katex .fontsize-ensurer.reset-size8.size3,.katex .katex-sizing.reset-size8.size3{font-size:.4861111111em}.katex .fontsize-ensurer.reset-size8.size4,.katex .katex-sizing.reset-size8.size4{font-size:.5555555556em}.katex .fontsize-ensurer.reset-size8.size5,.katex .katex-sizing.reset-size8.size5{font-size:.625em}.katex .fontsize-ensurer.reset-size8.size6,.katex .katex-sizing.reset-size8.size6{font-size:.6944444444em}.katex .fontsize-ensurer.reset-size8.size7,.katex .katex-sizing.reset-size8.size7{font-size:.8333333333em}.katex .fontsize-ensurer.reset-size8.size8,.katex .katex-sizing.reset-size8.size8{font-size:1em}.katex .fontsize-ensurer.reset-size8.size9,.katex .katex-sizing.reset-size8.size9{font-size:1.2em}.katex .fontsize-ensurer.reset-size8.size10,.katex .katex-sizing.reset-size8.size10{font-size:1.4402777778em}.katex .fontsize-ensurer.reset-size8.size11,.katex .katex-sizing.reset-size8.size11{font-size:1.7277777778em}.katex .fontsize-ensurer.reset-size9.size1,.katex .katex-sizing.reset-size9.size1{font-size:.2893518519em}.katex .fontsize-ensurer.reset-size9.size2,.katex .katex-sizing.reset-size9.size2{font-size:.3472222222em}.katex .fontsize-ensurer.reset-size9.size3,.katex .katex-sizing.reset-size9.size3{font-size:.4050925926em}.katex .fontsize-ensurer.reset-size9.size4,.katex .katex-sizing.reset-size9.size4{font-size:.462962963em}.katex .fontsize-ensurer.reset-size9.size5,.katex .katex-sizing.reset-size9.size5{font-size:.5208333333em}.katex .fontsize-ensurer.reset-size9.size6,.katex .katex-sizing.reset-size9.size6{font-size:.5787037037em}.katex .fontsize-ensurer.reset-size9.size7,.katex .katex-sizing.reset-size9.size7{font-size:.6944444444em}.katex .fontsize-ensurer.reset-size9.size8,.katex .katex-sizing.reset-size9.size8{font-size:.8333333333em}.katex .fontsize-ensurer.reset-size9.size9,.katex .katex-sizing.reset-size9.size9{font-size:1em}.katex .fontsize-ensurer.reset-size9.size10,.katex .katex-sizing.reset-size9.size10{font-size:1.2002314815em}.katex .fontsize-ensurer.reset-size9.size11,.katex .katex-sizing.reset-size9.size11{font-size:1.4398148148em}.katex .fontsize-ensurer.reset-size10.size1,.katex .katex-sizing.reset-size10.size1{font-size:.2410800386em}.katex .fontsize-ensurer.reset-size10.size2,.katex .katex-sizing.reset-size10.size2{font-size:.2892960463em}.katex .fontsize-ensurer.reset-size10.size3,.katex .katex-sizing.reset-size10.size3{font-size:.337512054em}.katex .fontsize-ensurer.reset-size10.size4,.katex .katex-sizing.reset-size10.size4{font-size:.3857280617em}.katex .fontsize-ensurer.reset-size10.size5,.katex .katex-sizing.reset-size10.size5{font-size:.4339440694em}.katex .fontsize-ensurer.reset-size10.size6,.katex .katex-sizing.reset-size10.size6{font-size:.4821600771em}.katex .fontsize-ensurer.reset-size10.size7,.katex .katex-sizing.reset-size10.size7{font-size:.5785920926em}.katex .fontsize-ensurer.reset-size10.size8,.katex .katex-sizing.reset-size10.size8{font-size:.6943105111em}.katex .fontsize-ensurer.reset-size10.size9,.katex .katex-sizing.reset-size10.size9{font-size:.8331726133em}.katex .fontsize-ensurer.reset-size10.size10,.katex .katex-sizing.reset-size10.size10{font-size:1em}.katex .fontsize-ensurer.reset-size10.size11,.katex .katex-sizing.reset-size10.size11{font-size:1.1996142719em}.katex .fontsize-ensurer.reset-size11.size1,.katex .katex-sizing.reset-size11.size1{font-size:.2009646302em}.katex .fontsize-ensurer.reset-size11.size2,.katex .katex-sizing.reset-size11.size2{font-size:.2411575563em}.katex .fontsize-ensurer.reset-size11.size3,.katex .katex-sizing.reset-size11.size3{font-size:.2813504823em}.katex .fontsize-ensurer.reset-size11.size4,.katex .katex-sizing.reset-size11.size4{font-size:.3215434084em}.katex .fontsize-ensurer.reset-size11.size5,.katex .katex-sizing.reset-size11.size5{font-size:.3617363344em}.katex .fontsize-ensurer.reset-size11.size6,.katex .katex-sizing.reset-size11.size6{font-size:.4019292605em}.katex .fontsize-ensurer.reset-size11.size7,.katex .katex-sizing.reset-size11.size7{font-size:.4823151125em}.katex .fontsize-ensurer.reset-size11.size8,.katex .katex-sizing.reset-size11.size8{font-size:.578778135em}.katex .fontsize-ensurer.reset-size11.size9,.katex .katex-sizing.reset-size11.size9{font-size:.6945337621em}.katex .fontsize-ensurer.reset-size11.size10,.katex .katex-sizing.reset-size11.size10{font-size:.8336012862em}.katex .fontsize-ensurer.reset-size11.size11,.katex .katex-sizing.reset-size11.size11{font-size:1em}.katex .delimsizing.size1{font-family:KaTeX_Size1}.katex .delimsizing.size2{font-family:KaTeX_Size2}.katex .delimsizing.size3{font-family:KaTeX_Size3}.katex .delimsizing.size4{font-family:KaTeX_Size4}.katex .delimsizing.mult .delim-size1>span{font-family:KaTeX_Size1}.katex .delimsizing.mult .delim-size4>span{font-family:KaTeX_Size4}.katex .nulldelimiter{display:inline-block;width:.12em}.katex .delimcenter,.katex .op-symbol{position:relative}.katex .op-symbol.small-op{font-family:KaTeX_Size1}.katex .op-symbol.large-op{font-family:KaTeX_Size2}.katex .katex-accent>.vlist-t,.katex .op-limits>.vlist-t{text-align:center}.katex .katex-accent .accent-body{position:relative}.katex .katex-accent .accent-body:not(.accent-full){width:0}.katex .katex-overlay{display:block}.katex .mtable .vertical-separator{display:inline-block;min-width:1px}.katex .mtable .arraycolsep{display:inline-block}.katex .mtable .col-align-c>.vlist-t{text-align:center}.katex .mtable .col-align-l>.vlist-t{text-align:left}.katex .mtable .col-align-r>.vlist-t{text-align:right}.katex .svg-align{text-align:left}.katex svg{fill:currentColor;stroke:currentColor;display:block;height:inherit;position:absolute;width:100%}.katex svg path{stroke:none}.katex svg{fill-rule:nonzero;fill-opacity:1;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1}.katex img{border-style:none;max-height:none;max-width:none;min-height:0;min-width:0}.katex .katex-stretchy{display:block;overflow:hidden;position:relative;width:100%}.katex .katex-stretchy:after,.katex .katex-stretchy:before{content:""}.katex .hide-tail{overflow:hidden;position:relative;width:100%}.katex .halfarrow-left{left:0;overflow:hidden;position:absolute;width:50.2%}.katex .halfarrow-right{overflow:hidden;position:absolute;right:0;width:50.2%}.katex .brace-left{left:0;overflow:hidden;position:absolute;width:25.1%}.katex .brace-center{left:25%;overflow:hidden;position:absolute;width:50%}.katex .brace-right{overflow:hidden;position:absolute;right:0;width:25.1%}.katex .x-arrow-pad{padding:0 .5em}.katex .cd-arrow-pad{padding:0 .55556em 0 .27778em}.katex .mover,.katex .munder,.katex .x-arrow{text-align:center}.katex .boxpad{padding:0 .3em}.katex .fbox,.katex .fcolorbox{border:.04em solid;box-sizing:border-box}.katex .cancel-pad{padding:0 .2em}.katex .cancel-lap{margin-left:-.2em;margin-right:-.2em}.katex .katex-sout{border-bottom-style:solid;border-bottom-width:.08em}.katex .angl{border-right:.049em solid;border-top:.049em solid;box-sizing:border-box;margin-right:.03889em}.katex .anglpad{padding:0 .03889em}.katex .eqn-num:before{content:"(" counter(katexEqnNo) ")";counter-increment:katexEqnNo}.katex .mml-eqn-num:before{content:"(" counter(mmlEqnNo) ")";counter-increment:mmlEqnNo}.katex .mtr-glue{width:50%}.katex .cd-vert-arrow{display:inline-block;position:relative}.katex .cd-label-left{display:inline-block;position:absolute;right:calc(50% + .3em);text-align:left}.katex .cd-label-right{display:inline-block;left:calc(50% + .3em);position:absolute;text-align:right}.katex-display{display:block;margin:1em 0;text-align:center}.katex-display>.katex{display:block;text-align:center;white-space:nowrap}.katex-display>.katex>.katex-html{display:block;position:relative}.katex-display>.katex>.katex-html>.katex-tag{position:absolute;right:0}.katex-display.leqno>.katex>.katex-html>.katex-tag{left:0;right:auto}.katex-display.fleqn>.katex{padding-left:2em;text-align:left}body{counter-reset:katexEqnNo mmlEqnNo} diff --git a/package-lock.json b/package-lock.json index bae829e..d8ab935 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,14 +1,15 @@ { "name": "markdown-converter", - "version": "4.5.0", + "version": "4.6.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "markdown-converter", - "version": "4.5.0", + "version": "4.6.0", "license": "MIT", "dependencies": { + "@cantoo/pdf-lib": "^2.9.1", "@codemirror/autocomplete": "^6.20.1", "@codemirror/commands": "^6.10.2", "@codemirror/lang-css": "^6.3.1", @@ -23,6 +24,7 @@ "@codemirror/state": "^6.5.4", "@codemirror/theme-one-dark": "^6.1.3", "@codemirror/view": "^6.39.16", + "@replit/codemirror-vim": "^6.4.0", "codemirror": "^6.0.2", "core-util-is": "^1.0.3", "docx": "^9.6.0", @@ -33,11 +35,11 @@ "highlight.js": "^11.11.1", "html2pdf.js": "^0.14.0", "jszip": "^3.10.1", + "katex": "^0.18.5", "marked": "^17.0.3", "marked-footnote": "^1.4.0", "marked-highlight": "^2.2.3", "mermaid": "^11.12.3", - "pdf-lib": "^1.17.1", "pdfjs-dist": "^5.5.207", "pdfkit": "^0.17.2", "pizzip": "^3.2.0", @@ -620,6 +622,23 @@ "integrity": "sha512-jigsZK+sMF/cuiB7sERuo9V7N9jx+dhmHHnQyDSVdpZwVutaBu7WvNYqMDLSgFgfB30n452TP3vjDAvFC973mA==", "license": "MIT" }, + "node_modules/@cantoo/pdf-lib": { + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@cantoo/pdf-lib/-/pdf-lib-2.9.1.tgz", + "integrity": "sha512-wAKXXDjp5lO0wS6d+k0FRpmWsULb95WhHKYx2fonTbv4zIfuIdCBz2nyTVVDGJpNDLl6o4w9aSTxQisBvvd60A==", + "dependencies": { + "@pdf-lib/standard-fonts": "^1.0.0", + "@pdf-lib/upng": "^1.0.1", + "color": "^4.2.3", + "html-entities": "^2.3.2", + "node-html-better-parser": ">=1.5.9", + "pako": "^2.2.0", + "tslib": ">=2" + }, + "peerDependencies": { + "html-entities": "^2.3.2" + } + }, "node_modules/@chevrotain/types": { "version": "11.1.2", "resolved": "https://registry.npmjs.org/@chevrotain/types/-/types-11.1.2.tgz", @@ -3501,6 +3520,26 @@ "url": "https://opencollective.com/pkgr" } }, + "node_modules/@replit/codemirror-vim": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/@replit/codemirror-vim/-/codemirror-vim-6.4.0.tgz", + "integrity": "sha512-t9UMDNhkmeAkl0uRbiJVotv97bGD6mf4GyJJoEbrjUqa/Pov0s9eL+4AaI0Xto3OGri17i9qwIpT0JbVlVXt8A==", + "dependencies": { + "@replit/codemirror-vim-core": "^0.1.0" + }, + "peerDependencies": { + "@codemirror/commands": "6.x.x", + "@codemirror/language": "6.x.x", + "@codemirror/search": "6.x.x", + "@codemirror/state": "6.x.x", + "@codemirror/view": "6.x.x" + } + }, + "node_modules/@replit/codemirror-vim-core": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/@replit/codemirror-vim-core/-/codemirror-vim-core-0.1.0.tgz", + "integrity": "sha512-1i6EBKpcNfDKvTmTh6N6g9lL6udD5t+uFNh4JCqozRnVlvUGOps7h/QzS2ne4zcvPUjvApKpmcP7Grc3fNbZiQ==" + }, "node_modules/@simple-git/args-pathspec": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/@simple-git/args-pathspec/-/args-pathspec-1.0.3.tgz", @@ -4597,26 +4636,6 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/ansi-styles/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/ansi-styles/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true, - "license": "MIT" - }, "node_modules/anymatch": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", @@ -5659,6 +5678,43 @@ "dev": true, "license": "MIT" }, + "node_modules/color": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz", + "integrity": "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==", + "dependencies": { + "color-convert": "^2.0.1", + "color-string": "^1.9.0" + }, + "engines": { + "node": ">=12.5.0" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/color-string": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", + "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", + "dependencies": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, "node_modules/combined-stream": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", @@ -8392,6 +8448,21 @@ "node": ">=18" } }, + "node_modules/html-entities": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.6.0.tgz", + "integrity": "sha512-kig+rMn/QOVRvr7c86gQ8lWXq+Hkv6CbAH1hLu+RG338StTpE8Z0b44SDVaqVu7HGKf27frdmUYEs9hTUX/cLQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/mdevils" + }, + { + "type": "patreon", + "url": "https://patreon.com/mdevils" + } + ] + }, "node_modules/html-escaper": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", @@ -10163,28 +10234,26 @@ } }, "node_modules/katex": { - "version": "0.16.42", - "resolved": "https://registry.npmjs.org/katex/-/katex-0.16.42.tgz", - "integrity": "sha512-sZ4jqyEXfHTLEFK+qsFYToa3UZ0rtFcPGwKpyiRYh2NJn8obPWOQ+/u7ux0F6CAU/y78+Mksh1YkxTPXTh47TQ==", + "version": "0.18.5", + "resolved": "https://registry.npmjs.org/katex/-/katex-0.18.5.tgz", + "integrity": "sha512-1FU5H3RjGJVj6GT9fMjf2uMIXmPQp232aXS3UEeQzf0dxefHg/CKMvNB3DuOC46LFG/E5PNxrE8dOwB782FDGg==", "funding": [ "https://opencollective.com/katex", "https://github.com/sponsors/katex" ], - "license": "MIT", "dependencies": { - "commander": "^8.3.0" + "commander": "^15.0.0" }, "bin": { "katex": "cli.js" } }, "node_modules/katex/node_modules/commander": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", - "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", - "license": "MIT", + "version": "15.0.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-15.0.0.tgz", + "integrity": "sha512-z67u4ZhzCL/Tydu1lJARtEZYWbWaN7oYLHbsuzocr6y4N6WZAagG3RQ4FW61V1/0+jImpj293XfrcYnd1qxtPg==", "engines": { - "node": ">= 12" + "node": ">=22.12.0" } }, "node_modules/keyv": { @@ -10512,6 +10581,29 @@ "uuid": "^11.1.0 || ^12 || ^13 || ^14.0.0" } }, + "node_modules/mermaid/node_modules/commander": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", + "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", + "engines": { + "node": ">= 12" + } + }, + "node_modules/mermaid/node_modules/katex": { + "version": "0.16.47", + "resolved": "https://registry.npmjs.org/katex/-/katex-0.16.47.tgz", + "integrity": "sha512-Eeo8Ys1doU1z+x8AZsPpQu+p/QcZBI5PeOo7QGQdy2x2m0MU/hYagBbGOmXwr5KVbEfVuWv9LpnQWeehogurjg==", + "funding": [ + "https://opencollective.com/katex", + "https://github.com/sponsors/katex" + ], + "dependencies": { + "commander": "^8.3.0" + }, + "bin": { + "katex": "cli.js" + } + }, "node_modules/mermaid/node_modules/marked": { "version": "16.4.2", "resolved": "https://registry.npmjs.org/marked/-/marked-16.4.2.tgz", @@ -10960,6 +11052,14 @@ "node": "^18.17.0 || >=20.5.0" } }, + "node_modules/node-html-better-parser": { + "version": "1.5.9", + "resolved": "https://registry.npmjs.org/node-html-better-parser/-/node-html-better-parser-1.5.9.tgz", + "integrity": "sha512-z1I5UINMezJXYL9cH3h0a9KBth2G978gSLlfkpQ+CQzzVHVQy9gpARgm9eDsz1O4gn1HtgUqjdAIYxKFZm6uHQ==", + "dependencies": { + "html-entities": "^2.3.2" + } + }, "node_modules/node-int64": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", @@ -11198,10 +11298,19 @@ "license": "MIT" }, "node_modules/pako": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/pako/-/pako-2.1.0.tgz", - "integrity": "sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug==", - "license": "(MIT AND Zlib)" + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/pako/-/pako-2.2.0.tgz", + "integrity": "sha512-zJq6RP/5q+TO2OpFV3FHzlPnFjmkb7Nc99a5SNjJE+uu/PkpChs+NIZSSzbBoD+6kjiISXjfYdwj1ZRQ81dz/w==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/puzrin" + }, + { + "type": "github", + "url": "https://github.com/sponsors/nodeca" + } + ] }, "node_modules/parent-module": { "version": "1.0.1", @@ -11332,30 +11441,6 @@ "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", "license": "MIT" }, - "node_modules/pdf-lib": { - "version": "1.17.1", - "resolved": "https://registry.npmjs.org/pdf-lib/-/pdf-lib-1.17.1.tgz", - "integrity": "sha512-V/mpyJAoTsN4cnP31vc0wfNA1+p20evqqnap0KLoRUN0Yk/p3wN52DOEsL4oBFcLdb76hlpKPtzJIgo67j/XLw==", - "license": "MIT", - "dependencies": { - "@pdf-lib/standard-fonts": "^1.0.0", - "@pdf-lib/upng": "^1.0.1", - "pako": "^1.0.11", - "tslib": "^1.11.1" - } - }, - "node_modules/pdf-lib/node_modules/pako": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", - "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", - "license": "(MIT AND Zlib)" - }, - "node_modules/pdf-lib/node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "license": "0BSD" - }, "node_modules/pdfjs-dist": { "version": "5.5.207", "resolved": "https://registry.npmjs.org/pdfjs-dist/-/pdfjs-dist-5.5.207.tgz", @@ -12215,6 +12300,19 @@ "url": "https://github.com/steveukx/git-js?sponsor=1" } }, + "node_modules/simple-swizzle": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.4.tgz", + "integrity": "sha512-nAu1WFPQSMNr2Zn9PGSZK9AGn4t/y97lEm+MXTtUDwfP0ksAIX4nO+6ruD9Jwut4C49SB1Ws+fbXsm/yScWOHw==", + "dependencies": { + "is-arrayish": "^0.3.1" + } + }, + "node_modules/simple-swizzle/node_modules/is-arrayish": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.4.tgz", + "integrity": "sha512-m6UrgzFVUYawGBh1dUsWR5M2Clqic9RVXC/9f8ceNlv2IcO9j9J/z8UoCLPqtsPBFNzEpfR3xftohbfqDx8EQA==" + }, "node_modules/simple-update-notifier": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz", diff --git a/package.json b/package.json index 6fc6760..37ec286 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "markdown-converter", - "version": "4.5.0", + "version": "4.6.0", "description": "Professional Markdown editor and universal file converter with PDF editing, batch processing, and syntax highlighting", "main": "src/main.js", "scripts": { @@ -55,6 +55,7 @@ "prettier": "^3.7.4" }, "dependencies": { + "@cantoo/pdf-lib": "^2.9.1", "@codemirror/autocomplete": "^6.20.1", "@codemirror/commands": "^6.10.2", "@codemirror/lang-css": "^6.3.1", @@ -69,6 +70,7 @@ "@codemirror/state": "^6.5.4", "@codemirror/theme-one-dark": "^6.1.3", "@codemirror/view": "^6.39.16", + "@replit/codemirror-vim": "^6.4.0", "codemirror": "^6.0.2", "core-util-is": "^1.0.3", "docx": "^9.6.0", @@ -79,11 +81,11 @@ "highlight.js": "^11.11.1", "html2pdf.js": "^0.14.0", "jszip": "^3.10.1", + "katex": "^0.18.5", "marked": "^17.0.3", "marked-footnote": "^1.4.0", "marked-highlight": "^2.2.3", "mermaid": "^11.12.3", - "pdf-lib": "^1.17.1", "pdfjs-dist": "^5.5.207", "pdfkit": "^0.17.2", "pizzip": "^3.2.0", diff --git a/src/editor/codemirror-setup.js b/src/editor/codemirror-setup.js index cd44a52..bea47d8 100644 --- a/src/editor/codemirror-setup.js +++ b/src/editor/codemirror-setup.js @@ -8,7 +8,7 @@ const { highlightActiveLine, drawSelection, } = require('@codemirror/view'); -const { EditorState } = require('@codemirror/state'); +const { EditorState, Compartment } = require('@codemirror/state'); const { markdown, markdownLanguage } = require('@codemirror/lang-markdown'); // Language extensions loaded lazily on first use let _javascript, _html, _css, _json, _python; @@ -18,6 +18,30 @@ const { autocompletion, completionKeymap } = require('@codemirror/autocomplete') const { bracketMatching, foldGutter, indentOnInput } = require('@codemirror/language'); const { oneDark } = require('@codemirror/theme-one-dark'); +// Compartments allow toggling features (vim mode) on a live editor without +// recreating the view — CodeMirror 6's intended mechanism for reconfiguration. +const vimCompartment = new Compartment(); +// Vim is loaded lazily: most users never enable it, and the module is heavy. +let _vimExtension = null; +function getVimExtension() { + if (!_vimExtension) { + _vimExtension = require('@replit/codemirror-vim').vim(); + } + return _vimExtension; +} + +/** + * Toggle vim keybindings on an editor created by createEditor. + * @param {EditorView} view + * @param {boolean} enabled + */ +function setVimMode(view, enabled) { + if (!view) return; + view.dispatch({ + effects: vimCompartment.reconfigure(enabled ? getVimExtension() : []), + }); +} + // Custom theme for JetBrains Mono font const jetBrainsMonoTheme = EditorView.theme({ '&': { @@ -31,6 +55,37 @@ const jetBrainsMonoTheme = EditorView.theme({ }, }); +/** + * Build the Tab keymap entry that expands snippets before falling through to + * indent. `getExpansion(prefix)` is synchronous and returns the replacement + * text (or null to decline), letting the host keep its snippets in a Map. + */ +function snippetTabKeymap(getExpansion) { + return { + key: 'Tab', + run: (view) => { + if (typeof getExpansion !== 'function') return false; + const { head } = view.state.selection.main; + const line = view.state.doc.lineAt(head); + // Word-before-cursor: letters, digits, underscore and hyphen + const before = line.text.slice(0, head - line.from); + const match = /[\w-]+$/.exec(before); + if (!match) return false; + const expansion = getExpansion(match[0].toLowerCase()); + if (typeof expansion !== 'string') return false; + view.dispatch({ + changes: { + from: head - match[0].length, + to: head, + insert: expansion, + }, + selection: { anchor: head - match[0].length + expansion.length }, + }); + return true; + }, + }; +} + /** * Create a CodeMirror 6 editor instance. * @@ -41,6 +96,8 @@ const jetBrainsMonoTheme = EditorView.theme({ * @param {Function} options.onUpdate - called with the EditorView on every update (selection, doc change, etc.) * @param {boolean} options.isDark - apply oneDark theme when true (default false) * @param {boolean} options.showLineNumbers - show line-number gutter (default true) + * @param {boolean} options.vimMode - start with vim keybindings (default false; toggle later via setVimMode) + * @param {Function} options.getTabExpansion - (prefix)=>string|null; Tab expands a matching snippet (default null) * @returns {EditorView} the created editor view */ function createEditor(parentElement, options = {}) { @@ -62,6 +119,8 @@ function createEditor(parentElement, options = {}) { onUpdate = null, isDark = false, showLineNumbers = true, + vimMode = false, + getTabExpansion = null, } = options; const extensions = [ @@ -75,13 +134,16 @@ function createEditor(parentElement, options = {}) { autocompletion(), foldGutter(), jetBrainsMonoTheme, + // Snippet Tab expansion must precede indentWithTab so it wins when matched keymap.of([ + ...(getTabExpansion ? [snippetTabKeymap(getTabExpansion)] : []), ...defaultKeymap, ...historyKeymap, ...searchKeymap, ...completionKeymap, indentWithTab, ]), + vimCompartment.of(vimMode ? getVimExtension() : []), EditorView.updateListener.of((update) => { if (update.docChanged) { onChange(update.state.doc.toString()); @@ -146,4 +208,4 @@ function getLanguageExtension(lang) { return loader ? loader() : markdown({ base: markdownLanguage }); } -module.exports = { createEditor, getLanguageExtension }; +module.exports = { createEditor, getLanguageExtension, setVimMode, snippetTabKeymap }; diff --git a/src/index.html b/src/index.html index 065fb81..b9842fd 100644 --- a/src/index.html +++ b/src/index.html @@ -22,6 +22,8 @@ + + @@ -1256,11 +1258,9 @@ @@ -2506,6 +2506,38 @@ + + + +