syscfg/emacs/module/module-denote-index.el

91 lines
3.4 KiB
EmacsLisp

;;; module-denote-index.el -- index and metadata for denote notes
;;;
;;; Commentary:
;;;
;;; Provides a mechanism for maintaining an index of denote notes with
;;; useful metadata to facilitate search.
;;;
;;; Code:
(require 'module-denote)
(with-eval-after-load 'denote
(defvar my/denote-metadata-index-file (concat denote-directory "../denote-metadata.org")
"Path to the metadata index file.")
(defun my/extract-date-from-filename (file)
"Extract date from FILE name. Assumes first 8 characters are YYYYMMDD."
(substring (file-name-nondirectory file) 0 8))
(defun my/format-date (date-string)
"Format DATE-STRING (YYYYMMDD) as YYYY-MM-DD."
(format "%s-%s-%s"
(substring date-string 0 4)
(substring date-string 4 6)
(substring date-string 6 8)))
(defun my/extract-summary (file)
"Extract summary from FILE."
(with-temp-buffer
(insert-file-contents file)
(goto-char (point-min))
(when (re-search-forward "^\\* Summary$" nil t)
(forward-line)
(let ((start (point)))
(if (re-search-forward "^\\*" nil t)
(string-trim (buffer-substring-no-properties start (line-beginning-position)))
(string-trim (buffer-substring-no-properties start (point-max))))))))
(defun my/update-denote-metadata-index ()
"Update the metadata index for Denote notes in Org format."
(interactive)
(with-temp-file my/denote-metadata-index-file
(insert "#+TITLE: Denote Metadata Index\n")
(insert "#+AUTHOR: Your Name\n")
(insert "#+DATE: " (format-time-string "%Y-%m-%d") "\n\n")
(dolist (file (directory-files-recursively denote-directory "\\.org$"))
(let ((file-contents (with-temp-buffer
(insert-file-contents file)
(buffer-string))))
(with-temp-buffer
(insert file-contents)
(goto-char (point-min))
(when (re-search-forward "^#\\+title: \\(.+\\)$" nil t)
(let* ((title (string-trim (match-string 1)))
(keywords (denote-extract-keywords-from-path file))
(date-string (my/extract-date-from-filename file))
(formatted-date (my/format-date date-string))
(is-journal (and (listp keywords) (member "journal" keywords)))
(summary (if is-journal
(format "Journal entry for [%s]" formatted-date)
(my/extract-summary file))))
(with-current-buffer (find-file-noselect my/denote-metadata-index-file)
(goto-char (point-max))
(insert (format "* [[file:%s][%s]]\n" file title))
(insert " :PROPERTIES:\n")
(insert (format " :KEYWORDS: %s\n" keywords))
(insert (format " :DATE: [%s]\n" formatted-date))
(insert " :END:\n\n")
(insert (if summary
summary
"No summary provided."))
(unless (string-suffix-p "\n\n" (or summary ""))
(insert "\n\n"))))))))))
(defun my/search-denote-notes ()
"Use consult-ripgrep to search Denote notes in denote-directory."
(interactive)
(let ((consult-ripgrep-args
"rg --null --ignore-case --type org --line-buffered --color=never --max-columns=500 --no-heading --line-number"))
(if (file-directory-p denote-directory)
(consult-ripgrep denote-directory)
(message "Denote directory not found: %s" denote-directory))))
(global-set-key (kbd "C-x n /") #'my/search-denote-notes))
(provide 'module-denote-index)
;;; module-denote-index.el ends here