Skip to content

DominikMendel/Doom-Emacs

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Config

Introduction

Hi, I’m Dominik. Welcome. Enjoy your stay.

Feel free to email me at dominik@mendel.family for any questions or discussions you’d like to have about my configuration.

I have a semi-complex task management, GTD, and roam set up that I think is worth sharing. I will try to explain and provide examples to the best of my ability.

Focuses

I strongly believe in keeping work and personal life separate. When I clock out of work, I don’t want to see or think about anything work related, ever. This includes work notes, projects, journals, or TODO tasks in org-agenda. However, in the off chance I’m not working and I need to see something work related, I want the ability to do so. Thus, I created a “focus” system.

This focus system is quite simple. I have a “personal”, “sirius” (current “work”), “vispero” (older “work”) and an “all” focus. I am able to swap focuses at any point of time and expect to see only files of that focus. I set this up in such a way that I don’t just have a “work” focus, but my current job. This will allow me to add more focuses if need be. i.e., jobs, major hobbies, side projects, etc.

Since I have a work machine (Ubuntu) and a personal machine (Arch btw) I have my focus variable set on startup based on what operating system is running. So when I sign into my work machine I’m always on my work focus.

Example

If I sign into my work machine, I’ll already be on my “work” focus. I can see all of my upcoming things scheduled or due for the day with org-agenda. All of my org-capture-templates keybindings will create files or TODOs in my designated work areas. All of my daily journal entries go to a my work journal via org-roam-dailies. Org-roam-dailies functions only show the date journal entries for the focus.

Now I’m sitting at work, but I need to check my personal agenda for any upcoming events. Swap my focus with the associated function to now “personal”. Open up org-agenda, look at my calendar. Great, all done, time to swap back. Swap back to “work” focus with the swap focus. Everything is back to being work mode.

Now the opposite can applied from my personal machine. In this situation I never want to see or think about work, but rarely I need to. So, swap focus, check things, then swap back. Then never think about work again.

Task Management

Header info

Just some personal information and my doom-theme.

  • I have been loving doom-horizon. I wanted something in dark mode that was best for my eyes.
    • After going through all the themes I ended up on horizon.
;;; $DOOMDIR/config.el -*- lexical-binding: t; -*-

;; Place your private configuration here! Remember, you do not need to run 'doom
;; sync' after modifying this file!


;; Some functionality uses this to identify you, e.g. GPG configuration, email
;; clients, file templates and snippets.
(setq user-full-name "Dominik Mendel"
      user-mail-address "Dominik@mendel.family")

