summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBrian Lester <[email protected]>2021-08-05 22:07:44 -0400
committerGitHub <[email protected]>2021-08-06 04:07:44 +0200
commitc3f16c3e702e7db4a456dfa24e34db8a6cb2d256 (patch)
tree50532d6e54eb25fe110729ddb54fea3fd70f982e
parent87ac58c08aa71d6b4bb3fe5c0d5079018c476da6 (diff)
Allow for user customization of citation node titles. (#40)
* Allow user styling of citation nodes via templates. This change updates the way that the title field is created for a citation node without an underlying node. Instead of manually calling `orb-bib-entry-get-value-function` and building the title via concatenation, it uses `orb--pre-xpand-template` to create a title. The template used can be customized with the `org-roam-ui-ref-title-template` variable. * Add the ability to retitle reference notes with bibliography information. This change adds the ability to update the title of notes that have a `:ROAM_REFS:` property and an associated bibtex entry. The new title will be created by `orb--pre-expand-template` and the `org-roam-ui-ref-title-template`, just like citation nodes that don't have associated nodes. This also requires that `org-ref` be loaded, otherwise it falls back to the original title. I put this behind another customizable variable in case it gets slow or a user wants to title reference nodes with the title they actually have in the node. Currently the handing of citation links throughout `org-roam` and `org-roam-bibtex` is rather scatter and seems rather brittle. At version points, different code processes the `:ROAM_REF:` filed differently, and it seems mostly because the fact that the default citation format `cite:%s` is so simple is why it works. For example, when inserting a ref into the database, org-roam uses the `org-link-plain-re` regex to normalize the reference. This results in the `cite:` being removed. When processing a link, it depends on the fact that `org` itself has split the link to `:type` and `:path`. The `:path` (without the `cite:`) is then inserted. In `org-roam-bibtex` they use `org-ref-cite-re` to remove the `cite:`, turning it into a key that is in the bibliography. In the PR, I followed the `org-roam-bibtex` method, parsing the `:ROAM_REFS:` property directly. We could also update the db node query to do a left outer join on the refs table. We then would have a new `refs` field on the node (we wouldn't need to send this over the wire) that is already formatted the way the database (and `org-roam-bibtex`) expect it to be. Then we wouldn't need to worry about our parsing getting out of sync with the other libraries. We would end up having to deal with multiple rows for the same node if it has multiple `refs`. I can look into a solution like this is we want. Another small thing to note, is that `:ROAM_REFS` doesn't have to specifically be a citation key for a bibliography. The examples have things like linking to google.com and then that is a reference where links to google can send you to your google note. In the UI we just check if `:ROAM_REFS:` is a there or not to making something a citation. Eventually we may want to actually include the `type` field from the `refs` table and make our decision based on that instead.
-rw-r--r--org-roam-ui.el69
1 files changed, 62 insertions, 7 deletions
diff --git a/org-roam-ui.el b/org-roam-ui.el
index 3ba3e21..b8a38fe 100644
--- a/org-roam-ui.el
+++ b/org-roam-ui.el
@@ -107,6 +107,20 @@ This can lead to some jank."
:group 'org-roam-ui
:type 'boolean)
+(defcustom org-roam-ui-retitle-ref-nodes t
+ "Should org-roam-ui use `org-roam-bibtex' to try to update the title of a
+reference node that has an underlying note, using information from the bibliography."
+ :group 'org-roam-ui
+ :type 'boolean)
+
+(defcustom org-roam-ui-ref-title-template "%^{author-abbrev} (%^{year}) %^{title}"
+ "A template for title creation, used for references without an associated nodes.
+
+This uses `orb--pre-expand-template' under the hood and therefore only org-style
+capture `%^{...}' are supported."
+ :group 'org-roam-ui
+ :type 'string)
+
(defcustom org-roam-ui-browser-function #'browse-url
"When non-nil launch org-roam-ui with a different browser function.
Takes a function name, such as #'browse-url-chromium.
@@ -201,17 +215,54 @@ Requires `org-roam-bibtex' and `bibtex-completion' (a dependency of `orb') to be
loaded. Returns `ref' if an entry could not be found."
(if (and org-roam-ui-find-ref-title
(fboundp 'bibtex-completion-get-entry)
- (boundp 'orb-bibtex-entry-get-value-function))
+ (fboundp 'orb--pre-expand-template))
(if-let ((entry (bibtex-completion-get-entry ref)))
- (concat
- (funcall orb-bibtex-entry-get-value-function "author-abbrev" entry ref)
- " ("
- (funcall orb-bibtex-entry-get-value-function "year" entry ref)
- ") "
- (funcall orb-bibtex-entry-get-value-function "title" entry ref))
+ ;; Create a fake capture template list, only the actual capture at 3
+ ;; matters. Interpolate the bibtex entries, and extract the filled
+ ;; template from the return value.
+ (nth 3 (orb--pre-expand-template `("" "" plain ,org-roam-ui-ref-title-template) entry))
ref)
ref))
+(defun org-roam-ui--replace-nth (el n lst)
+ "Non-destructively replace the `n'th element of `lst' with `el'."
+ (let ((head (butlast lst (- (length lst) n)))
+ (tail (nthcdr (+ n 1) lst)))
+ (append head (list el) tail)))
+
+(defun org-roam-ui--citekey-to-ref (citekey)
+ "Convert a citekey property (most likely with a `cite:' prefix) to just a key
+
+This method is mostly taken from `org-roam-bibtex' see https://github.com/org-roam/org-roam-bibtex/blob/919ec8d837a7a3bd25232bdba17a0208efaefb2a/orb-utils.el#L289
+but is has been adapted to operate on a sting instead of a node. Requires
+`org-ref' to be loaded. Returns the `key' or `nil' if the format does not match
+the `org-ref-cite-re'"
+ (if-let ((boundp 'org-ref-cite-re)
+ (citekey-list (split-string-and-unquote citekey)))
+ (catch 'found
+ (dolist (c citekey-list)
+ (when (string-match org-ref-cite-re c)
+ (throw 'found (match-string 2 c)))))))
+
+(defun org-roam-ui--retitle-node (node)
+ "Replace the title of citation nodes with associated notes.
+
+A new title is created using information from the bibliography and formatted
+according to `org-roam-ui-ref-title-template', just like the citation nodes with
+a note are. It requires `org-roam-bibtex' and it's dependencies
+(`bibtex-completion' and `org-ref') to be loaded.
+
+Returns the node with an updated title if the current node is a reference node
+and the key was found in the bibliography, otherwise the node is returned
+unchanged."
+ (if-let* (org-roam-ui-retitle-ref-nodes
+ (boundp 'org-ref-cite-re)
+ (citekey (cdr (assoc "ROAM_REFS" (nth 4 node))))
+ (ref (org-roam-ui--citekey-to-ref citekey))
+ (title (org-roam-ui--find-ref-title ref)))
+ (org-roam-ui--replace-nth title 2 node)
+ node))
+
(defun org-roam-ui--create-fake-node (ref)
(list ref ref (org-roam-ui--find-ref-title ref) 0 `(("ROAM_REFS" . ,(format "cite:%s" ref)) ("FILELESS" . t)) 'nil))
@@ -243,6 +294,10 @@ loaded. Returns `ref' if an entry could not be found."
(links-with-empty-refs (seq-filter (lambda (l) (equal (nth 2 l) "cite")) links-db-rows))
(empty-refs (delete-dups (seq-map (lambda (l) (nth 1 l)) links-with-empty-refs)))
(fake-nodes (seq-map 'org-roam-ui--create-fake-node empty-refs))
+ ;; Try to update real nodes that are reference with a title build from
+ ;; their bibliography entry. Check configuration here for avoid unneeded
+ ;; iteration though nodes.
+ (nodes-db-rows (if org-roam-ui-retitle-ref-nodes (seq-map 'org-roam-ui--retitle-node nodes-db-rows) nodes-db-rows))
(nodes-db-rows (append nodes-db-rows fake-nodes))
(response `((nodes . ,(mapcar (apply-partially #'org-roam-ui-sql-to-alist (append nodes-names nil)) nodes-db-rows))
(links . ,(mapcar (apply-partially #'org-roam-ui-sql-to-alist '(source target type)) links-db-rows))