Added
- Non-Markdown picker previews are configurable (
pickerNonMarkdownPreview,set pickerpreview,vim.opt.pickerpreview) —rendered(default),hidden, orraw. Markdown is always previewed and is unaffected by the setting. Requested in #172.- Plugin:
src/picker/sources/preview-utils.ts(policy),src/settings.ts(both settings implementations),src/vimrc/loader.ts(KNOWN_SET_OPTIONS),src/main.tsand the five file-previewing sources (live getter threading) renderedembeds images/svg/canvasnatively, and shows a name/type/size card for PDFs, video and audio. The card is deliberate, not a shortcut: Obsidian instantiates a PDF.js viewer per embed, and there is no released version in which repeated create/destroy is known to release that memory — the 1.9 load/unload rework was announced but the thread was closed for non-reproduction, and no changelog entry through 1.14.0 documents a PDF lifecycle or memory fix.minAppVersionis 1.7.2, below even that, so version-gating was not an option.- The setting is a live getter, so it takes effect without a reload or an Obsidian restart.
- Plugin:
Fixed
- The picker no longer reads binary files to preview them.
readFilePreviewcalledvault.cachedRead()on everyTFileregardless of type or size, so scrolling past a multi-megabyte PDF decoded the whole binary as UTF-8 — and Obsidian caches that string, so memory grew with the total size of every binary encountered. The 50 KB truncation ran after the read, bounding rendering cost but not read or memory cost. Size is now checked from file metadata before any read, in every mode. - Preview rendering is debounced.
updatePreview()coalesced only within a singlerequestAnimationFrame(~16 ms), but OS key repeat is ~30 ms, so every keystroke issued its own read and render — roughly 30 previews per second of heldj. It now uses a 100 ms leading-plus-trailing debounce, matchingOilManager.previewDebounceTimer: an isolated keypress still previews immediately, while a burst collapses to two. - The preview pane no longer leaks
Componentinstances. OnlyrenderMarkdownPreview()unloaded the previous component, so the raw-string,null, loading, and error paths all replaced pane content while leaving embeds, images and transclusions registered. A singleclearPreview()now owns unload → null → empty and is called on every transition, includingonClose(). - Synchronous throws from a picker source's
preview()are caught.Promise.resolve(source.preview(...))evaluated the provider before the promise wrapped it, so a synchronous throw escaped the.catchunhandled — despitedocs/development/picker-api.mddocumenting that exceptions inpreview()are caught. The call now runs inside the chain. - Stale previews are rejected by generation, not by item id. The previous guard compared
currentMatches[selectedIndex].item.id, which passes if the selection moves away and returns to the same item, letting a superseded in-flight result render. Replaced with a monotonicpreviewGeneration, following the existingsearchGenerationconvention in the same file.
Tests
test/unit/picker/preview-policy.test.ts(13 cases) pins the read policy: nocachedReadfor PDFs, images or video in any mode, size refusal above the byte budget, and Markdown exempt in all three modes. Verified red first — before the fix,cachedReadwas called once on a 5,000,000-byte PDF inrendered,hiddenandraw.test/unit/picker/preview-lifecycle.test.ts(6 cases) covers the debounce, leading edge, component teardown, synchronous throws, and stale-result rejection. Verified red first (10 preview calls where ≤2 are expected; components left loaded;Loading…left in place by an escaped provider error), and re-confirmed by sabotage: forcing the leading-edge guard true reproduced "expected 10 to be less than or equal to 2".
Documentation
configuration/settings.mdlisted three picker settings as unavailable via vimrc when all three have hadsetoptions.picker,pickerLeaderMappingsandpickerMatcherEnginewere under "Settings not available via vimrc" and showed—in their Lua and Vimrc columns, whileconfiguration/vimrc.mddocumentedset picker,set pickerleadermappingsandset pickermatchercorrectly — the two pages contradicted each other. The stale entries are removed and the columns now name the real options. Noticed while addingset pickerpreviewalongside them.
Full Changelog: 0.148.0...0.149.0