Skip to content

Instantly share code, notes, and snippets.

@amno1
Created April 30, 2021 17:49
Show Gist options
  • Save amno1/b51897bb65e4d5fe8800e525c9536d1b to your computer and use it in GitHub Desktop.
Save amno1/b51897bb65e4d5fe8800e525c9536d1b to your computer and use it in GitHub Desktop.
Programmatically add TODO labels in org-mode
(defun org-todo-per-file-keywords (kwds)
"Sets per file TODO labels. Takes as argument a list of strings to be used as
labels."
(let (alist)
(push "TODO" alist)
(dolist (kwd kwds)
(push kwd alist))
(setq alist (list (nreverse alist)))
;; TODO keywords.
(setq-local org-todo-kwd-alist nil)
(setq-local org-todo-key-alist nil)
(setq-local org-todo-key-trigger nil)
(setq-local org-todo-keywords-1 nil)
(setq-local org-done-keywords nil)
(setq-local org-todo-heads nil)
(setq-local org-todo-sets nil)
(setq-local org-todo-log-states nil)
(let ((todo-sequences alist))
(dolist (sequence todo-sequences)
(let* ((sequence (or (run-hook-with-args-until-success
'org-todo-setup-filter-hook sequence)
sequence))
(sequence-type (car sequence))
(keywords (cdr sequence))
(sep (member "|" keywords))
names alist)
(dolist (k (remove "|" keywords))
(unless (string-match "^\\(.*?\\)\\(?:(\\([^!@/]\\)?.*?)\\)?$"
k)
(error "Invalid TODO keyword %s" k))
(let ((name (match-string 1 k))
(key (match-string 2 k))
(log (org-extract-log-state-settings k)))
(push name names)
(push (cons name (and key (string-to-char key))) alist)
(when log (push log org-todo-log-states))))
(let* ((names (nreverse names))
(done (if sep (org-remove-keyword-keys (cdr sep))
(last names)))
(head (car names))
(tail (list sequence-type head (car done) (org-last done))))
(add-to-list 'org-todo-heads head 'append)
(push names org-todo-sets)
(setq org-done-keywords (append org-done-keywords done nil))
(setq org-todo-keywords-1 (append org-todo-keywords-1 names nil))
(setq org-todo-key-alist
(append org-todo-key-alist
(and alist
(append '((:startgroup))
(nreverse alist)
'((:endgroup))))))
(dolist (k names) (push (cons k tail) org-todo-kwd-alist))))))
(setq org-todo-sets (nreverse org-todo-sets)
org-todo-kwd-alist (nreverse org-todo-kwd-alist)
org-todo-key-trigger (delq nil (mapcar #'cdr org-todo-key-alist))
org-todo-key-alist (org-assign-fast-keys org-todo-key-alist))
;; Compute the regular expressions and other local variables.
;; Using `org-outline-regexp-bol' would complicate them much,
;; because of the fixed white space at the end of that string.
(unless org-done-keywords
(setq org-done-keywords
(and org-todo-keywords-1 (last org-todo-keywords-1))))
(setq org-not-done-keywords
(org-delete-all org-done-keywords
(copy-sequence org-todo-keywords-1))
org-todo-regexp (regexp-opt org-todo-keywords-1 t)
org-not-done-regexp (regexp-opt org-not-done-keywords t)
org-not-done-heading-regexp
(format org-heading-keyword-regexp-format org-not-done-regexp)
org-todo-line-regexp
(format org-heading-keyword-maybe-regexp-format org-todo-regexp)
org-complex-heading-regexp
(concat "^\\(\\*+\\)"
"\\(?: +" org-todo-regexp "\\)?"
"\\(?: +\\(\\[#.\\]\\)\\)?"
"\\(?: +\\(.*?\\)\\)??"
"\\(?:[ \t]+\\(:[[:alnum:]_@#%:]+:\\)\\)?"
"[ \t]*$")
org-complex-heading-regexp-format
(concat "^\\(\\*+\\)"
"\\(?: +" org-todo-regexp "\\)?"
"\\(?: +\\(\\[#.\\]\\)\\)?"
"\\(?: +"
;; Stats cookies can be stuck to body.
"\\(?:\\[[0-9%%/]+\\] *\\)*"
"\\(%s\\)"
"\\(?: *\\[[0-9%%/]+\\]\\)*"
"\\)"
"\\(?:[ \t]+\\(:[[:alnum:]_@#%%:]+:\\)\\)?"
"[ \t]*$")
org-todo-line-tags-regexp
(concat "^\\(\\*+\\)"
"\\(?: +" org-todo-regexp "\\)?"
"\\(?: +\\(.*?\\)\\)??"
"\\(?:[ \t]+\\(:[[:alnum:]:_@#%]+:\\)\\)?"
"[ \t]*$"))
(org-compute-latex-and-related-regexp)))
;; example of usage
(org-todo-per-file-keywords '("label 1" "label 2" "something" "last one"))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment