(feat)insert: add org-roam-node-formatted (#1909)

Format a node into a string using a templated string (e.g. "${title}")
or using a function.
This commit is contained in:
Jethro Kuan
2021-10-17 16:15:58 +08:00
committed by GitHub
parent 2b6f8ce615
commit dafcf0dcf8

View File

@ -82,6 +82,16 @@ 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-formatter nil
"The link description for node insertion.
If a function is provided, the function should take a single
argument, an `org-roam-node', and return a string.
If a string is provided, it is a template string expanded by
`org-roam-node--format-entry'."
:group 'org-roam
:type '(string function))
(defcustom org-roam-node-template-prefixes (defcustom org-roam-node-template-prefixes
'(("tags" . "#") '(("tags" . "#")
("todo" . "t:")) ("todo" . "t:"))
@ -178,6 +188,16 @@ It takes a single argument REF, which is a propertized string.")
(slug (-reduce-from #'cl-replace (strip-nonspacing-marks title) pairs))) (slug (-reduce-from #'cl-replace (strip-nonspacing-marks title) pairs)))
(downcase slug))))) (downcase slug)))))
(cl-defmethod org-roam-node-formatted ((node org-roam-node))
"Return a formatted string for NODE."
(pcase org-roam-node-formatter
((pred functionp)
(funcall org-roam-node-formatter node))
((pred stringp)
(org-roam-node--format-entry (org-roam-node--process-display-format org-roam-node-formatter) node))
(_
(org-roam-node-title node))))
;;; Nodes ;;; Nodes
;;;; Getters ;;;; Getters
(defun org-roam-node-at-point (&optional assert) (defun org-roam-node-at-point (&optional assert)
@ -483,28 +503,30 @@ If REQUIRE-MATCH, the minibuffer prompt will require a match."
(or (cdr (assoc node nodes)) (or (cdr (assoc node nodes))
(org-roam-node-create :title node)))) (org-roam-node-create :title node))))
(defvar org-roam-node-read--cached-display-format nil)
(defun org-roam-node-read--completions () (defun org-roam-node-read--completions ()
"Return an alist for node completion. "Return an alist for node completion.
The car is the displayed title or alias for the node, and the cdr The car is the displayed title or alias for the node, and the cdr
is the `org-roam-node'. is the `org-roam-node'.
The displayed title is formatted according to `org-roam-node-display-template'." The displayed title is formatted according to `org-roam-node-display-template'."
(setq org-roam-node-read--cached-display-format nil) (let ((template (org-roam-node--process-display-format org-roam-node-display-template))
(let ((nodes (org-roam-node-list))) (nodes (org-roam-node-list)))
(mapcar #'org-roam-node-read--to-candidate nodes))) (mapcar (lambda (node)
(org-roam-node-read--to-candidate node template)) nodes)))
(defun org-roam-node-read--to-candidate (node) (defun org-roam-node-read--to-candidate (node template)
"Return a minibuffer completion candidate given NODE." "Return a minibuffer completion candidate given NODE.
(let ((candidate-main (org-roam-node-read--format-entry node (1- (frame-width))))) TEMPLATE is the processed template used to format the entry."
(let ((candidate-main (org-roam-node--format-entry
template
node
(1- (frame-width)))))
(cons (propertize candidate-main 'node node) node))) (cons (propertize candidate-main 'node node) node)))
(defun org-roam-node-read--format-entry (node width) (defun org-roam-node--format-entry (template node &optional 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." TEMPLATE is the processed template used to format the entry."
(pcase-let ((`(,tmpl . ,tmpl-width) (pcase-let ((`(,tmpl . ,tmpl-width) template))
(org-roam-node-read--process-display-format org-roam-node-display-template)))
(org-roam-format-template (org-roam-format-template
tmpl tmpl
(lambda (field _default-val) (lambda (field _default-val)
@ -529,7 +551,9 @@ Uses `org-roam-node-display-template' to format the entry."
((not field-width) ((not field-width)
field-width) field-width)
((string-equal field-width "*") ((string-equal field-width "*")
(- width tmpl-width)) (if width
(- width tmpl-width)
tmpl-width))
((>= (string-to-number field-width) 0) ((>= (string-to-number field-width) 0)
(string-to-number field-width)))) (string-to-number field-width))))
(when field-width (when field-width
@ -547,22 +571,20 @@ Uses `org-roam-node-display-template' to format the entry."
(setq field-value truncated)))) (setq field-value truncated))))
field-value))))) field-value)))))
(defun org-roam-node-read--process-display-format (format) (defun org-roam-node--process-display-format (format)
"Pre-calculate minimal widths needed by the FORMAT string." "Pre-calculate minimal widths needed by the FORMAT string."
(or org-roam-node-read--cached-display-format (let* ((fields-width 0)
(setq org-roam-node-read--cached-display-format (string-width
(let* ((fields-width 0) (string-width
(string-width (org-roam-format-template
(string-width format
(org-roam-format-template (lambda (field _default-val)
format (setq fields-width
(lambda (field _default-val) (+ fields-width
(setq fields-width (string-to-number
(+ fields-width (or (cadr (split-string field ":"))
(string-to-number "")))))))))
(or (cadr (split-string field ":")) (cons format (+ fields-width string-width))))
"")))))))))
(cons format (+ fields-width string-width))))))
(defun org-roam-node-read-sort-by-file-mtime (completion-a completion-b) (defun org-roam-node-read-sort-by-file-mtime (completion-a completion-b)
"Sort files such that files modified more recently are shown first. "Sort files such that files modified more recently are shown first.
@ -606,7 +628,7 @@ The INFO, if provided, is passed to the underlying `org-roam-capture-'."
(setq region-text (org-link-display-format (buffer-substring-no-properties beg end))))) (setq region-text (org-link-display-format (buffer-substring-no-properties beg end)))))
(node (org-roam-node-read region-text filter-fn)) (node (org-roam-node-read region-text filter-fn))
(description (or region-text (description (or region-text
(org-roam-node-title node)))) (org-roam-node-formatted node))))
(if (org-roam-node-id node) (if (org-roam-node-id node)
(progn (progn
(when region-text (when region-text