Skip to content

feat: tree browser and VS Code-style tabs for clips#192

Merged
fuzzzerd merged 1 commit intomasterfrom
fuzzz/treeview-tabs
Apr 24, 2026
Merged

feat: tree browser and VS Code-style tabs for clips#192
fuzzzerd merged 1 commit intomasterfrom
fuzzz/treeview-tabs

Conversation

@fuzzzerd
Copy link
Copy Markdown
Owner

Summary

Replaces the flat clip list with a TreeView that mirrors the repository's folder hierarchy, and the single-clip editor pane with a tab strip that supports VS Code-style preview tabs, permanent tabs, and dirty indicators.

What's new

  • Repository hierarchy. ClipData gains an optional FolderPath; the filesystem ClipRepository recurses subdirectories, round-trips folder paths on save, cleans up now-empty subdirs, and rejects traversal segments. The hierarchy concept lives on the repository contract so non-filesystem providers can synthesise folders however they want.
  • TreeView. Left panel is a TreeView bound to a ClipTreeNodeViewModel structure built from the flat clip collection. Search filters the tree and auto-expands matching branches. Tree template kept compact with existing Fluent2 styling.
  • Preview/permanent tabs. Single-tap a clip in the tree → italic preview tab (reuses the one preview slot across further single-taps). Double-tap a clip, double-tap the tab header, or make the first edit → graduates the preview to a permanent tab. Close via the button; closing the active tab picks a neighbour.
  • Dirty indicator. ClipViewModel.IsDirty compares the live editor XML against a saved snapshot; MarkSaved() rebases after a bulk Ctrl+S. Tab headers show an accent dot while dirty; it clears on save.

Performance

Opening the tab-strip naively triggered a visible hitch on every tab switch because ScriptTextEditor reinstalls TextMate on construction. Three levers applied:

  1. ScriptTextEditor no longer tears down TextMate on visual-tree detach; it's now IDisposable and is only disposed when its owning ClipViewModel is removed.
  2. ClipViewModel caches its Avalonia editor control (EditorView) so tab switches can reparent the same instance instead of reconstructing it.
  3. FmScriptRegistryOptions caches the parsed FM script grammar; ScriptTextEditor shares a single static RegistryOptions / FmScriptRegistryOptions across instances.
  4. Tab contents are realised once into an ItemsControl and toggled via IsVisible, so switching is a visibility flip rather than a reparent + AvaloniaEdit layout/tokenise pass.

Notes

  • Drag-to-reorder tabs is intentionally out of scope here — built-in TabStrip doesn't offer it and pulling in a docking framework was too much churn for this pass. Easy to add later if wanted.
  • Plugin panels that listen to SelectedClip now also fire when the preview slot swaps its clip in place.

Closes #160

Replace the flat clip list with a TreeView that mirrors the repository's
folder hierarchy, and the single-clip editor pane with a tab strip that
supports preview/permanent tabs and dirty indicators.

- IClipRepository gains an optional FolderPath on ClipData; filesystem
  ClipRepository recurses subdirectories and round-trips folder paths on
  save, rejecting traversal segments.
- ClipViewModel gains IsDirty (computed) and caches its Avalonia editor
  control so tab switches reparent the same instance.
- ScriptTextEditor no longer disposes TextMate on visual-tree detach;
  lifetime is explicit via IDisposable. RegistryOptions and the FM
  script grammar are parsed once and shared across instances.
- Open tabs are realised once into an ItemsControl and toggled via
  IsVisible, avoiding AvaloniaEdit layout/tokenise work on every switch.
- Single-tap in the tree opens a preview tab (italic), double-tap or
  first edit graduates it to permanent. Dirty dot clears on save.
@github-actions
Copy link
Copy Markdown

Test Results

✔️ Tests 1177 / 1177 - passed in 10.1s
✔️ Coverage 78.46% - passed with 70% threshold
📏 13413 / 15637 lines covered 🌿 4652 / 7387 branches covered
🔍 click here for more details

✏️ updated for commit 17da26e

@fuzzzerd fuzzzerd merged commit e5db1c1 into master Apr 24, 2026
6 checks passed
@fuzzzerd fuzzzerd deleted the fuzzz/treeview-tabs branch April 24, 2026 22:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

The Script/Clip list needs some UI/UX love.

1 participant