feat[agenda] Swapped vulpea for ripgrep
I exchanged the bulky vulpea source code for ripgrep. It's faster, and much easier to understand.
This commit is contained in:
parent
83eddd3c9f
commit
17d5fdf03b
260
config.org
260
config.org
@ -143,6 +143,34 @@ Because I sometimes use Fish or another shell, it's good to make sure bash is ru
|
|||||||
(age-file-enable))
|
(age-file-enable))
|
||||||
#+end_src
|
#+end_src
|
||||||
|
|
||||||
|
*** Preprocessor
|
||||||
|
:PROPERTIES:
|
||||||
|
:CUSTOM_ID: ripgrep-pre
|
||||||
|
:END:
|
||||||
|
This preprocessor script allows me to use Ripgrep with Age to filter agenda files.
|
||||||
|
You can see the configuration for that in [[#agenda-efficient][this section]].
|
||||||
|
|
||||||
|
|
||||||
|
#+begin_src zsh :tangle "/home/user/age-preprocessor.zsh"
|
||||||
|
#!/usr/bin/env zsh
|
||||||
|
|
||||||
|
case "$1" in
|
||||||
|
*.age)
|
||||||
|
# The -s flag ensures that the file is non-empty.
|
||||||
|
if [ -s "$1" ]; then
|
||||||
|
exec /usr/bin/age --decrypt -i ~/.age/personal $1
|
||||||
|
else
|
||||||
|
exec cat
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
** Org-mode security settings
|
** Org-mode security settings
|
||||||
These mostly concern limiting evaluation of code-blocks without confirmation.
|
These mostly concern limiting evaluation of code-blocks without confirmation.
|
||||||
The final two lines concern local variables, which may try to evaluate code.
|
The final two lines concern local variables, which may try to evaluate code.
|
||||||
@ -162,232 +190,48 @@ Emacs has better default values now, so it will ask to evaluate local variables.
|
|||||||
#+end_src
|
#+end_src
|
||||||
* Org-mode for a great todo list
|
* Org-mode for a great todo list
|
||||||
** Making the Agenda features more efficient
|
** Making the Agenda features more efficient
|
||||||
|
Using ripgrep we can automatically narrow org-agenda files.
|
||||||
|
|
||||||
#+begin_src emacs-lisp :tangle no
|
*** Finding Files with Ripgrep
|
||||||
(dolist (file (org-roam-list-files))
|
:PROPERTIES:
|
||||||
(message "processing %s" file)
|
:CUSTOM_ID: agenda-efficient
|
||||||
(with-current-buffer (or (find-buffer-visiting file)
|
:END:
|
||||||
(find-file-noselect file))
|
This piece of code will allow us to capture all the agenda files using the preprocessor we wrote [[#ripgrep-pre][here]]
|
||||||
(vulpea-project-update-tag)
|
#+name: search-agenda-files
|
||||||
(save-buffer)))
|
#+begin_src sh :exports code :tangle no
|
||||||
|
rg --type-add 'aorg:*.org.age' \
|
||||||
|
-torg -taorg \
|
||||||
|
--pre ~/age-preprocessor.zsh --pre-glob '*.age' -l TODO /home/user/org
|
||||||
#+end_src
|
#+end_src
|
||||||
|
|
||||||
#+RESULTS:
|
Now, of course, this code is not useful as it is--after all, we can't tangle a ~.sh~ script into [[file:config.el]].
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Only include files with the hastodos tag.
|
|
||||||
This section is contributed from [[https://gist.github.com/d12frosted/a60e8ccb9aceba031af243dff0d19b2e][d12frosted]] and use his vulpea.el package's functions.
|
|
||||||
I ripped out the essentials because I don't want all the other stuff in that package.
|
|
||||||
|
|
||||||
|
|
||||||
|
*** Adding results to agenda files
|
||||||
|
The rubber hits the road here.
|
||||||
|
I'll call that shell command to set the agenda files correctly.
|
||||||
#+begin_src emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(after! org-roam
|
(defun set-org-agenda-files-ripgrep ()
|
||||||
(defun vulpea-project-p ()
|
(setq org-agenda-files (split-string (shell-command-to-string "rg --type-add \'aorg:*.org.age\' -torg -taorg --pre ~/age-preprocessor.zsh --pre-glob \'*.age\' -l TODO /home/user/org "))))
|
||||||
"Return non-nil if current buffer has any todo entry.
|
|
||||||
TODO entries marked as done are ignored, meaning the this
|
|
||||||
function returns nil if current buffer contains only completed
|
|
||||||
tasks."
|
|
||||||
(seq-find ; (3)
|
|
||||||
(lambda (type)
|
|
||||||
(eq type 'todo))
|
|
||||||
(org-element-map ; (2)
|
|
||||||
(org-element-parse-buffer 'headline) ; (1)
|
|
||||||
'headline
|
|
||||||
(lambda (h)
|
|
||||||
(org-element-property :todo-type h)))))
|
|
||||||
|
|
||||||
(defun vulpea-project-update-tag ()
|
|
||||||
"Update PROJECT tag in the current buffer."
|
|
||||||
(when (and (not (active-minibuffer-window))
|
|
||||||
(vulpea-buffer-p))
|
|
||||||
(save-excursion
|
|
||||||
(goto-char (point-min))
|
|
||||||
(let* ((tags (vulpea-buffer-tags-get))
|
|
||||||
(original-tags tags))
|
|
||||||
(if (vulpea-project-p)
|
|
||||||
(setq tags (cons "hastodos" tags))
|
|
||||||
(setq tags (remove "hastodos" tags)))
|
|
||||||
|
|
||||||
;; cleanup duplicates
|
|
||||||
(setq tags (seq-uniq tags))
|
|
||||||
|
|
||||||
;; update tags if changed
|
|
||||||
(when (or (seq-difference tags original-tags)
|
|
||||||
(seq-difference original-tags tags))
|
|
||||||
(apply #'vulpea-buffer-tags-set tags))))))
|
|
||||||
|
|
||||||
(defun vulpea-buffer-p ()
|
|
||||||
"Return non-nil if the currently visited buffer is a note."
|
|
||||||
(and buffer-file-name
|
|
||||||
(string-prefix-p
|
|
||||||
(expand-file-name (file-name-as-directory org-roam-directory))
|
|
||||||
(file-name-directory buffer-file-name))))
|
|
||||||
|
|
||||||
(defun vulpea-project-files ()
|
|
||||||
"Return a list of note files containing 'hastodos' tag." ;
|
|
||||||
(seq-uniq
|
|
||||||
(seq-map
|
|
||||||
#'car
|
|
||||||
(org-roam-db-query
|
|
||||||
[:select [nodes:file]
|
|
||||||
:from tags
|
|
||||||
:left-join nodes
|
|
||||||
:on (= tags:node-id nodes:id)
|
|
||||||
:where (like tag (quote "%\"hastodos\"%"))]))))
|
|
||||||
|
|
||||||
(defun vulpea-agenda-files-update (&rest _)
|
|
||||||
"Update the value of `org-agenda-files'."
|
|
||||||
(setq org-agenda-files (vulpea-project-files)))
|
|
||||||
|
|
||||||
(add-hook 'find-file-hook #'vulpea-project-update-tag)
|
|
||||||
(add-hook 'before-save-hook #'vulpea-project-update-tag)
|
|
||||||
|
|
||||||
(advice-add 'org-agenda :before #'vulpea-agenda-files-update)
|
|
||||||
(advice-add 'org-todo-list :before #'vulpea-agenda-files-update)
|
|
||||||
|
|
||||||
;; functions borrowed from `vulpea' library
|
|
||||||
;; https://github.com/d12frosted/vulpea/blob/6a735c34f1f64e1f70da77989e9ce8da7864e5ff/vulpea-buffer.el
|
|
||||||
|
|
||||||
(defun vulpea-buffer-tags-get ()
|
|
||||||
"Return filetags value in current buffer."
|
|
||||||
(vulpea-buffer-prop-get-list "filetags" "[ :]"))
|
|
||||||
|
|
||||||
(defun vulpea-buffer-tags-set (&rest tags)
|
|
||||||
"Set TAGS in current buffer.
|
|
||||||
If filetags value is already set, replace it."
|
|
||||||
(if tags
|
|
||||||
(vulpea-buffer-prop-set
|
|
||||||
"filetags" (concat ":" (string-join tags ":") ":"))
|
|
||||||
(vulpea-buffer-prop-remove "filetags")))
|
|
||||||
|
|
||||||
(defun vulpea-buffer-tags-add (tag)
|
|
||||||
"Add a TAG to filetags in current buffer."
|
|
||||||
(let* ((tags (vulpea-buffer-tags-get))
|
|
||||||
(tags (append tags (list tag))))
|
|
||||||
(apply #'vulpea-buffer-tags-set tags)))
|
|
||||||
|
|
||||||
(defun vulpea-buffer-tags-remove (tag)
|
|
||||||
"Remove a TAG from filetags in current buffer."
|
|
||||||
(let* ((tags (vulpea-buffer-tags-get))
|
|
||||||
(tags (delete tag tags)))
|
|
||||||
(apply #'vulpea-buffer-tags-set tags)))
|
|
||||||
|
|
||||||
(defun vulpea-buffer-prop-set (name value)
|
|
||||||
"Set a file property called NAME to VALUE in buffer file.
|
|
||||||
If the property is already set, replace its value."
|
|
||||||
(setq name (downcase name))
|
|
||||||
(org-with-point-at 1
|
|
||||||
(let ((case-fold-search t))
|
|
||||||
(if (re-search-forward (concat "^#\\+" name ":\\(.*\\)")
|
|
||||||
(point-max) t)
|
|
||||||
(replace-match (concat "#+" name ": " value) 'fixedcase)
|
|
||||||
(while (and (not (eobp))
|
|
||||||
(looking-at "^[#:]"))
|
|
||||||
(if (save-excursion (end-of-line) (eobp))
|
|
||||||
(progn
|
|
||||||
(end-of-line)
|
|
||||||
(insert "\n"))
|
|
||||||
(forward-line)
|
|
||||||
(beginning-of-line)))
|
|
||||||
(insert "#+" name ": " value "\n")))))
|
|
||||||
|
|
||||||
(defun vulpea-buffer-prop-set-list (name values &optional separators)
|
|
||||||
"Set a file property called NAME to VALUES in current buffer.
|
|
||||||
VALUES are quoted and combined into single string using
|
|
||||||
`combine-and-quote-strings'.
|
|
||||||
If SEPARATORS is non-nil, it should be a regular expression
|
|
||||||
matching text that separates, but is not part of, the substrings.
|
|
||||||
If nil it defaults to `split-string-default-separators', normally
|
|
||||||
\"[ \f\t\n\r\v]+\", and OMIT-NULLS is forced to t.
|
|
||||||
If the property is already set, replace its value."
|
|
||||||
(vulpea-buffer-prop-set
|
|
||||||
name (combine-and-quote-strings values separators)))
|
|
||||||
|
|
||||||
(defun vulpea-buffer-prop-get (name)
|
|
||||||
"Get a buffer property called NAME as a string."
|
|
||||||
(org-with-point-at 1
|
|
||||||
(when (re-search-forward (concat "^#\\+" name ": \\(.*\\)")
|
|
||||||
(point-max) t)
|
|
||||||
(buffer-substring-no-properties
|
|
||||||
(match-beginning 1)
|
|
||||||
(match-end 1)))))
|
|
||||||
|
|
||||||
(defun vulpea-buffer-prop-get-list (name &optional separators)
|
|
||||||
"Get a buffer property NAME as a list using SEPARATORS.
|
|
||||||
If SEPARATORS is non-nil, it should be a regular expression
|
|
||||||
matching text that separates, but is not part of, the substrings.
|
|
||||||
If nil it defaults to `split-string-default-separators', normally
|
|
||||||
\"[ \f\t\n\r\v]+\", and OMIT-NULLS is forced to t."
|
|
||||||
(let ((value (vulpea-buffer-prop-get name)))
|
|
||||||
(when (and value (not (string-empty-p value)))
|
|
||||||
(split-string-and-unquote value separators))))
|
|
||||||
|
|
||||||
(defun vulpea-buffer-prop-remove (name)
|
|
||||||
"Remove a buffer property called NAME."
|
|
||||||
(org-with-point-at 1
|
|
||||||
(when (re-search-forward (concat "\\(^#\\+" name ":.*\n?\\)")
|
|
||||||
(point-max) t)
|
|
||||||
(replace-match ""))))
|
|
||||||
|
|
||||||
(setq org-agenda-files (vulpea-project-files)))
|
|
||||||
#+end_src
|
#+end_src
|
||||||
|
|
||||||
|
And then we want to call this before building the agenda:
|
||||||
|
#+begin_src emacs-lisp
|
||||||
|
(add-hook 'org-agenda-mode-hook 'set-org-agenda-files-ripgrep)
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
** Basic settings
|
** Basic settings
|
||||||
#+begin_src emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(setq org-log-done 'time)
|
(setq org-log-done 'time)
|
||||||
(after! org-mode
|
(after! org
|
||||||
(setq org-log-done 'time)
|
(setq org-log-done 'time)
|
||||||
(setq org-archive-location "~/org/archive.org")
|
(setq org-archive-location "~/org/archive.org")
|
||||||
(add-to-list 'org-tags-exclude-from-inheritance "hastodos")
|
|
||||||
(setq org-hide-emphasis-markers nil))
|
(setq org-hide-emphasis-markers nil))
|
||||||
(setq org-directory "~/org/")
|
(setq org-directory "~/org/")
|
||||||
(setq org-roam-directory org-directory)
|
(setq org-roam-directory org-directory)
|
||||||
#+end_src
|
#+end_src
|
||||||
|
|
||||||
** Appearances
|
** Appearances
|
||||||
*** Deprecated: TODO Keywords
|
|
||||||
I like to have a few different todo keywords for different sorts of activities.
|
|
||||||
Purchasing todos:
|
|
||||||
#+begin_src emacs-lisp :tangle no
|
|
||||||
|
|
||||||
(setq org-todo-keywords
|
|
||||||
'((sequence "PROJ(p)" "|" "COMPLETE")
|
|
||||||
(type "TICKLE")
|
|
||||||
(type "DELE")
|
|
||||||
(type "WAIT")
|
|
||||||
(sequence "TODO(t)" "|" "DONE")
|
|
||||||
(sequence "DELEGATED" "VERIFY" "|" "DONE")
|
|
||||||
(sequence "BUY(b)" "|" "BOUGHT")
|
|
||||||
))
|
|
||||||
(setq org-todo-keyword-faces
|
|
||||||
'(("TODO" . "salmon1")
|
|
||||||
("START" . "spring green" )
|
|
||||||
("DELE" . "gold")
|
|
||||||
("TICKLE" . "magenta")
|
|
||||||
("WAIT" . "gold")
|
|
||||||
("PROJ" . "deep sky blue")))
|
|
||||||
#+end_src
|
|
||||||
|
|
||||||
These settings aren't very useful for me, as I like default colors and keywords.
|
|
||||||
*** Deprecated: Settings for org-modern
|
|
||||||
|
|
||||||
#+begin_src emacs-lisp :tangle no
|
|
||||||
(setq org-modern-todo-faces
|
|
||||||
'(("START" :background "spring green" :foreground "black")
|
|
||||||
("DELE" :background "gold" :foreground "black")
|
|
||||||
("WAIT" :background "gold" :foreground "black")
|
|
||||||
("PROJ" :background "deep sky blue" :foreground "black")
|
|
||||||
("TICKLE" :background "magenta" :foreground "black")))
|
|
||||||
|
|
||||||
(setq org-modern-priority-faces
|
|
||||||
'((?A :background "salmon1" :foreground "black")
|
|
||||||
(?B :background "gold" :foreground "black")
|
|
||||||
(?C :background "spring green" :foreground "black")))
|
|
||||||
#+end_src
|
|
||||||
|
|
||||||
I currently have org-modern stripped out of my config.
|
|
||||||
I probably won't need this again, but in case I do I want all my preferences to be there.
|
|
||||||
*** Images Preferences
|
*** Images Preferences
|
||||||
We want to show images when loading a file, and also after evaluating code blocks.
|
We want to show images when loading a file, and also after evaluating code blocks.
|
||||||
#+begin_src emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
|
Loading…
Reference in New Issue
Block a user