Conversation
A note whose body does not open with its own `# heading` exported from the self-hosted web build as a PDF that starts mid-thought, with the title nowhere on the page. The same note exported from the desktop app got its title. A note that named itself in frontmatter (`title:`) also came out under its filename instead, both in the document and in the filename the browser's print dialog suggested. The rule already exists and is shared: `withExportTitle` resolves the title (a body H1 wins, then frontmatter `title:`, then the filename) and inserts it as a leading heading when the body does not state one, so it flows through the ordinary rendering pipeline. 4214c59 wired it into the desktop PDF window, the Word export and the copy-for-email path, and its own header note says it covers "every export format that builds on this module". The web export window predates that change by three months and was simply never connected to it. So this connects it. It is the same call the desktop window makes, on the same shared helper: no new rule, no second definition of what an export title is, and nothing changes for a note that already opens with its own H1. `document.title` is resolved through it too, because the browser seeds the saved PDF's filename from there and a note titled in frontmatter should not save itself under its filename. How to test locally: run `npm run dev:web` with the Go server on :7878, open a note whose body has no `# heading` (a frontmatter-titled note is the clearest case), and export it as a PDF. Before: the PDF opens on the first paragraph and the title appears nowhere. After: the note's title is the first line, and the print dialog offers it as the filename. Claude-Session: https://claude.ai/code/session_01GCwiToGRTKKsDENaY56Vm2
… registers
In Vim mode a WYSIWYG table cell runs its own modal normal mode, and
that mini-Vim knew how to delete but not how to move text: `y` and `p`
were swallowed as stray printable keys, and the one yank that existed
(visual mode `y`) wrote straight to the system clipboard, where no `p`
could reach it. You could destroy text in a table. You could not move
it, and nothing yanked in the note body could be pasted into a cell.
The fix is not a private cell clipboard, on purpose. The cell's y/d/p
now go through codemirror-vim's register controller, the same module
state the main editor's motions use ('"' is the unnamed register object
itself in the vim dist), so text moves freely in both directions: yank
a word in your prose and paste it into a cell, or `yy` a cell and `p`
it onto a line. It also means cm-vim-clipboard's pushText patch applies
unchanged, so with "Sync clipboard with Vim registers" on, table yanks
and pastes ride the system clipboard exactly like editor yanks, with no
second implementation of that setting.
What the cell understands now: `y` as an operator (`yy`/`Y` for the
cell, `yw`, `y$`, `yiw`, `ya"`, the motions the existing `d`/`c`
operators already took), `p`/`P` around the block cursor, visual `y`,
and visual `p` replacing the selection with the Vim register swap.
Deletes and changes feed the register too, so `dd` then `p` moves text
the way it does everywhere else. A multi-line register flattens to one
line on paste (interior breaks become spaces) because a cell is one
line of a row's markdown and a pasted newline must never break the
table.
One deliberate behavior change rides along: visual-mode `y` in a cell
used to hit the system clipboard unconditionally; it now respects the
clipboard-sync setting like every other yank in the app.
Verified live over CDP against the built app, vim mode on: cell to
cell, cell to body, body to cell, dd+p round-trip, visual yank and
paste, and the serialized markdown on disk after blur carries every
edit.
How to test locally: npm run dev, vim mode on, a note with a table.
Click a cell, `yy`, click another cell, `p`: the text lands there. Esc
to the body, `yiw` on a word, back into a cell, `p`. Before: those keys
did nothing in a cell. After: they behave like Vim.
Closes #706
Claude-Session: https://claude.ai/code/session_01GCwiToGRTKKsDENaY56Vm2
Typing a == comparison inside a fenced code block and following it with a space wrapped the pair into a ==highlight== snippet, because the Auto-close Markdown engine never asked where it was: every inline pair (==, **, ~~, a backtick, [[, %%) fired anywhere in the note. The only escape was turning the whole feature off, which trades one wrong trigger in code for losing auto-closed bold, fences, and math blocks everywhere else. That trade is what #718 was living with. The snippet engine now consults the syntax tree at trigger time: inside a FencedCode block or an InlineCode span, no inline pair fires, and a $$ or nested fence marker typed inside someone else's code block no longer expands into a block on Enter. This is a rule, not a setting, on purpose: markdown formatting means nothing inside code, so there is no situation where firing there is right, and no toggle is worth the explanation it would need. Two edges are deliberate. The check runs only at trigger time, on a settled state, never inside the pending-block StateField update, where the syntax tree can be one keystroke stale. And a fence's own opener line stays exempt: the moment ``` is typed it parses as an unclosed FencedCode, so a naive inside-code test would kill the Enter-to-close snippet that the feature is named for. Verified live over CDP against the built app: == then space inside a fence stays literal, the same keystrokes in prose still wrap, and a bare ``` still expands with Enter, with the saved markdown as proof. How to test locally: npm run dev, a note with a fenced code block, type `a == b ` inside it. Before: on the space, == wrapped into a highlight pair around the cursor. After: it stays code, and == followed by space in a prose paragraph still wraps like it always did. Closes #718 Claude-Session: https://claude.ai/code/session_01GCwiToGRTKKsDENaY56Vm2
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Release branch for 2.41.0. Work accumulates here;
mainfast-forwards at release time.Shipped so far
Fix(editor): Auto-close Markdown keeps its hands off code (9cb2008, closes #718)
Typing
a == binside a fenced code block wrapped the==into a==highlight==snippet, and the only escape was disabling Auto-close Markdown entirely. The snippet engine now consults the syntax tree at trigger time: inside FencedCode or InlineCode no inline pair fires (==,**,~~, backtick,[[,%%), and a$$typed inside a code block no longer expands on Enter. Prose is untouched, and the fence-opener line stays exempt so ``` + Enter still expands (an opener parses as unclosed code the moment it is typed). A rule, not a setting: formatting means nothing inside code. Validated live over CDP, plus 6 new parser-backed unit tests.Fix(tables): yank and paste work inside table cells, through the real registers (87b316f, closes #706)
In Vim mode a WYSIWYG table cell runs its own modal normal mode, and that mini-Vim knew how to delete but not how to move text:
yandpwere swallowed as stray keys, and visual-modeywrote only to the system clipboard, where nopcould reach it. The cell's y/d/p now go through codemirror-vim's register controller, the same unnamed register the main editor uses, so text moves freely in both directions:yya cell andpit onto a line of prose, oryiwa word in the body and paste it into a cell.yworks as an operator (yy/Y,yw,y$,yiw,ya"),p/Ppaste around the block cursor, visualy/pbehave like Vim (including the register swap on visual paste), and deletes feed the register soddthenpmoves text. With "Sync clipboard with Vim registers" on, table yanks ride the system clipboard exactly like editor yanks; a multi-line register flattens to one line on paste so a row's markdown can never break. Verified live over CDP, plus 8 new unit tests.Fix(export): a note exported from the web build carries its title (1f1dbff)
Exporting a note to PDF from the self-hosted web app dropped its title whenever the body did not already open with an
# heading. The sharedwithExportTitlerule (body H1 wins, then frontmattertitle:, then filename) was wired into the desktop PDF window, Word export and copy-for-email in 4214c59; the web export window predates that by three months and was never connected. This connects it, and resolvesdocument.titlethrough it too, since the browser seeds the saved PDF's filename from there. Found while investigating #715, whose wikilink-image bug does not reproduce (the markdown pipeline converts![[image.png]]before the export ever sees it), but which correctly sensed the web export window was missing something the other exports had.Verification
npm run typecheckclean,npm run test:rungreen (4,007 tests)https://claude.ai/code/session_01GCwiToGRTKKsDENaY56Vm2