Add markdown preview type and per result preview visibility control

Merged
TR
3mo ago
+2321-106

What

The preview pane can now render formatted markdown with syntax-highlighted code blocks. Plugins opt in by setting Result.Preview.ContentType to Markdown and providing a markdown description.

A new Result.PreviewVisibility lets plugins control whether the preview pane shows:

  • Optional (default) - respects the user's Always Preview setting and preference from the preview toggle
  • Always - forces the pane open so users see the preview without manual toggling
  • Never - hides the pane for results with nothing useful to preview

And PreviewContentType controls how the preview is rendered:

  • ImageWithText (default) - the classic preview: image above, plain text below
  • Markdown - formatted markdown with headings, links, and syntax-highlighted code blocks

Existing plugins are unaffected as all defaults match current behavior.

Why

Plugins that produce rich text (AI assistants, documentation/snippet/note search, dictionary-style lookups) currently have to cram everything into plain SubTitle/Description text. This lets them opt into a proper rendered preview per result without affecting any existing plugin: every current result keeps the default text behavior.

The visibility controls exist so plugins can make sure users see the preview when it matters, without relying on them to manually toggle it or change settings. Results that exist primarily for their rendered content (like markdown) always show their preview; results with nothing useful to preview can hide it.

Details

Markdown rendering — Built on MdXaml (already a dependency) with code blocks highlighted through AvalonEdit (the one new package). A CodeHighlightTheme setting under Settings > Theme lets users pick a syntax theme or use Auto to match the app colour scheme. Bundled themes include VS Code Dark+, VS Code Light, One Dark, and Catppuccin Macchiato.

JSON-RPC — Both contentType and previewVisibility are added as keys on the result object (with contentType nested in preview):

{ "preview": { "contentType": "markdown", "description": "**hello**" }, "previewVisibility": "always" }

Themed horizontal scrollbars — Code blocks need horizontal scrolling, so horizontal scrollbar styles were added to Base.xaml and every built-in theme. Minimum thickness is 5px since horizontal bars are harder to click and have no scrollwheel alternative.

New dependency — AvalonEdit 6.3.0.90.

Tests

Full suite passes (256/256), including new coverage: pane gating rules (MainViewModelPreviewTest), markdown control behavior (PreviewMarkdownScrollViewerTest, PreviewMarkdownStyleTest), and JSON-RPC contentType deserialization (JsonRPCPluginTest).

Demo

Slightly outdated but still a good demonstration
📹

TODO

  1. Update https://github.com/Flow-Launcher/flow-launcher.github.io theme builder with the new changes
  2. Update documentation on markdown usage

Summary by cubic

Adds a markdown preview pane with syntax-highlighted code, per-result preview visibility (optional/never/always), and a Code Highlight Theme setting with Auto that follows the app theme. The pane won’t open without a selected result; existing results default to imageWithText.

Summary of changes

  • Changed
    • Preview visibility: single toggle preference _previewPreferenceFromToggle; results can force show/hide via PreviewVisibility; forced previews restore on reopen; internal preview is no longer auto-hidden on window hide; toggle always affects the current result; no selection keeps the pane hidden; fixed startup so preview doesn’t show before ResetPreviewAsync runs.
    • Preview flow: UpdatePreviewAsync delegates to ShowPreviewAsync; all preview calls awaited with try/catch; Reset closes external before opening internal; navigation still respects plugin visibility.
    • Input/UX: only code‑block navigation keys are captured; while a code block is focused the window key handler is skipped; hyperlinks open with improved error handling; preview height bound to the result list.
    • Styling: themed horizontal scrollbars with overrideable HorizontalScrollBarStyle/HorizontalThumbStyle; explicit code‑block scrollbar template avoids last‑line overlap; subtler thumbs; hyperlink underlines persist on hover/focus; preview and code‑block scrollbars themed across built‑in themes.
    • Naming/strings: default preview type renamed to imageWithText; PreviewVisibility.Default to Optional; tooltips and README updated; Result.Preview now a new instance per result and cloning deep‑copies to avoid shared state.
  • Added
    • Result.Preview.ContentType (imageWithText, markdown) and Result.PreviewVisibility (optional, never, always) with JSON‑RPC wire values.
    • PreviewMarkdownScrollViewer using MdXaml + AvalonEdit, per‑editor themed colorizer, language aliases, themed code‑block scrollbars, and IsCodeBlockFocused.
    • Settings.CodeHighlightTheme (default "Auto") with a Theme dropdown; Auto tracks light/dark and updates on theme change and startup. Dependency: AvalonEdit 6.3.0.90.
  • Removed
    • Old hidden preview content type (use PreviewVisibility.Never), HidePreviewPane/ForcePreviewPane wrappers, and the IsSafeScheme helper (allow only http/https).
    • Automatic hide of the internal preview on window hide.
  • Memory
    • Small increase from AvalonEdit, per‑editor colorizers, and style resources; editors are created on demand.
  • Security
    • Low risk: markdown renders to a FlowDocument (no scripts/autonavigation); links restricted to http/https; code blocks are read‑only.
  • Unit tests
    • Added: MainViewModelPreviewTest, PreviewMarkdownScrollViewerTest, PreviewMarkdownStyleTest, CodeHighlightThemeTest, and JsonRPCPluginTest. Tests cover toggle behavior, startup/reset edge cases, no‑selection guard, restore on reopen, JSON‑RPC content types, and theme auto‑resolve.

Release Note
You can preview markdown with clickable links and highlighted code, choose a code theme, and plugins can auto‑show or hide previews for their results.