New Features
- Preview width is configurable: a setting, a shortcut pair to widen/narrow, and the preference persists (#346, #347, #348, #349)

- Editor toolbar : new icons and a show/hide toggle (#282)

- Window tags and pinned sessions rebuilt (#280)

- Moving tabs between windows rebuilt (#279)
- macOS settings menu (#339)

- Floating table-of-contents toggle (#331)

Documents
- A file over 50 KB opened as a truncated preview, and saving wrote that preview back over the whole document (#374)
- A non-UTF-8 file opened as mojibake, and auto-save wrote the mojibake over the original 1.5 s later (#379)
- Dropping two images with the same name in the same second silently replaced the first while the document still linked to it (#383)
- A read failure during session restore evicted the tab and saved the trimmed list, so an unplugged drive lost the tab permanently (#401)
- Re-opening a file that was already open with unsaved edits discarded them, and cleared the dirty flag so nothing said so (#412)
- Two tabs could hold one path with two auto-save timers writing over each other (#413, #416)
- A tab moved between windows could end up open in both, each copy with its own auto-save timer writing over the other (#366).
- Pressing ⌘S while an auto-save was mid-write could leave the older text on disk (#436, #438).
- Quitting with two tagged windows could lose one window's pinned tags (#424).
- A stale preview render could overwrite a newer one (#254), and an interrupted session restore left the app unable to recover (#260).
Security
- Exported HTML skipped the sanitizer entirely (#376)
- The preview never used the shared sanitize policy, so a document's
<style>reached the app's own UI — reproduced hiding the title bar and fetching a remote beacon (#384) - A link could read as
http://…everywhere the user can see it and open a local file instead (#415) - Imported VS Code theme colours are validated before being injected as CSS (#362), and imported theme slugs are normalized (#301)
- Theme and image file paths are constrained to their directories (#249, #270)
- File IO, decoding and Markdown boundaries hardened on the Rust side (#371)
Export and printing
- Exported HTML now contains rendered math, syntax highlighting and Mermaid diagrams instead of raw source (#411)


- Exported HTML carries the theme, and no longer cuts collapsed sections out of the document (#382)
- PDF exports are readable in every theme; diagrams no longer come out dark-on-dark (#359)

- A PDF exported from edit mode is no longer blank (#407)
- Local images are inlined on Windows (#363)
- Find highlights no longer print, and collapsed matches are revealed (#377)
- Print layout: native controls, full page width, and tighter content rhythm (#329, #333)
- The export menu is no longer greyed out for an unsaved document you're editing (#441)
Editor and preview
- Task checkboxes work in the preview, and the change is written back to the file (#345, #352)
- Three separate LaTeX reports turned out to be one bug :
_{1}becoming italics,\\being eaten so a multi-rowalignedcollapses,\%being eaten so KaTeX treats the rest of the line as a comment. All three are comrak applying Markdown inline rules inside math delimiters; fixed by masking the span before parsing rather than patching one character at a time (#351, #402; closes #174 / #177 / #197) - Escaped dollars stay escaped, and
$$…$$inside a paragraph renders (#422) - The editor context menu is fully localized and follows a language change (#381)
- URLs pasted inside code blocks are no longer turned into links (#381)
- Scroll position returns to the block you left, not to a percentage (#420)
- Heading folds are per-document, and are cleared when a tab follows a link to a different file (#425, #448)
- A leading
---no longer swallows the paragraph after it (#375) Copy Referenceproduces a link Markpad can actually follow (#403)- Preview works without saving first (#421)
- ToC jumps use heading source position (#335)
- Editor options and keyboard shortcuts now do what their labels claim (#369)
- Saving works from reading mode (#365)
- "Save image as" works for local images, and says so honestly for remote ones (#408)
- A relative link to a non-Markdown file resolves against the document instead of the app (#409, #415)
Copy Referenceproduces a link Markpad can follow (#380), and "open the exported file" had never worked because the opener plugin had no path scope (#403)- Live Mode watched the wrong file after a tab switch (#296)
- YouTube embeds open externally instead of failing in place (#338)
- Settings: the modal stays draggable (#312), collapsed toolbar sections are remembered (#286), and every setting syncs across windows instead of the last window overwriting the rest (#370)
- Recent files are merged across windows instead of overwritten (#405)
- The auto-save failure toast no longer repeats (#406)
- A malformed UTF-8 code fence crashed the renderer (#265)
- Window titles update natively (#288); a window created at startup is reused instead of a second one appearing (#318)
Windows
- "Move to New Window" froze the app.
create_transfer_windowbuilt the window synchronously, and on Windows that deadlocks. WebView2 needs the main thread free to pump messages while the window is created (#360) - Right-clicking a tab twice opened the document menu the second time, because the first menu's full-viewport overlay swallowed the click and only called
preventDefault()(#360) - Install failed outright when the Desktop or Start Menu folder did not exist — this is the cause of the
OS Error 3reports (#400) - Uninstall could terminate unrelated processes with the same name (#358)
- Install and uninstall are recoverable if interrupted (#364)
- Markpad no longer registers itself for plain text files (#302)
- The Install button stays reachable at large system text sizes (#428)
macOS
- PDF export did not work at all (#287)
- Opening several documents at once from Finder kept only one of them (#298, #300)
- The editor paste menu was missing (#266)
Performance
- Startup JavaScript down 81 % : Monaco now loads when you open the editor rather than before the first paint. First paint went from 4770 KB to 904 KB; entering edit mode costs ~330 ms once per window (#423)
- Mermaid-heavy documents ~12× faster to type in; diagrams are no longer redrawn on every keystroke (2185 ms → 189 ms on a 20-diagram document) (#419)
Changelog
- fix: restore collapsed toolbar settings by @PathGao in #286
- fix: enable PDF export on macOS by @PathGao in #287
- fix: allow native window title updates by @PathGao in #288
- fix: preserve tabs after document read errors by @PathGao in #293
- fix: route Live Mode changes to the watched file by @PathGao in #296
- fix: allow opening multiple documents by @PathGao in #298
- fix: retain all macOS open-document paths by @PathGao in #300
- fix: normalize imported VS Code theme slugs by @PathGao in #301
- fix: stop associating plain text files by @PathGao in #302
- Fix split scroll sync triggered by typing by @PathGao in #304
- Update vulnerable Markdown rendering dependencies by @PathGao in #306
- Audit production dependencies in pull requests by @PathGao in #308
- fix: delimit parenthesized autolinks by @PathGao in #291
- Update vulnerable Svelte build toolchain by @PathGao in #310
- Add a minimal macOS Settings menu by @PathGao in #339
- fix: open YouTube embeds externally by @PathGao in #338
- chore: remove internal planning documents by @PathGao in #344
- Keep Settings modal drag accessible by @PathGao in #312
- Audit complete dependency lockfile in CI by @PathGao in #314
- Exclude editor bottom padding from split scroll sync by @PathGao in #316
- Reuse the created window handle during startup by @PathGao in #318
- fix(print): use native controls and full page width by @PathGao in #329
- Make the floating TOC toggle visible in preview mode by @PathGao in #331
- Refine printed Markdown content rhythm by @PathGao in #333
- Fix duplicate-heading ToC jumps in the editor by @PathGao in #335
- i18n: complete Simplified Chinese labels by @PathGao in #336
- build: harden release inputs and isolate test bundles by @PathGao in #355
- fix(editor): preserve copied image path for undo by @PathGao in #357
- fix: enable preview task checkboxes by @PathGao in #345
- Persist a validated preview width preference by @PathGao in #346
- Apply the preview width preference to layout by @PathGao in #347
- feat(settings): configure preview content width by @PathGao in #348
- feat(preview): add width adjustment shortcuts by @PathGao in #349
- fix(windows): avoid terminating unrelated app instances by @PathGao in #358
- fix(themes): validate imported theme colours before injecting CSS by @PathGao in #362
- fix(preview): migrate full-width preference by @PathGao in #350
- fix(math): preserve display math subscripts by @PathGao in #351
- fix(preview): persist task checkbox changes by @PathGao in #352
- ci: verify behaviour on every platform and halve the macOS queue by @PathGao in #361
- fix(print): keep PDF exports readable in all themes by @PathGao in #359
- fix(tabs): stop the tab context menu from leaking and deadlocking by @PathGao in #360
- fix(export): inline local images on Windows by @PathGao in #363
- fix(windows): make install and uninstall recoverable by @PathGao in #364
- fix(editor): allow saving from reading mode by @PathGao in #365
- fix(transfer): never leave a moved tab open in both windows by @PathGao in #366
- fix(editor): wire editor options and shortcuts to what they claim by @PathGao in #369
- fix(backend): harden file IO, decoding and markdown boundaries by @PathGao in #371
- fix(settings): persist each setting on its own key and sync across windows by @PathGao in #370
- fix(documents): stop partial buffers and external changes from destroying work by @PathGao in #374
- fix(preview): stop a leading --- from swallowing prose, and batch fold measurement by @PathGao in #375
- fix(find): reveal collapsed matches, and keep them out of the PDF by @PathGao in #377
- fix(export): sanitize exported HTML by @PathGao in #376
- test: pin the render protocol between Rust and the preview by @PathGao in #378
- fix(documents): refuse to save a buffer that was decoded lossily by @PathGao in #379
- fix(links): make Copy Reference output a working link by @PathGao in #380
- fix(editor): localize the context menu and stop linkifying URLs in code by @PathGao in #381
- fix(export): carry the theme into exported HTML, and stop cutting collapsed sections by @PathGao in #382
- fix(images): never overwrite an image a document already links to by @PathGao in #383
- fix(preview): route the preview through the shared sanitize contract by @PathGao in #384
- chore: correct package metadata and close two release-path gaps by @PathGao in #386
- fix(i18n): make three keys reachable, and add a coverage test by @PathGao in #387
- refactor(preview): drop the dead YouTube iframe copy from the viewer by @PathGao in #388
- chore: delete pre-fix copies that survived their own fixes by @PathGao in #397
- fix(test): master is red — retire the iframe allowlist entry #388 made stale by @PathGao in #398
- fix(markdown): keep every preprocessing step on the same source line by @PathGao in #389
- fix(session): stop startup from throwing away tabs it could not read by @PathGao in #401
- fix(windows): create the shortcut directory before writing the shortcut by @PathGao in #400
- fix(markdown): hide math delimiters from comrak instead of patching characters by @PathGao in #402
- fix(capabilities): give open_path a scope so it can actually run by @PathGao in #403
- fix(recents): merge the recent-files list instead of overwriting it by @PathGao in #405
- fix(documents): read through the checked command everywhere, and stop the auto-save toast repeating by @PathGao in #406
- fix(print): make an editor-mode PDF export contain the document by @PathGao in #407
- fix(images): make "Save image as" work for local images and refuse honestly for remote ones by @PathGao in #408
- fix(links): resolve a relative link to a local file against the document by @PathGao in #409
- fix(export): render math, highlighting and diagrams into the exported HTML by @PathGao in #411
- fix(documents): never reload a file over its own unsaved edits by @PathGao in #412
- fix(tabs): one tab per file path by @PathGao in #413
- fix(links): stop a document link from opening a local file through an asset URL by @PathGao in #415
- fix(tabs): ask the filesystem whether two paths name the same file by @PathGao in #416
- test: pin what the compiler cannot see, not how it is spelled by @PathGao in #418
- perf(preview): stop redrawing unchanged mermaid diagrams on every keystroke by @PathGao in #419
- fix(preview): restore the scroll position to the block it was taken from by @PathGao in #420
- fix(editor): show the preview without making the user save first by @PathGao in #421
- perf(editor): load Monaco when the editor is opened, not at startup by @PathGao in #423
- fix(markdown): keep an escaped dollar escaped, and render display math inside a paragraph by @PathGao in #422
- fix(tags): stop two windows from erasing each other's pinned tags by @PathGao in #424
- fix(preview): give each document its own heading fold state by @PathGao in #425
- chore(markdown): upgrade comrak 0.18 → 0.54 by @PathGao in #426
- fix(installer): keep the Install button reachable when the window is shorter than the content by @PathGao in #428
- fix(home): render the home screen when the home tab is active by @PathGao in #429
- chore(preview): delete six declarations nothing reads by @PathGao in #427
- chore(check): type-check scripts/, and fix an assertion that could not fail by @PathGao in #432
- fix(markdown): make the code-region order an invariant instead of a sort by @PathGao in #434
- refactor(rust): move lib.rs's test module below the code it tests by @PathGao in #435
- chore(tests): delete 14 source-text tests that no defect can fail by @PathGao in #433
- fix(save): stop two writers on one file from breaking each other by @PathGao in #436
- docs(tabs): say what content, rawContent and originalContent each hold by @PathGao in #437
- fix(save): let one write per tab be in flight at a time by @PathGao in #438
- fix(save): stop a stale lossy-save refusal from silencing real auto-save failures by @PathGao in #439
- fix(export): gate the export menu on the buffer, not the render cache by @PathGao in #441
- test(scroll-sync): cover the split-view mapping by running it by @PathGao in #442
- test(scripts): answer scope questions by parsing, and guard 71 slice bounds by @PathGao in #440
- docs(tabs): say which of the three scroll-position fields to use by @PathGao in #443
- refactor(lib): stop exporting 23 symbols that never leave their module by @PathGao in #444
- test(save): cover the branch where the partial-buffer guard refuses by @PathGao in #445
- refactor(settings): derive the language codes and TOC bounds from one source by @PathGao in #446
- fix(tabs): clear the whole reading position when a tab changes document by @PathGao in #447
- fix(tabs): forget a document's folds when the tab is pointed at another one by @PathGao in #448
- test(scripts): re-anchor 12 assertions that could not fail by @PathGao in #449
- test(guards): re-anchor nine assertions that could not fail by @PathGao in #450
- fix(tabs): fix tab transfer and window borders by @alecdotdev in #452
Full Changelog: v2.6.14...v2.7.0