2019-07-30 21:23:01 +00:00
|
|
|
;;; org-auto-id.el --- Add custom id to all org entries, useful for html exporting. -*- lexical-binding: t; -*-
|
|
|
|
|
|
|
|
;; Copyright (C) 2019 Yann Esposito
|
|
|
|
|
|
|
|
;; Author: Yann Esposito <yann@esposito.host>
|
|
|
|
;; Maintainer: Yann Esposito <yann@esposito.host>
|
|
|
|
;; Created: 28 Jul 2019
|
|
|
|
;; Version: 0.1
|
|
|
|
;; Keywords: org
|
|
|
|
;; Homepage: https://gitlab.esy.fun/yogsototh/org-auto-id
|
2019-07-31 10:53:17 +00:00
|
|
|
;; Package-Requires: ((emacs "24.4") org)
|
2019-07-30 21:23:01 +00:00
|
|
|
|
|
|
|
;; This file is not part of GNU Emacs
|
|
|
|
|
|
|
|
;;; Commentary:
|
|
|
|
;; Will warn you if you have duplicate CUSTOM_ID.
|
|
|
|
|
|
|
|
;;; License:
|
|
|
|
|
|
|
|
;; Licensed under the same terms as Emacs.
|
|
|
|
|
|
|
|
;;; Code:
|
|
|
|
|
|
|
|
(require 'org)
|
|
|
|
|
2019-07-31 11:01:15 +00:00
|
|
|
(with-eval-after-load 'org
|
2019-07-30 21:23:01 +00:00
|
|
|
(defvar org-auto-id--all-ids '()
|
|
|
|
"List as set of all ids of the current org-file")
|
|
|
|
|
|
|
|
(defun org-auto-id-format (title)
|
|
|
|
"Generate a new org-id using TITLE."
|
|
|
|
(concat (downcase (replace-regexp-in-string "\\W" "-" title))))
|
|
|
|
|
|
|
|
(defun org-auto-id-add-id (id &optional new?)
|
|
|
|
"Add the id to the set of existing ids, warn if not a generation of new id."
|
|
|
|
(if (member id org-auto-id--all-ids)
|
|
|
|
(progn (unless new?
|
|
|
|
(message "Duplicate CUSTOM_ID found: %s" id))
|
|
|
|
(org-auto-id-add-id (format "%s-%04x" id (random (expt 16 4))) new?))
|
|
|
|
(progn
|
|
|
|
(add-to-list 'org-auto-id--all-ids id)
|
|
|
|
id)))
|
|
|
|
|
|
|
|
(defun org-auto-id-custom-id-get (&optional pom create)
|
|
|
|
"Get the CUSTOM_ID property of the entry at point-or-marker POM.
|
|
|
|
If POM is nil, refer to the entry at point.
|
|
|
|
If the entry does not have an CUSTOM_ID, the function returns nil.
|
|
|
|
However, when CREATE is non nil, create a CUSTOM_ID if none is present already.
|
|
|
|
In any case, the CUSTOM_ID of the entry is returned."
|
|
|
|
(interactive)
|
|
|
|
(org-with-point-at pom
|
|
|
|
(let ((id (org-entry-get nil "CUSTOM_ID")))
|
|
|
|
(cond
|
|
|
|
((and id (stringp id) (string-match "\\S-" id))
|
|
|
|
(progn
|
|
|
|
(org-auto-id-add-id id)
|
|
|
|
id))
|
|
|
|
(create
|
|
|
|
(let ((id (org-auto-id-format (org-entry-get nil "ITEM"))))
|
|
|
|
(let ((new-id (org-auto-id-add-id id t)))
|
|
|
|
(org-entry-put pom "CUSTOM_ID" new-id)
|
|
|
|
new-id)))))))
|
|
|
|
|
|
|
|
(defun org-auto-id-add-ids-to-headlines-in-file ()
|
|
|
|
"Add CUSTOM_ID properties to all headlines.
|
|
|
|
In the current file, all headlines which do not already have a CUSTOM_ID.
|
|
|
|
Only adds ids if the `auto-id' option is set to `t' in the file somewhere.
|
|
|
|
ie, #+OPTIONS: auto-id:t"
|
|
|
|
(interactive)
|
|
|
|
(save-excursion
|
|
|
|
(widen)
|
|
|
|
(goto-char (point-min))
|
|
|
|
(let ((add-suffix (re-search-forward "^#\\+OPTIONS:.* auto-id-add-suffix:t" (point-max) t)))
|
|
|
|
(when (re-search-forward "^#\\+OPTIONS:.* auto-id:t" (point-max) t)
|
|
|
|
(setq org-auto-id--all-ids '())
|
|
|
|
(org-map-entries (lambda () (org-auto-id-custom-id-get (point) 'create)))))))
|
|
|
|
|
|
|
|
(add-hook 'org-mode-hook
|
|
|
|
(lambda ()
|
|
|
|
(add-hook 'before-save-hook
|
|
|
|
(lambda ()
|
|
|
|
(when (and (eq major-mode 'org-mode)
|
|
|
|
(eq buffer-read-only nil))
|
|
|
|
(org-auto-id-add-ids-to-headlines-in-file)))))))
|
|
|
|
|
|
|
|
(provide 'org-auto-id)
|
|
|
|
|
|
|
|
;;; org-auto-id.el ends here
|