Sidebar infrastructure and widget framework for vulpea notes.
- Per-frame sidebar with configurable position and size
- Widget system built on vui components
- Default widgets: outline, backlinks, forward links, stats
- Easy API for creating custom widgets
- Auto-hide when switching to non-vulpea buffers
(straight-use-package
'(vulpea-ui :host github :repo "d12frosted/vulpea-ui"))(elpaca (vulpea-ui :host github :repo "d12frosted/vulpea-ui"))(require 'vulpea-ui)
;; Open sidebar
(vulpea-ui-sidebar-open)
;; Or toggle with a keybinding
(global-set-key (kbd "C-c v s") #'vulpea-ui-sidebar-toggle)To automatically open the sidebar when entering org-mode buffers:
(add-hook 'org-mode-hook #'vulpea-ui-sidebar-open);; Position: 'right (default), 'left, 'top, 'bottom
(setq vulpea-ui-sidebar-position 'right)
;; Size as fraction of frame (0.0-1.0)
(setq vulpea-ui-sidebar-size 0.33);; Maximum heading depth (nil = unlimited)
(setq vulpea-ui-outline-max-depth 3);; Show/hide content previews
(setq vulpea-ui-backlinks-show-preview t)
;; Lines to show in prose previews
(setq vulpea-ui-backlinks-preview-lines 2)
;; Characters before/after link in prose previews
(setq vulpea-ui-backlinks-prose-chars-before 30)
(setq vulpea-ui-backlinks-prose-chars-after 50)
;; Filter which notes appear in backlinks
;; (function receiving vulpea-note, return non-nil to include)
(setq vulpea-ui-backlinks-note-filter
(lambda (note)
(not (member "archive" (vulpea-note-tags note)))))
;; Filter by context type
;; t = all types, or a list of: meta, header, table, list, quote, code, footnote, prose
(setq vulpea-ui-backlinks-context-types t)
;; Sorting: nil (no sorting), 'title-asc, 'title-desc, or custom function
(setq vulpea-ui-backlinks-sort 'title-asc);; Auto-hide sidebar when switching to non-vulpea buffers
(setq vulpea-ui-sidebar-auto-hide t)
;; Start widgets collapsed
(setq vulpea-ui-default-widget-collapsed nil)For large org files or many backlinks, enable fast parsing:
;; Skip org-mode hooks during parsing (faster but may cause issues
;; if your setup depends on mode hooks for org-element parsing)
(setq vulpea-ui-fast-parse t)| Command | Description |
|---|---|
vulpea-ui-sidebar-open | Open the sidebar |
vulpea-ui-sidebar-close | Close the sidebar |
vulpea-ui-sidebar-toggle | Toggle sidebar visibility |
vulpea-ui-sidebar-refresh | Force refresh content |
| Key | Action |
|---|---|
q | Close sidebar |
g | Refresh content |
TAB | Navigate to next widget |
S-TAB | Navigate to previous widget |
RET | Activate widget at point |
For quick navigation to any widget, consider ace-link-vui.
Shows character count, word count, and link count for the current note.
Displays the heading structure of the note. Click headings to navigate.
Shows notes that link to the current note, grouped by file with:
- Heading path context (where in the document the link appears)
- Content preview with context type indicators:
⊢meta property§header▤table·list item>quoteλcode†footnote- (no indicator) prose
Shows notes that the current note links to.
Widgets are registered with vulpea-ui-register-widget, which allows filtering by predicate and ordering.
vulpea-ui registers these widgets by default:
| Widget | Order | Component |
|---|---|---|
stats | 100 | vulpea-ui-widget-stats |
outline | 200 | vulpea-ui-widget-outline |
backlinks | 300 | vulpea-ui-widget-backlinks |
links | 400 | vulpea-ui-widget-links |
(vulpea-ui-register-widget 'my-widget
:component 'my-custom-widget-component
:predicate #'my-note-predicate ; optional: only show when this returns non-nil
:order 150) ; optional: default 100;; Change a widget's order
(vulpea-ui-widget-set 'stats :order 50)
;; Remove a widget
(vulpea-ui-unregister-widget 'links)- Widgets are filtered by their
:predicate(if any) against the current note - Remaining widgets are sorted by
:order(ascending) - Each widget’s
:componentis rendered
This allows packages like vulpea-journal to register context-specific widgets that only appear when viewing certain notes.
Create custom widgets using vui’s defcomponent macro:
(defcomponent my-custom-widget ()
"My custom widget."
:render
(let ((note (use-vulpea-ui-note)))
(vui-component 'vulpea-ui-widget
:title "My Widget"
:count 42
:children
(lambda ()
(vui-text "Custom content here")))))Register the widget:
(vulpea-ui-register-widget 'my-widget
:component 'my-custom-widget
:order 250) ; after outline, before backlinksFor context-specific widgets (e.g., only for notes with a certain tag):
(defun my-project-note-p (note)
"Return non-nil if NOTE is a project note."
(member "project" (vulpea-note-tags note)))
(vulpea-ui-register-widget 'project-tasks
:component 'my-project-tasks-widget
:predicate #'my-project-note-p
:order 150)Cleans org-mode markup from text for display purposes:
(vulpea-ui-clean-org-markup text)Transformations:
- Links:
[[url][title]]→title,[[url]]→url(bare[[id:...]]links are removed) - Drawers:
:PROPERTIES:...:END:blocks are removed - Metadata:
#+TITLE:,#+FILETAGS:, etc. lines are removed - Whitespace: multiple spaces/tabs collapsed to single space
Useful for rendering previews in custom widgets.
| Face | Description |
|---|---|
vulpea-ui-widget-header-face | Widget header text |
vulpea-ui-widget-count-face | Widget count numbers |
vulpea-ui-outline-heading-face | Outline headings |
vulpea-ui-stats-face | Statistics text |
vulpea-ui-backlink-preview-face | Backlink preview text |
vulpea-ui-backlink-heading-face | Backlink heading path |
vulpea-ui-backlink-meta-key-face | Meta block keys |
vulpea-ui-backlink-meta-value-face | Meta block values |
vulpea-ui-backlink-context-face | Context type indicators |
- vulpea-journal - Daily journaling with calendar, navigation, and “on this day” widgets
- ace-link-vui - Ace-link style navigation for VUI buffers
Copyright (C) 2024-2025 Boris Buliga
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.