From 837f9393d950c97f1aea3909676cc3c7842af70f Mon Sep 17 00:00:00 2001 From: jao Date: Thu, 15 Feb 2024 23:54:04 +0000 Subject: jao-org-notes: polishing and jao-org-notes-open-tags --- init.el | 1 + lib/doc/jao-org-notes.el | 92 +++++++++++++++++++++++------------------------- 2 files changed, 45 insertions(+), 48 deletions(-) diff --git a/init.el b/init.el index f29fb75..57c7a7b 100644 --- a/init.el +++ b/init.el @@ -3216,6 +3216,7 @@ [["Notes" ("n" "create new note" jao-org-notes-create) ("/" "open note" jao-org-notes-open) + ("\\" "open note by tags" jao-org-notes-open-tags) ("d" "go to doc" jao-select-pdf :if display-graphic-p) ("d" "search docs" jao-recoll-consult-docs :if-not display-graphic-p) ("D" "open doc" jao-open-doc)] diff --git a/lib/doc/jao-org-notes.el b/lib/doc/jao-org-notes.el index b7700ec..05481b7 100644 --- a/lib/doc/jao-org-notes.el +++ b/lib/doc/jao-org-notes.el @@ -1,6 +1,6 @@ ;;; jao-org-notes.el --- A simple system for org note taking -*- lexical-binding: t; -*- -;; Copyright (C) 2020, 2021, 2022 jao +;; Copyright (C) 2020, 2021, 2022, 2024 jao ;; Author: jao ;; Keywords: tools @@ -26,30 +26,42 @@ ;;; Code: (require 'org) (require 'consult) +(require 'jao-shell) (defvar jao-org-notes-dir (expand-file-name "notes" org-directory)) -(defun jao-org-notes--rg (str) +(defun jao-org-notes--title-or-tags (str) + (let ((ts (split-string str "[:,]+" t))) + (format "^#.(title: .*%s|tags:.*(%s:))" str (mapconcat #'identity ts ":|")))) + +(defun jao-org-notes--rg-cmd (rgx &rest args) `("rg" "--null" "--line-buffered" "--color=never" "--max-columns=250" - "--no-heading" "--line-number" "--smart-case" "." "-e" - ,(format "^(#.(title|tags): .*)%s" str))) + "--no-heading" "--smart-case" ,@args "." "-e" ,rgx)) + +(defun jao-org-notes--rg-title-or-tags (str) + (jao-org-notes--rg-cmd (jao-org-notes--title-or-tags str) "-m" "2")) (defun jao-org-notes--clean-match (m) (cons (format "%s %s" (replace-regexp-in-string "^\\./" "" (car m)) - (replace-regexp-in-string "[0-9]+:#\\+\\(title\\|tags\\):" + (replace-regexp-in-string "#\\+\\(title\\|tags\\):" " (\\1)" (cadr m))) (expand-file-name (car m) default-directory))) (defun jao-org-notes--matches (lines) (mapcar (lambda (l) (jao-org-notes--clean-match (split-string l "\0" t))) lines)) +(defun jao-org-notes--grep-rx (rx) + (let ((default-directory jao-org-notes-dir)) + (jao-org-notes--matches + (apply #'jao-shell-cmd-lines (jao-org-notes--rg-cmd rx))))) + (defvar jao-org-notes--grep-history nil) -(defun jao-org--grep (prompt &optional cat no-req) +(defun jao-org-notes--consult-rg (prompt &optional cat no-req) (let ((default-directory (expand-file-name (or cat "") jao-org-notes-dir))) (consult--read - (consult--async-command #'jao-org-notes--rg + (consult--async-command #'jao-org-notes--rg-title-or-tags (consult--async-transform jao-org-notes--matches)) :prompt prompt :initial (consult--async-split-initial "") @@ -66,12 +78,11 @@ (defun jao-org-notes--cat () (let* ((cat (completing-read "Top level category: " (jao-org-notes-cats)))) (cond ((file-exists-p (expand-file-name cat jao-org-notes-dir)) cat) - ((yes-or-no-p "New category, create?") cat) - (t (jao-roam--cat))))) + ((yes-or-no-p "New category, create?") cat)))) (defun jao-org-notes--insert-title () (let* ((cat (jao-org-notes--cat)) - (title (file-name-base (jao-org--grep "Title: " cat t))) + (title (file-name-base (jao-org-notes--consult-rg "Title: " cat t))) (title (replace-regexp-in-string "^#" "" title))) (when (not (string-empty-p title)) (let* ((base (replace-regexp-in-string " +" "-" (downcase title))) @@ -83,30 +94,13 @@ (insert "#+title: " title "\n") t))))) -(defvar jao-org-notes--tags nil) -(defvar jao-org-notes-tags-cache-file "~/.emacs.d/cache/tags.eld") - -(defun jao-org-notes--save-tags () - (with-current-buffer (find-file-noselect jao-org-notes-tags-cache-file) - (delete-region (point-min) (point-max)) - (print jao-org-notes--tags (current-buffer)) - (let ((message-log-max nil) - (inhibit-message t)) - (save-buffer)))) - -(defun jao-org-notes--read-tags-cache () - (let ((b (find-file-noselect jao-org-notes-tags-cache-file))) - (with-current-buffer b (goto-char (point-min))) - (setq jao-org-notes--tags (read b)))) +(persist-defvar jao-org-notes--tags nil "Tags used so far in notes.") +(defvar jao-org-notes--tag-history nil) (defun jao-org-notes--read-tags () - (unless jao-org-notes--tags (jao-org-notes--read-tags-cache)) - (let* ((tags (completing-read-multiple "Tags: " jao-org-notes--tags)) - (new-tags (seq-difference tags jao-org-notes--tags))) - (when new-tags - (setq jao-org--notes-tags - (sort (append new-tags jao-org-notes--tags) #'string<)) - (jao-org-notes--save-tags)) + (let* ((tags (completing-read-multiple "Tags: " jao-org-notes--tags nil nil nil + 'jao-org-notes--tag-history))) + (setq jao-org-notes--tags (seq-union jao-org-notes--tags tags #'string=)) tags)) (defun jao-org-notes--insert-tags () @@ -115,21 +109,31 @@ ":\n")) (defun jao-org-notes--insert-date () - (insert "#+date: ") - (org-insert-time-stamp (current-time)) - (insert "\n")) + (org-insert-time-stamp (current-time) t t "#+date: " "\n")) (defun jao-org-notes--template (k) - `(,k "Note" plain (file jao-org-notes-create) - "\n- %a\n %i" :jump-to-captured t)) + `(,k "Note" plain (file jao-org-notes-create) "\n- %a\n %i" :jump-to-captured t)) ;;;###autoload (defun jao-org-notes-open () "Search for a note file, matching tags and titles with completion." (interactive) - (when-let (f (jao-org--grep "Search notes: ")) + (when-let (f (jao-org-notes--consult-rg "Search notes: ")) (find-file f))) +(defun jao-org-notes-open-tags () + "Search for a note file, matching all tags with completion." + (interactive) + (let* ((tags (jao-org-notes--read-tags)) + (fn (lambda () + (prog1 (jao-org-notes--grep-rx (format "^#.tags:.*:%s:" (car tags))) + (setq tags (cdr tags))))) + (res (funcall fn))) + (while (and res tags) (setq res (seq-intersection res (funcall fn)))) + (unless res (user-error "No notes found")) + (when-let (f (completing-read "Select file: " (mapcar #'car res))) + (find-file (cdr (assoc f res)))))) + ;;;###autoload (defun jao-org-notes-create () "Create a new note file, matching tags and titles with completion." @@ -153,19 +157,11 @@ (d (file-name-as-directory d))) (expand-file-name (concat d bn ".org") jao-org-notes-dir))))) -;;;###autoload -(defun jao-org-notes-grep () - "Perform a grep search on all org notes body, via consult-ripgrep." - (interactive) - (consult-ripgrep jao-org-notes-dir initial)) - -(make-obsolete 'jao-org-notes-grep 'consult-recoll "2022-08-22") - ;;;###autoload (defun jao-org-notes-backlinks () "Show a list of note files linking to the current one." (interactive) - (jao-org--grep (concat "\\[\\[file:\\(.*/\\)?" (buffer-name)))) + (jao-org-notes--grep-rx (concat "\\[\\[file:\\(.*/\\)?" (buffer-name)))) ;;;###autoload (defun jao-org-notes-insert-tags () @@ -177,7 +173,7 @@ (defun jao-org-notes-insert-link () "Select a note file (with completion) and insert a link to it." (interactive) - (when-let (f (jao-org--grep "Notes file: ")) + (when-let (f (jao-org-notes--consult-rg "Notes file: ")) (let ((rel-path (file-relative-name f default-directory)) (title (with-current-buffer (find-file-noselect f) (save-excursion -- cgit v1.2.3