;; Doom exposes five (optional) variables for controlling fonts in Doom. Here
;; are the three important ones:
;;
;; + `doom-font'
;; + `doom-variable-pitch-font'
;; + `doom-big-font' -- used for `doom-big-font-mode'; use this for
;;   presentations or streaming.
;;
;; They all accept either a font-spec, font string ("Input Mono-12"), or xlfd
;; font string. You generally only need these two:
;; (setq doom-font (font-spec :family "monospace" :size 12 :weight 'semi-light)
;;       doom-variable-pitch-font (font-spec :family "sans" :size 13))

;; There are two ways to load a theme. Both assume the theme is installed and
;; available. You can either set `doom-theme' or manually load a theme with the
;; `load-theme' function. This is the default:
;; (setq doom-theme 'doom-one)

General values and Org-journal

;; If you use `org' and don't want your org files in the default location below,
;; change `org-directory'. It must be set before org loads!
(setq org-directory "~/Dropbox/org"
      org-journal-date-prefix "* "
      org-journal-enable-agenda-integration t
      org-journal-enable-cache t
      +org-roam-open-buffer-on-find-file nil
      +snippets-dir "~/Dropbox/snippets"
      display-line-numbers-type 'visual
      scroll-margin 8
      vertico-scroll-margin 4
      )

(setq! org-journal-time-format "")

;; PDF auto-refresh after changes
(add-hook 'pdf-view-mode-hook (lambda () (auto-revert-mode 1)))

;; Auto recenter screen after jumping
(add-hook 'imenu-after-jump-hook #'recenter)
(add-hook 'evil-post-jump-hook #'recenter)
(add-hook 'better-jumper-post-jump-hook #'recenter)
(add-hook 'evil-jumps-post-jump-hook #'recenter)

(after! org-journal
  (setq! org-journal-carryover-items "TODO=\"TODO\"|TODO=\"INPROGRESS\"|TODO=\"WAITING\"|TODO=\"BLOCKED\"|TODO=\"QUESTION\""))

Custom functions

Youtube url link

I wanted to extend the YouTube url link in Org Mode by including time markings. This function will concat the minutes and seconds to the end of the url link

(defun make-youtube-time-link (link-text)
  (let ((substrings (split-string link-text ",")))
    (browse-url (format "%s&t=%sm%ss" (first substrings) (second substrings) (third substrings)))))

Clocktable function

This function is used in the “:match” parameter for an Org-clocktable. It will pull all clocked times from my entire work journal directory.

  • This is very useful to record how much time I spent working on a specific project.
  • I usually follow the Org-clocktable with the corresponding tag associated with the project to filter all of my total work to the work in the project I want.
(defun vispero-journals() (directory-files-recursively "~/Dropbox/org/roam/vispero/journal" "\\.org$"))

(defun vispero-roam() (directory-files-recursively "~/Dropbox/org/roam/vispero" "\\.\\(org\\|org_archive\\)$"))

(defun sirius-journals() (directory-files-recursively "~/Dropbox/org/roam/sirius/journal" "\\.org$"))

(defun sirius-roam() (directory-files-recursively "~/Dropbox/org/roam/sirius" "\\.\\(org\\|org_archive\\)$"))

(defun personal-journals() (directory-files-recursively "~/Dropbox/org/roam/journal" "\\.org$"))

(defun all-roam() (directory-files-recursively "~/Dropbox/org/roam" "\\.\\(org\\|org_archive\\)$"))

Create linkable UUID

  • Credit to Rainer König

I use this function all the time to create a UUID link to a header file so I can keep track of the link even after I archive it. This is especially useful in my workflow where I would copy a task from my agenda to my journal to show that I am working on said task for the day. Later when I finish that task and archive it I still have a valid link.

(defun my/copy-idlink-to-clipboard() "Copy an ID link with the
headline to killring, if no ID is there then create a new unique
ID.  This function works only in org-mode or org-agenda buffers.

The purpose of this function is to easily construct id:-links to
org-mode items. If its assigned to a key it saves you marking the
text and copying to the killring."
       (interactive)
       (when (eq major-mode 'org-agenda-mode) ;if we are in agenda mode we switch to orgmode
         (org-agenda-show)
         (org-agenda-goto))
       (when (eq major-mode 'org-mode) ; do this only in org-mode buffers
         (setq mytmphead (nth 4 (org-heading-components)))
         (setq mytmpid (funcall 'org-id-get-create))
         (setq mytmplink (format "[[id:%s][%s]]" mytmpid mytmphead))
         (kill-new mytmplink)
         (message "Copied %s to killring (clipboard)" mytmplink)))
(global-set-key (kbd "<f5>") 'my/copy-idlink-to-clipboard)

Deft

(setq deft-directory "~/Dropbox/org"
      deft-extensions '("org" "txt" "org_archive")
      deft-use-filename-as-title t
      deft-strip-summary-regexp ":PROPERTIES:\n\\(.+\n\\)+:END:\n"
      deft-recursive t)

Logging

(setq org-startup-indented t           ;; Indent according to section
      org-log-reschedule t
      org-log-into-drawer t
      org-enforce-todo-checkbox-dependencies t)

Theme

;; (setq doom-theme 'doom-solarized-dark)
(setq doom-theme 'doom-gruvbox)
;;(setq doom-theme 'doom-monokai-classic)
;; (setq doom-theme 'doom-moonlight)
(after! doom-themes
  (setq doom-themes-enable-bold t
        doom-themes-enable-italic t))
(custom-set-faces!
  '(font-lock-comment-face :slant italic)
  '(font-lock-keyword-face :slant italic)
  '(vterm-color-blue :foreground "color-51")
  ;; '(region :background "DarkSlateBlue")
  ;; '(vertico-current :background "DarkSlateBlue")
  )
  ;; '(region :background "#094959"))

(defun my/next-theme ()
"Switch to the next theme in ‘custom-known-themes’.
If exhausted, disable themes.  If run again thereafter, wrap to
the beginning of the list."
  (interactive)
  (let* ((ct (or (car custom-enabled-themes)
                 (car custom-known-themes)))
         (next (cadr (memq ct custom-known-themes))))
    (when (memq next '(user changed))
      (setq next nil))
    (dolist (theme custom-enabled-themes)
      (disable-theme theme))
    (if next
        (progn
          (load-theme next t)
          (message "Loaded theme ‘%S" next))
      (message "All themes disabled"))))

Org

General org

;; Marks a ToDo entry as done but makes the "LAST_REPEAT" the day of the schedule
;; This currenlty ONLY works with SCHEDULED items and not DEADLINES
(defun willdo-naggins--mark-done ()
  (interactive)
  (let* ((sched-ts (org-timestamp-from-string
                    (org-entry-get nil "SCHEDULED")))
         (thetime (org-timestamp-to-time sched-ts)))
    ;trick org-store-note into thinking the task was done when scheduled
    (define-advice org-add-log-setup (:after (&rest _) trick-store-note)
      (setq org-log-note-effective-time thetime))
    (org-todo 'done)
    (advice-remove 'org-add-log-setup #'org-add-log-setup@trick-store-note)
    ;set LAST_REPEAT to reflect the latest scheduling of task
    (org-add-planning-info 'closed (format-time-string
                    (org-time-stamp-format t t)
                    thetime))
    ;; (org-entry-put nil "LAST_REPEAT"
    ;; (org-entry-put nil "CLOSED"
    ;;                (format-time-string
    ;;                 (org-time-stamp-format t t)
    ;;                 thetime))
    ))

(use-package! org-roam-dailies
  :commands (my/mark-done-at-scheduled-time my/mark-done-testing)
  :config
        ;; This doesn't work from org-agenda views
        (defun my/mark-done-at-scheduled-time ()
            (interactive)
            (let* ((sched-ts (org-timestamp-from-string
                            (org-entry-get nil "SCHEDULED")))
                    (org-refile-keep t) ;; Set this to nil to delete the original!
                    (org-id-link-to-org-use-id t)
                    (org-after-refile-insert-hook #'save-buffer)
                    (org-after-todo-state-change-hook (remq #'my/org-roam-copy-to-today-wrapper org-after-todo-state-change-hook))
                    (thetime (org-timestamp-to-time sched-ts)))

            ;trick org-store-note into thinking the task was done when scheduled
            (define-advice org-add-log-setup (:after (&rest _) trick-store-note)
            (setq org-log-note-effective-time thetime))
            (org-todo 'done)
            ;; (org-agenda-todo 'done) ;; This doesn't work
            (advice-remove 'org-add-log-setup #'org-add-log-setup@trick-store-note)
            ;set LAST_REPEAT to reflect the latest scheduling of task
            (org-add-planning-info 'closed (format-time-string
                            (org-time-stamp-format t t)
                            thetime))

            (save-window-excursion
                (call-interactively 'org-store-link)
                (org-roam-dailies--capture thetime nil "!D"))))

        (defun my/mark-done-at-defined-time ()
          (interactive)
            (let* (
                (org-refile-keep t) ;; Set this to nil to delete the original!
                (org-id-link-to-org-use-id t)
                (org-after-refile-insert-hook #'save-buffer)
                (org-after-todo-state-change-hook (remq #'my/org-roam-copy-to-today-wrapper org-after-todo-state-change-hook))
                (thetime (org-read-date))
                (timestamp (org-encode-time (parse-time-string thetime))))

            ;trick org-store-note into thinking the task was done when scheduled
            (define-advice org-add-log-setup (:after (&rest _) trick-store-note)
            (setq org-log-note-effective-time thetime))
            (org-todo 'done)
            (advice-remove 'org-add-log-setup #'org-add-log-setup@trick-store-note)
            ;set LAST_REPEAT to reflect the latest scheduling of task
            (org-add-planning-info 'closed timestamp)

            (save-window-excursion
                (call-interactively 'org-store-link)
                (org-roam-dailies--capture timestamp nil "!D"))))
    )

  (defun my/org-clock-in-at-specified-time (&rest _)
    (interactive)
    (require 'org-clock)
    (require 'org-roam-dailies)
    (let* ((thetime (org-read-date))
           (timestamp (org-encode-time (parse-time-string thetime)))
           (org-clock-in-hook (remq #'my/org-roam-capture-clock-in org-clock-in-hook))
           (tags (vulpea-buffer-tags-get))
           (org-id-link-to-org-use-id (if (-contains? tags "journal") "use-existing" t)))
      (when (org-clock-is-active)
          (my/org-clock-out-at-specified-time thetime))

      (org-clock-in nil timestamp)
      (org-roam-dailies--capture timestamp nil "!CI")))

  (defun my/org-clock-out-at-specified-time (&optional time &rest _)
    (interactive)
    (require 'org-clock)
    (require 'org-roam-dailies)
    ;; (cl-letf* ((thetime (or time (org-read-date)))
    (let* ((thetime (or time (org-read-date)))
           (timestamp (org-encode-time (parse-time-string thetime)))
           (org-clock-out-hook (remq #'my/org-roam-capture-clock-out org-clock-out-hook))
           ;; ((symbol-function #'temp/org-clock-out) (symbol-function #'org-clock-out))
           (tags (vulpea-buffer-tags-get))
           (org-id-link-to-org-use-id (if (-contains? tags "journal") "use-existing" t)))

      ;; (advice-remove #'temp/org-clock-out #'my/org-roam-capture-clock-out)
      ;; The capture needs to be called before the clock-out due to the %K in the template
      (org-roam-dailies--capture timestamp nil "!CO")
      ;; (temp/org-clock-out nil nil timestamp)))
      (org-clock-out nil nil timestamp)))

(after! (:and org org-roam)
  ;; (defvar dm--org-archive-type "%s_archive::datetree/")
  ;; (defvar dm--org-archive-location-personal (concat (expand-file-name "archive" org-roam-directory) "/" dm--org-archive-type))
  ;; (defvar dm--org-archive-location-vispero (concat (expand-file-name "archive" dm--org-roam-vispero-dir) "/" dm--org-archive-type))
  (defvar dm--org-archive-type "archive.org_archive::datetree/")
  (defvar dm--org-archive-location-personal (concat org-roam-directory "personal_" dm--org-archive-type))
  (defvar dm--org-archive-location-vispero (concat dm--org-roam-vispero-dir "/" "vispero_" dm--org-archive-type))
  (defvar dm--org-archive-location-sirius (concat dm--org-roam-sirius-dir "/" "sirius_" dm--org-archive-type))

  (defvar dm--org-archive-header-personal "\nArchived entries from personal files\n\n")
  (defvar dm--org-archive-header-vispero "\nArchived entries from Vispero files\n\n")
  (defvar dm--org-archive-header-sirius "\nArchived entries from Sirius files\n\n")

  (defun my/set-org-variables ()
        (cond
         ((string-equal dm--my-focus "vispero")
            (setq org-archive-location dm--org-archive-location-vispero
                org-archive-file-header-format dm--org-archive-header-vispero))
         ((string-equal dm--my-focus "sirius")
            (setq org-archive-location dm--org-archive-location-sirius
                org-archive-file-header-format dm--org-archive-header-sirius))
        ((string-equal dm--my-focus "personal")
            (setq org-archive-location dm--org-archive-location-personal
                org-archive-file-header-format dm--org-archive-header-personal))
        ((string-equal dm--my-focus "all")
             (setq org-archive-location dm--org-archive-location-personal
                org-archive-file-header-format dm--org-archive-header-personal))
            (t (setq org-archive-location dm--org-archive-location-personal
                     org-archive-file-header-format dm--org-archive-header-personal))))

  (my/set-org-variables)
  )

(after! org
  (setq org-startup-folded t)
  (setq org-ellipsis "")
  (setq org-hide-emphasis-markers t)
  (setq org-sparse-tree-open-archived-trees t) ;;For finding archived headings
  (setq org-clock-into-drawer "CLOCKING")
  (org-add-link-type "yt" #'make-youtube-time-link)
  (setq org-todo-keywords
        '((sequence  "TODO(t)" "INPROGRESS(i!)" "IN-REVIEW(r!)" "NEXT(n!)" "WAITING(w@/!)" "BLOCKED(b@/!)" "SOMEDAY(s!)" "|" "DONE(d@)" "CANCELLED(c!)" "ABANDONED(a@)")
          (sequence "QUESTION(q)" "|" "ANSWERED(@/!)")
          (sequence "GOAL(G)" "|" "ACHIEVED(A@)" "MISSED(M@)")
          (sequence "REPEAT" "|" "COMPLETED")
          (sequence "[ ](T)" "[-](I)" "[?](?)" "|" "[X](D)")))
  (setq org-log-done 'time)
  (setq org-refile-targets '((+org/opened-buffer-files :maxlevel . 9)))
  (setq org-list-demote-modify-bullet
       '(("+" . "-") ("-" . "+") ("*" . "+") ("1." . "a.") ("a." . "-")))
  (setq org-log-redeadline 'note)
  (setq org-cycle-open-archived-trees t)
  (setq org-blank-before-new-entry
        '((heading . nil)
        (plain-list-item . nil)))
  (setq org-fold-core-style 'overlays)
  )

  (defun +org/opened-buffer-files ()
    "Return the list of files currently opened in emacs"
    (delq nil
          (mapcar (lambda (x)
                    (if (and (buffer-file-name x)
                             (string-match "\\.org$"
                                           (buffer-file-name x)))
                        (buffer-file-name x)))
                  (buffer-list))))

Org-capture-templates

  • %a allows for a link inserted from the file/headline you are currently at and inserts it into the capture
  • %A is the same as %a but prompts for a description of the link
(defvar org-journal--date-location-scheduled-time nil)

(defun org-journal-date-location (&optional scheduled-time)
  (let ((scheduled-time (or scheduled-time (org-read-date nil nil nil "Date:"))))
    (setq org-journal--date-location-scheduled-time scheduled-time)
    (org-journal-new-entry t (org-time-string-to-time scheduled-time))
    (unless (eq org-journal-file-type 'daily)
      (org-narrow-to-subtree))
    (goto-char (point-max))))

(defun org-journal-find-location ()
  ;; Open today's journal, but specify a non-nil prefix argument in order to
  ;; inhibit inserting the heading; org-capture will insert the heading.
  (org-journal-new-entry t)
  (unless (eq org-journal-file-type 'daily)
    (org-narrow-to-subtree))
  (goto-char (point-max)))

(defun my/org-capture-plus-store-link()
  (interactive)
  (call-interactively 'org-store-link)
  ;; (org-capture nil "jJ"))
  (org-roam-dailies-capture-today nil "jl"))
;; (global-set-key (kbd "<f4>") 'my/org-capture-plus-store-link)

(after! (:and org org-roam)
  (defun my/set-org-capture-templates()
      "Sets the org-capture-templates value based on what my current focus is. If my focus is 'personal' then the template, file name, and file path will be set to what I have defined as my personal tempaltes. This applies for all other defined focuses."

    (cond ((string-equal dm--my-focus "vispero") (setq +org-capture-todo-file dm--org-vispero-inbox-file-name))
        ((string-equal dm--my-focus "sirius") (setq +org-capture-todo-file dm--org-sirius-inbox-file-name))
        ((string-equal dm--my-focus "personal") (setq +org-capture-todo-file dm--org-personal-inbox-file-name))
        ((string-equal dm--my-focus "all") (setq +org-capture-todo-file dm--org-personal-inbox-file-name))
        (t (setq +org-capture-todo-file dm--org-personal-inbox-file-name)))

      (setq org-capture-templates
        `(("l" "Japanese")
          ("lv" "Vocabulary" plain
           (file (lambda () (dm/get-japanese-filename (dm/prompt-string "English alias:" 'dm--org-capture-area))))
           (file ,dm--org-roam-japanese-vocabulary-template)
           :unnarrowed t)

          ;; TODO add meetings section with meetings by ID and one for a "new" meeting not specified
          ;; ("m" "Meetings")

          ;; TODO Try using org-clock-current-task for file+olp+datetree
          ("c" "Clock entry" plain (clock)
           ""
           :unnarrowed t
           )

          ("t" "General ToDo" entry (file+headline +org-capture-todo-file "Tasks")
           "* TODO %^{What ToDo?}%? :new:")

          ("T" "Scheduled ToDo" entry (file+headline +org-capture-todo-file "Tasks")
           "* TODO %^{What Todo?}%? :new:\nSCHEDULED: %^{Schedule}t")

          ("i" "General New Idea" entry (file+headline +org-capture-todo-file "Ideas")
           "* %^{What's your idea?}%? :new:\n%i")

          ("I" "General Inprogress" entry (file+headline +org-capture-todo-file "Tasks")
           "* INPROGRESS %?")

          ("p" "General Project" entry (file+headline +org-capture-todo-file "Projects")
           "* TODO %^{What ToDo?}%? :new:\n%i\nFrom : %a\n")

          ("g" "New Goal" entry (file+headline +org-capture-todo-file "Goals")
           "* GOAL %^{Describe your goal} %? :new:
Added on %U - Last reviewed on %U
:SMART:
:Sense: %^{What is the sense of this goal? Or why?}
:Measurable: %^{How do you measure it?}
:Actions: %^{What actions are needed?}
:Resources: %^{Which resources do you need?}
:Timebox: %^{How much time are you spending for it?}
:END:")

          ("j" "Journal")
          ;; ("jj" "Journal New Entry" plain (function org-journal-find-location)
          ;;  ;; "** %(format-time-string org-journal-time-format)%^{Title}%i%?"
          ;;  "** %(format-time-string org-journal-time-format)%i%?"
          ;;  :jump-to-captured nil
          ;;  :immediate-finish nil
          ;;  :unnarrowed nil)

          ;; ("jt" "Journal New Clock Entry" plain (function org-journal-find-location)
          ;;  "** %(format-time-string org-journal-time-format)%i%?"
          ;;  :jump-to-captured nil
          ;;  :immediate-finish nil
          ;;  :clock-in t)

          ;; Testing by removing %i
          ("jf" "Journal Future" plain (function org-journal-date-location)
                               "** TODO %?\n <%(princ org-journal--date-location-scheduled-time)>\n"
                               :jump-to-captured t)

          ("jj" "Journal New Entry" plain (function org-journal-find-location)
           ;; "** %(format-time-string org-journal-time-format)%^{Title}%i%?"
           "** %(format-time-string org-journal-time-format)%?"
           :jump-to-captured nil
           :immediate-finish nil
           :unnarrowed nil)

          ("jJ" "Journal Insert Roam" plain (function org-journal-find-location)
           "** %(format-time-string org-journal-time-format)%a"
           :jump-to-captured nil
           :immediate-finish t)

          ;; ("jJ" "Journal Inset Roam" plain (function org-journal-find-location)
          ;;  "** %(format-time-string org-journal-time-format) %?"
          ;;  :jump-to-captured nil
          ;;  :immediate-finish nil
          ;;  :unnarrowed nil)

          ("jt" "Journal New Clock Entry" plain (function org-journal-find-location)
           "** %(format-time-string org-journal-time-format)%?"
           :jump-to-captured nil
           :immediate-finish nil
           :clock-in t)

          ("jm" "Journal New Meeting" plain (function org-journal-find-location)
           "** %(format-time-string org-journal-time-format)%^{Select Meeting|Standup|Embedded Software Team|CAP Schedule Review|Embedded Software Knowledge Sharing|Technical Brief - One on One with Rob|Townhall}%? :meeting:"
           :jump-to-captured nil
           :immediate-finish nil
           :clock-in t)

          ("jr" "Journal Review" plain (function org-journal-find-location)
           "** %(format-time-string org-journal-time-format)Review %^{prompt} for %^{prompt}%? :review:"
           :jump-to-captured nil
           :immediate-finish nil
           :clock-in t)

          ("jh" "Journal Helping" plain (function org-journal-find-location)
           "** %(format-time-string org-journal-time-format)Helping %^{prompt}%? :helping:"
           :jump-to-captured nil
           :immediate-finish nil
           :clock-in t)

          ;; ("jl" "Journal Lunch" plain (function org-journal-find-location)
          ;;  "** %(format-time-string org-journal-time-format)Lunch :break:"
          ;;  :jump-to-captured nil
          ;;  :immediate-finish t
          ;;  :clock-in t)

          ("jl" "Journal Lunch" plain
           ;; (file+olp "/home/dominik/Dropbox/org/roam/vispero/vispero_agenda.org" "Logging" "Lunch")
           (file+olp "/home/dominik/Dropbox/org/roam/vispero/vispero_agenda.org" "Lunch")
           ""
           :jump-to-captured nil
           :immediate-finish t
           :clock-in t)

          ("js" "Journal Startup" plain
           ;; (file+olp "/home/dominik/Dropbox/org/roam/vispero/vispero_agenda.org" "Logging" "Startup")
           (file+olp "/home/dominik/Dropbox/org/roam/vispero/vispero_agenda.org" "Startup")
           ""
           :jump-to-captured nil
           :immediate-finish t
           :clock-in t)

          ("jS" "Journal Startup jump to" plain (function org-journal-find-location)
           "** %(format-time-string org-journal-time-format)Startup"
           :jump-to-captured t
           :immediate-finish t
           :clock-in t)

          ;; ("js" "Journal Startup" plain (function org-journal-find-location)
          ;;  "** %(format-time-string org-journal-time-format)Startup"
          ;;  :jump-to-captured nil
          ;;  :immediate-finish t
          ;;  :clock-in t)

          ;; ("jS" "Journal Startup jump to" plain (function org-journal-find-location)
          ;;  "** %(format-time-string org-journal-time-format)Startup"
          ;;  :jump-to-captured t
          ;;  :immediate-finish t
          ;;  :clock-in t)

          ("jT" "Journal Testing" plain (function org-journal-find-location)
           "** %(format-time-string org-journal-time-format)Testing : %a"
           :jump-to-captured nil
           :immediate-finish t)

          ;; ("jm" "Journal Meetings")
          ;; ("jme" "Embedded Software Team" plain (function org-journal-find-location)
          ;;  "** %(format-time-string org-journal-time-format)Embedded Software Team :meeting:"
          ;;  :jump-to-captured nil
          ;;  :immediate-finish t
          ;;  :clock-in t)


          ("s" "Specific location")
          ("sp" "Personal")
          ("spt" "todoDOM" entry (file+headline "~/Dropbox/org/roam/personal_agenda.org" "Tasks")
           "* TODO %?\n %i\n")

          ("sw" "Work")
          ("swt" "Work General ToDo" entry (file+headline "~/Dropbox/org/roam/vispero/vispero_agenda.org" "Tasks")
           "* TODO %?\n %i\n")

          ("swp" "Work Project" entry (file+headline "~/Dropbox/org/roam/vispero/vispero_agenda.org" "Projects")
           "* TODO %?\n %i\n%a\n")
          )))
  (my/set-org-capture-templates))

Org Agenda

;; Doing this to clean up my org-agenda to view since ALL of my org-agenda-files
;; are tagged with "project", so it is redundant.
(after! org
    (add-to-list 'org-tags-exclude-from-inheritance "project")
    (add-to-list 'org-tags-exclude-from-inheritance "ARCHIVE"))

(defun my/enable-relative-line-numbers ()
  (display-line-numbers-mode)
  (setq-local display-line-numbers 'visual))

(add-hook 'org-agenda-mode-hook #'my/enable-relative-line-numbers)

;; @TODO Need to set the list. The goal is to remove "A" as archive as subtree.
;; (after! org-agenda
;;   (add-to-list 'org-agenda-bulk-custom-functions
;;                '(?A org-agenda-archive)))

Unused

(after! org-agenda
  (add-to-list 'org-agenda-bulk-custom-functions
               '(?a org-agenda-archive-to-archive-sibling)))

Org-super-agenda

  • Types of agenda custom command keywords: (link) The desired agenda display/search. The options include agenda, todo, search, tags, alltodo, tags-todo, todo-tree, tags-tree, occur-tree, or a user-defined function.
(after! org-agenda
  (add-hook 'org-agenda-mode-hook #'origami-mode))

;; (use-package origami
;;     ;; :general (:keymaps 'org-super-agenda-header-map
;;     ;;                  "TAB" #'origami-toggle-node)
;;     :hook ((org-agenda-mode . origami-mode)))

(use-package! org-super-agenda
  :commands (org-super-agenda-mode))

(after! org-agenda
  (org-super-agenda-mode))

;; Vulpea functions to help with naming view
(setq org-agenda-prefix-format
      '((agenda . " %i %(vulpea-agenda-category 20)%?-20t% s")
        (todo . " %i %(vulpea-agenda-category 20) ")
        (tags . " %i %(vulpea-agenda-category 20) ")
        (search . " %i %(vulpea-agenda-category 20) ")))

(defun vulpea-agenda-category (&optional len)
  "Get category of item at point for agenda.

Category is defined by one of the following items:

- CATEGORY property
- TITLE keyword
- TITLE property
- filename without directory and extension

When LEN is a number, resulting string is padded right with
spaces and then truncated with ... on the right if result is
longer than LEN.

Usage example:

  (setq org-agenda-prefix-format
        '((agenda . \" %(vulpea-agenda-category) %?-12t %12s\")))

Refer to `org-agenda-prefix-format' for more information."
  (let* ((file-name (when buffer-file-name
                      (file-name-sans-extension
                       (file-name-nondirectory buffer-file-name))))
         (title (vulpea-buffer-prop-get "title"))
         (category (org-get-category))
         (result
          (or (if (and
                   title
                   (string-equal category file-name))
                  title
                category)
              "")))
    (if (numberp len)
        (s-truncate len (s-pad-right len " " result))
      result)))

(setq org-agenda-skip-scheduled-if-done t
      org-agenda-skip-deadline-if-done t
      org-agenda-skip-timestamp-if-done t
      org-agenda-include-deadlines t
      org-agenda-block-separator nil
      org-agenda-tags-column 100 ;; from testing this seems to be a good value
      org-agenda-compact-blocks t
      )

(defun my-agenda-skip-work ()
  "Skip tasks that as work related by checking the file name."
  (save-restriction
    (widen)
    (let ((subtree-end (save-excursion (org-end-of-subtree t))))
      (cond
       ;; Use this for checking tags instead of path name
       ;; ((seq-contains-p (org-get-tags) "vispero")
       ((string-match-p "vispero" (buffer-file-name))
        subtree-end)
       ((string-match-p "sirius" (buffer-file-name))
        subtree-end)
       ((seq-contains-p (org-get-tags) "ignore")
        subtree-end)
       (t
        nil)))))

(defun my-agenda-skip-non-vispero ()
  "Skip tasks that are Vispero related by checking the file name."
  (save-restriction
    (widen)
    (let ((subtree-end (save-excursion (org-end-of-subtree t))))
      (cond
       ;; Use this for checking tags instead of path name
       ;; ((not (seq-contains-p (org-get-tags) "vispero"))
       ((not (string-match-p "vispero" (buffer-file-name)))
        subtree-end)
       ((seq-contains-p (org-get-tags) "ignore")
        subtree-end)
       (t
        nil)))))

(defun my-agenda-skip-non-sirius ()
  "Skip tasks that are Sirius related by checking the file name."
  (save-restriction
    (widen)
    (let ((subtree-end (save-excursion (org-end-of-subtree t))))
      (cond
       ;; Use this for checking tags instead of path name
       ;; ((not (seq-contains-p (org-get-tags) "sirius"))
       ((not (string-match-p "sirius" (buffer-file-name)))
        subtree-end)
       ((seq-contains-p (org-get-tags) "ignore")
        subtree-end)
       (t
        nil)))))

(defun my-agenda-skip-function-selector ()
  (cond ((string-equal dm--my-focus "vispero") (funcall #'my-agenda-skip-non-vispero))
        ((string-equal dm--my-focus "sirius") (funcall #'my-agenda-skip-non-sirius))
        ((string-equal dm--my-focus "personal") (funcall #'my-agenda-skip-work))
        ((string-equal dm--my-focus "all") nil)
        (t nil)))

(setq org-agenda-skip-function 'my-agenda-skip-function-selector)

;; This isn't used anymore
;; @TODO clean this up
(setq my-agenda-work-cmd '(agenda
                           ""
                           ((org-agenda-span 'day)
                            (org-agenda-skip-function 'my-agenda-skip-non-vispero)))
      my-agenda-non-work-cmd '(agenda
                               ""
                               ((org-agenda-span 'day)
                                (org-agenda-skip-function 'my-agenda-skip-work))))

(setq my-super-group-agenda-today
      '(
        (:name "Clocked today"
         :log t)
        (:name "Scheduled Today"
         :time-grid t
         :date today
         :order 1)
        (:name "Habbits"
         :habit t
         :date today
         :order 2)
        (:name "Overdue Deadline"
         :face error
         :deadline past
         :order 3)
        (:name "Approaching Deadline"
         :face warning
         :deadline future
         :order 4)
        (:discard (:not (:scheduled past)))
        ;; (:name "Previously Scheduled"
        ;;  :face warning
        ;;  :scheduled past
        ;;  :order 5)
        (:order-multi (5
                       (:name "Reviews To-Do"
                        :tag "review")
                       (:name "Previously Scheduled To-Do"
                        :face warning
                        :and (:scheduled past :todo "TODO"))
                       (:name "Previously Scheduled Inprogress"
                        :face warning
                        :and (:scheduled past :todo "INPROGRESS"))
                       (:name "Previously Scheduled In-Review"
                        :face warning
                        :and (:scheduled past :todo "IN-REVIEW"))
                       ))
        (:auto-parent t
         :order 6)
        (:discard (:anything t))))

(setq my-super-group-alltodo-today
      '(
        ;; (:auto-category t)
        ;; You will see scheduled items from the agenda view, so discard any extras.
        (:discard (:scheduled today))
        (:discard (:scheduled past))
        (:discard (:todo "SOMEDAY"))
        (:name "Important"
         :priority "A"
         :order 1)
        (:name "Reviews To-Do"
         :tag "review"
         :order 2)
        (:name "Currently Open"
         :todo "INPROGRESS"
         :order 3)
        (:name "Bugs Todo"
         :tag "bug"
         :order 4)
        (:name "My Reviews"
         :todo "IN-REVIEW"
         :order 5)
        (:name "Pending"
         :todo "WAITING"
         :order 6)
        (:name "Blocked"
         :todo "BLOCKED"
         :order 7)
        (:discard (:not (:todo "TODO")))
        (:discard (:scheduled future))
        ;; (:auto-parent t
        ;; Auto-parent for whatever reason excludes titles with "[ ]" like Jira tickets
        (:auto-todo t
         :order 8)
        (:discard (:anything t))))

(setq my-super-group-agenda-overview
      '(
        (:auto-parent t)
        ))

(setq my-super-group-todo-done-groups
      '((:discard (:tag "jira"))))

(defun my/get-time-string-today-offset (dayOffSet)
  (format-time-string "%Y-%m-%d %H:%M" (+ (string-to-number (format-time-string "%s" (current-time))) (* 86400 dayOffSet))))

(defun my/get-super-group-alltodo-overview (dayOffSet)
  (let ((date (my/get-time-string-today-offset dayOffSet)))
    `(
        ;; (:auto-category t)
        ;; You will see scheduled items from the agenda view, so discard any extras.
        ;; (:discard (:scheduled today))
        (:name "Overdue (Past scheduled/deadline)"
         :face warning
         :deadline past
         :scheduled past
         :order 1)
        (:name "Inprogress"
         :todo "INPROGRESS"
         :order 2)
        (:name "In Review"
         :todo "IN-REVIEW"
         :order 3)
        (:order-multi (4 (:name "Waiting Tasks"
                          :todo "WAITING")
                         (:name "Blocked Tasks"
                          :todo "BLOCKED")))
        (:name "Next Tasks"
         :todo "NEXT"
         :order 5)
        (:name "Someday"
         :todo "SOMEDAY"
         :order 7)
        (:discard (:not (:todo t)))
        (:discard (:todo "GOAL"))
        (:discard (:tag "meeting"))
        (:discard (:scheduled (after ,date)))
        (
         ;; :auto-category t
         ;; :auto-parent t
         ;; Auto-parent for whatever reason excludes titles with "[ ]" like Jira tickets
         :auto-todo t
         :order 6)

        ;; (:order-multi (6 (:todo "TODO") (:auto-category t)))
        ;; (:todo "TODO"
        ;;  :order 6)
        ;;  (:auto-category t
        ;;  ;;:todo "TODO"
        ;;  :order 6)
        ;; (:order-multi (5 (:auto-category t)
        ;;                (:name "Current Tasks"
        ;;                   :todo ("INPROGRESS" "IN-REVIEW"))
        ;;                  (:name "Open Tasks"
        ;;                   :todo "TODO")))

        ;; (:order-multi (3 (:name "Current Tasks"
        ;;                   :todo ("INPROGRESS" "IN-REVIEW"))
        ;;                  (:name "Open Tasks"
        ;;                   :todo "TODO")))
        (:discard (:anything t)))))

(setq my-super-group-agenda-planning
      '(
        (:discard (:todo "GOAL"))
        (:discard (:todo "REPEAT"))
         (:scheduled t)))

(setq my-super-group-todo-planning
      '((:name "High Priority"
         :priority>= "B")
        (:name "Inprogress"
         :todo "INPROGRESS"
         :order 1)
        (:name "In Review"
         :todo "IN-REVIEW"
         :order 2)
        (:order-multi (3 (:name "Waiting Tasks"
                          :todo "WAITING")
                         (:name "Blocked Tasks"
                          :todo "BLOCKED")))
        (:name "Next Tasks"
         :todo "NEXT"
         :order 4)
        ;; Specifically doing this out of order
        (:name "Some Day Tasks"
         :todo "SOMEDAY"
         :order 6)
        (:discard (:todo ("REPEAT" "GOAL")))
        (:name "Individual Tasks"
         :auto-todo t
         ;; :todo t
         ;;:auto-category t
         :order 5)
        (:discard (:anything t))))

(setq my-agenda-super-group-alltodo
      '(
        ;; Discarding the file path works and I don't need the functions anymore
        ;; (:discard (:file-path "vispero"))
        (:name "Next to do"
            :todo "NEXT"
            :order 4)
        (:name "Due Today"
            :deadline today
            :order 2)
        (:name "Important"
            :tag "Important"
            :priority "A"
            :order 6)
        (:name "Due Soon"
            :deadline future
            :order 8)
        (:name "Overdue"
            :deadline past
            :face error
            :order 7)
        (:name "Inprogress"
            :todo "INPROGRESS"
            :order 3)
        (:name "Questions"
            ;; :regexp (:todo "QUESTION" :tag "question")
            :todo "QUESTION"
            :tag "question"
            :order 10)
        (:name "Questions tags"
            :tag "question"
            :order 11)
        (:name "Projects"
            :tag "Project"
            :order 15)
        (:name "In review"
            :todo "IN-REVIEW"
            :order 14)
        (:name "Waiting"
            :todo "WAITING"
            :order 20)
        (:name "Some day"
            :todo "SOMEDAY"
            :order 25)
        (:name "Done"
            :todo "DONE"
            :order 26)
        (:name "Trivial"
            :priority<= "C"
            :tag ("Trivial" "Unimportant")
            :todo ("SOMEDAY")
            :order 90)
        (:name "Everything else"
            :anything t
            :auto-tags t
            :order 89)
        ;; (:name "Random shit"
        ;;  :auto-tags t
        ;;  :priority<= "C"
        ;;  :order 89)
        (:discard (:tag ("Chore" "Routine" "Daily")))))

(setq my-agenda-super-group-agenda '((:name "Today"
                            :time-grid t
                            :date today
                            :todo "TODAY"
                            :scheduled today
                            :order 1)))

(setq my-agenda-super-group-tags
      '((:name "Questions"
        ;; '((
        :tag "question"
        ;; :anything t
        ;; :auto-tags t
        :order 12)
        (:discard (:anything t))))

(setq org-super-agenda-header-map (make-sparse-keymap)) ;;Needed for evil keys in org-super-agenda
(after! org
  (setq org-agenda-custom-commands
        '(
          ;; An example of how to use org-super-agenda-groups in-line
          ;; ("p" "Projects"
          ;;  ;; (
          ;;  ((agenda "" ((org-agenda-span 'day)
          ;;               (org-super-agenda-groups
          ;;                '((:name "Today"
          ;;                   :time-grid t
          ;;                   :date today
          ;;                   :todo "TODAY"
          ;;                   :scheduled today
          ;;                   :order 1)))))
          ;;   (alltodo "" ((org-agenda-overriding-header "")
          ;;                (org-super-agenda-groups
          ;;                 `((:name "WAITING"
          ;;                    :children "WAITING"
          ;;                    :order 2)
          ;;                   (:discard (:anything t)))
          ;;                 )))))

          ("t" "Today view"
           ((agenda "" ((org-agenda-overriding-header "")
                        (org-agenda-span 'day)
                        (org-agenda-start-day nil)
                        (org-agenda-start-on-weekday nil)
                        (org-agenda-time-grid '((daily today) (800 1000 1200 1400 1600 1800 2000) "" "----------------"))
                        (org-super-agenda-groups my-super-group-agenda-today)
                        ))
            (alltodo "" ((org-agenda-overriding-header "")
                         (org-super-agenda-groups my-super-group-alltodo-today)))))

          ("pw" "Planning Week"
          ((tags-todo "goal" ((org-agenda-overriding-header "Goals")))
           (agenda "" ((org-agenda-overriding-header "Month Planner")
                       (org-agenda-span 14)
                        (org-super-agenda-groups my-super-group-agenda-planning)
                        ;; (org-agenda-time-grid '(nil (800 1000 1200 1400 1600 1800 2000) "" "----------------"))
                        )
                    )
            (todo "" ((org-agenda-overriding-header "Things to schedule")
                         (org-super-agenda-groups my-super-group-todo-planning)))))

          ("pm" "Planning Month"
          ((tags-todo "goal" ((org-agenda-overriding-header "Goals")))
           (agenda "" ((org-agenda-overriding-header "Month Planner")
                       (org-agenda-span 'month)
                        (org-super-agenda-groups my-super-group-agenda-planning)
                        ;; (org-agenda-time-grid '(nil (800 1000 1200 1400 1600 1800 2000) "" "----------------"))
                        )
                    )
            (todo "" ((org-agenda-overriding-header "Things to schedule")
                         (org-super-agenda-groups my-super-group-todo-planning)))))

          ("w" "Week Overview"
          ((agenda "" ((org-agenda-overriding-header "Week view")
                        (org-agenda-span 'week)
                        (org-agenda-start-day nil)
                        (org-agenda-start-on-weekday nil)
                        (org-super-agenda-groups my-super-group-agenda-overview)
                        (org-agenda-time-grid '(nil (800 1000 1200 1400 1600 1800 2000) "" "----------------"))
                        )
                    )
            (alltodo "" ((org-agenda-overriding-header "")
                         (org-super-agenda-groups (my/get-super-group-alltodo-overview 5))))))

          ("b" "Bi-Week Overview"
          ((agenda "" ((org-agenda-overriding-header "Bi-Weekly view")
                        (org-agenda-span 14)
                        (org-super-agenda-groups my-super-group-agenda-overview)
                        (org-agenda-time-grid '(nil (800 1000 1200 1400 1600 1800 2000) "" "----------------"))
                        )
                    )
            (alltodo "" ((org-agenda-overriding-header "")
                         (org-super-agenda-groups (my/get-super-group-alltodo-overview 14))))))

          ("m" "Month Overview"
          ((agenda "" ((org-agenda-overriding-header "Month view")
                        (org-agenda-span 'month)
                        (org-agenda-start-day nil)
                        (org-agenda-start-on-weekday nil)
                        (org-super-agenda-groups my-super-group-agenda-overview)
                        (org-agenda-time-grid '(nil (800 1000 1200 1400 1600 1800 2000) "" "----------------"))
                        )
                    )
            (alltodo "" ((org-agenda-overriding-header "")
                         (org-super-agenda-groups (my/get-super-group-alltodo-overview 30))))))

          ("y" "Year Overview"
          ((agenda "" ((org-agenda-overriding-header "Year view")
                        (org-agenda-span 'year)
                        (org-super-agenda-groups my-super-group-agenda-overview)
                        (org-agenda-time-grid '(nil (800 1000 1200 1400 1600 1800 2000) "" "----------------"))
                        )
                    )
            (alltodo "" ((org-agenda-overriding-header "")
                         (org-super-agenda-groups (my/get-super-group-alltodo-overview 365))))))


          ("W" . "Weekly Review Helper")
          ("Wn" "New Tasks"
           ((tags "new" ((org-agenda-overriding-header "Remove new tag and assign TODO states and priorities")))))
          ("Wd" "Done Tasks"
           ((todo "DONE|COMPLETED|CANCELLED|ABANDONED|ANSWERED|ACHIEVED|MISSED"
                  ((org-agenda-overriding-header "Archive all DONE items")
                   (org-super-agenda-groups my-super-group-todo-done-groups)
                         ))))
          ))

  )

Org-journal

  • I’m currently not using org-journal anymore. I found a lot of bugs for anything I tried implementing past the normal, and very basic, use case.
    • Now I use org-roam-dailies and couldn’t be happier.
  • This section shows some of the hacks I needed to make “roam” files from org-journal function calls.
    • Like creating an org-ID in the header location.
(add-hook 'org-journal-after-entry-create-hook #'org-roam-db-autosync--setup-file-h)
(add-hook 'org-journal-after-entry-create-hook #'org-journal-restore-hooks)

(defun org-journal-restore-hooks ()
  (add-hook 'find-file-hook #'vulpea-project-update-tag)
  (add-hook 'before-save-hook #'vulpea-project-update-tag))

(add-hook 'org-journal-after-header-create-hook 'org-create-new-id-journal)
(defun org-create-new-id-journal ()
  (goto-char (point-min))
  (org-id-get-create)
  (goto-char (point-max)))

Org-roam

General

(setq lexical-binding t)

(after! roam
  (setq org-roam-directory "~/Dropbox/org/roam"))

(setq org-roam-node-default-sort nil)

(defun org-roam-node-insert-immediate (arg &rest args)
  (interactive "P")
  (let ((args (cons arg args))
        (org-roam-capture-templates (list (append (car org-roam-capture-templates)
                                                  '(:immediate-finish t)))))
    (apply #'org-roam-node-insert args)))

(defun my/org-roam-filter-by-tag (tag-name)
  (lambda (node)
    (member tag-name (org-roam-node-tags node))))

(defun my/org-roam-list-notes-by-tag (tag-name)
  (mapcar #'org-roam-node-file
          (seq-filter
           (my/org-roam-filter-by-tag tag-name)
           (org-roam-node-list))))

(defun my/org-roam-project-finalize-hook ()
  "Adds the captured project file to `org-agenda-files' if the
capture was not aborted."
  ;; Remove the hook since it was added temporarily
  (remove-hook 'org-capture-after-finalize-hook #'my/org-roam-project-finalize-hook)

  ;; Add project file to the agenda list if the capture was confirmed
  (unless org-note-abort
    (with-current-buffer (org-capture-get :buffer)
      (add-to-list 'org-agenda-files (buffer-file-name)))))

(defun my/org-roam-find-project ()
  (interactive)
  ;; Add the project file to the agenda after capture is finished
  (add-hook 'org-capture-after-finalize-hook #'my/org-roam-project-finalize-hook)

  ;; Select a project file to open, creating it if necessary
  (org-roam-node-find
   nil
   nil
   (my/org-roam-filter-by-tag "project")
   :templates org-roam-capture-templates))

(defun my/org-roam-find-people ()
  (interactive)
  ;; Select a project file to open, creating it if necessary
  (org-roam-node-find
   nil
   nil
   (my/org-roam-filter-by-tag "people")
   :templates org-roam-capture-templates))

(defun my/org-roam-help-people ()
  (interactive)
  ;; Select a project file to open, creating it if necessary

  (let ((head
        (with-temp-buffer
        (cond
         ((string-equal dm--my-focus "vispero") (insert-file-contents dm--org-roam-vispero-people-template))
         ((string-equal dm--my-focus "sirius") (insert-file-contents dm--org-roam-sirius-people-template))
         (t (insert-file-contents dm--org-roam-sirius-people-template)))
                (buffer-string)))
        (file-name
            (cond
             ((string-equal dm--my-focus "sirius") (expand-file-name "${slug}.org" dm--org-roam-sirius-dir))
             ((string-equal dm--my-focus "vispero") (expand-file-name "${slug}.org" dm--org-roam-vispero-dir))
             (t (expand-file-name "${slug}.org" org-roam-directory)))))
    ;; @TODO DJM clean up template system, add custom templates
   (org-roam-capture
   nil
   nil
   :filter-fn (my/org-roam-filter-by-tag "people")
   :templates
   ;; `(("h" "Helping" plain ""
   `(("h" "Helping" entry "* Helping %<%Y-%m-%d %a %H:%M>"
      :clock-in t
      :unnarrowed t
        :target (file+head+olp ,file-name ,head ("Helping :helping:"))))
                        )))

(defun my/org-roam-capture-projects ()
  (interactive)
  (org-roam-capture
   nil
   "!t"
   :filter-fn (my/org-roam-filter-by-tag "project")
   ))

Attempting automatic done logging

(defun my/test-org-roam-copy-todo-to-today (&rest _)
  (interactive)
  (let ((org-refile-keep t) ;; Set this to nil to delete the original!
        (head
            (with-temp-buffer
            (cond ((string-equal dm--my-focus "vispero") (insert-file-contents dm--org-vispero-daily-template))
                    (t (insert-file-contents dm--org-personal-daily-template)))
                (buffer-string)))
                (file-name
                (cond ((string-equal dm--my-focus "vispero") dm--org-vispero-file-name)
                        (t dm--org-personal-file-name)))
        (org-roam-dailies-capture-templates
          '(
            ("t" "tasks" entry "%?"
             (file+head+olp "%<%Y-%m-%d>.org" "#+title: %<%Y-%m-%d>\n" ("Tasks")))
            ))
        (org-after-refile-insert-hook #'save-buffer)
        today-file
        pos)
    (save-window-excursion
      (org-roam-dailies-capture-today nil "c")
      (setq today-file (buffer-file-name))
      (setq pos (point)))
    ))

(defun my/org-roam-copy-todo-to-today (&rest _)
  (interactive)
  (let ((org-refile-keep t) ;; Set this to nil to delete the original!
        (org-id-link-to-org-use-id t)
        (org-after-refile-insert-hook #'save-buffer))

    (save-window-excursion
      (call-interactively 'org-store-link)
      (org-roam-dailies-capture-today nil "!D"))))

(defun my/org-roam-capture-plus-store-link (&rest _)
  (interactive)
  (call-interactively 'org-store-link)
  (org-roam-dailies-capture-today nil "!D"))

(after! (:and org org-roam)
    (add-hook 'org-after-todo-state-change-hook #'my/org-roam-copy-to-today-wrapper))

(defun my/org-roam-copy-to-today-wrapper (&rest _)
  (when (or (equal org-state "DONE") (equal org-state "COMPLETED"))
                    (my/org-roam-copy-todo-to-today)))

(defun my/org-roam-capture-clock-in (&rest _)
  (interactive)
  (let* ((tags (vulpea-buffer-tags-get))
         ;; Should this use doom--setq-org-id-link-to-org-use-id-for-org-roam-find-file-h ?
         (org-id-link-to-org-use-id (if (-contains? tags "journal") "use-existing" t)))
        (org-roam-dailies-capture-today nil "!CI")))

(defun my/org-roam-capture-clock-out (&rest _)
  (interactive)
  (let* ((tags (vulpea-buffer-tags-get))
         ;; Should this use doom--setq-org-id-link-to-org-use-id-for-org-roam-find-file-h ?
         (org-id-link-to-org-use-id (if (-contains? tags "journal") "use-existing" t))
         (+org-roam-link-to-org-use-id (if (-contains? tags "journal") "use-existing" t)))
    (message "Tags are %s" tags)
    (message "OrgId = %s, roam ID = %s" org-id-link-to-org-use-id +org-roam-link-to-org-use-id)
    ;; (save-window-excursion
    ;; (save-mark-and-excursion
    ;; (org-clock-goto)
    ;; (call-interactively 'org-store-link))
    ;; (org-store-link))
        (org-roam-dailies-capture-today nil "!CO")))

;; (defun my/org-clock-in (&rest _)
;;   (interactive)
;;   (when (org-clocking-p)
;;     (my/org-roam-capture-clock-out))

;;   (org-clock-in)
;;   (my/org-roam-capture-clock-in))

;; (defun my/org-clock-out (&rest _)
;;   (interactive)
;;   (when (org-clocking-p)
;;     (my/org-roam-capture-clock-out))

;;   (org-clock-out))

(add-hook 'org-clock-in-hook #'my/org-roam-capture-clock-in)
;; (add-hook 'org-clock-in-hook #'save-buffer)
(add-hook 'org-clock-out-hook #'my/org-roam-capture-clock-out)
;; I've had some timing issues with org-clock-in versus clock-out,
;; so to fix that I'm using advices before the clock-out.
;; (advice-add 'org-clock-out :before #'my/org-roam-capture-clock-out)

Capture templates

;; Remapping functions to default to the default template
(defun my/org-roam-dailies-goto-today ()
  (interactive)
  (org-roam-dailies-goto-today "d"))

(defun my/org-roam-dailies-goto-date (&optional prefer-future)
  (interactive)
  (org-roam-dailies-goto-date prefer-future "d"))

(defun my/org-roam-dailies-goto-tomorrow (n)
  (interactive "p")
  (org-roam-dailies-goto-tomorrow n "d"))

(defun my/org-roam-dailies-goto-yesterday (n)
  (interactive "p")
  (org-roam-dailies-goto-yesterday n "d"))

(after! org-roam
    ;; Template and directory locations
    (defvar dm--org-templates-dir (expand-file-name "templates" doom-private-dir))
    (defvar dm--org-personal-inbox-file-name (expand-file-name "personal_agenda.org" org-roam-directory))
    (defvar dm--org-roam-website-dir (expand-file-name "website" org-roam-directory))
    (defvar dm--org-roam-default-template (expand-file-name "roam-default.org" dm--org-templates-dir))
    (defvar dm--org-roam-new-area-template (expand-file-name "roam-new-area.org" dm--org-templates-dir))
    (defvar dm--org-roam-reading-template (expand-file-name "roam-reading.org" dm--org-templates-dir))
    (defvar dm--org-roam-reading-character-template (expand-file-name "roam-reading-character.org" dm--org-templates-dir))
    (defvar dm--org-roam-japanese-vocabulary-template (expand-file-name "roam-japanese-vocabulary.org" dm--org-templates-dir))
    (defvar dm--org-roam-japanese-dir (expand-file-name "japanese" org-roam-directory))



    (defvar dm--org-roam-sirius-dir (expand-file-name "sirius" org-roam-directory))
    (defvar dm--org-roam-sirius-review-dir (expand-file-name "reviews" dm--org-roam-sirius-dir))
    (defvar dm--org-roam-jama-review-template (expand-file-name "roam-jama-review.org" dm--org-templates-dir))

    (defvar dm--org-roam-vispero-dir (expand-file-name "vispero" org-roam-directory))
    (defvar dm--org-vispero-inbox-file-name (expand-file-name "vispero_agenda.org" dm--org-roam-vispero-dir))
    (defvar dm--org-roam-vispero-default-template (expand-file-name "roam-vispero-default.org" dm--org-templates-dir))
    (defvar dm--org-roam-vispero-tagged-template (expand-file-name "roam-vispero-tagged.org" dm--org-templates-dir))
    (defvar dm--org-roam-vispero-people-template (expand-file-name "roam-vispero-people.org" dm--org-templates-dir))

    (defvar dm--org-roam-sirius-dir (expand-file-name "sirius" org-roam-directory))
    (defvar dm--org-sirius-inbox-file-name (expand-file-name "sirius_agenda.org" dm--org-roam-sirius-dir))
    (defvar dm--org-roam-sirius-default-template (expand-file-name "roam-sirius-default.org" dm--org-templates-dir))
    (defvar dm--org-roam-sirius-tagged-template (expand-file-name "roam-sirius-tagged.org" dm--org-templates-dir))
    (defvar dm--org-roam-sirius-people-template (expand-file-name "roam-sirius-people.org" dm--org-templates-dir))

    ;; Dailies file name and templates
    (defvar dm--org-roam-ref-general-template (expand-file-name "roam-ref-general.org" dm--org-templates-dir))

    (defvar dm--org-roam-personal-dailies-dir (expand-file-name "daily" org-roam-directory))
    (defvar dm--org-personal-daily-template (expand-file-name "personal-daily.org" dm--org-templates-dir))
    (defvar dm--org-personal-file-name "Personal %<%Y-%m-%d>.org")

    (defvar dm--org-roam-vispero-dailies-dir (expand-file-name "daily" dm--org-roam-vispero-dir))
    (defvar dm--org-vispero-daily-template (expand-file-name "vispero-daily.org" dm--org-templates-dir))
    (defvar dm--org-vispero-file-name "Vispero %<%Y-%m-%d>.org")

    (defvar dm--org-roam-sirius-dailies-dir (expand-file-name "daily" dm--org-roam-sirius-dir))
    (defvar dm--org-sirius-daily-template (expand-file-name "sirius-daily.org" dm--org-templates-dir))
    (defvar dm--org-sirius-file-name "Sirius %<%Y-%m-%d>.org")

    (defun dm/prompt-string (prompt variable)
      (set variable (read-string prompt)))

    (defun dm/get-japanese-filename (name)
      (expand-file-name
       (format "%s.org" (s-dashed-words name)) dm--org-roam-japanese-dir))

    (defun my/set-org-roam-dailies-capture ()
      "Sets the org-roam-dailies-capture-templates value based on what my current focus is. If my focus is 'personal' then the template, file name, and file path will be set to what I have defined as my personal journal. This applies for all other defined focuses."

      ;; Set the dailies directory based on focus
        (cond
            ((string-equal dm--my-focus "sirius") (setq org-roam-dailies-directory dm--org-roam-sirius-dailies-dir))
            ((string-equal dm--my-focus "vispero") (setq org-roam-dailies-directory dm--org-roam-vispero-dailies-dir))
            ((string-equal dm--my-focus "personal") (setq org-roam-dailies-directory dm--org-roam-personal-dailies-dir))
            ((string-equal dm--my-focus "all") (setq org-roam-dailies-directory dm--org-roam-personal-dailies-dir))
            (t (setq org-roam-dailies-directory dm--org-roam-personal-dailies-dir)))

        (setq org-roam-dailies-capture-templates
            (let ((head
                (with-temp-buffer
                (cond
                 ((string-equal dm--my-focus "sirius") (insert-file-contents dm--org-sirius-daily-template))
                 ((string-equal dm--my-focus "vispero") (insert-file-contents dm--org-vispero-daily-template))
                    (t (insert-file-contents dm--org-personal-daily-template)))
                    (buffer-string)))
                  (file-name
                   (cond
                    ((string-equal dm--my-focus "sirius") dm--org-sirius-file-name)
                    ((string-equal dm--my-focus "vispero") dm--org-vispero-file-name)
                    (t dm--org-personal-file-name))))

            ;; Backtick list
            `(("d" "default" plain "%?"
                :target (file+head ,file-name ,head)
                :unarrowed t)
                ;; ("!CI" "Clocking In" item "1. %<%H:%M> %K"
                ("!CI" "Clocking In" item "1. %<%H:%M> %a"
                ;; ("!CI" "Clocking In" item "1. %<%H:%M> [[roam:%k]]"
                :unnarrowed t
                :immediate-finish t
                :clock-keep t
                :target (file+head+olp ,file-name ,head ("Clock History" "Clock In")))
                ;; %K is the current clocked in task. So this capture template must be ran
                ;; BEFORE the clock is clocked out.
                ;; ("!CO" "Clocking Out" item "1. %<%H:%M> %K"
                ("!CO" "Clocking Out" item "1. %<%H:%M> %a"
                ;; ("!CO" "Clocking Out" item "1. %<%H:%M> [[roam:%k]]"
                :unnarrowed t
                :immediate-finish t
                :clock-keep t
                :target (file+head+olp ,file-name ,head ("Clock History" "Clock Out")))
                ("!D" "Done Log" item "1. %<%H:%M> %a"
                :immediate-finish t
                :target (file+head+olp ,file-name ,head ("Closed Tasks")))
                ("!JS" "Journal Startup" entry "* Startup%?"
                :target (file+head+olp ,file-name ,head ("Journal"))
                :unnarrowed t
                :immediate-finish t
                ;; :clock-in t)
                :jump-to-captured t)
                ("!JL" "Journal Lunch" entry "* Lunch :break:%?"
                :target (file+head+olp ,file-name ,head ("Journal"))
                :unnarrowed t
                :immediate-finish t
                ;; :clock-in t)
                :jump-to-captured t)
                ("jj" "Journal New Entry" entry "* %?"
                :target (file+head+olp ,file-name ,head ("Journal")))
                ("jl" "Journal Link" entry "* %a %?"
                :target (file+head+olp ,file-name ,head ("Journal"))
                :immediate-finish t)
                ("jc" "Journal New Clock Entry" entry "* %^{What are you doing?}%?"
                :target (file+head+olp ,file-name ,head ("Journal"))
                :jump-to-captured nil
                :immediate-finish t
                :clock-in t)
                ("jt" "Journal ToDo" item "[ ] %?"
                :target (file+head+olp ,file-name ,head ("Things ToDo")))
                ;; TODO Eventually remove these/replace:
                ("t" "ToDo" item "[ ] %?"
                :target (file+head+olp ,file-name ,head ("Test"))))
                )))

    (my/set-org-roam-dailies-capture)

;; I used to use this
(defun azr/print-node-link (title)
  "Insert a org-roam-node-link to a title if the file is found, if not print the title as it is"
  (let* ((nd (org-roam-node-from-title-or-alias title)) )
  (if nd
        (let* ((ID (org-roam-node-id nd)))
        (print (format " [[id:%s][%s]]" ID title)))
    (print title))))

(setq org-roam-capture-templates
        ;; Backtick list
        `(("d" "default" plain (file ,dm--org-roam-default-template)
           :target (file ,(expand-file-name "${slug}.org" org-roam-directory))
           :unnarrowed t)

          ("a" "New Area" plain (file ,dm--org-roam-new-area-template)
           :target (file ,(expand-file-name "${slug}.org" org-roam-directory))
           :unnarrowed t)

          ("!t" "test capture" entry "* TEST %?"
           :target (file+datetree "${slug}.org" day)
           ;; :if-new (file+head "${slug}.org" "#+TITLE: ${title}\n")
           :immediate-finish t
           :unnarrowed t)

          ;; Doesn't work with Roam v2 atm.
          ("e" "New Entry" entry "* %?"
           :if-new (file+head "${slug}.org" "#+TITLE: ${title}\n")
           :unnarrowed t)

          ("E" "New Entry with ID" entry "* %?\nPROPERTIES:
:ID:%(org-id-get-create t)
:END:"
           :if-new (file+head "${slug}.org" "#+TITLE: ${title}\n")
           :unnarrowed t)

          ("r" "Reading General")
          ("rr" "Reading" plain (file ,dm--org-roam-reading-template)
           :target (file ,(expand-file-name "${slug}.org" org-roam-directory))
           :unnarrowed t)

          ("rc" "Reading Character" plain (file ,dm--org-roam-reading-character-template)
           :target (file ,(expand-file-name "${slug}.org" org-roam-directory))
           :unnarrowed t)

          ("j" "Japanese")
          ;; ("jj" "Japanese Vocabulary" plain
          ;;  (file (lambda () (dm/get-japanese-filename (dm/prompt-string "Test input:" 'dm--org-capture-area))))
          ;;  (file ,dm--org-roam-japanese-vocabulary-template)
          ;;  :unnarrowed t)

          ;; ("jj" "Japanese Vocabulary" plain (file ,dm--org-roam-japanese-vocabulary-template)
          ;;  :target (file ,(expand-file-name "${slug}.org" org-roam-directory))
          ;;  :unnarrowed t)

;;           ("jj" "Japanese Vocabulary" plain "- tags :: [[roam:Japanese]]\n* Definition %?"
;;            :if-new (file+head "${slug}.org" ":PROPERTIES:
;; :ROAM_ALIASES: %^{prompt}
;; :END:
;; ,#+TITLE: ${title}\n")
;;            :unnarrowed t)

          ;; TODO refactor this to normal org capture
          ("jk" "Japanese Kanji" plain "- tags :: [[roam:Japanese]]\n* Readings\n** onyomi %?\n** kunyomi"
           :if-new (file+head "${slug}.org" ":PROPERTIES:
:ROAM_ALIASES: %^{prompt}
:END:
#+TITLE: ${title}\n")
           :unnarrowed t)

          ("v" "Vispero")
          ("vv" "Vispero Default" plain (file ,dm--org-roam-default-template)
           :target (file ,(expand-file-name "${slug}.org" dm--org-roam-vispero-dir))
           :unnarrowed t)

          ("vt" "Vispero Tagged" plain (file ,dm--org-roam-vispero-tagged-template)
           :target (file ,(expand-file-name "${slug}.org" dm--org-roam-vispero-dir))
           :unnarrowed t)

          ("vp" "Vispero People" plain (file ,dm--org-roam-vispero-people-template)
           :target (file ,(expand-file-name "${slug}.org" dm--org-roam-vispero-dir))
           :unnarrowed t)

          ;; Need to add ":ROAM_REFS: http://bugzilla.fsi.local/show_bug.cgi?id=${slug}" to property
          ("vb" "Vispero Bug" plain "- tags :: [[roam:Vispero Bugzilla]] %?\n* Notes\n* Logging\n"
           :if-new (file+head "vispero/bugs/Bug ${slug}.org" ":PROPERTIES:
:ROAM_REFS: http://bugzilla.fsi.local/show_bug.cgi?id=${slug}
:END:
#+TITLE: Bug ${title}\n#+filetags: :bug:\n")
           :unnarrowed t)

          ("s" "Sirius")
          ("ss" "Sirius Default" plain (file ,dm--org-roam-default-template)
           :target (file ,(expand-file-name "${slug}.org" dm--org-roam-sirius-dir))
           :unnarrowed t)

          ("st" "Sirius Tagged" plain (file ,dm--org-roam-sirius-tagged-template)
           :target (file ,(expand-file-name "${slug}.org" dm--org-roam-sirius-dir))
           :unnarrowed t)

          ("sp" "Sirius People" plain (file ,dm--org-roam-sirius-people-template)
           :target (file ,(expand-file-name "${slug}.org" dm--org-roam-sirius-dir))
           :unnarrowed t)

          ;; @TODO this might need to be removed or changed to whatever bug system is used at Sirius
          ;; Need to add ":ROAM_REFS: http://bugzilla.fsi.local/show_bug.cgi?id=${slug}" to property
          ("sb" "Sirius Bug" plain "- tags :: [[roam:Sirius Bugzilla]] %?\n* Notes\n* Logging\n"
           :if-new (file+head "sirius/bugs/Bug ${slug}.org" ":PROPERTIES:
:ROAM_REFS: http://bugzilla.fsi.local/show_bug.cgi?id=${slug}
:END:
#+TITLE: Bug ${title}\n#+filetags: :bug:\n")
           :unnarrowed t)
          ))

(defun my/url-format (path1 path2 title)
  (concat path1 "/" path2 "/" (string-replace "/" "-" title) ".org"))

(defun my/parse-jama-review (path1 path2 title url)
 (concat path1 "/" path2 "/" title (string-remove-prefix "/r:REV-" (url-target (url-generic-parse-url (string url))))))

(defun my/parse-jama-review-url (url)
  (message "Url being called = " url)
 (string-remove-prefix "/r:REV-" (url-target (url-generic-parse-url url))))

(defun my/parse-jama-review-short (url)
  (concat ":PROPERTIES:\n:ROAM_REFS: " url "\n:END:\n#+TITLE: Jama review - " (my/parse-jama-review-url url) "\n#+filetags: :review:\n"))

(defun my/jama-test (url)
  (expand-file-name (concat "Jama review - " (my/parse-jama-review-url url) ".org") dm--org-roam-sirius-review-dir))

  (setq org-roam-capture-ref-templates
        `(("g" "general" plain (file ,dm--org-roam-ref-general-template)
           :target (file ,(expand-file-name "%(url-host (url-generic-parse-url \"${ref}\"))-${slug}.org" dm--org-roam-website-dir))
           :unnarrowed t)

        ("j" "jira" plain "- tags :: [[roam:Sirius Jira]] %?\n* TODO ${title}\nSCHEDULED: %^{Schedule}t"
           :if-new (file+head "sirius/jira/${title}.org" ":PROPERTIES:
:ROAM_REFS: ${ref}
:END:
#+TITLE: ${title}\n#+filetags: :jira:\n")
           :unnarrowed t)

        ("r" "review" plain "- tags :: [[roam:Sirius Reviews]] %?\n* TODO Review ${title}\nSCHEDULED: %^{Schedule}t"
           :if-new (file+head ,(my/url-format "sirius" "reviews" "${slug}") ":PROPERTIES:
:ROAM_REFS: ${ref}
:END:
#+TITLE: ${title}\n#+filetags: :review:\n")
           :unnarrowed t)

        ;; ("z" "jama" plain "- tags :: [[roam:Sirius Reviews]] %?\n* TODO ${title}\nSCHEDULED: %^{Schedule}t"
        ;;    :if-new (file ,dm--org-roam-jama-review-template)

        ("z" "jama" plain (file ,dm--org-roam-jama-review-template)
           :target (file ,(expand-file-name "Jama_Reviews.org" dm--org-roam-sirius-review-dir))
           ;; :target (file ,(expand-file-name (my/parse-jama-review-url "${ref}") dm--org-roam-sirius-review-dir))
           ;; :target (file ,(expand-file-name (concat "Jama review - " (my/parse-jama-review-url "${ref}") ".org") dm--org-roam-sirius-review-dir))

         ;; Working-ish
           ;; :target (file ,(my/jama-test "${ref}"))

           ;; :if-new (file+head ,(my/parse-jama-review "sirius" "reviews" "Jama review - " "${ref}") ,(my/parse-jama-review-short "${ref}"))

;;            :if-new (file+head ,(my/parse-jama-review "sirius" "reviews" "Jama review - " "${ref}") ":PROPERTIES:
;; :ROAM_REFS: ${ref}
;; :END:
;; ,#+TITLE: Jama review - %(my/parse-jama-review-short ${ref})\n#+filetags: :review:\n")
;; ,#+TITLE: ${title}\n#+filetags: :review:\n")
           :unnarrowed t)

;;         ("r" "review" plain "- tags :: [[roam:Vispero Swarm Reviews]] %?\n* TODO ${title}\nSCHEDULED: %^{Schedule}t"
;;            :if-new (file+head "vispero/reviews/${title}.org" ":PROPERTIES:
;; :ROAM_REFS: ${ref}
;; :END:
;; ,#+TITLE: ${title} for %^{prompt}\n#+filetags: :review:\n")
;;            :unnarrowed t)

        ("b" "bug" plain "- tags :: [[roam:Vispero Bugzilla]] %?\n* ${title}\n** Notes\n"
           :if-new (file+head "vispero/bugs/${title}.org" ":PROPERTIES:
:ROAM_REFS: ${ref}
:END:
#+TITLE: ${title}\n#+filetags: :bug:\n")
           :unnarrowed t)


;; Generic roam reg remplate for reference
;; (setq org-roam-capture-ref-templates
;;       '(("r" "ref" plain #'org-roam-capture--get-point "%?"
;;          :file-name "website/%(url-host (url-generic-parse-url \"${ref}\"))-${slug}"
;;          :head "#+TITLE: ${title}\n#+roam_key: ${ref}\n- tags ::  "
;;          :unnarrowed t))))
                        )))

Vulpea

  • GitHub
  • A convenient wrapper around org-roam which adds extra functionality
(use-package! vulpea
  :ensure t
  ;; hook into org-roam-db-autosync-mode you wish to enable
  ;; persistence of meta values (see respective section in README to
  ;; find out what meta means)
  :hook ((org-roam-db-autosync-mode . vulpea-db-autosync-enable)))

Main Functionality

  • This is the original implementation from d12frosted with some personal edits.
(defun vulpea-project-p ()
  "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
   (lambda (type)
     (eq type 'todo))
   (org-element-map
       (org-element-parse-buffer 'headline)
       'headline
     (lambda (h)
       (org-element-property :todo-type h)))))

;; Original function
;; (defun vulpea-project-p ()
;;   "Return non-nil if current buffer has any todo entry."
;;   (org-element-map
;;       (org-element-parse-buffer 'headline)
;;       'headline
;;     (lambda (h)
;;       (and (org-element-property :todo-type h)
;;            (not (org-element-property :archivedp h))))
;;            ;; (not (org-in-archived-heading-p h))))
;;            ;; (not (seq-contains-p (org-element-property :tags h)
;;            ;;                      "ARCHIVE"))))
;;     nil 'first-match))

(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 "project" tags))
            (setq tags (remove "project" 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 'project' 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 "%\"project\"%"))]))))

Required Vulpea functions

  • Functions borrowed from Vulpea library
    • Not needed if you include the Vulpea package
    • Link
(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 ""))))

Custom functions to see DONE files

(defun my/set-agenda-files-personal ()
  "Sets the org-agenda-files to personal non journal/dailies"
  (setq org-agenda-files (seq-filter (lambda(x) (not (string-match "/\\(sirius\\|vispero\\|journal\\|daily\\)/" (file-name-directory x))))
        (directory-files-recursively "~/Dropbox/org/roam" "\\.org$"))))

(defun my/set-agenda-files-vispero ()
  "Sets the org-agenda-files to Vispero non journal/dailies/bugs/reviews"
  (setq org-agenda-files (seq-filter (lambda(x) (not (string-match "/\\(journal\\|daily\\|bugs\\|reviews\\)/" (file-name-directory x))))
        (directory-files-recursively "~/Dropbox/org/roam/vispero" "\\.org$"))))

(defun my/set-agenda-files-sirius ()
  "Sets the org-agenda-files to Sirius non journal/dailies/bugs/reviews"
  (setq org-agenda-files (seq-filter (lambda(x) (not (string-match "/\\(journal\\|daily\\|bugs\\|reviews\\)/" (file-name-directory x))))
        (directory-files-recursively "~/Dropbox/org/roam/sirius" "\\.org$"))))

(defun my/set-agenda-files-all ()
  "Sets the org-agenda-files to everything except journal/dailies"
  (setq org-agenda-files (seq-filter (lambda(x) (not (string-match "/\\(journal\\|daily\\)/" (file-name-directory x))))
        (directory-files-recursively "~/Dropbox/org/roam" "\\.org$"))))

(defun vulpea-agenda-files-update (&rest _)
  "Update the value of `org-agenda-files'."
  (message "vulpea-agenda-files-updated called. Should ignore = %s" dm--ignore-vulpea-agenda-files-update-for-done-state)
  (if dm--ignore-vulpea-agenda-files-update-for-done-state
        (cond
                ((string-equal dm--my-focus "vispero") (funcall #'my/set-agenda-files-vispero))
                ((string-equal dm--my-focus "sirius") (funcall #'my/set-agenda-files-sirius))
                ((string-equal dm--my-focus "personal") (funcall #'my/set-agenda-files-personal))
                ((string-equal dm--my-focus "all") (funcall #'my/set-agenda-files-all))
                (t (funcall #'my/set-org-agenda-files-all)))
    (setq org-agenda-files (vulpea-project-files))))

(defvar dm--ignore-vulpea-agenda-files-update-for-done-state nil
  "If this is set to 't' org-agenda-files will be set to a custom filter on what I want to see for DONE org items. If nil, normally call what vulpea-agenda-files-update would use.")

(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)

(defun my/org-agenda-view-all-done ()
  (interactive)
  (let ((dm--ignore-vulpea-agenda-files-update-for-done-state t))
    (org-agenda nil "Wd")))

(defun my/org-agenda-view-all-new-tags ()
  (interactive)
  (let ((dm--ignore-vulpea-agenda-files-update-for-done-state t))
    (org-agenda nil "Wn")))

Automatic tagging people

(defun vulpea-ensure-filetag ()
"Add respective file tag if it's missing in the current note."
(interactive)
(let ((tags (vulpea-buffer-tags-get))
        (tag (vulpea--title-as-tag)))
    (when (and (seq-contains-p tags "people")
            (not (seq-contains-p tags tag)))
    (vulpea-buffer-tags-add tag))))

(defun vulpea--title-as-tag ()
"Return title of the current note as tag."
(vulpea--title-to-tag (vulpea-buffer-title-get)))

(defun vulpea--title-to-tag (title)
"Convert TITLE to tag."
;; (concat "@" (s-replace " " "" title)))
(s-replace " " "" title))

;; (defun vulpea-tags-add (orig-fun &rest args)
(defun vulpea-tags-add ()
  "Add a tag to current note."
  (interactive)
  ;; since https://github.com/org-roam/org-roam/pull/1515
  ;; `org-roam-tag-add' returns added tag, we could avoid reading tags
  ;; in `vulpea-ensure-filetag', but this way it can be used in
  ;; different contexts while having simple implementation.
  (when (call-interactively #'org-roam-tag-add)
    (vulpea-ensure-filetag)))
  ;; (let ((res (apply orig-fun args)))
  ;;       (when (call-interactively #'org-roam-tag-add)
  ;;       (vulpea-ensure-filetag))))

;; This doesn't work
;; (advice-add 'org-roam-tag-add :around #'vulpea-tags-add)

;; This doesn't work
;; (defun org-roam-node-insert-wrapper (fn)
;;   "Insert a link to the note using FN.

;; If inserted node has PEOPLE tag on it, tag the current outline
;; accordingly."
;;   (interactive)
;;   (when-let*
;;       ((node (funcall fn))
;;        (title (org-roam-node-title node))
;;        (tags (org-roam-node-tags node)))
;;     (when (seq-contains-p tags "people")
;;       (save-excursion
;;         (ignore-errors
;;           (org-back-to-heading)
;;           (org-set-tags
;;            (seq-uniq
;;             (cons
;;              (vulpea--title-to-tag title)
;;              (org-get-tags nil t)))))))))

;; (advice-add
;;  #'org-roam-node-insert
;;  :around
;;  #'org-roam-node-insert-wrapper)

(defun my-vulpea-insert-handle (note)
  "Hook to be called on NOTE after `vulpea-insert'."
  (when-let* ((title (vulpea-note-title note))
              (tags (vulpea-note-tags note)))
    (when (seq-contains-p tags "people")
      (save-excursion
        (ignore-errors
          (org-back-to-heading)
          ;; (when (eq 'todo (org-element-property
          ;;                  :todo-type
          ;;                  (org-element-at-point)))
            (org-set-tags
             (seq-uniq
              (cons
               (vulpea--title-to-tag title)
               (org-get-tags nil t)))))))))
;; )

(add-hook 'vulpea-insert-handle-functions
          #'my-vulpea-insert-handle)

My version for testing

Used for testing. Not currently included.

;; This replaces vulpea-project-files
(defun vulpea-agenda-files ()
  "Return a list of note files that are part of `org-agenda'."
  (seq-map
   #'vulpea-note-path
   (vulpea-db-query-by-tags-some '("project" "agenda" "vispero"))))

;; (defun vulpea-project-files ()
;;   "Return a list of note files that are part of `org-agenda'."
;;   (seq-map
;;    #'vulpea-note-path
;;    (vulpea-db-query-by-tags-some '("project"))))

;; (defun vulpea-agenda-files ()
;;   "Return a list of note files that are part of `org-agenda'."
;;   (seq-map
;;    #'vulpea-note-path
;;    (vulpea-db-query-by-tags-some '("agenda"))))

;; (defun vulpea-journal-files ()
;;   "Return a list of note files that are part of `org-agenda'."
;;   (seq-map
;;    #'vulpea-note-path
;;    (vulpea-db-query-by-tags-some '("journal"))))

;; This replaces vulpea-project-update-tag
(defun my-update-filetags ()
  "Update filetags 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)
             (meta (vulpea-buffer-meta))
             (tags (vulpea-buffer-meta-get-list! meta "tags" 'link)))

        (if (vulpea-project-p)
            (setq tags (cons "project" tags))
          (setq tags (remove "project" tags)))

        ;; (if (seq-contains-p tags "[[id:c0a1e283-0329-4546-b391-18ac52099f01][Vispero]]")
        ;;     (setq tags (cons "vispero" tags))
        ;;   (setq tags (remove "vispero" 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))))))

;; Function to convert files to add a tag
;; But I don't know how to use
;; (defun my-update-files-with-tags ()
;; (interactive)
;; (seq-do
;;  (lambda (note)
;;    ;; do something with buffer visiting note
;;    (vulpea-utils-with-note note
;;      ;; just add a single tag (it handles duplication etc)
;;      (vulpea-buffer-tags-add "vispero")
;;      ;; save buffer
;;      (save-buffer)))
;;  (vulpea-db-query
;;   (lambda (note)
;;     (seq-contains-p
;;      (vulpea-note-meta-get-list
;;       note
;;       "tags"
;;       ;; you could use note here, but (a) it does unnecessary db
;;       ;; call and (b) all we care about is id
;;       'link)
;;      "[[id:c0a1e283-0329-4546-b391-18ac52099f01][Vispero]]")))))

(defun vulpea-project-p ()
  "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-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-agenda-files-update (&rest _)
  "Update the value of `org-agenda-files'."
  (setq org-agenda-files (vulpea-agenda-files)))

(add-hook 'find-file-hook #'my-update-filetags)
(add-hook 'before-save-hook #'my-update-filetags)

(advice-add 'org-agenda :before #'vulpea-agenda-files-update)
(advice-add 'org-todo-list :before #'vulpea-agenda-files-update)

Vertico

  • Search and auto-complete
(after! vertico
  (setq vertico-sort-function 'vertico-sort-alpha))

Key mappings

General

(defun my/org-next-parent-heading ()
  "Jumps to the next parent heading."
    (interactive)
    (org-up-element)
    (org-forward-element))

;; Code completion to use TAB
(map! :after company
      :map company-active-map
      [tab] #'company-complete-selection)

(map! :leader
      "+" #'hydra/text-zoom/body
      "W" #'my/hydra/window-nav/body
      "A" #'my/hydra/agenda-nav/body
      "X" #'my/hydra/general-capture/body
      "R" #'my/hydra/roam/body
      "w /" #'evil-window-vsplit
      "w -" #'evil-window-split
      "RET" #'org-insert-subheading
      "k" #'org-previous-visible-heading
      "K" #'outline-up-heading
      "j" #'org-next-visible-heading
      "J" #'my/org-next-parent-heading
      ;; "J" #'(lambda () (interactive) (call-interactively #'outline-up-heading) (call-interactively #'org/insert-item-below))
      ;; "J" #'(lambda () (interactive) (call-interactively #'outline-up-heading) (#'org/insert-item-below 1))
      "I" #'org-roam-insert
      :desc "Insert Immediate" "n r I" #'org-roam-node-insert-immediate
      :desc "Roam Refile Header" "n r !" #'org-roam-refile
      :desc "Journal Schedule View" "n j S" #'org-journal-schedule-view
      :desc "Journal Reschedule Scheduled Entry" "n j r" #'org-journal-reschedule-scheduled-entry
      ;; Org-roam-dailies key-remapping :
      :desc "Goto today" "n r d t" #'my/org-roam-dailies-goto-today
      :desc "Goto date" "n r d d" #'my/org-roam-dailies-goto-date
      :desc "Goto tomorrow" "n r d m" #'my/org-roam-dailies-goto-tomorrow
      :desc "Goto yesterday" "n r d y" #'my/org-roam-dailies-goto-yesterday
      ;; Clang keymappings for C/C++ coding
      :desc "Jump to Header/C++" "c h" #'lsp-clangd-find-other-file
      :desc "Jump to Header/C++ other window" "c H"  #'(lambda () (interactive) (lsp-clangd-find-other-file t))
      :desc "Find file - Invalidate Cache" "p F"  #'(lambda () (interactive) (projectile-find-file t))
      ;; :desc "Find file - Other Project" "p O"  #'(lambda () (interactive) (doom/find-file-in-other-project))
      )

;; Remove C-z keybind
(after! evil
  (map! :map 'evil-motion-state-map "C-z" nil)
  (map! :map 'magit-mode-map :n "C-z" nil)
  (map! "C-z" nil))

;; Make Tab to fold groups and Shift-Tab to default back to org-agenda-goto
(map! :after evil-org-agenda
      :map evil-org-agenda-mode-map
      :m [tab] #'origami-toggle-node
      :m [backtab] #'org-agenda-goto)

;; Could instead set doom-localleader-key to ","
(map! :n "," (cmd! (push (cons t ?m) unread-command-events)
                   (push (cons t 32) unread-command-events)))

(map! :v "J" #'drag-stuff-down)
(map! :v "K" #'drag-stuff-up)

(map!
:leader
:prefix "f"
:desc "Find file in private config" "P" #'doom/find-file-in-private-config
:desc "Browse private config" "p" #'doom/open-private-config)

;; Harpoon keymaps
(after! harpoon (setq harpoon-project-package 'projectile))
(map! :leader "l c" 'harpoon-clear)
(map! :leader "l f" 'harpoon-toggle-file)
(map! :n "C-s" 'harpoon-add-file)
;; (map! :n "C-SPC" 'harpoon-toggle-quick-menu)
(map! :n "C-SPC" 'harpoon-quick-menu-hydra)
(map! :n "<f1>" 'harpoon-go-to-1)
(map! :n "<f2>" 'harpoon-go-to-2)
(map! :n "<f3>" 'harpoon-go-to-3)
(map! :n "<f4>" 'harpoon-go-to-4)
(map! :n "<f5>" 'harpoon-go-to-5)
(map! :n "<f6>" 'harpoon-go-to-6)
(map! :n "<f7>" 'harpoon-go-to-7)
(map! :n "<f8>" 'harpoon-go-to-8)
(map! :n "<f9>" 'harpoon-go-to-9)

;; Custom clocking functions
(map!
 :after org
 :map org-mode-map
 :localleader
 (:prefix ("c" . "clock")
  :desc "org-clock-in-at-time" "I" #'my/org-clock-in-at-specified-time
  :desc "org-clock-in-at-time" "O" #'my/org-clock-out-at-specified-time
  ))

;; winum like spacemacs
(map! :after winum :leader
      :n "0" #'winum-select-window-0-or-10
      :n "1" #'winum-select-window-1
      :n "2" #'winum-select-window-2
      :n "3" #'winum-select-window-3
      :n "4" #'winum-select-window-4
      :n "5" #'winum-select-window-5
      :n "6" #'winum-select-window-6
      :n "7" #'winum-select-window-7
      :n "8" #'winum-select-window-8
      :n "9" #'winum-select-window-9)
(after! (winum which-key)
  (push '((nil . "winum-select-window-[0-9]") . t) which-key-replacement-alist))
(after! winum
  (setq winum-scope 'global))

Unused

(map! :after org-journal
      :map org-journal-mode-map
      :localleader
      "c" 'nil
      )

(map!
 :after org-journal
 :map org-journal-mode-map
 :localleader
 (:prefix ("c" . "clock")
  "c" #'org-clock-cancel
  "l" #'+org/toggle-last-clock
  "i" #'org-clock-in
  "I" #'org-clock-in-last
  "o" #'org-clock-out
  "r" #'org-resolve-clocks
  "R" #'org-clock-report
  "t" #'org-evaluate-time-range
  ))

;; Adding to org-capture list
(map!
 :after org
 :map org-capture-mode-map
 ;; :localleader
 ;; (:prefix ("R" . "clock")
  "c" #'org-clock-cancel
  "l" #'+org/toggle-last-clock
  "i" #'org-clock-in
  "I" #'org-clock-in-last
  "o" #'org-clock-out
  "r" #'org-resolve-clocks
  "R" #'org-clock-report
  "t" #'org-evaluate-time-range
  )

;; (map!
;;  :leader
;;  :prefix "X p"
;;  :desc "Project ToDo" "p")
;; (map! :localleader
;; "j j" #'(lambda () (interactive) (call-interactively) (outline-up-heading) (org/insert-item-below)))
;; "j j" #'(lambda () (interactive) (call-interactively #'outline-up-heading) (call-interactively #'org/insert-item-below))
;; "j k" #'outline-up-heading)

Hydra keymaps

Stack functions

(defvar hydra-stack nil)

(defun hydra-push (expr)
  (push `(lambda () ,expr) hydra-stack))

(defun hydra-pop ()
  (interactive)
  (let ((x (pop hydra-stack)))
    (when x
      (funcall x))))

Window navigation

(defhydra my/hydra/window-nav (:hint nil)
  "
          Split: _-_/_v_ert  _/_/_s_:horz
         Delete: _c_lose  _o_nly
  Switch Window: _h_:left  _j_:down  _k_:up  _l_:right  _U_:undo  _R_:redo
    Move Window: _H_:left  _J_:down  _K_:up  _L_:right
        Buffers: _p_revious  _n_ext  _b_:select  _f_ind-file  _p_roject
         Resize: _y_:splitter left  _u_:splitter down  _i_:splitter up  _o_:splitter right  _=_:balance
         Scroll: _a_:up  _z_:down
     Workspaces: _1_  _2_  _3_  _4_  _5_  _N_ew  _D_elete
"
  ("z" scroll-up-line)
  ("a" scroll-down-line)

  ("h" windmove-left)
  ("j" windmove-down)
  ("k" windmove-up)
  ("l" windmove-right)
  ("U" winner-undo)
  ("R" winner-redo)

  ("H" +evil/window-move-left)
  ("J" +evil/window-move-down)
  ("K" +evil/window-move-up)
  ("L" +evil/window-move-right)

  ("p" previous-buffer)
  ("n" next-buffer)
  ("b" switch-to-buffer)
  ("f" find-file)
  ("p" projectile-switch-project)

  ("s" split-window-below)
  ("-" split-window-below)
  ("v" split-window-right)
  ("/" split-window-right)

  ("c" delete-window)
  ("x" delete-window)
  ("o" delete-other-windows)

  ("y" (lambda()
         (interactive)
         (call-interactively (hydra-move-splitter-left 10))))
  ("u" (lambda()
         (interactive)
         (call-interactively (hydra-move-splitter-down 10))))
  ("i" (lambda()
         (interactive)
         (call-interactively (hydra-move-splitter-up 10))))
  ("o" (lambda()
         (interactive)
         (call-interactively (hydra-move-splitter-right 10))))
  ("=" balance-windows)

  ("1" +workspace/switch-to-0)
  ("2" +workspace/switch-to-1)
  ("3" +workspace/switch-to-2)
  ("4" +workspace/switch-to-3)
  ("5" +workspace/switch-to-4)
  ("D" +workspace/delete)
  ("N" +workspace/new)

  ("q" nil))

Agenda

(defvar dm--focus-current-buffer nil)

(defun dm--toggle-agenda-buffer-focus ()
  "Toggles agenda focus for custom hydra menu."
  (interactive)

        (message "focus current value IN SETTER before = %s" dm--focus-current-buffer)
  (if (equal dm--focus-current-buffer "<")
        (setq dm--focus-current-buffer nil)
        (setq dm--focus-current-buffer "<")
        (message "focus current value IN SETTER after = %s" dm--focus-current-buffer)
        )
  )

(defun dm--reset-agenda-buffer-focus (&rest _)
  "Resets agenda focus for custom hydra menu."
    (interactive)
    (message "focus current value in RESET initial value = %s" dm--focus-current-buffer)
    (setq dm--focus-current-buffer nil))

(defun dm--org-agenda-wrapper (key)
    (interactive)
    ()
    (message "focus current value in wrapper = %s" dm--focus-current-buffer)
    (with-current-buffer (buffer-name) (call-interactively (org-agenda nil key dm--focus-current-buffer))))

;; Reset the custom variable on each entry. Hydra's pre/post is buggy.
(advice-add 'my/hydra/agenda-nav/body :before #'dm--reset-agenda-buffer-focus)

(defhydra my/hydra/agenda-nav (:hint nil
                               :exit t
                               )
"
Current focus : %`dm--my-focus
Current buffer focus : %`dm--focus-current-buffer
"
  ("A" org-agenda "Org Agenda")
  ("q" nil "Quit")
  ("1" my/org-focus-personal "Personal ":exit nil :column "Focus")
  ("2" my/org-focus-sirius "Sirius ":exit nil :column "Focus")
  ("3" my/org-focus-vispero "Vispero ":exit nil :column "Focus")
  ("4" my/org-focus-all "All":exit nil :column "Focus")
  ("<" (lambda()
         (interactive)
         (call-interactively #'dm--toggle-agenda-buffer-focus))
   "Buffer Focus":exit nil :column "Buffer")
  (">" (lambda()
         (interactive)
         (call-interactively #'dm--reset-agenda-buffer-focus))
   "Reset Focus":exit nil :column "Buffer")
  ("t"
        (lambda()
         (interactive)
         (message "Current buffer = %s" (buffer-name))
         (message "Org-agenda-files = %s" org-agenda-files)
        (message "focus current value = %s" dm--focus-current-buffer)
         (call-interactively (dm--org-agenda-wrapper "t")))
   "Today" :column "Agenda Views"
   )

  ("w" (lambda()
         (interactive)
         (call-interactively (dm--org-agenda-wrapper "w")))
   "Week" :column "Agenda Views")
  ("b" (lambda()
         (interactive)
         (call-interactively (dm--org-agenda-wrapper "b")))
   "2 Weeks" :column "Agenda Views")
  ("m" (lambda()
         (interactive)
         (call-interactively (dm--org-agenda-wrapper "m")))
   "Month" :column "Agenda Views")
  ("y" (lambda()
         (interactive)
         (call-interactively (dm--org-agenda-wrapper "y")))
   "Year" :column "Agenda Views")

  ("W" (lambda()
         (interactive)
         (call-interactively (dm--org-agenda-wrapper "pw")))
   "Planning week" :column "Planning")
  ("M" (lambda()
         (interactive)
         (call-interactively (dm--org-agenda-wrapper "pm")))
   "Planning month" :column "Planning")

  ("d" my/org-agenda-view-all-done "All 'DONE'" :column "Misc")
  ("n" my/org-agenda-view-all-new-tags "All 'new'" :column "Misc")
  ("o" (lambda()
         (interactive)
         (call-interactively (org-open-file +org-capture-todo-file)))
   "Open agenda file" :column "Misc")
)

General capture

(defhydra my/hydra/general-capture (:hint nil
                               :exit t)
"
Current focus : %`dm--my-focus
"
  ("X" org-capture "Org Capture")
  ("q" nil "Quit")
  ("1" my/org-focus-personal "Personal ":exit nil :column "Focus")
  ("2" my/org-focus-sirius "Sirius ":exit nil :column "Focus")
  ("3" my/org-focus-vispero "Vispero ":exit nil :column "Focus")
  ("4" my/org-focus-all "All":exit nil :column "Focus")

  ("j" my/hydra/journal-capture/body "Journal Capture" :exit t)
  ("d" my/org-roam-dailies-goto-date "Goto Dailies" :exit t)
  ("D" my/org-roam-capture-goto-date "Capture Dailies" :exit t)

  ("t" (lambda()
         (interactive)
         (call-interactively (org-capture nil "t")))
   "ToDo")
  ("T" (lambda()
         (interactive)
         (call-interactively (org-capture nil "T")))
   "Scheduled ToDo")
  ("i" (lambda()
         (interactive)
         (call-interactively (org-capture nil "i")))
   "New Idea")
)

Journal capture

(defhydra my/hydra/journal-capture (:hint nil
                               :exit t)
"
Current focus : %`dm--my-focus
"
  ("q" nil "Quit")
  ("1" my/org-focus-personal "Personal ":exit nil :column "Focus")
  ("2" my/org-focus-sirius "Sirius ":exit nil :column "Focus")
  ("3" my/org-focus-vispero "Vispero ":exit nil :column "Focus")
  ("4" my/org-focus-all "All":exit nil :column "Focus")

  ("j" (lambda()
         (interactive)
         (call-interactively (org-roam-dailies-capture-today nil "jj")))
   "Entry")
  ("J" (lambda()
         (interactive)
         (call-interactively 'org-store-link) (org-roam-dailies-capture-today nil "jl"))
   "Link")
  ("t" (lambda()
         (interactive)
         (call-interactively (org-roam-dailies-capture-today nil "jc")))
   "Clocked In")
  ("T" (lambda()
         (interactive)
         (call-interactively (my/org-clock-in-at-specified-time)))
   "Clocked In at Time")
  ("O" (lambda()
         (interactive)
         (call-interactively (my/org-clock-out-at-specified-time)))
   "Clock Out at Time")
  ("l" (lambda()
         (interactive)
         (call-interactively (org-roam-dailies-capture-today nil "!JL")))
   "Lunch")
  ("s" (lambda()
         (interactive)
         (call-interactively (org-roam-dailies-capture-today nil "!JS")))
   "Startup")
  ("h" my/org-roam-help-people "Helping Person")
)

Roam

(defhydra my/hydra/roam (:hint nil
                               :exit t)
"
Current focus : %`dm--my-focus
"
  ("q" nil "Quit")
  ("1" my/org-focus-personal "Personal ":exit nil :column "Focus")
  ("2" my/org-focus-sirius "Sirius ":exit nil :column "Focus")
  ("3" my/org-focus-vispero "Vispero ":exit nil :column "Focus")
  ("4" my/org-focus-all "All":exit nil :column "Focus")

  ("R" org-roam-capture "Org-Roam Capture" :exit t)
  ("i" org-roam-node-insert  "Insert Node" :exit t)
  ("I" org-roam-node-insert-immediate  "Insert Immediate" :exit t)

  ("j" (lambda()
         (interactive)
         (call-interactively (org-roam-dailies-capture-today nil "jj")))
   "Journal Entry")
  ("t" (lambda()
         (interactive)
         (call-interactively (org-roam-dailies-capture-today nil "jt")))
   "Journal ToDo")
  ("l" (lambda()
         (interactive)
         (call-interactively 'org-store-link) (org-roam-dailies-capture-today nil "jl"))
   "Journal Link")
)

Example with automatic columns

(defhydra my/hydra/agenda-nav (:hint nil
                               :exit t)
"
Testing something %`dm--my-focus
"
  ("1" my/org-focus-personal "Focus personal" :exit nil :column "Vertical")
  ("2" my/org-focus-sirius "Focus Sirius" :exit nil :column "Vertical")
  ("3" my/org-focus-vispero "Focus Vispero" :exit nil :column "Vertical")
  ("4" my/org-focus-all "All":exit nil :column "Vertical")
  ;; ("3" (cmd! (org-agenda nil "t")))
  ("5" (lambda()
         (interactive)
         (call-interactively (org-agenda nil "t")))
   "Today" :column "Test")

  ("6" my/org-focus-vispero "Focus Vispero" :exit nil :column "Horizontal")
  ("7" my/org-focus-vispero "Focus Vispero" :exit nil :column "Test")
  ("8" my/org-focus-vispero "Focus Vispero" :exit nil)

  ("q" nil))

Swap focuses

  • Functions used to swap focuses between personal and work.
  • This utilized in various places in my configuration.
    • Capture templates
    • Org-agenda files
    • Org-agenda views
    • Org-roam functionality
(defun my/org-focus-personal ()
  (interactive)
  (setq dm--my-focus "personal")
  (my/call-focus-function-setters))

(defun my/org-focus-vispero ()
  (interactive)
  (setq dm--my-focus "vispero")
  (my/call-focus-function-setters))

(defun my/org-focus-sirius ()
  (interactive)
  (setq dm--my-focus "sirius")
  (my/call-focus-function-setters))

(defun my/org-focus-all ()
  (interactive)
  (setq dm--my-focus "all")
  (my/call-focus-function-setters))

(defun my/call-focus-function-setters ()
  "Reset templates to their new values"
  (my/set-org-variables)
  (my/set-org-roam-dailies-capture)
  (my/set-org-capture-templates))

Coding

Rust

(after! lsp-rust
  (setq
  lsp-rust-analyzer-server-display-inlay-hints t
  lsp-rust-analyzer-display-parameter-hints t
  lsp-rust-analyzer-max-inlay-hint-length 25
  lsp-rust-analyzer-proc-macro-enable t
  lsp-rust-analyzer-experimental-proc-attr-macros t
  lsp-rust-analyzer-cargo-watch-command "clippy"
  ))

C++

(after! lsp-clangd
  (setq lsp-clients-clangd-args
        '("-j=3"
          "--background-index"
          "--clang-tidy"
          "--completion-style=detailed"
          "--header-insertion=never"
          "--header-insertion-decorators=0"))
  (set-lsp-priority! 'clangd 2))

Jira

;; (setq jiralib-url "https://ips-jira.siriusxm.com")
(setq jiralib-url "ips-jira-int.siriusxm.com")
(setq request-log-level 'blather)
(setq request-message-level 'blather)

Personal Machine

  • This is only tangled if my operating system is “arch”, thus my personal machine.
(setq dm--my-focus "personal")

(setq org-journal-dir "~/Dropbox/org/roam/daily"
    org-journal-date-format "%A, %d %B %Y"
    org-journal-file-header ":PROPERTIES:\n:ROAM_ALIASES: \"Personal %A, %B %d %Y\"\n:END:\n#+TITLE: Personal %Y-%m-%d\n"
    org-journal-file-type 'daily
    org-journal-file-format "Personal %Y-%m-%d.org"
    )

(setq doom-font (font-spec :family "Fira Code Retina" :size 18)
      doom-unicode-font (font-spec :family "JuliaMono Medium" :size 18)
      doom-variable-pitch-font (font-spec :family "JuliaMono Medium" :size 18)
      doom-big-font (font-spec :family "Fira Code Retina" :size 24))

(defun test-directory-string (file-path)
  (concat "testDirectory/" file-path))

(defun test-directory-multiple (a b c d)
  (concat "testDirectory/" a b c d))

;; Unused journal code that needs to be removed
;; (setq org-journal-dir "~/Dropbox/org/roam/journal"
;;       ;; org-agenda-files (seq-filter (lambda(x) (not (string-match "/vispero/"(file-name-directory x))))
;;       ;;                              (directory-files-recursively "~/Dropbox/org" "\\.org$"))

;;       org-journal-date-format "%A, %d %B %Y\n"
;;       +org-capture-todo-file "~/Dropbox/org/roam/personal_agenda.org"
;;       ;; org-agenda-files 'personal-agenda-files
;;       org-journal-file-type 'monthly
;;       org-journal-file-format "Journal %Y-%m.org"
;;       )

mu4e

  • I have my mbsyncrc in a different folder on my system.
    • To keep mbsyncrc from being public in my dotfiles.
  • Be sure that the following command is: “mbsync -c ~/.config/mu4e/mbsyncrc -a”.
    • Or wherever your stored mbsyncrc is located.
(after! mu4e
    (set-email-account! "Gmail"
    '((mu4e-sent-folder       . "/Gmail/[Gmail]/Sent Mail")
        (mu4e-drafts-folder     . "/Gmail/[Gmail]/Drafts")
        (mu4e-trash-folder      . "/Gmail/[Gmail]/Trash")
        (mu4e-refile-folder     . "/Gmail/[Gmail]/All Mail")
        (smtpmail-smtp-user     . "dominikmendel95@gmail.com")
        (smtpmail-smtp-server  . "smtp.gmail.com")
        (smtpmail-default-smtp-server  . "smtp.gmail.com")
        (smtpmail-smtp-service . 465)
        (smtpmail-stream-type  . ssl)
        (user-mail-address      . "dominikmendel95@gmail.com")    ;; only needed for mu < 1.4
        (mu4e-compose-signature . "Dominik Mendel"))
    t)

    (set-email-account! "Dominik@Mendel.family"
    '((mu4e-sent-folder       . "/Dominik-Mendel/Sent")
        (mu4e-drafts-folder     . "/Dominik-Mendel/Drafts")
        (mu4e-trash-folder      . "/Dominik-Mendel/Trash")
        (mu4e-refile-folder     . "/Dominik-Mendel/All Mail")
        (smtpmail-smtp-user     . "dominik@mendel.family")
        (smtpmail-smtp-server  . "smtp.migadu.com")
        (smtpmail-default-smtp-server  . "smtp.migadu.com")
        (smtpmail-smtp-service . 465)
        (smtpmail-stream-type  . ssl)
        (user-mail-address      . "dominik@mendel.family")    ;; only needed for mu < 1.4
        (mu4e-compose-signature . "Dominik Mendel"))
    t)

    (setq
        mu4e-get-mail-command "mbsync -c ~/.config/mu4e/mbsyncrc -a"
        mu4e-update-interval  300
        mu4e-main-buffer-hide-personal-addresses t
        message-send-mail-function 'smtpmail-send-it
        mu4e-compose-format-flowed t
        mu4e-change-filenames-when-moving t

        mu4e-maildir-shortcuts
          '((:maildir "/Dominik-Mendel/Inbox" :key ?I :hide-unread t)
            (:maildir "/Dominik-Mendel/Sent" :key ?S :hide-unread t)
            (:maildir "/Dominik-Mendel/spam" :key ?p :hide-unread nil)
            (:maildir "/Gmail/Inbox" :key ?i :hide-unread t)
            (:maildir "/Gmail/[Gmail]/Sent Mail" :key ?s :hide-unread t))

        mu4e-bookmarks
        '((:name "Sent Dom"
            :query "maildir:/Dominik-Mendel/ and testing"
            :key ?d)
        (:name  "Unread messages"
            :query "flag:unread AND NOT flag:trashed"
            :key ?u)
        (:name "Today's messages"
            :query "date:today..now"
            :key ?t)
        (:name "Last 7 days"
            :query "date:7d..now"
            :hide-unread t
            :key ?w)
        (:name "Messages with images"
            :query "mime:image/*"
            :key ?p))
                        ))

Work machine

  • This is only tangled if my operating system is “ubuntu”, thus my work machine.
(setq dm--my-focus "sirius")

;; This is used to help with Windows to WSL Ubuntu file paths.
;; The `find-file-visit-truename nil` only works if manually navigating to a path
(setq directory-abbrev-alist '(("/mnt/c/Users/dmendel/Dropbox" . "/home/dmendel/Dropbox")))

;; (setq org-journal-dir "~/Dropbox/org/roam/vispero/daily"
;;       ;; org-journal-date-format "%A, %d %B %Y\n:CLOCKTABLE:\n#+BEGIN: clocktable :scope subtree :maxlevel 9\n#+END:\n:END:\n"
;;       org-journal-date-format "%A, %d %B %Y"
;;       org-journal-file-header ":PROPERTIES:
;; :ROAM_ALIASES: \"Vispero %A, %B %d %Y\"
;; :END:
;; :CLOCKTABLE:\n#+BEGIN: clocktable :scope vispero-roam :block %Y-%m-%d :maxlevel 9 :fileskip0 t\n#+END:\n:END:\n#+TITLE: Vispero %Y-%m-%d"
;;       org-journal-file-type 'daily
;;       org-journal-file-format "Vispero %Y-%m-%d.org"
;;       )


(setq doom-font (font-spec :family "Fira Code" :size 18)
      doom-variable-pitch-font (font-spec :family "Fira Code" :size 18)
      doom-unicode-font (font-spec :family "JuliaMono Medium" :size 18)
      doom-big-font (font-spec :family "Fira Code" :size 24))

Unused functions

Checkbox attempts

;;Reset checkboxes from Rainer
(defun org-reset-checkbox-state-maybe ()
  "Reset all checkboxes in an entry if the `RESET_CHECK_BOXES' property is set"
  (interactive "*")
  (if (org-entry-get (point) "RESET_CHECK_BOXES")
      (org-reset-checkbox-state-subtree)))

(defun org-checklist ()
  (when (member org-state org-done-keywords) ;; org-state dynamically bound in org.el/org-todo
    (org-reset-checkbox-state-maybe)))

(add-hook 'org-after-todo-state-change-hook 'org-checklist)

;;new attempt
(defun glasser-org-reset-check-on-repeat ()
  (when (and (org-get-repeat) (member org-state org-done-keywords))
    (org-reset-checkbox-state-subtree)))
(add-hook 'org-after-todo-state-change-hook 'glasser-org-reset-check-on-repeat)

Testing functionality

(defun do-nothing-carry-over (old_entries))
(setq org-journal-handle-old-carryover 'do-nothing-carry-over
      org-journal-skip-carryover-drawers (list "CLOCKING"))

;; This doesn't work. Need to add more parameters to satisfy defcustom
(defcustom personal-agenda-files (append (seq-filter (lambda(x) (not (string-match "/vispero/"(file-name-directory x))))
                                                     (directory-files-recursively "~/Dropbox/org/roam" "\\.org$")) (directory-files-recursively "~/Dropbox/org/journal" "\\.org$")))

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages