feat(ui): an embed reads as its link, and an image resource shows the image - #223
Conversation
… image Two halves of the same complaint: a note that embeds a picture rendered the grammar instead of the picture, and selecting the picture itself offered only an OS handoff. **`![[file]]` reads as its link.** The reading view's wikilink rule now spans the embed marker rather than starting after it, so the `!` is consumed as grammar instead of surviving beside the anchor as prose. The `|`-part changes meaning with the marker — a label on a plain wikilink, a display *size* on an embed (`![[shot.png|400]]`) — and B2 does not size images, so an embed labels itself with its target and drops the hint. Before, `![[shot.png|400]]` rendered as `!400`: the unsupported half was eating the supported one. **An image resource shows the image.** `Vault::read_resource_bytes` is `read`'s non-note sibling, inventory-checked before the filesystem is touched (the posture *Open in system default* already took), so a link a note authored cannot turn it into "read any file this process can reach". The host encodes base64 for the JSON IPC — `import_file`'s encoding, the other direction — and the card turns it into the `data:` URL the CSP already admits. The picture replaces the *No viewer available* line, not the card: metadata, backlinks and the OS handoff stay, and they are the whole card again for a class with no viewer, for an image past `IMAGE_VIEWER_MAX_BYTES` (a memory bound — the URL is held while the card is open), and for a read that failed. That last one is deliberate: the card is the truth about the file whether or not its bytes can be read, so a failed read must not fail the navigation. Tests first, each failing before its fix: `embedlink.test.ts` goes through `renderMarkdown` rather than the extension object, because the bug was the `start` hook's anchoring and the extension alone would still have passed; `resourceview.test.ts` pins the card's three states and the `data:` rule; the core test proves the inventory check by asking for a note and for an uninventoried file that is really on disk. Known gap, deliberately left: in the *editor*, `![[file]]` is claimed by CodeMirror's own image rule before B2's wikilink parser sees the `[`, so an embed stays raw text there — byte-honest, but not yet mod-clickable. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
You've used all your free Kodus-paid PR reviews 🎁Your trial is still active — this just means the PR reviews we cover during the trial are used up. Connect your own AI key to keep Kody reviewing — unlimited reviews, on any plan (Free included). Want more trial reviews to finish evaluating before adding a key? Talk to our founders. 😎 |
|
Warning Review limit reachedNext included review available in 47 minutes. View limit detailsLimit details: You’ve used the included review currently available. You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. Review configuration: ⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (12)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Two halves of the same complaint: a note that embeds a picture rendered the grammar instead of the picture, and selecting the picture itself offered only an OS handoff.
![[file]]reads as its linkThe reading view's wikilink rule now spans the embed marker rather than starting after it, so the
!is consumed as grammar instead of surviving beside the anchor as prose.The
|-part changes meaning with the marker — a label on a plain wikilink, a display size on an embed (![[shot.png|400]]) — and B2 does not size images, so an embed labels itself with its target and drops the hint.![[__Attachments/Shot.png]]!+ link![[__Attachments/Shot.png|400]]!+ link labelled400[[concepts/memory|how it works]]The sized case is the sharper one: the unsupported half was eating the supported one.
An image resource shows the image
Vault::read_resource_bytesisread's non-note sibling, inventory-checked before the filesystem is touched — the posture Open in system default already took — so a link a note authored cannot turn it into "read any file this process can reach". The host encodes base64 for the JSON IPC (import_file's encoding, the other direction) and the card turns it into thedata:URL the CSP already admits (img-src 'self' data:, unchanged).The picture replaces the No viewer available line, not the card: metadata, backlinks and the OS handoff stay put. They are the whole card again in three cases:
pdf,binary, …) — unchanged behaviourIMAGE_VIEWER_MAX_BYTES(25 MB) — a memory bound, since thedata:URL is held for as long as the card is openA transparent PNG sits on a checkerboard, so it is legible in either theme without the card guessing a background colour for it.
Tests
Each was written first and failed before its fix.
ui/src/embedlink.test.ts(15 checks) goes throughrenderMarkdownrather than the extension object, because the bug was thestarthook's anchoring — the extension in isolation would still have passed. Covers the neighbours the grammar must not swallow: Markdown's own, a!that isn't a marker, an unclosed[[.ui/src/resourceview.test.ts(16 checks) pins the card's three states and the extension → MIME rule.crates/b2-core/tests/resources.rsproves the inventory check rather than assuming it: it asks for a note, and for an uninventoried file that is genuinely on disk beside an inventoried one. A barefs::readwould pass both.make cigreen.Known gap, deliberately left
In the editor,
![[file]]is claimed by CodeMirror's own image rule before B2's wikilink parser sees the[, so an embed stays raw text there — byte-honest, but not yet mod-clickable. Matching the editor to the reading view means moving the Lezer node's start over the marker, which touchesdroplink,wikicompleteand the decoration engine; out of scope here.Also unchanged: the backlinks panel still shows
"400"as an embed's caption, because the engine records the authored alias verbatim.🤖 Generated with Claude Code