system-manager-wakasu
  1;;; config-org.el --- -*- lexical-binding: t; -*-
  2;;; Commentary:
  3;;; Configuration of orgmode.
  4;;; Code:
  5
  6(use-package s)
  7(use-package dash)
  8
  9(defconst org-directory "~/desktop/org/"
 10  "org-mode directory, where most of the org-mode file lives")
 11(defconst org-notes-directory (expand-file-name "notes" org-directory)
 12  "org-mode notes directory, for notes, managed by denote")
 13(defconst org-inbox-file (expand-file-name "inbox.org" org-directory)
 14  "New stuff collected in this file.")
 15(defconst org-todos-file (expand-file-name "todos.org" org-directory)
 16  "TODOs collected in this file.")
 17;; I am not using this too much
 18(defconst org-remember-file (expand-file-name "remember.org" org-directory)
 19  "Remember file, very quick and dirty scratch notes, to be refiled later on.")
 20
 21(defconst org-archive-dir (expand-file-name "archive" org-directory)
 22  "Directory of archived files.")
 23
 24(defconst org-people-dir (expand-file-name "people" org-notes-directory)
 25  "People files directory.")
 26
 27(defconst src-www-dir (expand-file-name "~/src/www" org-directory)
 28  "Directory of my www repository, can contain todos there.")
 29
 30(defconst org-babel-library-file (expand-file-name "org_library_of_babel.org" org-directory)
 31  "Org babel library.")
 32
 33(set-register ?i `(file . ,org-inbox-file))
 34(set-register ?t `(file . ,org-todos-file))
 35(set-register ?o `(file . ,org-directory))
 36(set-register ?P `(file . ,org-people-dir))
 37
 38(defun vde/agenda-goto-view ()
 39  "Jump to the task narrowed but in view mode only to get a glance."
 40  (interactive)
 41  (org-agenda-goto)
 42  (org-narrow-to-subtree)
 43  (view-mode t))
 44
 45(defun vde/org-mode-hook ()
 46  "Org-mode hook."
 47  (setq show-trailing-whitespace t)
 48  (when (not (eq major-mode 'org-agenda-mode))
 49    (setq fill-column 90)
 50    (auto-revert-mode 1)
 51    (auto-fill-mode 1)
 52    (org-indent-mode 1)
 53    (visual-line-mode 1)
 54    (add-hook 'before-save-hook 'org-update-all-dblocks)
 55    (add-hook 'auto-save-hook 'org-update-all-dblocks)
 56    (add-hook 'before-save-hook #'save-and-update-includes nil 'make-it-local)))
 57
 58(use-package org
 59  :mode (("\\.org$" . org-mode)
 60         ("\\.org.draft$" . org-mode))
 61  :commands (org-agenda org-capture)
 62  :bind (("C-c o l" . org-store-link)
 63         ("C-c o r r" . org-refile)
 64	 ("C-c o r R" . vde/reload-org-refile-targets)
 65         ("C-c o a a" . org-agenda)
 66	 ("C-c o a r" . vde/reload-org-agenda-files)
 67	 ("C-c C-x i" . vde/org-clock-in-any-heading)
 68         ("C-c o s" . org-sort)
 69	 ("C-c O" . org-open-at-point-global)
 70         ("<f12>" . org-agenda))
 71  :hook (org-mode . vde/org-mode-hook)
 72  :custom
 73  ;; (org-reverse-note-order '((org-inbox-file . t) ;; Insert items on top of inbox
 74  ;;                           (".*" . nil)))    ;; On any other file, insert at the bottom
 75  (org-archive-location (concat org-archive-dir "/%s::datetree/"))
 76  (org-agenda-file-regexp "^[a-zA-Z0-9-_]+.org$")
 77  (org-agenda-remove-tags t)
 78  (org-use-speed-commands t)
 79  (org-special-ctrl-a/e t)
 80  (org-special-ctrl-k t)
 81  (org-hide-emphasis-markers t)
 82  (org-pretty-entities t)
 83  (org-ellipsis "")
 84  (org-return-follows-link t)
 85  
 86  (org-todo-keywords '((sequence "STRT(s)" "NEXT(n)" "TODO(t)" "WAIT(w)" "|" "DONE(d!)" "CANX(c@/!)")))
 87  (org-todo-state-tags-triggers '(("CANX" ("CANX" . t))
 88                                  ("WAIT" ("WAIT" . t))
 89                                  (done ("WAIT"))
 90                                  ("TODO" ("WAIT") ("CANX"))
 91                                  ("NEXT" ("WAIT") ("CANX"))
 92                                  ("DONE" ("WAIT") ("CANX"))))
 93  (org-tag-alist
 94   '((:startgroup)
 95     ("Handson" . ?o)
 96     (:grouptags)
 97     ("Write" . ?w) ("Code" . ?c)
 98     (:endgroup)
 99     
100     (:startgroup)
101     ("Handsoff" . ?f)
102     (:grouptags)
103     ("Read" . ?r) ("Watch" . ?W) ("Listen" . ?l)
104     (:endgroup)))
105
106  (org-log-done 'time)
107  (org-log-redeadline 'time)
108  (org-log-reschedule 'time)
109  (org-log-into-drawer t)
110  (org-refile-use-cache t)
111  (org-refile-use-outline-path 'file)
112  (org-refile-allow-creating-parent-nodes 'confirm)
113  (org-list-demote-modify-bullet '(("+" . "-") ("-" . "+")))
114  (org-agenda-span 'day)
115  (org-agenda-start-on-weekday 1)
116  (org-agenda-window-setup 'current-window)
117  (org-agenda-skip-scheduled-if-deadline-is-shown t)
118  (org-agenda-skip-timestamp-if-deadline-is-shown t)
119  (org-agenda-skip-scheduled-if-done nil)
120  (org-agenda-current-time-string "")
121  (org-agenda-time-grid '((daily) () "" ""))
122  ;; ((agenda . " %i %-12:c%?-12t% s")
123  ;;  (todo . " %i %-12:c")
124  ;;  (tags . " %i %-12:c")
125  ;;  (search . " %i %-12:c"))
126  ;; (org-agenda-prefix-format "   %i %?-2 t%s")
127  (org-agenda-prefix-format '((agenda . " %i %?-12t% s")
128			      (todo . " %i")
129			      (tags . " %i")
130			      (search . " %i")))
131  (org-insert-heading-respect-content t)
132  (org-M-RET-may-split-line '((default . nil)))
133  (org-goto-interface 'outline-path-completion)
134  (org-outline-path-complete-in-steps nil)
135  (org-goto-max-level 2)
136
137  (org-agenda-category-icon-alist `(("personal"  ,(list (propertize "🏡")))
138				    ("work"  ,(list (propertize "🏢")))
139				    ("appointments"  ,(list (propertize "📅")))
140				    ("health"  ,(list (propertize "⚕️")))
141				    ("systems"  ,(list (propertize "🖥️")))
142				    ("journal"  ,(list (propertize "📝")))
143				    ("project--" ,(list (propertize "💼" )))
144				    ("tekton", (list (propertize "😼")))
145				    ("openshift-pipelines", (list (propertize "🎩")))
146				    ("redhat", (list (propertize "🎩")))
147				    ("area--"  ,(list (propertize"🏢" )))
148				    ("area--home"  ,(list (propertize "🏡")))
149				    ("home"  ,(list (propertize "🏡")))
150				    ("home-services" ,(list (propertize "")))
151				    ("email"  ,(list (propertize"📨" )))
152				    ("people"  ,(list (propertize"👤" )))
153				    ("machine" ,(list (propertize "🖥️")))
154				    ("website" ,(list (propertize "🌍")))
155				    ("bike" ,(list (propertize "🚴‍♂️")))
156				    ("security" ,(list (propertize "🛡️")))
157				    ("i*" ,(list (propertize "📒")))))
158  (org-agenda-sticky t)
159  :config
160
161  (defun vde/org-use-speed-commands-for-headings-and-lists ()
162    "Activate speed commands on list items too."
163    (or (and (looking-at org-outline-regexp) (looking-back "^\**" nil))
164	(save-excursion (and (looking-at (org-item-re)) (looking-back "^[ \t]*" nil)))))
165  (setq org-use-speed-commands 'vde/org-use-speed-commands-for-headings-and-lists)
166  ;; TODO: see https://sachachua.com/blog/2025/03/org-mode-cutting-the-current-list-item-including-nested-lists-with-a-speed-command/
167  
168  ;; Refile org-mode cache when emacs has been idled for 5 minutes
169  (run-with-idle-timer 300 t (lambda ()
170                               (org-refile-cache-clear)
171                               (org-refile-get-targets)))
172  
173  ;; Org Babel configurations
174  (when (file-exists-p org-babel-library-file)
175    (org-babel-lob-ingest org-babel-library-file))
176  (defun vde/all-org-agenda-files ()
177    (seq-filter (lambda(x) (and (not (string-match "/archive/" (file-name-directory x)))
178				(not (string-match ".*==readwise=.*" x))))
179		(apply 'append
180		       (mapcar
181			(lambda (directory)
182			  (directory-files-recursively
183			   directory org-agenda-file-regexp))
184			`(,org-directory)))))
185  ;; (defun vde/reload-org-agenda-files ()
186  ;;   "Reload org-agenda-files variables with up-to-date org files"
187  ;;   (interactive)
188  ;;   (setq org-agenda-files (vde/org-agenda-files)))
189  (defun vde/reload-org-refile-targets ()
190    "Reload org-refile-targets variables with up-to-date org files"
191    (interactive)
192    (setq org-refile-targets (vde/org-refile-targets)))
193  (defun vde/org-refile-targets ()
194    (append '((org-inbox-file :level . 0))
195	    (->>
196	     (directory-files org-directory nil ".org$")
197	     (--remove (s-starts-with? "." it))
198	     (--map (format "%s/%s" org-directory it))
199	     (--map `(,it :maxlevel . 3)))
200	    (->>
201	     (directory-files org-notes-directory nil ".org$")
202	     (--remove (s-starts-with? "." it))
203	     (--map (format "%s/%s" org-notes-directory it))
204	     (--map `(,it :maxlevel . 3)))
205	    (->>
206	     (directory-files-recursively org-people-dir ".org$")
207	     (--remove (s-starts-with? (format "%s/legacy" org-people-dir) it))
208	     (--map (format "%s" it))
209	     (--map `(,it :maxlevel . 3)))))
210  (setq org-agenda-files `(,org-inbox-file ,org-todos-file)
211	;; TODO: extract org-refile-targets into a function
212	org-refile-targets (vde/org-refile-targets))
213  (setopt org-agenda-sorting-strategy
214	  '((agenda time-up deadline-up scheduled-up todo-state-up priority-down)
215	    (todo todo-state-up priority-down deadline-up)
216	    (tags todo-state-up priority-down deadline-up)
217	    (search todo-state-up priority-down deadline-up)))
218  (setq org-agenda-custom-commands
219	'(
220	  ;; Archive tasks
221   	  ("#" "To archive" todo "DONE|CANX")
222	  ;; TODO take inspiration from those
223	  ;; ("$" "Appointments" agenda* "Appointments")
224	  ;; ("b" "Week tasks" agenda "Scheduled tasks for this week"
225   	  ;;  ((org-agenda-category-filter-preset '("-RDV")) ; RDV for Rendez-vous
226   	  ;;   (org-agenda-use-time-grid nil)))
227   	  ;; 
228   	  ;; ;; Review started and next tasks
229   	  ;; ("j" "STRT/NEXT" tags-todo "TODO={STRT\\|NEXT}")
230   	  ;; 
231   	  ;; ;; Review other non-scheduled/deadlined to-do tasks
232   	  ;; ("k" "TODO" tags-todo "TODO={TODO}+DEADLINE=\"\"+SCHEDULED=\"\"")
233   	  ;; 
234   	  ;; ;; Review other non-scheduled/deadlined pending tasks
235   	  ;; ("l" "WAIT" tags-todo "TODO={WAIT}+DEADLINE=\"\"+SCHEDULED=\"\"")
236   	  ;; 
237   	  ;; ;; Review upcoming deadlines for the next 60 days
238   	  ;; ("!" "Deadlines all" agenda "Past/upcoming deadlines"
239   	  ;;  ((org-agenda-span 1)
240   	  ;;   (org-deadline-warning-days 60)
241   	  ;;   (org-agenda-entry-types '(:deadline))))
242
243	  ("d" "Daily Agenda"
244	   ((agenda ""
245		    ((org-agenda-span 'day)
246		     (org-deadline-warning-days 5)))
247	    (tags-todo "+PRIORITY=\"A\""
248		       ((org-agenda-overriding-header "High Priority Tasks")))
249	    (todo "NEXT"
250		  ((org-agenda-overriding-header "Next Tasks")))))
251	  ("D" "Daily Agenda (old)"
252	   ((agenda ""
253		    ((org-agenda-files (vde/all-org-agenda-files))
254		     (org-agenda-span 'day)
255		     (org-deadline-warning-days 5)))
256	    (tags-todo "+PRIORITY=\"A\""
257		       ((org-agenda-files (vde/all-org-agenda-files))
258			(org-agenda-overriding-header "High Priority Tasks")))
259	    (todo "NEXT"
260		  ((org-agenda-files (vde/all-org-agenda-files))
261		   (org-agenda-overriding-header "Next Tasks")))))
262	  ("i" "Inbox (triage)"
263	   ((tags-todo ".*"
264		       ((org-agenda-files `(,org-inbox-file)) ;; FIXME use constant here
265			(org-agenda-overriding-header "Unprocessed Inbox Item")))))
266	  ("A" "All (old)"
267	   ((tags-todo ".*"
268		       ((org-agenda-files (vde/all-org-agenda-files))))))
269	  ("u" "Untagged Tasks"
270	   ((tags-todo "-{.*}"
271		       ((org-agenda-overriding-header "Untagged tasks")))))
272	  ("w" "Weekly Review"
273	   ((agenda ""
274		    ((org-agenda-overriding-header "Completed Tasks")
275		     (org-agenda-skip-function '(org-agenda-skip-entry-if 'nottodo 'done))
276		     (org-agenda-span 'week)))
277	    (agenda ""
278		    ((org-agenda-overriding-header "Unfinished Scheduled Tasks")
279		     (org-agenda-skip-function '(org-agenda-skip-entry-if 'todo 'done))
280		     (org-agenda-span 'week)))))
281	  ;; FIXME Should only take into account projects and areas ?
282	  ("R" "Review projects" tags-todo "-CANX/"
283           ((org-agenda-overriding-header "Reviews Scheduled")
284            (org-agenda-skip-function 'org-review-agenda-skip)
285            (org-agenda-cmp-user-defined 'org-review-compare)
286	    (org-agenda-sorting-strategy '(user-defined-down)))))))
287
288(use-package org-review
289  :defer t
290  :after (org)
291  :config
292  (setopt org-review-delay "+1w")
293  (add-hook 'org-agenda-mode-hook
294          (lambda ()
295            (local-set-key (kbd "C-c C-r")
296                           'org-review-insert-last-review))))
297
298;; Make sure we load org-protocol
299(use-package org-protocol
300  :after org)
301
302(use-package org-tempo
303  :after (org)
304  :custom
305  (org-structure-template-alist '(("a" . "aside")
306				  ("c" . "center")
307				  ("C" . "comment")
308				  ("e" . "example")
309				  ("E" . "export")
310				  ("Ea" . "export ascii")
311				  ("Eh" . "export html")
312				  ("El" . "export latex")
313				  ("q" . "quote")
314				  ("s" . "src")
315				  ("se" . "src emacs-lisp")
316				  ("sE" . "src emacs-lisp :results value code :lexical t")
317				  ("sg" . "src go")
318				  ("sr" . "src rust")
319				  ("sp" . "src python")
320				  ("v" . "verse"))))
321
322(use-package org-id
323  :after org
324  :commands contrib/org-id-headlines
325  :init
326  (defun contrib/org-id-headlines ()
327    "Add CUSTOM_ID properties to all headlines in the current
328file which do not already have one."
329    (interactive)
330    (org-map-entries
331     (funcall 'contrib/org-get-id (point) 'create)))
332  :config
333  (setq org-id-link-to-org-use-id
334        'create-if-interactive-and-no-custom-id))
335
336(use-package org-capture
337  :after org
338  :commands (org-capture)
339  :config
340
341  ;; TODO: refine this, create a function that reset this
342  (add-to-list 'org-capture-templates
343               `("l" "Link" entry
344                 (file ,org-inbox-file)
345                 "* %a\n%U\n%?\n%i"
346                 :empty-lines 1))
347  (add-to-list 'org-capture-templates
348	       `("d" "daily entry" entry
349		 (function denote-journal-extras-new-or-existing-entry)
350                 "* %a\n%U\n%?\n%i"
351                 :empty-lines 1))
352  (add-to-list 'org-capture-templates
353               `("t" "Tasks"))
354  (add-to-list 'org-capture-templates
355               `("tt" "New task" entry
356                 (file ,org-inbox-file)
357                 "* %?\n:PROPERTIES:\n:CREATED:\t%U\n:END:\n\n%i\n\nFrom: %a"
358                 :empty-lines 1))
359  ;; Refine this
360  (add-to-list 'org-capture-templates
361               `("tr" "PR Review" entry
362                 (file ,org-inbox-file)
363                 "* TODO review gh:%^{issue} :review:\n:PROPERTIES:\n:CREATED:%U\n:END:\n\n%i\n%?\nFrom: %a"
364                 :empty-lines 1))
365  ;; emails
366  (add-to-list 'org-capture-templates
367	       `("m" "Email Workflow"))
368  (add-to-list 'org-capture-templates
369	       `("mf" "Follow Up" entry
370		 (file ,org-inbox-file)
371		 "* TODO Follow up with %:from on %a\nSCHEDULED:%t\nDEADLINE: %(org-insert-time-stamp (org-read-date nil t \"+2d\"))\n\n%i"
372		 :immediate-finish t))
373  (add-to-list 'org-capture-templates
374	       `("mr" "Read Later" entry
375		 (file ,org-inbox-file)
376		 "* TODO Read %:subject\nSCHEDULED:%t\nDEADLINE: %(org-insert-time-stamp (org-read-date nil t \"+2d\"))\n\n%a\n\n%i" :immediate-finish t))
377  ;; (add-to-list 'org-capture-templates
378  ;;              `("m" "Meeting notes" entry
379  ;;                (file+datetree ,org-meeting-notes-file)
380  ;;                (file ,(concat user-emacs-directory "/etc/orgmode/meeting-notes.org"))))
381
382  (add-to-list 'org-capture-templates
383               `("w" "Writing"))
384  (add-hook 'org-capture-after-finalize-hook #'vde/window-delete-popup-frame)
385  :bind (("C-c o c" . org-capture)))
386
387(defun vde/dired-notes ()
388  "Open a dired buffer with all my notes"
389  (interactive)
390  (find-dired org-directory "-type f -not -path '*/archive/*'"))
391
392;; Using denote as the "source" of my second brain *in* org-mode.
393(use-package denote
394  :commands (denote denote-region denote-type denote-date
395		    denote-signature denote-subdirectory
396		    denote-template denote-link-or-create
397		    denote-add-links denote-find-link
398		    denote-find-backlink denote-rename-file
399		    denote-rename-file-using-front-matter)
400  :bind (("C-c n n" . vde/dired-notes)
401	 ("C-c n N" . denote)
402	 ("C-c n c" . denote-region)
403	 ("C-c n N" . denote-type)
404	 ("C-c n d" . denote-date)
405	 ("C-c n z" . denote-signature)
406	 ("C-c n S" . denote-subdirectory)
407	 ("C-c n t" . denote-template)
408	 ;; Links
409	 ("C-c n i" . denote-link-or-create)
410	 ("C-c n I" . denote-add-links)
411	 ("C-c n b" . denote-backlinks)
412	 ("C-c n F f" . denote-find-link)
413	 ("C-c n F b" . denote-find-backlink)
414	 ;; Renaming
415	 ("C-c n r" . denote-rename-file)
416	 ("C-c n R" . denote-rename-file-using-front-matter)
417	 ;; Dired
418	 (:map dired-mode-map
419	       ("C-c C-d C-i" . denote-link-dired-marked-notes)))
420  :custom
421  (denote-directory org-notes-directory)
422  (denote-rename-buffer-format "📝 %t")
423  (denote-date-prompt-denote-date-prompt-use-org-read-date t)
424  (denote-prompts '(subdirectory title keywords))
425  (denote-backlinks-display-buffer-action
426   '((display-buffer-reuse-window
427      display-buffer-in-side-window)
428     (side . bottom)
429     (slot . 99)
430     (window-width . 0.3)
431     (dedicated . t)
432     (preserve-size . (t . t))))
433  :hook (dired-mode . denote-dired-mode)
434  :config
435  (denote-rename-buffer-mode 1)
436  (defun my-denote-always-rename-on-save-based-on-front-matter ()
437    "Rename the current Denote file, if needed, upon saving the file.
438Rename the file based on its front matter, checking for changes in the
439title or keywords fields.
440
441Add this function to the `after-save-hook'."
442    (let ((denote-rename-confirmations nil)
443          (denote-save-buffers t)) ; to save again post-rename
444      (when (and buffer-file-name (denote-file-is-note-p buffer-file-name))
445	(ignore-errors (denote-rename-file-using-front-matter buffer-file-name))
446	(message "Buffer saved; Denote file renamed"))))
447
448  (add-hook 'after-save-hook #'my-denote-always-rename-on-save-based-on-front-matter)
449  
450  (with-eval-after-load 'org-capture
451    (setq denote-org-capture-specifiers "%l\n%i\n%?")
452    (add-to-list 'org-capture-templates
453		 '("n" "New note (with denote.el)" plain
454                   (file denote-last-path)
455                   #'denote-org-capture
456                   :no-save t
457                   :immediate-finish nil
458                   :kill-buffer t
459                   :jump-to-captured t)))
460  (defun vde/org-category-from-buffer ()
461    "Get the org category (#+category:) value from the buffer"
462    (cond
463     ((string-match "__journal.org$" (buffer-file-name))
464      "journal")
465     (t
466      (denote-sluggify (denote--retrieve-title-or-filename (buffer-file-name) 'org))))))
467
468(use-package denote-journal
469  :commands (denote-journal-new-entry
470             denote-journal-new-or-existing-entry
471             denote-journal-link-or-create-entry)
472  :custom
473  (denote-journal-directory nil) ;; use denote-directory
474  (denote-journal-title-format 'day-date-month-year)
475  :hook (calendar-mode . denote-journal-calendar-mode)
476  :bind (("C-c n j j" . denote-journal-new-or-existing-entry)
477	 ("C-c n j i" . denote-journal-link-or-create-entry)
478	 ("C-c n j n" . denote-journal-new-entry)))
479
480(use-package denote-org
481  :after denote)
482
483(use-package denote-menu
484  :after denote
485  :bind (("C-c n m" . list-denotes)
486	 (:map denote-menu-mode-map
487	       ("c" . denote-menu-clear-filters)
488	       ("/ r" . denote-menu-filter)
489	       ("/ k" . denote-menu-filter-by-keyword)
490	       ("/ o" . denote-menu-filter-out-keyword)
491	       ("e" . denote-menu-export-to-dired))))
492
493(use-package consult-denote
494  :commands (consult-denote-mode
495	     consult-denote-find
496	     consult-denote-grep)
497  :bind (("C-c n f" . consult-denote-find)
498	 ("C-c n s" . consult-denote-grep))
499  :config
500  (consult-denote-mode 1))
501
502(use-package orgit
503  :defer t)
504
505(use-package ob-async
506  :after org
507  :commands (ob-async-org-babel-execute-src-block))
508(use-package ob-emacs-lisp
509  :after org
510  :commands (org-babel-execute:emacs-lisp org-babel-execute:elisp))
511(use-package ob-go
512  :after org
513  :commands (org-babel-execute:go))
514(use-package ob-python
515  :after org
516  :commands (org-babel-execute:python))
517(use-package ob-shell
518  :after org
519  :commands (org-babel-execute:ash
520             org-babel-execute:bash
521             org-babel-execute:csh
522             org-babel-execute:dash
523             org-babel-execute:fish
524             org-babel-execute:ksh
525             org-babel-execute:mksh
526             org-babel-execute:posh
527             org-babel-execute:sh
528             org-babel-execute:shell
529             org-babel-execute:zsh))
530;; my personal
531(use-package ol-github
532  :after (org))
533(use-package ol-gitlab
534  :after (org))
535(use-package ol-rg
536  :disabled
537  :after (org))
538(use-package ol-grep
539  :after (org))
540
541;; built-in org-mode
542(use-package ol-eshell
543  :after (org))
544(use-package ol-git-link
545  :defer 2
546  :after (org))
547(use-package ol-gnus
548  :defer 2
549  :after (org))
550(use-package ol-irc
551  :defer 2
552  :after (org))
553(use-package ol-info
554  :defer 2
555  :after (org))
556(use-package ol-man
557  :defer 2
558  :after (org))
559;; (use-package ol-notmuch
560;;   :defer 2
561;;   :after (org))
562;; (use-package ob-dot
563;;   :after org
564;;   :commands (org-babel-execute:dot))
565;; (use-package ob-ditaa
566;;   :after org
567;;   :commands (org-babel-execute:ditaa)
568;;   :config
569;;   (setq org-ditaa-jar-path "/home/vincent/.nix-profile/lib/ditaa.jar"))
570;; (use-package ob-doc-makefile
571;;   :after org
572;;   :commands (org-babel-execute:makefile))
573
574(use-package org-nix-shell
575  :hook (org-mode . org-nix-shell-mode))
576
577(use-package org-rich-yank
578  :after org
579  :bind (:map org-mode-map
580              ("C-M-y" . org-rich-yank)))
581
582;; from https://sachachua.com/blog/2024/01/using-consult-and-org-ql-to-search-my-org-mode-agenda-files-and-sort-the-results-to-prioritize-heading-matches/
583(defun my-consult-org-ql-agenda-jump ()
584  "Search agenda files with preview."
585  (interactive)
586  (let* ((marker (consult--read
587                  (consult--dynamic-collection
588                   #'my-consult-org-ql-agenda-match)
589                  :state (consult--jump-state)
590                  :category 'consult-org-heading
591                  :prompt "Heading: "
592                  :sort nil
593                  :lookup #'consult--lookup-candidate))
594         (buffer (marker-buffer marker))
595         (pos (marker-position marker)))
596    ;; based on org-agenda-switch-to
597    (unless buffer (user-error "Trying to switch to non-existent buffer"))
598    (pop-to-buffer-same-window buffer)
599    (goto-char pos)
600    (when (derived-mode-p 'org-mode)
601      (org-fold-show-context 'agenda)
602      (run-hooks 'org-agenda-after-show-hook))))
603
604(defun my-consult-org-ql-agenda-format (o)
605  (propertize
606   (org-ql-view--format-element o)
607   'consult--candidate (org-element-property :org-hd-marker o)))
608
609(defun my-consult-org-ql-agenda-match (string)
610  "Return candidates that match STRING.
611Sort heading matches first, followed by other matches.
612Within those groups, sort by date and priority."
613  (let* ((query (org-ql--query-string-to-sexp string))
614         (sort '(date reverse priority))
615         (heading-query (-tree-map (lambda (x) (if (eq x 'rifle) 'heading x)) query))
616         (matched-heading
617          (mapcar #'my-consult-org-ql-agenda-format
618                  (org-ql-select 'org-agenda-files heading-query
619				 :action 'element-with-markers
620				 :sort sort)))
621         (all-matches
622          (mapcar #'my-consult-org-ql-agenda-format
623                  (org-ql-select 'org-agenda-files query
624				 :action 'element-with-markers
625				 :sort sort))))
626    (append
627     matched-heading
628     (seq-difference all-matches matched-heading))))
629
630(use-package org-ql
631  :after org
632  :bind ("M-s a" . my-consult-org-ql-agenda-jump))
633
634(use-package org-ql-view
635  :after org-ql)
636
637(defun my-org-todo-set-keyword-faces ()
638  (setq org-todo-keyword-faces
639        `(("TODO" . (:foreground ,(modus-themes-get-color-value 'red-faint) :weight bold))
640          ("NEXT" . (:foreground ,(modus-themes-get-color-value 'yellow-warmer) :weight bold))
641          ("STARTED" . (:foreground ,(modus-themes-get-color-value 'yellow-intense) :weight bold))
642          ("IN-REVIEW" . (:foreground ,(modus-themes-get-color-value 'blue-faint) :weight bold))
643          ("DONE" . (:foreground ,(modus-themes-get-color-value 'green-warmer) :weight bold))
644          ("CANX" . (:foreground ,(modus-themes-get-color-value 'comment) :weight bold))
645          ("WAIT" . (:foreground ,(modus-themes-get-color-value 'magenta-faint) :weight bold))
646          ("SOMEDAY" . (:foreground ,(modus-themes-get-color-value 'cyan-warmer) :weight bold))
647          ("IDEA" . (:foreground ,(modus-themes-get-color-value 'magenta-cooler) :weight bold))))
648  (when (derived-mode-p 'org-mode)
649    (font-lock-fontify-buffer)))
650(my-org-todo-set-keyword-faces)
651(with-eval-after-load 'modus-themes
652  (add-hook 'modus-themes-after-load-theme-hook #'my-org-todo-set-keyword-faces))
653
654(use-package ox-publish
655  :after org
656  :commands (org-publish org-publish-all org-publish-project org-publish-current-project org-publish-current-file)
657  :config
658  (setq org-html-coding-system 'utf-8-unix
659	org-publish-use-timestamps-flag nil)
660  (defun vde-org-git-exportable-files (directory)
661    "Return a list of files from `DIRECTORY' that can be exported."
662    (directory-files directory nil ".*_www.*\\.org$"))
663  (setq org-publish-project-alist
664	`(("resources"
665	   :base-directory ,org-directory
666	   :base-extension "org"
667	   ;; :include ".*_www*.org"
668	   :include ,(vde-org-git-exportable-files org-directory)
669	   :exclude ".*"
670	   :publishing-directory ,(expand-file-name "resources" src-www-dir)
671	   :publishing-function org-html-publish-to-html
672	   :recursive t
673	   :with-toc nil
674	   :section-numbers nil
675	   :html-head "<link rel=\"stylesheet\" type=\"text/css\" href=\"../css/2022.css\" />"
676	   :html-head-extra "<link rel=\"stylesheet\" type=\"text/css\" href=\"../css/syntax.css\" />"
677	   :html-preamble t
678	   :html-postamble t
679	   :auto-sitemap t
680	   :sitemap-filename "index.org"
681	   :sitemap-title "Resources"
682	   :sitemap-sort-files anti-chronologically
683	   :sitemap-file-entry-format "%d %t"
684	   :sitemap-date-format "%Y-%m-%d"
685	   ;; :sitemap-function org-publish-org-sitemap
686	   ))))
687(use-package org-habit
688  :after (org)
689  :config
690  (setq org-habit-show-habits-only-for-today nil
691        org-habit-graph-column 80))
692(use-package org-download
693  :after (org)
694  :hook ((dired-mode . org-download-enable)
695         (org-mode . org-download-enable))
696  :config
697  (org-download-enable)
698  (setq org-startup-with-inline-images t)
699  (setq org-download-display-inline-images t)
700  (setq org-download-method 'attach))
701
702;; Persistent notes (like persistent-scratch, but built-in)
703(setq remember-data-file org-remember-file
704      remember-handler-functions '(remember-append-to-file)
705      remember-notes-initial-major-mode 'org-mode
706      remember-notes-auto-save-visited-file-name t
707      remember-in-new-frame t)
708
709(use-package consult-org
710  :after (consult org)
711  :commands (consult-org-agenda consult-org-heading))
712
713(provide 'config-org)
714;;; config-org.el ends here