From 1349f1ffe914c6a8bb34c11892890d1656ee81a6 Mon Sep 17 00:00:00 2001 From: Szymon Szukalski Date: Wed, 8 Apr 2026 09:57:39 +1000 Subject: fix: align config with documented org workflow --- config.org | 152 ++++++++++++++++++++++++------------------------------------- 1 file changed, 60 insertions(+), 92 deletions(-) diff --git a/config.org b/config.org index ed8e7e6..c4eaced 100644 --- a/config.org +++ b/config.org @@ -390,17 +390,15 @@ short and phrase-like so summaries and completion annotations stay readable. (format ":%s: %s\n" key value) "")) - (defun ss/people--ensure-file () - "Create `ss/people-file' when it is missing." - (make-directory (file-name-directory ss/people-file) t) + (defun ss/people--require-file () + "Return `ss/people-file', signaling when it is unavailable." (unless (file-exists-p ss/people-file) - (with-temp-file ss/people-file - (insert "#+title: People\n\n"))) + (user-error "People file does not exist: %s" ss/people-file)) ss/people-file) (defun ss/people-entries () "Return top-level people cards from `ss/people-file'." - (let* ((file (ss/people--ensure-file)) + (let* ((file (ss/people--require-file)) (attributes (file-attributes file)) (mtime (file-attribute-modification-time attributes))) (unless (and ss/people--cache @@ -507,7 +505,7 @@ short and phrase-like so summaries and completion annotations stay readable. (unless (and buffer-file-name (string= (file-truename buffer-file-name) (file-truename ss/people-file))) - (find-file (ss/people--ensure-file))) + (find-file (ss/people--require-file))) (widen) (goto-char (point-min)) (org-overview) @@ -533,7 +531,7 @@ short and phrase-like so summaries and completion annotations stay readable. (defun ss/people--open-entry (entry) "Open the people rolodex file, then narrow to ENTRY for card view." - (find-file (ss/people--ensure-file)) + (find-file (ss/people--require-file)) (widen) (let ((position (org-find-exact-headline-in-buffer (ss/people--entry-name entry)))) @@ -659,7 +657,7 @@ short and phrase-like so summaries and completion annotations stay readable. (user-error "A person card for %s already exists" name)) (when (string-empty-p abbrev) (setq abbrev (ss/people-default-abbrev name))) - (find-file (ss/people--ensure-file)) + (find-file (ss/people--require-file)) (widen) (goto-char (point-max)) (unless (bolp) @@ -683,18 +681,29 @@ short and phrase-like so summaries and completion annotations stay readable. (ss/people-reload) (ss/people--open-entry (ss/people--entry-by-name name)))) + (defun ss/people--clear-installed-abbrevs () + "Remove people-specific abbrevs from the current local table." + (mapatoms + (lambda (symbol) + (when (abbrev-get symbol :ss/people) + (define-abbrev local-abbrev-table (symbol-name symbol) nil))) + local-abbrev-table)) + (defun ss/people-install-abbrevs () "Install people abbrevs into the current buffer." (unless (ss/people--source-buffer-p) (setq-local local-abbrev-table (copy-abbrev-table local-abbrev-table)) + (ss/people--clear-installed-abbrevs) (dolist (entry (ss/people-entries)) (let ((name (ss/people--entry-name entry)) (abbrev (ss/people--entry-abbrev entry))) - (define-abbrev local-abbrev-table - (if (or (null abbrev) (string-empty-p abbrev)) - (ss/people-default-abbrev name) - abbrev) - name))))) + (abbrev-put + (define-abbrev local-abbrev-table + (if (or (null abbrev) (string-empty-p abbrev)) + (ss/people-default-abbrev name) + abbrev) + name) + :ss/people t))))) (defun ss/people-refresh-buffers () "Refresh people abbrevs in every prose buffer." @@ -756,15 +765,13 @@ same root directory and rely on links for relationships. ** Org foundations -The Org setup establishes the shared directories, ensures the PARA structure is -present at startup, and provides a small helper for opening today's daily note -with the standard section layout already in place. Agenda views stay focused on -PARA notes, so project, area, and resource files can surface TODOs without -pulling in daily or archived notes. A small directory helper keeps PARA -subdirectories easy to create from the minibuffer before capturing into them. -A curated =moc.org= in the Org root acts as the startup landing page and quick -navigation surface. The config assumes that file already exists and opens it -directly during startup rather than creating it on demand. +The Org setup establishes the shared directories used by the workflow and +provides helpers that open existing notes at point of use. Agenda views stay +focused on PARA notes, so project, area, and resource files can surface TODOs +without pulling in daily or archived notes. A curated =moc.org= in the Org root +acts as the startup landing page and quick navigation surface. The config +assumes that file already exists and opens it directly during startup rather +than creating it on demand. #+begin_src emacs-lisp (use-package org @@ -793,30 +800,29 @@ directly during startup rather than creating it on demand. (defconst ss/moc-file (expand-file-name "moc.org" ss/org-directory) "Central MOC note.") - (defconst ss/org-note-directories - (list ss/org-directory - ss/org-daily-directory - ss/org-projects-directory - ss/org-areas-directory - ss/org-resources-directory - ss/org-archives-directory) - "Directories that make up the note-taking workflow.") - (defconst ss/org-agenda-directories (list ss/org-projects-directory - ss/org-areas-directory) + ss/org-areas-directory + ss/org-resources-directory) "Directories whose Org files feed the agenda.") - (defconst ss/org-subdirectory-roots - `(("projects" . ,ss/org-projects-directory) - ("areas" . ,ss/org-areas-directory) - ("resources" . ,ss/org-resources-directory)) - "Capture roots offered when creating note subdirectories.") + (defun ss/require-existing-directory (directory) + "Return DIRECTORY, signaling when it does not exist." + (unless (file-directory-p directory) + (user-error "Directory does not exist: %s" directory)) + directory) + + (defun ss/require-existing-file (file) + "Return FILE, signaling when it does not exist." + (unless (file-exists-p file) + (user-error "File does not exist: %s" file)) + file) (defun ss/denote-capture-in-directory (directory &optional keywords &rest prompts) "Start a Denote Org capture in DIRECTORY with KEYWORDS and PROMPTS. If PROMPTS is empty, rely on `denote-prompts'." (let* ((prompt-for-keywords (memq :keywords prompts)) + (directory (ss/require-existing-directory directory)) (denote-directory directory) (denote-use-directory (unless (memq :subdirectory prompts) directory)) (denote-use-keywords @@ -832,62 +838,28 @@ directly during startup rather than creating it on demand. (memq :template prompts)) (denote-org-capture)))) - (defun ss/create-note-subdirectory () - "Create a PARA subdirectory using minibuffer completion." - (interactive) - (let* ((root-name (completing-read - "Capture root: " - (mapcar #'car ss/org-subdirectory-roots) - nil t)) - (root (alist-get root-name ss/org-subdirectory-roots nil nil #'string=)) - (completion-extra-properties '(:category file)) - (candidates - (sort - (delete-dups - (mapcar (lambda (path) - (directory-file-name (file-relative-name path root))) - (seq-filter - #'file-directory-p - (directory-files-recursively root directory-files-no-dot-files-regexp t t)))) - #'string<)) - (subdirectory (completing-read - (format "Subdirectory in %s: " root-name) - candidates - nil nil)) - (target (expand-file-name subdirectory root)) - (existing (file-directory-p target))) - (make-directory target t) - (ss/refresh-org-agenda-files) - (message "%s note directory: %s" - (if existing "Using existing" "Created") - target))) - (defun ss/refresh-org-agenda-files (&rest _) "Refresh `org-agenda-files' from the current PARA directories. Ignore any arguments passed by advice wrappers." (require 'org-agenda) (setq org-agenda-files - (delete-dups - (apply #'append - (mapcar (lambda (directory) - (if (file-directory-p directory) - (directory-files-recursively directory org-agenda-file-regexp) - nil)) - ss/org-agenda-directories))))) + (sort + (delete-dups + (apply #'append + (mapcar (lambda (directory) + (directory-files-recursively + (ss/require-existing-directory directory) + "\\.org\\'")) + ss/org-agenda-directories))) + #'string<))) (defun ss/ensure-daily-note (&optional time) - "Create the daily note for TIME when it does not exist. - Return the path to the note." + "Return the existing daily note path for TIME." (let* ((date (or time (current-time))) (file (expand-file-name (format-time-string "%Y-%m-%d.org" date) ss/org-daily-directory))) - (unless (file-exists-p file) - (make-directory (file-name-directory file) t) - (with-temp-file file - (insert (format "#+title: %s\n\n* Tasks\n\n* Notes\n\n* Open Loops\n" - (format-time-string "%Y-%m-%d" date))))) - file)) + (ss/require-existing-file file))) (defun ss/open-todays-note () "Open today's daily Org note." @@ -897,14 +869,16 @@ directly during startup rather than creating it on demand. (defun ss/open-moc () "Open the central MOC note." (interactive) - (find-file ss/moc-file)) + (find-file (ss/require-existing-file ss/moc-file))) (defun ss/open-agenda () "Refresh agenda files and invoke `org-agenda'." (interactive) (call-interactively #'org-agenda)) :init - (add-hook 'emacs-startup-hook (lambda () (find-file ss/moc-file))) + (add-hook 'emacs-startup-hook + (lambda () + (find-file (ss/require-existing-file ss/moc-file)))) :bind (("C-c a" . ss/open-agenda) ("C-c c" . org-capture) ("C-c n M" . ss/open-moc) @@ -913,7 +887,6 @@ directly during startup rather than creating it on demand. ("C-c n i" . ss/people-insert-name) ("C-c n I" . ss/people-insert-summary) ("C-c n L" . ss/people-report-by-location) - ("C-c n m" . ss/create-note-subdirectory) ("C-c n d" . ss/open-todays-note) ("C-c n o" . ss/people-overview) ("C-c n O" . ss/people-report-by-role) @@ -928,12 +901,7 @@ directly during startup rather than creating it on demand. (setq-local org-hide-emphasis-markers t) (font-lock-flush) (font-lock-ensure))) - (ss/refresh-org-agenda-files) - (advice-add 'org-agenda :before #'ss/refresh-org-agenda-files) - (mapc (lambda (directory) - (make-directory directory t)) - ss/org-note-directories) - (ss/people--ensure-file)) + (advice-add 'org-agenda :before #'ss/refresh-org-agenda-files)) #+end_src ** Capture entry points -- cgit v1.2.3