gists/gists/tempel-org-links.el

81 lines
2.7 KiB
EmacsLisp

;;; Introduction
;;
;; In my Org notes I often refer to terms like JIRA tickets or some
;; queries to an (internal) search engine. Doing it natively with Org
;; mode is a bit involved:
;;
;; 1. org-insert-link
;; 2. Type link, e.g. "JIRA:MYPRJ-1234"
;; 3. Type the visible description again: "MYPRJ-1234".
;;
;; The repetition is a bit cumbersome and a template to insert the
;; link would be more convenient. And sometimes I already typed the
;; ticket number and I want to turn it into a link quickly.
;;
;; The code below adds a element which can be used in Tempel templates
;; to insert [[org:links][links]]. It works with and without active
;; region. If no region is active, a term is prompted in the
;; minibuffer.
;;
;; The following template:
;;
;; (jira (ol "JIRA"))
;;
;; results in [[JIRA:ticket][ticket]] where ticket is prompted or
;; taken from the region.
;;
;; This relies on having link types configured in your
;; `org-link-abbrev-alist', the link type accepts one parameter
;; matching a link type.
;;
;;; Requirements / why na(t)ive templates don't work
;;
;; The template has to meet the following requirements:
;;
;; - type the search term / ID only once
;; - or, use the region instead, if active
;; - no visible prefixes (link abbrevations)
;;
;; We need to store the region before the templating kicks
;; in, because the region can be used only once in a template. For
;; example, this doesn't work:
;;
;; (jira "[[JIRA:" r "][" r "]]")
;;
;; (and it's a region-only template, so another template would be
;; needed for a prompt).
;;
;; Also, a prompting variant doesn't work due to a bug in Org mode
;; which makes the element cache trip:
;;
;; (jira "[[JIRA:" (p "Ticket: " ticket) "][" (s ticket) "]]")
;;
;; Unfortunately, this not-so-elegant code is needed to meet the
;; requirements.
(defun my/tempel-org-link (elt)
"Tempel field to insert an org link."
(when (eq (car-safe elt) 'ol)
(let ((link-type (cadr elt)))
(if (and (boundp 'my/region) my/region)
;; consume region with r and use the stored region
;; afterwards, as r can be used only once
`(l "[[" ,link-type ":" r "][" ,my/region "]]")
;; NOINSERT is used for the prompt because the org-mode
;; element cache doesn't handle simultaneous edits well. So
;; prompt in minibuffer and insert the result twice.
`(l "[[" ,link-type ":" (p "Term: " term t) term "][" term "]]")))))
(defun my/store-region (f &rest args)
"Store the region in the my/region variable."
(setq my/region (when (use-region-p)
(buffer-substring (region-beginning) (region-end))))
(apply f args)
(setq my/region nil))
(add-to-list 'tempel-user-elements #'my/tempel-org-link)
(advice-add #'tempel-insert :around #'my/store-region)