(feat): add generalized template prefixes (#1723)

Adds org-roam-node-template-prefixes to split and prefix node properties
as a query language during completions, and allow 0-width template portions.
This commit is contained in:
Jethro Kuan
2021-08-17 23:40:56 +08:00
committed by GitHub
parent 95afbc676a
commit aafc8606bb

View File

@@ -76,6 +76,21 @@ It takes a single argument NODE, which is an `org-roam-node' construct."
(const :tag "file-atime" file-atime)) (const :tag "file-atime" file-atime))
:group 'org-roam) :group 'org-roam)
(defcustom org-roam-node-template-prefixes
'(("tags" . "#")
("todo" . "t:"))
"Prefixes for each of the node's properties.
This is used in conjunction with
`org-roam-node-display-template': in minibuffer completions the
node properties will be prefixed with strings in this variable,
acting as a query language of sorts.
For example, if a node has tags (\"foo\" \"bar\") and the alist
has the entry (\"tags\" . \"#\"), these will appear as
\"#foo #bar\"."
:group 'org-roam
:type '(alist))
(defcustom org-roam-ref-annotation-function #'org-roam-ref-read--annotation (defcustom org-roam-ref-annotation-function #'org-roam-ref-read--annotation
"This function used to attach annotations for `org-roam-ref-read'. "This function used to attach annotations for `org-roam-ref-read'.
It takes a single argument REF, which is a propertized string.") It takes a single argument REF, which is a propertized string.")
@@ -455,50 +470,47 @@ The displayed title is formatted according to `org-roam-node-display-template'."
(let ((candidate-main (org-roam-node-read--format-entry node (1- (frame-width))))) (let ((candidate-main (org-roam-node-read--format-entry node (1- (frame-width)))))
(cons (propertize candidate-main 'node node) node))) (cons (propertize candidate-main 'node node) node)))
(defun org-roam-node-read--tags-to-str (tags)
"Convert list of TAGS into a string."
(mapconcat (lambda (s) (concat "#" s)) tags " "))
(defun org-roam-node-read--format-entry (node width) (defun org-roam-node-read--format-entry (node width)
"Formats NODE for display in the results list. "Formats NODE for display in the results list.
WIDTH is the width of the results list. WIDTH is the width of the results list.
Uses `org-roam-node-display-template' to format the entry." Uses `org-roam-node-display-template' to format the entry."
(let ((fmt (org-roam-node-read--process-display-format org-roam-node-display-template))) (pcase-let ((`(,tmpl . ,tmpl-width)
(org-roam-node-read--process-display-format org-roam-node-display-template)))
(org-roam-format-template (org-roam-format-template
(car fmt) tmpl
(lambda (field _default-val) (lambda (field _default-val)
(let* ((field (split-string field ":")) (pcase-let* ((`(,field-name ,field-width) (split-string field ":"))
(field-name (car field)) (getter (intern (concat "org-roam-node-" field-name)))
(field-width (cadr field)) (field-value (funcall getter node)))
(getter (intern (concat "org-roam-node-" field-name)))
(field-value (or (funcall getter node) "")))
(when (and (equal field-name "tags")
field-value)
(setq field-value (org-roam-node-read--tags-to-str field-value)))
(when (and (equal field-name "file") (when (and (equal field-name "file")
field-value) field-value)
(setq field-value (file-relative-name field-value org-roam-directory))) (setq field-value (file-relative-name field-value org-roam-directory)))
(when (and (equal field-name "olp") (when (and (equal field-name "olp")
field-value) field-value)
(setq field-value (string-join field-value " > "))) (setq field-value (string-join field-value " > ")))
(if (not field-width) (when (and field-value (not (listp field-value)))
field-value (setq field-value (list field-value)))
(setq field-width (string-to-number field-width)) (setq field-value (mapconcat
(let ((display-string (truncate-string-to-width (lambda (v)
field-value (concat (or (cdr (assoc field-name org-roam-node-template-prefixes))
(if (> field-width 0) "")
field-width v))
(- width (cdr fmt))) field-value " "))
0 ?\s))) (setq field-width (cond
;; Setting the display (which would be padded out to the field length) for an ((string-equal field-width "*")
;; empty string results in an empty string and misalignment for candidates that (- width tmpl-width))
;; don't have some field. This uses the actual display string, made of spaces ((>= (string-to-number field-width) 0)
;; when the field-value is "" so that we actually take up space. (string-to-number field-width))))
(if (not (equal field-value "")) ;; Setting the display (which would be padded out to the field length) for an
;; Remove properties from the full candidate string, otherwise the display ;; empty string results in an empty string and misalignment for candidates that
;; formatting with pre-prioritized field-values gets messed up. ;; don't have some field. This uses the actual display string, made of spaces
(propertize (substring-no-properties field-value) 'display display-string) ;; when the field-value is "" so that we actually take up space.
display-string)))))))) (let ((display-string (truncate-string-to-width field-value field-width 0 ?\s)))
(if (equal field-value "")
display-string
;; Remove properties from the full candidate string, otherwise the display
;; formatting with pre-prioritized field-values gets messed up.
(propertize (substring-no-properties field-value) 'display display-string))))))))
(defun org-roam-node-read--process-display-format (format) (defun org-roam-node-read--process-display-format (format)
"Pre-calculate minimal widths needed by the FORMAT string." "Pre-calculate minimal widths needed by the FORMAT string."