# Changelog All notable changes to MarkdownGlance are recorded here. The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and the project follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] ## [0.5.2] - 2026-10-10 ### Fixed - **A render failure now says what failed, and where the traceback is.** Every exception on the render pool used to become the card "Serialise / Render failed", with nothing in the console and nothing more in the diagnostics -- which is all [#5](https://github.com/feibuilds/MarkdownGlance/issues/5) had to go on. The pipeline now names the stage that failed (parse, asset or serialise), the card carries the exception's class and message, the traceback is printed to the console whether or not `debug_logging` is on, and **Copy Diagnostics** carries it under `last_error` together with the version and location of the `Markdown` and `pymdown-extensions` this host actually imports, or the error if it cannot. ## [0.5.1] - 2026-09-15 ### Fixed - **`` and `` in raw HTML are raised and lowered in the preview.** minihtml does not implement either tag, so `x2` used to show as `x2`. Each is now a span that `preview.css` shrinks and moves off the baseline, which minihtml can do; the line height is unchanged, and the browser page keeps the real tags. Reported in [#2](https://github.com/feibuilds/MarkdownGlance/issues/2). ## [0.5.0] - 2026-09-15 ### Changed - **The install note tells a first-time user how to open the preview.** The message Package Control shows once after installing gives the quick start, the key bindings per platform, which features are opt-in and why, and where the settings are. It used to describe another package. - **Clicking a heading in the contents panel now takes you there in both panes.** It used to move only the pane the panel's current half belonged to, which was the wrong one exactly when it mattered: you read a preview by scrolling, the wheel does not move the focus, so the panel was showing the source outline while you were looking at the preview, and clicking an entry moved the caret and left the preview where it was. Either half now moves the caret *and* scrolls the preview, from either pane, without taking the focus. Headings the two lists cannot be matched on — one inside a raw HTML block or a block quote is in the rendered document and not in the source scan — still move only their own pane rather than guessing. See [ADR 0016](docs/adr/0016-navigation-and-zoom-do-not-wait-for-the-focus.md). - **The zoom keys reach the preview from your Markdown file.** `Ctrl+=` and `Ctrl+-` zoom the preview while you are editing, as long as the window has one; without a preview they are Sublime's font size, as before. `Ctrl`-scroll over a preview zooms it without clicking it first. `Ctrl+0` still resets from inside the preview only, because in the editor it belongs to the side bar. - **One preview tab and one contents tab per window, showing the file you are working on.** Every Markdown document used to get a preview tab of its own, and after the change below a contents tab too, so a window with three files open had three of each and the tab in front was a matter of which document you had touched last -- the source, the preview and the panel could each be showing a different file. Both are views onto the current document now rather than documents themselves: each is titled for what is on it and follows the focus, and switching to a file that has already rendered is a repaint rather than a render. Where you had scrolled to in each document comes back with it. Closing the preview closes it for the window, and zoom belongs to the pane, so it no longer jumps when you switch files. See [ADR 0015](docs/adr/0015-one-preview-and-one-panel-per-window.md). - **The outline and the table of contents are now one panel**, showing the half that matches the tab you are on: the source outline while you edit, the rendered table of contents while you read the preview. They used to be two surfaces in two groups, so a document with both open took four editor groups and left whichever list you were not using in front of you; it takes three now, and switching is a repaint rather than a tab moving. `Ctrl+Shift+B` and the `mdglance_toggle_outline` command are unchanged, the palette entry is now **Toggle Contents Panel**, and the tab is named `Contents: `. `enable_toc` governs only whether a panel opens by itself; one you open yourself shows both halves whichever way it is set. See [ADR 0014](docs/adr/0014-one-contents-panel-for-both-halves.md). ### Fixed - **Reopening Sublime Text brings the preview back, instead of a blank pane.** A window remembered its three-column layout across a restart and nothing else: the preview and the contents panel are scratch buffers, which Sublime does not keep, so the file came back beside two empty groups that nothing in the package could account for — the marks that identify a surface do not survive a restart either. A window now records the panes this package made in the window's own settings, which Sublime does persist, along with the document that was on the preview and its zoom. The next start puts that document back in the same pane at the same zoom, with the contents panel beside it if it was there, without taking the focus off the file you land on. When it cannot — the document is not open any more, or was an unsaved buffer — the panes are taken away instead, so a restart, a crash and a package reload all end with a window you could have arranged yourself. See [ADR 0018](docs/adr/0018-groups-outlive-the-process-that-made-them.md). Where the preview was scrolled to is not restored; it opens at the top. - **SVG images are drawn in the preview.** A diagram beside the document and the badges at the top of a README appear like any other image: the file, or the download, is converted to a PNG on your machine by [resvg](https://github.com/linebender/resvg), which you install and the package finds on your `PATH` or at `svg_renderer_path`. Nothing is uploaded, no service or account is involved, and the document keeps its own image reference. The image is drawn at twice the size it is shown at, so it stays sharp on a high-DPI display, and the conversion runs off the editor's thread. A local drawing may reference images beside it; one from the web is drawn with no access to your files. With no renderer installed the image reads *No SVG renderer* and says what to install; one the renderer cannot draw reads *Could not be drawn*. `"enable_svg": false` turns it off. This is the first thing the package runs as a process on the preview path — see [ADR 0019](docs/adr/0019-svg-is-drawn-by-a-local-renderer.md). - **A WebP or any other image the preview cannot draw now says which failure it was.** The preview is drawn by minihtml, which decodes PNG, JPEG and GIF and nothing else, so an image in any other format could never appear — but it reported "Unavailable", the same words as a missing file or a dead link, and the reader had no way to tell an intact file from a broken path. The placeholder now reads *Not a PNG, JPEG or GIF — The preview cannot draw it; Open in Browser can*, and the export does draw it, since it hands the parser's own output to a real browser. The format is recognised by its bytes rather than its extension. See [ADR 0017](docs/adr/0017-formats-minihtml-cannot-draw.md). - **The preview and the contents panel now follow you to a document that has never been previewed.** With several Markdown files open, the preview group and the panel group each hold one tab per document, and the tab in front is the focused document's -- but a file you had never opened a preview for had no tab to bring forward, so both groups went on describing whichever file did. Three groups, three different documents. Focusing a Markdown file in a window that already has a side-by-side preview now gives that file one too, and a panel if the window has one, without taking the focus off what you clicked. A panel you closed by hand stays closed. - **A file opened from the sidebar or Goto Anything was never noticed.** It is activated while it is still loading, before Sublime has given it a syntax, and no second activation follows; the package now listens for the load as well. - **Closing a side panel left an empty pane behind** whenever the window had changed since the panel was opened -- which, with the contents panel, is any time you open the preview after it. The layout owner used to put back the layout it had recorded when it made the group, and only while the window still matched it exactly; it now takes the empty cell out of the current layout and gives the space to the pane beside it, so every other divider stays where you left it. - **A preview opened after the panel landed inside the panel's group**, where it took the panel's place instead of appearing beside it -- the command looked as though it had done nothing at all. `LayoutOwner` reused any group of its own to the right of the source; it now reuses one only for its own role. This is as old as the outline: the same sequence with `Ctrl+Shift+B` and then a preview did the same thing. - **A table of contents that opened by itself took the caret with it**, because Sublime focuses the view `new_file` makes. The focus is now read before the surface exists and given back afterwards. - The preview and the table of contents now follow the focus. Two documents previewed at once share one preview group and one table-of-contents group, so the tabs left in front used to be whichever document was previewed last, and they stayed there while you read the other file. Focusing a Markdown source, its preview or its table of contents now brings that document's other surfaces forward, without moving the focus off what you clicked. In Full Screen the preview shares the source's own group and is left alone. - Numbered lists now display explicit numbers in the minihtml preview, including non-1 starts and nested lists. Loose items keep the number in their first paragraph. Adjacent ordered and unordered lists separated by a blank line retain their own list types. Wrapped lines do not yet use hanging indents. ## [0.4.2] - 2026-09-06 ### Added - **LaTeX math, off by default.** `$...$` and `$$...$$` (and `\(...\)`, `\[...\]`) are recognised by `pymdownx.arithmatex`, which is already installed with `pymdown-extensions`. With `"enable_math": true` each formula is fetched from `math_server` (`https://latex.codecogs.com`) as a PNG typeset in the colour scheme's foreground, the way a Mermaid diagram is, under the same HTTPS, timeout, size, cache and one-time privacy caption rules. Off, a formula is shown as its source in a code span or block. Asked for in [#2](https://github.com/feibuilds/MarkdownGlance/issues/2); see [ADR 0013](docs/adr/0013-latex-math-as-a-baked-image.md). - **`Open in Browser` renders Mermaid diagrams and LaTeX math.** A Mermaid fence used to reach the browser as a code block, and a formula as text. The page now loads Mermaid and KaTeX from jsDelivr, at a pinned release with a subresource integrity hash, and only when the document has a diagram or a formula; both render in the browser, so nothing of the document is sent anywhere, and the setting for the preview does not apply. Offline, a diagram stays readable source and a formula keeps its `\(...\)` delimiters. ## [0.4.1] - 2026-09-06 Fixes from a review of 0.4.0 before it was verified in Sublime Text; none of them changes the channel entry. ### Fixed - **A Mermaid fence stopped being a diagram when Pygments was installed.** superfences hands every fenced block to Pygments whenever it can be imported, and Pygments is a Package Control library other packages (for one, MarkdownPreview) install. Highlighted, a block is a `div` with no `code` element and no language class, so the preview saw code where a diagram was asked for. Pygments is now switched off explicitly, and a test holds it off. - **`Open in Browser` sent `#heading` links to the directory.** The page carried a `` so that relative images resolved beside the source, and a base URL captures fragment links too. Relative images and links are now resolved in the tree and the `` is gone. The page also gives headings the ids the preview does (`same`, `same-2`), not Python-Markdown's (`same_1`), so a link that works in one works in the other. - **Two list-shape mistakes in the preprocessor.** A code line starting with `>` inside a fence reset the fence and let the lines after it be rewritten as a list; and a heading or rule at an item's content column ended the list instead of belonging to the item. Both now render as they did in 0.3.1. - **Missing libraries are a message, not a dead package.** The parser was imported at load, so a manual install without the libraries failed to load at all and left a traceback in the console. The libraries are now looked up without being imported; at load, and again on the first command, a dialog says which are missing and to run **Package Control: Satisfy Libraries** and restart. The README's manual steps now satisfy the libraries before the restart rather than after. - **`Open in Browser` reports a browser that would not start**, with the path of the page it wrote, instead of claiming success; the page and its directory are created private to the user on hosts that honour modes, and the file is replaced rather than followed. ## [0.4.0] - 2026-09-06 ### Changed - **The parser is now the Package Control `Markdown` library** (Python-Markdown, with `pymdown-extensions` for fenced code) instead of a vendored copy of `markdown2`, as the channel review asked. Package Control installs both beside the package; a manual install needs them too, see the README. A small preprocessor keeps GitHub-flavoured lists rendering as before: two-column nested items, a list cuddled to the paragraph above it, and a fenced block inside an item. Rendering of the repository's own 24 Markdown files is identical apart from three corrections: a code block no longer ends in a blank line, `[Unreleased]`-style reference links resolve, and `a_b_c` no longer becomes `abc`. The 100 KiB benchmark is 5% faster. [ADR 0012](docs/adr/0012-package-control-markdown-library.md) records the decision and what each host receives. - **Package Control messages are down to the install note.** The per-release notes are gone; a release will carry one only when it needs something from you, kept to a few lines with a link to this changelog. ### Added - **`MarkdownGlance: Open in Browser`** writes the document as a standalone page under the temporary directory and opens it in the default browser, for the moment a page has to be seen at browser width or handed to someone. The preview itself is unchanged and still never leaves the editor. ## [0.3.1] - 2026-09-02 ### Changed - Documentation only; no code, settings or key bindings change, and rendering is byte-for-byte what 0.3.0 produced. **Manual installation now has a route that does not need Git**: download the source ZIP from the latest release, rename the unzipped folder to `MarkdownGlance`, and move it into the directory **Preferences → Browse Packages…** opens. The Installation section also says plainly that the Package Control [submission is still pending](https://github.com/sublimehq/package_control_channel/pull/9539), and the README's preview screenshot is a light and dark pair, so it follows the colour scheme of whoever is reading it. - [ADR 0002](docs/adr/0002-product-and-package-name.md) gains an addendum recording why `MarkdownPreviewPlus` and `MarkdownPreviewExtended` were considered and rejected, and that the name is frozen once the Package Control channel pull request is merged. `docs/` is `export-ignore`'d, so this reaches the repository only. ## [0.3.0] - 2026-08-30 ### Added - **`enable_toc`, and it defaults to `false`.** The table of contents beside the preview takes an editor group of its own, which is a lot to spend without being asked for; set it to `true` for the old behaviour, where a document past `toc_minimum_length` and `toc_minimum_headings` gets one. - **`auto_width`, defaulting to `true`.** The table of contents and the outline are given the width their longest heading needs instead of a fixed share of the window, so the rest goes to the content. It is a ceiling, not a target: neither group is ever wider than it used to be. Dragging the divider yourself turns it off for that group, and setting `auto_width` to `false` restores the fixed share everywhere. See [ADR 0011](docs/adr/0011-panel-width-fits-its-content.md). - **`mdglance_copy_diagnostics` now reports what a repaint cost.** The payload carries `recent_renders` -- the Python half, with the size of the Markdown in and the HTML out -- and `recent_paints`, the wall clock around `PhantomSet.update` together with the size of the HTML and whether the paint was skipped as unchanged. With `debug_logging` on, each paint is printed to the console as it happens. The paint number is a floor: it covers the layout only to the extent Sublime does that work synchronously. ### Changed - **A Mermaid diagram now follows the editor's colour scheme.** The request asked mermaid.ink for the light theme on a transparent background, so on a dark scheme every label drawn straight onto that background — sequence messages, loop and note text — was near-black on near-black while the filled actor boxes stayed readable. The request now carries the Mermaid `dark` theme and the preview's own background colour when the scheme is dark. The scheme is read from the Markdown view, so one chosen with `MarkdownEditing: Select Color Scheme` wins over the global `UI: Select Color Scheme`, exactly as it does in the editor. A diagram is baked by the server and cannot be recoloured by a repaint, so changing scheme under an open preview now renders the document again for the new diagram URLs instead of leaving the old images in place. - The table of contents and the outline no longer carry the preview's page margins. They are lists in a narrow group, so they get 0.8rem of padding rather than the document's 1.5rem, and the table of contents loses the margin above its card. - Closing the table of contents now keeps it closed for that preview. It used to reappear within a second, because every render reopens one for a document that qualifies and the viewport poll renders again as soon as the preview grows into the group just given back. A close is remembered until the preview itself is closed and reopened, or until `enable_toc` is switched off and on. ### Performance - **A repaint no longer costs a full minihtml layout when nothing changed.** `PhantomSet.update` identifies a phantom by its region, content, layout *and* its `on_navigate` callback, and the backend built that callback fresh on every repaint, so the set never recognised the phantom already on screen: it erased it and added it back, and Sublime laid the whole document out again. One callback per surface now lives for the life of the surface, and identical HTML is dropped before it reaches the phantom set at all. Repaints arrive from the viewport poll, from a theme re-read on every focus change and from every table-of-contents render, so most of them were doing no work worth the layout. - **Indentation in a code block no longer costs an element per space.** minihtml collapses a run of spaces, which the serialiser held open with one background-coloured `.` per space -- 5774 of them in this repository's own 69 KB design document, more than half of every element on the page. A run of two or more spaces is now a run of U+00A0, the technique [ADR 0007](docs/adr/0007-table-rendering-under-minihtml.md) already measured for table padding. Single spaces stay plain, so a long code line keeps its wrap points. The document's HTML falls from 296 KB to 178 KB and its element count from 9332 to 3558. - **Repainting the table of contents no longer spins the window's focus.** It called `reveal`, which focuses the group, then the view, then the previous group back; each of those makes Sublime fire `on_activated`, which re-reads the theme and repaints -- landing back in the same place. Creation and a mode switch still reveal the tab; a repaint does not. A theme that has not changed is also no longer a reason to repaint. - **The vendored parser drew a megabyte-sized hash salt.** Upstream markdown2 writes `SECRET_SALT = bytes(randint(0, 1000000))`, which is not a random salt but a zero-filled buffer of random *length*, re-hashed on each of the several hundred `_hash_text` calls a parse makes. The draw happens once per `plugin_host`, so the same document parsed in 123 ms or in 1628 ms depending on the launch. Three random bytes keep the intent. ### Fixed - **The preview, the table of contents and the outline now follow the colour scheme the Markdown file itself resolved.** A Markdown buffer usually has one of its own -- `markdownediting: select color scheme` writes `color_scheme` into `Markdown.sublime-settings`, and a syntax-specific setting beats the global `ui: select color scheme` -- but every surface is a plain scratch view, so it inherited the global scheme instead. That is the scheme minihtml resolves `var(--background)`, `var(--foreground)` and `var(--bluish)` against, and `preview.css` is built out of those three, so the whole page was painted in the wrong palette: a light MarkdownEditing scheme over a dark editor read as a dark preview beside a light source. Each surface is now put on the source's scheme, and re-put on it whenever the source's moves. - Closing the table of contents from its tab left its empty group behind. The group was released by asking the backend which group the surface was in, but the view is already gone by then and a dead handle has no group, so nothing was released and the pane stayed on screen. The session now records the group it placed the table of contents in and falls back to it. ## [0.2.1] - 2026-08-29 ### Changed - Documentation only; no code, settings or key bindings change. The README now opens with a screenshot of the preview, its Mermaid diagram, an aligned table and the table of contents beside them, and the outline screenshot shows the outline reading this repository's own README. Both images live in `docs/screenshots/`, which `export-ignore` keeps out of the installed package. ## [0.2.0] - 2026-08-29 ### Added - **An outline of the Markdown source**, on `Ctrl+Shift+B` / `Cmd+Shift+B` and as `MarkdownGlance: Toggle Outline` in the command palette. It lists the headings as they are written in the buffer, in a group of its own beside the file, marks the one holding the caret, re-scans as you type, and moves the caret to a heading when its entry is clicked. It needs no preview and no successful render, which is what separates it from the table of contents inside the preview. The key toggles the way Zed's outline panel does — open and focus, focus, then close from inside — and shadows Sublime Text's **Build With…** only while a Markdown source view or an outline this package created is focused. See [ADR 0010](docs/adr/0010-source-outline-and-ctrl-shift-b.md). ## [0.1.4] - 2026-08-29 ### Changed - The **Settings** menu item and the `Preferences: MarkdownGlance Settings` palette entry now call `edit_settings` with `base_file` directly, the form every other package uses, instead of routing through a package command. - The vendored copy of markdown2 no longer carries its command-line mainline. A Sublime Text package never runs it, and it brought `optparse`, a `Markdown.pl` comparison through `subprocess.Popen` and a `sys.path` insert with it. Two regex literals are raw strings now, so recent Python versions stop warning about invalid escape sequences. The library API is unchanged. ### Removed - The `mdglance_open_settings` command. Anything bound to it should call `edit_settings` with `"base_file": "${packages}/MarkdownGlance/MarkdownGlance.sublime-settings"`. ## [0.1.3] - 2026-08-29 ### Fixed - **The Full Screen toggle is `Ctrl+Shift+V` again** (`Cmd+Shift+V` on macOS). The `Ctrl+K`, `Shift+V` chord that 0.1.2 moved it to never fired: Sublime Text lists it in the command palette but does not dispatch it, and its own keymap binds no chord whose second key is bare or shift-only. Taking the key back costs Paste and Indent while a Markdown source view is focused, where **Edit → Paste and Indent** still runs it by name; removing one entry from **Preferences → Package Settings → MarkdownGlance → Key Bindings** undoes it. See [ADR 0009](docs/adr/0009-full-screen-toggle-returns-to-ctrl-shift-v.md). ## [0.1.2] - 2026-08-28 ### Changed - **The Full Screen toggle moved from `Ctrl+Shift+V` to `Ctrl+K`, `Shift+V`** (`Cmd+K`, `Shift+V` on macOS). `Ctrl+Shift+V` is Sublime Text's own Paste and Indent, and a context that fires exactly while you are editing Markdown is exactly when you reach for it. The new chord collides with nothing on any platform. See [ADR 0008](docs/adr/0008-default-key-bindings.md). ## [0.1.1] - 2026-08-28 ### Added - **Preferences → Package Settings → MarkdownGlance → Key Bindings**, and the matching `Preferences: MarkdownGlance Key Bindings` palette entry, both opening the defaults beside your overrides. ### Changed - The settings entry is now `Preferences: MarkdownGlance Settings`, following the convention the rest of Sublime Text uses. - The installed package no longer carries the documentation, the ADRs or the test suite — 310 KB instead of 3.2 MB. ### Removed - `Run Contract Tests` and `Run Benchmark` no longer appear in the command palette. They are developer commands; run them from the console with `window.run_command("mdglance_run_contract_tests")`. ## [0.1.0] - 2026-08-28 First public release. ### Added - Same-window live Markdown preview for saved and unsaved buffers, in either a Side-by-Side or a Full Screen editor group. - Theme-aware styling that follows the active color scheme, and per-session zoom. - A separate, navigable table of contents. - Local images, and remote images fetched asynchronously under scheme, redirect, timeout, payload and dimension limits, cached only in memory. - GFM tables, typeset to the measured width of the preview. - Opt-in Mermaid rendering, disabled by default; diagram source reaches the configured server only once it is enabled. - `MarkdownGlance: Copy Diagnostics`, which redacts source text, paths, URLs and Mermaid payloads. [Unreleased]: https://github.com/feibuilds/MarkdownGlance/compare/0.5.2...HEAD [0.5.2]: https://github.com/feibuilds/MarkdownGlance/compare/0.5.1...0.5.2 [0.5.1]: https://github.com/feibuilds/MarkdownGlance/compare/0.5.0...0.5.1 [0.5.0]: https://github.com/feibuilds/MarkdownGlance/compare/0.4.2...0.5.0 [0.4.2]: https://github.com/feibuilds/MarkdownGlance/compare/0.4.1...0.4.2 [0.4.1]: https://github.com/feibuilds/MarkdownGlance/compare/0.4.0...0.4.1 [0.4.0]: https://github.com/feibuilds/MarkdownGlance/compare/0.3.1...0.4.0 [0.3.1]: https://github.com/feibuilds/MarkdownGlance/compare/0.3.0...0.3.1 [0.3.0]: https://github.com/feibuilds/MarkdownGlance/compare/0.2.1...0.3.0 [0.2.1]: https://github.com/feibuilds/MarkdownGlance/compare/0.2.0...0.2.1 [0.2.0]: https://github.com/feibuilds/MarkdownGlance/compare/0.1.4...0.2.0 [0.1.4]: https://github.com/feibuilds/MarkdownGlance/compare/0.1.3...0.1.4 [0.1.3]: https://github.com/feibuilds/MarkdownGlance/compare/0.1.2...0.1.3 [0.1.2]: https://github.com/feibuilds/MarkdownGlance/compare/0.1.1...0.1.2 [0.1.1]: https://github.com/feibuilds/MarkdownGlance/compare/0.1.0...0.1.1 [0.1.0]: https://github.com/feibuilds/MarkdownGlance/releases/tag/0.1.0