Add rich previews made of sequential blocks and on preview file loading
This is a follow up #4529
I make API changes that seem breaking but only in regards to that pr which has not seen a full release yet.
Reasoning
This is prep work for recreating and improving the existing previews shown for markdown files in the explorer plugin
I found that I needed to show both the markdown content of the file as well as a separator and then the file metadata, to not lose info that the old preview showed - so that's what those new types are for
It was also necessary to be able to load file previews at preview time to avoid unnecessary loads when there are many results.
I also found that it was better to separate this system completely from the old legacy PreviewInfo - it makes things cleaner and lets us focus on this new system.
Summary
With this there is no need for the old way to show markdown previews added in #4529 so I removed that.
This new API should be clearer and more flexible, a separate RichPreviewInfo class that contains a list of PreviewContentBlocks such as a MarkdownPreviewBlock
The RichPreviewInfo is just a wrapper of the list but it makes it possible to add metadata / extra fields later on.
We now show a list of "content blocks" which can be of different types e.g. markdown, plain text, or separator
Each of which is its own subclass (record) which can have its own fields - instead of trying to share that description field or crowding it with type specific fields
The markdown block reuses the viewer from #4529, the text block is actually a textbox so that the text is selectable (it has a custom context menu as well), and the separator is a horizontal rectangle using the preexisting SeparatorStyle
Markdown and text blocks can also load their content from a passed file path when the preview is shown, instead of loading all the content when the results are created.
If inline markdown or text is provided, that is used instead of loading the file. Relative paths are resolved from the plugin directory and absolute paths are supported.
File-backed preview content is loaded lazily and cancelled when the selected result changes. The loaded content is kept on the result view model so it is not loaded again while that result remains available.
Follow up
As said before this should have everything we need to add markdown previews to the explorer plugin
After this, an image type should definitely be added, and then probably types for previewing other types of files like pdfs
Manual Testing
My markdown preview example plugin has been updated to include these changes
https://github.com/DavidGBrett/Flow.Launcher.Plugin.MarkdownPreviewTest
Images
Summary by cubic
Summary of changes
Adds a block-based rich preview so plugins can mix markdown, text, and separators in one scrollable panel.
- Changed: preview precedence is now
PreviewDefinition>PreviewPanel> legacyPreviewInfo. Text blocks render as a read-only selectable text box with copy/select-all context menu;PreviewBlockTextStyleadded to all themes. - Added:
ResultPreviewpolymorphic base withBlocksPreviewderived type holding orderedContentBlocks(MarkdownPreviewBlock,TextPreviewBlock,SeparatorPreviewBlock). Future preview types are new derived types rather than extra properties. - Added: markdown and text blocks load content from a file when the preview shows. Absolute paths supported, relative paths resolve from the plugin directory, loads cancel on result change, content is cached on the result view model, files over 1 MiB are rejected, failed loads are not retried, and generation tracking discards stale loads finishing late.
- Added: shared
MouseWheelHelperforwards wheel events from nested blocks to the outer preview (also reused by release notes) and stops code-block focus from jumping the preview to the top of its block. - Added: JSON-RPC deserialization allows the
typediscriminator to appear after other block properties viaAllowOutOfOrderMetadataProperties. - Added: preview types without JSON registration serialize as null instead of failing, keeping results with unregistered previews (such as WPF controls) persistable for history.
- Removed:
PreviewContentTypeenum andPreviewInfo.ContentType; JSON-RPC payloads usingcontentTypemust migrate topreviewDefinition.contentBlocks. The legacy preview image is no longer loaded when content blocks are shown. - Memory impact: minimal; blocks are small records and cloned results deep-copy the block list.
- Security risk: none new; content renders in the existing markdown/text viewers and no scripts execute.
- Unit tests: cover preview precedence, preview visibility, JSON-RPC deserialization for all three block types, out-of-order
typemetadata, derived-type registration and discriminators, unregistered preview serialization, and stale load discarding.
Release Note
Plugins can now show richer previews made of markdown, text, and section separators.