consult-symbol

an Emacs package to navigate obarray symbols via Consult
git clone https://git.trogloxene.org/consult-symbol.git
Log | Files | Refs | README

commit 050dbf30aeda1b0f57fbce84a1d682ae256e1514
Author: andsy10 <andsy1016@gmail.com>
Date:   Mon, 19 Oct 2026 09:19:43 +0800

Initial commit

Diffstat:
AREADME | 1+
Aconsult-symbol.el | 162+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 163 insertions(+), 0 deletions(-)

diff --git a/README b/README @@ -0,0 +1 @@ +This package was generated by LLM and has NOT been fully reviewed. diff --git a/consult-symbol.el b/consult-symbol.el @@ -0,0 +1,162 @@ +;;; consult-symbol.el --- Consult commands for browsing obarray symbols -*- lexical-binding: t -*- + +;;; Commentary: + +;; This package provide `consult-symbol' which completes over the +;; symbols in `obarray' and previews their source definitions. +;; +;; Usage: +;; +;; M-x consult-symbol RET + + +;;; Code: + +(require 'consult) +(require 'find-func) +(require 'help-fns) +(require 'xref) + +(defvar consult-symbol--history nil) + +(defconst consult-symbol--narrow + '((?f . "Function") + (?v . "Variable") + (?a . "Face")) + "Narrowing configuration for `consult-symbol'.") + +(defun consult-symbol--type (sym) + "Return the narrowing type character of SYM." + (cond + ((fboundp sym) ?f) + ((boundp sym) ?v) + ((facep sym) ?a))) + +(defun consult-symbol--candidates () + "Return symbol name candidates from `obarray'." + (let (cands) + (mapatoms + (lambda (sym) + (when-let* ((type (consult-symbol--type sym))) + (push (propertize (symbol-name sym) + 'consult--symbol sym + 'consult--type type) + cands)))) + cands)) + +(defun consult-symbol--file (sym type) + "Return the source file name of SYM's definition of TYPE. +TYPE is either a function definition, `defvar' or `defface', as accepted +by `find-lisp-object-file-name'. Definitions in the C sources are +translated to a \"src/*.c\" file name." + (when-let* ((file (find-lisp-object-file-name sym type))) + (if (eq file 'C-source) + (help-C-file-name sym (if (eq type 'defvar) 'var 'subr)) + file))) + +(defun consult-symbol--definition (sym) + "Return (TYPE . FILE) for the source definition of SYM, or nil. +TYPE is nil for a function definition, `defvar' for a variable +definition or `defface' for a face definition, as accepted by +`find-function-search-for-symbol'." + (or + (and (fboundp sym) + (when-let* ((file (consult-symbol--file sym (symbol-function sym)))) + (cons nil file))) + (and (boundp sym) + (when-let* ((file (consult-symbol--file sym 'defvar))) + (cons 'defvar file))) + (and (facep sym) + (when-let* ((file (consult-symbol--file sym 'defface))) + (cons 'defface file))))) + +(defun consult-symbol--find (sym open) + "Return a marker to the source definition of SYM, or nil. +OPEN is a temporary file opener as returned by +`consult--temporary-files'. Nested calls to `find-file-noselect', e.g., +from the OPEN function itself, are passed through to the original +function, in order to avoid infinite recursion." + (pcase-let ((`(,type . ,file) (consult-symbol--definition sym))) + (when file + (condition-case nil + (let ((orig (symbol-function #'find-file-noselect)) + (nested nil)) + (pcase-let ((`(,buf . ,pos) + (cl-letf (((symbol-function #'find-file-noselect) + (lambda (name &rest args) + (if nested + (apply orig name args) + (setq nested t) + (unwind-protect + (funcall open name) + (setq nested nil)))))) + (find-function-search-for-symbol sym type file)))) + (when (buffer-live-p buf) + (with-current-buffer buf + (save-excursion + (save-restriction + (widen) + (goto-char (or pos (point-min))) + (point-marker))))))) + (error nil))))) + +(defun consult-symbol--preview () + "Symbol preview function, usable as :state argument of `consult--read'. +Files are opened temporarily via `consult--temporary-files' and the +definition is previewed via `consult--jump-preview'. Symbols whose +source cannot be located are not previewed." + (let ((open (consult--temporary-files)) + (preview (consult--jump-preview))) + (lambda (action sym) + (unless sym + (funcall open)) + (funcall preview action + (and sym + (eq action 'preview) + (consult-symbol--find sym open)))))) + +(defun consult-symbol--jump (sym) + "Jump to the source definition of SYM." + (pcase-let ((`(,type . ,file) (consult-symbol--definition sym))) + (if (not file) + (message "Unknown source location of `%s'" sym) + (xref-push-marker-stack) + (pcase-let ((`(,buf . ,pos) + (find-function-search-for-symbol sym type file))) + (consult--jump + (with-current-buffer buf + (save-excursion + (save-restriction + (widen) + (goto-char (or pos (point-min))) + (point-marker)))))) + (run-hooks 'find-function-after-hook)))) + +;;;###autoload +(defun consult-symbol () + "Browse `obarray' symbols with preview of their source definition. + +The command completes over all interned symbols which are defined as +function, variable or face. While browsing, the definition of the +current candidate is previewed; the source file is only opened +temporarily. After selection, jump to the definition, pushing the +previous position to the xref marker stack. Symbols can be narrowed by +type, see `consult-symbol--narrow'." + (interactive) + (let ((sym (symbol-at-point))) + (consult--read + (consult-symbol--candidates) + :prompt "Symbol: " + :category 'symbol + :require-match t + :history 'consult-symbol--history + :default (and sym (consult-symbol--type sym) (symbol-name sym)) + :lookup (apply-partially #'consult--lookup-prop 'consult--symbol) + :state (consult--state-with-return + (consult-symbol--preview) + #'consult-symbol--jump) + :group (consult--type-group consult-symbol--narrow) + :narrow (consult--type-narrow consult-symbol--narrow)))) + +(provide 'consult-symbol) +;;; consult-symbol.el ends here