Skip to content

d12frosted/vulpea-ui

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

85 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

vulpea-ui

Sidebar infrastructure and widget framework for vulpea notes.

MELPA CI version Sponsor

Screenshot

Features

  • 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

Installation

Dependencies

Using package.el (MELPA)

(package-install 'vulpea-ui)

Using straight.el

(straight-use-package 'vulpea-ui)

Using elpaca

(elpaca vulpea-ui)

Usage

(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)

Automatic sidebar

To automatically open the sidebar when entering org-mode buffers:

(add-hook 'org-mode-hook #'vulpea-ui-sidebar-open)

Configuration

Sidebar position and size

;; 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)

Outline widget

;; Maximum heading depth (nil = unlimited)
(setq vulpea-ui-outline-max-depth 3)

Backlinks widget

;; Show/hide content previews
(setq vulpea-ui-backlinks-show-preview t)

;; 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)

Behaviour options

;; Auto-hide sidebar when switching to non-vulpea buffers
;; When nil, sidebar remains visible with stale content
(setq vulpea-ui-sidebar-auto-hide t)

;; Start widgets collapsed
(setq vulpea-ui-default-widget-collapsed nil)

;; Auto-refresh sidebar on save and idle (enabled by default)
(setq vulpea-ui-auto-refresh t)

;; Idle delay before auto-refresh (in seconds)
(setq vulpea-ui-auto-refresh-delay 1.5)

Performance

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)

Commands

CommandDescription
vulpea-ui-sidebar-openOpen the sidebar
vulpea-ui-sidebar-closeClose the sidebar
vulpea-ui-sidebar-toggleToggle sidebar visibility
vulpea-ui-sidebar-refreshForce refresh content

Sidebar keybindings

KeyAction
qClose sidebar
gRefresh content
TABNavigate to next widget
S-TABNavigate to previous widget
RETActivate widget at point

TAB, S-TAB, and RET are inherited from vui-mode. q and g are sidebar-specific.

For quick navigation to any widget, consider ace-link-vui.

Default widgets

Stats widget

Screenshot

Shows character count, word count, and link count for the current note.

Outline widget

Screenshot

Displays the heading structure of the note. Click headings to navigate.

Backlinks widget

Screenshot

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

Links widget

Screenshot

Shows notes that the current note links to.

Widget Registration

Widgets are registered with vulpea-ui-register-widget, which allows filtering by predicate and ordering.

Built-in widgets

vulpea-ui registers these widgets by default:

WidgetOrderComponent
stats100vulpea-ui-widget-stats
outline200vulpea-ui-widget-outline
backlinks300vulpea-ui-widget-backlinks
links400vulpea-ui-widget-links

Registering widgets

(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

Modifying widget properties

vulpea-ui-widget-set updates a single property on an already-registered widget. This works for any widget, including the built-in ones, so you can customise them without redefining anything.

;; Change a widget's order
(vulpea-ui-widget-set 'stats :order 50)

;; Attach a predicate to a built-in widget
(vulpea-ui-widget-set 'outline :predicate #'my/show-outline-p)

;; Remove a widget
(vulpea-ui-unregister-widget 'links)

Toggling a widget per note

Built-in widgets have no predicate by default, so they are shown for every note. You can install one with vulpea-ui-widget-set to decide per note whether the widget shows up. A common recipe is a global default variable combined with an org property that overrides it on individual notes.

The example below hides the outline widget by default and shows it only on notes that set :OUTLINE: t. Flip my/vulpea-ui-always-show-outline to t to invert the default, in which case :OUTLINE: nil hides the widget on specific notes.

(defvar my/vulpea-ui-always-show-outline nil
  "When non-nil, show the outline widget unless a note opts out.")

(defun my/vulpea-ui-show-outline-p (note)
  "Return non-nil if the outline widget should be shown for NOTE.
An `OUTLINE' property on the note overrides the default variable."
  (if-let* ((props (vulpea-note-properties note))
            (entry (assoc "OUTLINE" props)))
      (not (equal (cdr entry) "nil"))
    my/vulpea-ui-always-show-outline))

(vulpea-ui-widget-set 'outline :predicate #'my/vulpea-ui-show-outline-p)

The same pattern works for any widget (stats, backlinks, links, or your own).

How it works

  1. Widgets are filtered by their :predicate (if any) against the current note
  2. Remaining widgets are sorted by :order (ascending)
  3. Each widget’s :component is rendered

This allows packages like vulpea-journal to register context-specific widgets that only appear when viewing certain notes.

Custom widgets

Create custom widgets using vui’s vui-defcomponent macro:

(vui-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 backlinks

For 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)

Utility Functions

vulpea-ui-clean-org-markup

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.

Faces

FaceDescription
vulpea-ui-widget-header-faceWidget header text
vulpea-ui-widget-count-faceWidget count numbers
vulpea-ui-outline-heading-faceOutline headings
vulpea-ui-stats-faceStatistics text
vulpea-ui-backlink-preview-faceBacklink preview text
vulpea-ui-backlink-heading-faceBacklink heading path
vulpea-ui-backlink-meta-key-faceMeta block keys
vulpea-ui-backlink-meta-value-faceMeta block values
vulpea-ui-backlink-context-faceContext type indicators

Related Projects

  • vulpea-journal - Daily journaling with calendar, navigation, and “on this day” widgets
  • ace-link-vui - Ace-link style navigation for VUI buffers

License

Copyright (C) 2024-2026 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.

Support

If you enjoy this project, you can support its development via GitHub Sponsors or Patreon.

About

A widget-based sidebar for Emacs that displays contextual information (stats, outline, backlinks, links) for vulpea notes

Topics

Resources

License

Stars

Watchers

Forks

Sponsor this project

  •  

Packages

 
 
 

Contributors