- The way the nodes are processed for the template is very slow.
- To test how slow, I replaced the code and returned the value of the field
without any extra manipulation
See below
- With these changes, the take home:
- for my database
- org-roam-node-list takes 1/3 of the time,
- 2/3 is the formatting. most inside org-roam-format-template–replace (see below)
- for my database
if we would want to make this code, most of this postprocessing should be done by the DBMS (faster, and no emacs gc)
- removed large lambdas, I suspect they generate a lot of garbage
- this already has some improvement
- it is easier to profile this code, since now the lambda has a name
(defun org-roam-node--retrieve-field (node field _default-val)
(pcase-let* ((`(,field-name ,field-width) (split-string field ":"))
(getter (intern (concat "org-roam-node-" field-name)))
(field-value (funcall getter node)))
;; if the field-name is file, replace it with its
;; relative name
(when (and (equal field-name "file")
field-value)
(setq field-value (file-relative-name field-value org-roam-directory)))
;; if field name is olp
;; append " > "
(when (and (equal field-name "olp")
field-value)
(setq field-value (string-join field-value " > ")))
;; if field value is not a list, make it one
(when (and field-value (not (listp field-value)))
(setq field-value (list field-value)))
;; ????
(setq field-value (mapconcat
(lambda (v)
(concat (or (cdr (assoc field-name org-roam-node-template-prefixes))
"")
v))
field-value " "))
;; set the width of the field
(setq field-width (cond
((not field-width)
field-width)
((string-equal field-width "*")
(if width
(- width tmpl-width)
tmpl-width))
((>= (string-to-number field-width) 0)
(string-to-number field-width))))
(when field-width
(let* ((truncated (truncate-string-to-width field-value field-width 0 ?\s))
(tlen (length truncated))
(len (length field-value)))
(if (< tlen len)
;; Make the truncated part of the string invisible. If strings
;; are pre-propertized with display or invisible properties, the
;; formatting may get messed up. Ideally, truncated strings are
;; not preformatted with these properties. Face properties are
;; allowed without restriction.
(put-text-property tlen len 'invisible t field-value)
;; If the string wasn't truncated, but padded, use this string instead.
(setq field-value truncated))))
field-value))
(defun org-roam-node--format-entry (template node &optional width)
"Formats NODE for display in the results list.
WIDTH is the width of the results list.
TEMPLATE is the processed template used to format the entry."
(pcase-let ((`(,tmpl . ,tmpl-width) template))
(org-roam-format-template
tmpl
(lambda (field _default-val)
(org-roam-node--retrieve-field node field _default-val)
)
)
)
)
(defun org-roam-format-template--replace (replacer md var replacer-match-data)
(let (;(var (match-string 1 md))
;(replacer-match-data (match-data))
default-val)
(when (string-match "\\(.+\\)=\\(.+\\)" var)
(setq default-val (match-string 2 var)
var (match-string 1 var)))
(unwind-protect
(let ((v (progn
(set-match-data saved-match-data)
(funcall replacer var default-val))))
(if v
(format (apply #'propertize "%s" (text-properties-at 0 var)) v)
(signal 'org-roam-format-resolve md)))
(set-match-data replacer-match-data)))
)
(defun org-roam-format-template (template replacer)
"Format TEMPLATE with the function REPLACER.
The templates are of form ${foo} for variable foo, and
${foo=default} for variable foo with default value \"default\".
REPLACER takes an argument of the format variable and the default
value (possibly nil). Adapted from `s-format'."
; (message (format "org-roam-format-template [%S][%S]" template replacer))
(let ((saved-match-data (match-data)))
(unwind-protect
(replace-regexp-in-string
"\\${\\([^}]+\\)}"
(lambda (md)
(org-roam-format-template--replace replacer md (match-string 1 md) (match-data)))
(if (functionp template)
(funcall template)
template)
;; Need literal to make sure it works
t t)
(set-match-data saved-match-data))))
org-roam-format-template
(cl-loop
for i from 1 to 10
collect (benchmark-run 1
(org-roam-node-read--completions)
))
0.412061 | 0 | 0.0 |
0.397887 | 0 | 0.0 |
0.64908 | 1 | 0.2558129999999892 |
0.39279400000000003 | 0 | 0.0 |
0.39737500000000003 | 0 | 0.0 |
0.396787 | 0 | 0.0 |
0.648724 | 1 | 0.25631900000001906 |
0.393802 | 0 | 0.0 |
0.39527100000000004 | 0 | 0.0 |
0.398236 | 0 | 0.0 |
- remove pcase-let (they are slow)
- simply retrieve the field, without any formatting
(defun org-roam-node--retrieve-field (node field _default-val)
(let* (
(getter (intern (concat "org-roam-node-" field)))
(field-value (funcall getter node))
)
(if (listp field-value)
(mapconcat 'identity field-value " ")
field-value)
)
)
(defun org-roam-node--format-entry (template node &optional width)
"Formats NODE for display in the results list.
WIDTH is the width of the results list.
TEMPLATE is the processed template used to format the entry."
(org-roam-format-template
(car template)
(lambda (field _default-val)
(org-roam-node--retrieve-field node field _default-val)
)
)
)
(defun org-roam-format-template--replace (replacer md var replacer-match-data)
(let (;(var (match-string 1 md))
;(replacer-match-data (match-data))
default-val)
(when (string-match "\\(.+\\)=\\(.+\\)" var)
(setq default-val (match-string 2 var)
var (match-string 1 var)))
(unwind-protect
(let ((v (progn
(set-match-data saved-match-data)
(funcall replacer var default-val))))
(if v
(format (apply #'propertize "%s" (text-properties-at 0 var)) v)
(signal 'org-roam-format-resolve md)))
(set-match-data replacer-match-data)))
)
(defun org-roam-format-template (template replacer)
"Format TEMPLATE with the function REPLACER.
The templates are of form ${foo} for variable foo, and
${foo=default} for variable foo with default value \"default\".
REPLACER takes an argument of the format variable and the default
value (possibly nil). Adapted from `s-format'."
; (message (format "org-roam-format-template [%S][%S]" template replacer))
(let ((saved-match-data (match-data)))
(unwind-protect
(replace-regexp-in-string
"\\${\\([^}]+\\)}"
(lambda (md)
(org-roam-format-template--replace replacer md (match-string 1 md) (match-data)))
(if (functionp template)
(funcall template)
template)
;; Need literal to make sure it works
t t)
(set-match-data saved-match-data))))
org-roam-format-template
(cl-loop
for i from 1 to 10
collect (benchmark-run 1
(org-roam-node-read--completions)
))
0.195719 | 0 | 0.0 |
0.176511 | 0 | 0.0 |
0.18973399999999999 | 0 | 0.0 |
0.43086800000000003 | 1 | 0.25443200000000843 |
0.175176 | 0 | 0.0 |
0.174871 | 0 | 0.0 |
0.179221 | 0 | 0.0 |
0.177346 | 0 | 0.0 |
0.179422 | 0 | 0.0 |
0.434545 | 1 | 0.25984799999997676 |