Define list of variables for org files used for capturing various tasks
(defvar +org-capture-books-file (concat org-directory "books.org")
"Default, centralized target for org-capture templates.")
(defvar +org-contacts-file (concat org-directory "contacts.org")
"Org contacts path")
(defvar +org-capture-diabetes-file (concat org-directory "diabetes.org")
"Capture diabetes related records")
Let’s setup some org-capture templates
(,(format "%s\tAdd contact" (all-the-icons-octicon "star" :face 'all-the-icons-green :v-adjust 0.01))
:keys "c"
:file +org-contacts-file
:prepend t
:headline "New"
;; :olp ("Inbox" "Family" "Close friends" "Work coleagues")
:type entry
:template ("* %^{Name Surname}"
":PROPERTIES:"
":address: %^{Address}"
":birthday: \"%^{yyyy-mm-dd}\""
":email: \"%^{Email}\""
":note: \"%^{Note}\""
":END:"))
(,(format "%s\tBooks to read" (all-the-icons-octicon "book" :face 'all-the-icons-green :v-adjust 0.01))
:keys "b"
:file +org-capture-books-file
:prepend t
:headline "Inbox"
:type entry
:template ("* TOREAD %^{Author}. %^{Book Title} %? :book:"
"- Why do I want to read this book?"
" %^{Why do you want to read this book}"
"- How did I found this book?"
" %^{How did you found this book}\n"
"- After reading:"
" + What did I learn from this book?"
" + What its this book about?"
" + Would I recommend this book?\n"))
(,(format "%s\tAzure task" (all-the-icons-material "cloud" :face 'all-the-icons-blue :v-adjust 0.01))
:keys "a"
:file +org-capture-todo-file
:prepend t
:headline "Inbox"
:type entry
:template ("* TODO [[azure:%^{Task ID}][%\\1]] P:[[azure:%^{Parent ID}][%\\2]] %^{Task Title} %?:%^G:"))
(,(format "%s\tPersonal todo"
(all-the-icons-octicon "checklist" :face 'all-the-icons-green :v-adjust 0.01))
:keys "t"
:file +org-capture-todo-file
:prepend t
:headline "Inbox"
:type entry
:template ("* TODO %?" "%i %a"))
(,(format "%s\tPersonal note" (all-the-icons-faicon "sticky-note-o" :face 'all-the-icons-green :v-adjust 0.01))
:keys "n"
:file +org-capture-todo-file
:prepend t
:headline "Inbox"
:type entry
:template ("* %?"
"%i %a")
)
(,(format "%s\tEmail" (all-the-icons-faicon "envelope" :face 'all-the-icons-blue :v-adjust 0.01))
:keys "e"
:file +org-capture-todo-file
:prepend t
:headline "Inbox"
:type entry
:template ("* TODO %^{type|reply to|contact} %\\3 %? :email:"
"Send an email %^{urgancy|soon|ASAP|anon|at some point|eventually} to %^{recipiant}"
"about %^{topic}"
"%U %i %a"))
(,(format "%s\tWebpage" (all-the-icons-faicon "globe" :face 'all-the-icons-green :v-adjust 0.01))
:keys "w"
:desc "%(org-cliplink-capture) "
:i-type "read:web"
)
(,(format "%s\tArticle" (all-the-icons-octicon "file-text" :face 'all-the-icons-yellow :v-adjust 0.01))
:keys "a"
:desc ""
:i-type "read:reaserch"
)
(,(format "%s\tInformation" (all-the-icons-faicon "info-circle" :face 'all-the-icons-blue :v-adjust 0.01))
:keys "i"
:desc ""
:i-type "read:info"
)
(,(format "%s\tIdea" (all-the-icons-material "bubble_chart" :face 'all-the-icons-silver :v-adjust 0.01))
:keys "I"
:desc ""
:i-type "idea"
)
(,(format "%s\tGeneral Task" (all-the-icons-octicon "inbox" :face 'all-the-icons-yellow :v-adjust 0.01))
:keys "k"
:extra ""
)
(,(format "%s\tTask with deadline" (all-the-icons-material "timer" :face 'all-the-icons-orange :v-adjust -0.1))
:keys "d"
:extra "\nDEADLINE: %^{Deadline:}t"
)
(,(format "%s\tScheduled Task" (all-the-icons-octicon "calendar" :face 'all-the-icons-orange :v-adjust 0.01))
:keys "s"
:extra "\nSCHEDULED: %^{Start time:}t"
)
(,(format "%s\tProject-local todo" (all-the-icons-octicon "checklist" :face 'all-the-icons-green :v-adjust 0.01))
:keys "t"
:time-or-todo "TODO"
:file +org-capture-project-todo-file)
(,(format "%s\tProject-local note" (all-the-icons-faicon "sticky-note" :face 'all-the-icons-yellow :v-adjust 0.01))
:keys "n"
:time-or-todo "%U"
:file +org-capture-project-notes-file)
(,(format "%s\tProject-local changelog" (all-the-icons-faicon "list" :face 'all-the-icons-blue :v-adjust 0.01))
:keys "c"
:time-or-todo "%U"
:heading "Unreleased"
:file +org-capture-project-changelog-file)
(,(format "%s\tNew blog post" (all-the-icons-octicon "star" :face 'all-the-icons-green :v-adjust 0.01))
:keys "z"
:file (lambda () (concat
"~/blog/org/posts/"
(format-time-string "%Y_%m_%d_%H-")
(read-string "Post File name :")
".org"))
:prepend nil
:type plain
:template ("#+title: %^{Post title}"
"#+date: <%<%Y-%m-%d>>"
"#+keywords: draft\n\n"))
(,(format "%s\tMeal" (all-the-icons-faicon "apple" :face 'all-the-icons-green :v-adjust 0.01))
:keys "m"
:type entry
:headline "Meals"
:template ("* %<%Y-%m-%d %H:%M>\n- %?\n"))
(,(format "%s\tInsulin injection" (all-the-icons-material "healing" :face 'all-the-icons-yellow :v-adjust 0.01))
:keys "i"
:type table-line
:headline "Insulin Injections"
:template ("| %<%Y-%m-%d | %H:%M> | %^{Units} |"))
(,(format "%s\tGlucose level" (all-the-icons-faicon "heart" :face 'all-the-icons-red :v-adjust 0.01))
:keys "g"
:type table-line
:headline "Glucose Levels"
:template ("| %<%Y-%m-%d | %H:%M> | %^{Glucose level} |"))
(use-package! doct
:commands (doct))
(after! org-capture
;; <<prettify-capture>>
(setq org-capture-templates
(doct `(
<<add-blog-post>>
(,(format "%s\tDiabet" (all-the-icons-faicon "medkit" :face 'all-the-icons-red :v-adjust 0.01))
:keys "d"
:file +org-capture-diabetes-file
:prepend nil
;; :headline (format "%s" (format-time-string "%D"))
:children (
<<diabet-meal>>
<<diabet-injection>>
<<diabet-glucose>>
))
<<add-contact>>
<<books-to-read>>
<<personal-todo>>
<<personal-note>>
<<email>>
(,(format "%s\tInteresting" (all-the-icons-faicon "eye" :face 'all-the-icons-lcyan :v-adjust 0.01))
:keys "i"
:file +org-capture-todo-file
:prepend t
:headline "Interesting"
:type entry
:template ("* [ ] %{desc}%? :%{i-type}:"
"%i %a")
:children (
<<interesting-webpage>>
<<interesting-article>>
<<interesting-information>>
<<interesting-idea>>
))
(,(format "%s\tTasks" (all-the-icons-octicon "inbox" :face 'all-the-icons-yellow :v-adjust 0.01))
:keys "k"
:file +org-capture-todo-file
:prepend t
:headline "Tasks"
:type entry
:template ("* TODO %? %^G%{extra}"
"%i %a")
:children (
<<task-azure>> ; a
<<task-general>>
<<task-with-deadline>>
<<task-scheduled>>
))
(,(format "%s\tProject" (all-the-icons-octicon "repo" :face 'all-the-icons-silver :v-adjust 0.01))
:keys "p"
:prepend t
:type entry
:headline "Inbox"
:template ("* %{time-or-todo} %?"
"%i"
"%a")
:file ""
:custom (:time-or-todo "")
:children (
<<project-local-todo>>
<<project-local-note>>
<<project-local-changelog>>
))
))))
It would also be nice to improve how the capture dialogue looks
(defun org-capture-select-template-prettier (&optional keys)
"Select a capture template, in a prettier way than default
Lisp programs can force the template by setting KEYS to a string."
(let ((org-capture-templates
(or (org-contextualize-keys
(org-capture-upgrade-templates org-capture-templates)
org-capture-templates-contexts)
'(("t" "Task" entry (file+headline "" "Tasks")
"* TODO %?\n %u\n %a")))))
(if keys
(or (assoc keys org-capture-templates)
(error "No capture template referred to by \"%s\" keys" keys))
(org-mks org-capture-templates
"Select a capture template\n━━━━━━━━━━━━━━━━━━━━━━━━━"
"Template key: "
`(("q" ,(concat (all-the-icons-octicon "stop" :face 'all-the-icons-red :v-adjust 0.01) "\tAbort")))))))
(advice-add 'org-capture-select-template :override #'org-capture-select-template-prettier)
(defun org-mks-pretty (table title &optional prompt specials)
"Select a member of an alist with multiple keys. Prettified.
TABLE is the alist which should contain entries where the car is a string.
There should be two types of entries.
1. prefix descriptions like (\"a\" \"Description\")
This indicates that `a' is a prefix key for multi-letter selection, and
that there are entries following with keys like \"ab\", \"ax\"…
2. Select-able members must have more than two elements, with the first
being the string of keys that lead to selecting it, and the second a
short description string of the item.
The command will then make a temporary buffer listing all entries
that can be selected with a single key, and all the single key
prefixes. When you press the key for a single-letter entry, it is selected.
When you press a prefix key, the commands (and maybe further prefixes)
under this key will be shown and offered for selection.
TITLE will be placed over the selection in the temporary buffer,
PROMPT will be used when prompting for a key. SPECIALS is an
alist with (\"key\" \"description\") entries. When one of these
is selected, only the bare key is returned."
(save-window-excursion
(let ((inhibit-quit t)
(buffer (org-switch-to-buffer-other-window "*Org Select*"))
(prompt (or prompt "Select: "))
case-fold-search
current)
(unwind-protect
(catch 'exit
(while t
(setq-local evil-normal-state-cursor (list nil))
(erase-buffer)
(insert title "\n\n")
(let ((des-keys nil)
(allowed-keys '("\C-g"))
(tab-alternatives '("\s" "\t" "\r"))
(cursor-type nil))
;; Populate allowed keys and descriptions keys
;; available with CURRENT selector.
(let ((re (format "\\`%s\\(.\\)\\'"
(if current (regexp-quote current) "")))
(prefix (if current (concat current " ") "")))
(dolist (entry table)
(pcase entry
;; Description.
(`(,(and key (pred (string-match re))) ,desc)
(let ((k (match-string 1 key)))
(push k des-keys)
;; Keys ending in tab, space or RET are equivalent.
(if (member k tab-alternatives)
(push "\t" allowed-keys)
(push k allowed-keys))
(insert (propertize prefix 'face 'font-lock-comment-face) (propertize k 'face 'bold) (propertize "›" 'face 'font-lock-comment-face) " " desc "…" "\n")))
;; Usable entry.
(`(,(and key (pred (string-match re))) ,desc . ,_)
(let ((k (match-string 1 key)))
(insert (propertize prefix 'face 'font-lock-comment-face) (propertize k 'face 'bold) " " desc "\n")
(push k allowed-keys)))
(_ nil))))
;; Insert special entries, if any.
(when specials
(insert "─────────────────────────\n")
(pcase-dolist (`(,key ,description) specials)
(insert (format "%s %s\n" (propertize key 'face '(bold all-the-icons-red)) description))
(push key allowed-keys)))
;; Display UI and let user select an entry or
;; a sub-level prefix.
(goto-char (point-min))
(unless (pos-visible-in-window-p (point-max))
(org-fit-window-to-buffer))
(let ((pressed (org--mks-read-key allowed-keys prompt)))
(setq current (concat current pressed))
(cond
((equal pressed "\C-g") (user-error "Abort"))
;; Selection is a prefix: open a new menu.
((member pressed des-keys))
;; Selection matches an association: return it.
((let ((entry (assoc current table)))
(and entry (throw 'exit entry))))
;; Selection matches a special entry: return the
;; selection prefix.
((assoc current specials) (throw 'exit current))
(t (error "No entry available")))))))
(when buffer (kill-buffer buffer))))))
(advice-add 'org-mks :override #'org-mks-pretty)
The org-capture bin is rather nice, but I’d be nicer with a smaller frame, and no modeline.
(setf (alist-get 'height +org-capture-frame-parameters) 15)
;; (alist-get 'name +org-capture-frame-parameters) "❖ Capture") ;; ATM hardcoded in other places, so changing breaks stuff
(setq +org-capture-fn
(lambda ()
(interactive)
(set-window-parameter nil 'mode-line-format 'none)
(org-capture)))