;;; 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 ;; Maintainer: Yann Esposito ;; Created: 28 Jul 2019 ;; Version: 0.1 ;; Keywords: org ;; Homepage: https://gitlab.esy.fun/yogsototh/org-auto-id ;; Package-Requires: ((emacs "24.4") org) ;; 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) (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