summaryrefslogtreecommitdiff
path: root/config.org
diff options
context:
space:
mode:
Diffstat (limited to 'config.org')
-rw-r--r--config.org155
1 files changed, 113 insertions, 42 deletions
diff --git a/config.org b/config.org
index 1940874..bbf2457 100644
--- a/config.org
+++ b/config.org
@@ -759,19 +759,19 @@ short and phrase-like so summaries and completion annotations stay readable.
* Notes workflow
-The note-taking system remains deliberately small. Daily notes stay as plain
-Org files in =~/org/daily/=, while longer-lived notes use Denote inside the
+The note-taking system remains deliberately small. Fast operational capture
+goes into =~/org/journal.org=, while longer-lived notes use Denote inside the
same root directory and rely on links for relationships.
** Org foundations
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.
+focused on the journal plus PARA notes, so quick operational tasks and durable
+project, area, and resource files can surface TODOs without pulling in 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
@@ -782,8 +782,8 @@ than creating it on demand.
(defconst ss/org-directory (expand-file-name "~/org/")
"Root directory for Org files.")
- (defconst ss/org-daily-directory (expand-file-name "daily/" ss/org-directory)
- "Directory for plain daily Org notes.")
+ (defconst ss/journal-file (expand-file-name "journal.org" ss/org-directory)
+ "Single-file work journal for operational capture.")
(defconst ss/org-projects-directory (expand-file-name "projects/" ss/org-directory)
"Directory for project notes.")
@@ -800,6 +800,10 @@ than creating it on demand.
(defconst ss/moc-file (expand-file-name "moc.org" ss/org-directory)
"Central MOC note.")
+ (defconst ss/journal-section-headings
+ '("Tasks" "Notes" "Meetings")
+ "Per-day section headings maintained under each journal datetree entry.")
+
(defconst ss/org-agenda-directories
(list ss/org-projects-directory
ss/org-areas-directory
@@ -838,33 +842,100 @@ than creating it on demand.
(memq :template prompts))
(denote-org-capture))))
+ (defun ss/journal-capture-time ()
+ "Return the effective timestamp for the current journal capture."
+ (or org-overriding-default-time
+ (org-capture-get :default-time)
+ (current-time)))
+
+ (defun ss/journal-calendar-date (&optional time)
+ "Return TIME as a Gregorian date list for datetree helpers."
+ (calendar-gregorian-from-absolute
+ (time-to-days (or time (current-time)))))
+
+ (defun ss/journal-goto-date (&optional time create)
+ "Move to TIME's journal date heading.
+When CREATE is non-nil, create the datetree entry when missing."
+ (goto-char (point-min))
+ (if create
+ (progn
+ (require 'org-datetree)
+ (org-datetree-find-date-create (ss/journal-calendar-date time))
+ (org-back-to-heading t)
+ t)
+ (when (re-search-forward
+ (format "^\\*+ %s\\b"
+ (format-time-string "%Y-%m-%d" (or time (current-time))))
+ nil t)
+ (goto-char (match-beginning 0))
+ t)))
+
+ (defun ss/journal-ensure-day-sections ()
+ "Ensure the standard section headings exist under the current journal day."
+ (org-back-to-heading t)
+ (let ((section-level (1+ (org-outline-level))))
+ (save-restriction
+ (org-narrow-to-subtree)
+ (dolist (section ss/journal-section-headings)
+ (goto-char (point-min))
+ (unless (org-find-exact-headline-in-buffer section)
+ (goto-char (point-max))
+ (unless (bolp)
+ (insert "\n"))
+ (insert (make-string section-level ?*) " " section "\n"))))))
+
+ (defun ss/journal-goto-section (section &optional time)
+ "Move to SECTION beneath TIME's journal date, creating structure as needed."
+ (unless (member section ss/journal-section-headings)
+ (user-error "Unknown journal section: %s" section))
+ (ss/journal-goto-date time 'create)
+ (ss/journal-ensure-day-sections)
+ (let ((section-level (1+ (org-outline-level)))
+ position)
+ (save-restriction
+ (org-narrow-to-subtree)
+ (goto-char (point-min))
+ (when (re-search-forward
+ (format "^%s %s$"
+ (make-string section-level ?*)
+ (regexp-quote section))
+ nil t)
+ (setq position (match-beginning 0))))
+ (unless position
+ (user-error "Journal section not found: %s" section))
+ (goto-char position)
+ (org-back-to-heading t)))
+
+ (defun ss/journal-capture-target (section)
+ "Select SECTION under today's journal datetree entry for capture."
+ (set-buffer (find-file-noselect (ss/require-existing-file ss/journal-file)))
+ (widen)
+ (ss/journal-goto-section section (ss/journal-capture-time)))
+
(defun ss/refresh-org-agenda-files (&rest _)
- "Refresh `org-agenda-files' from the current PARA directories.
+ "Refresh `org-agenda-files' from the journal and PARA directories.
Ignore any arguments passed by advice wrappers."
(require 'org-agenda)
(setq org-agenda-files
(sort
(delete-dups
- (apply #'append
- (mapcar (lambda (directory)
- (directory-files-recursively
- (ss/require-existing-directory directory)
- "\\.org\\'"))
- ss/org-agenda-directories)))
+ (append
+ (list (ss/require-existing-file ss/journal-file))
+ (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)
- "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)))
- (ss/require-existing-file file)))
-
- (defun ss/open-todays-note ()
- "Open today's daily Org note."
+ (defun ss/open-journal ()
+ "Open `ss/journal-file', moving to today's entry when it exists."
(interactive)
- (find-file (ss/ensure-daily-note)))
+ (find-file (ss/require-existing-file ss/journal-file))
+ (widen)
+ (unless (ss/journal-goto-date)
+ (goto-char (point-max))))
(defun ss/open-moc ()
"Open the central MOC note."
@@ -887,7 +958,7 @@ 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 d" . ss/open-todays-note)
+ ("C-c n d" . ss/open-journal)
("C-c n o" . ss/people-overview)
("C-c n O" . ss/people-report-by-role)
("C-c n p" . ss/people-open)
@@ -906,13 +977,13 @@ than creating it on demand.
** Capture entry points
-Daily capture goes to today's plain Org file. Tasks land under =Tasks= while
-notes and meetings land under =Notes=. Denote capture uses Denote's own Org
-integration so note identity, metadata, and directories stay under Denote's
-control rather than custom code. The convenience templates keep the familiar
-entry points, but only project capture injects a structural keyword by default.
-The people rolodex lives outside =org-capture=: adding a person uses the
-dedicated =ss/people-add= command so =~/org/areas/people/people.org= stays a compact,
+Fast operational capture goes to =~/org/journal.org= using a datetree with
+per-day =Tasks=, =Notes=, and =Meetings= headings. Denote capture uses Denote's
+own Org integration so note identity, metadata, and directories stay under
+Denote's control rather than custom code. The convenience templates keep the
+familiar entry points, but only project capture injects a structural keyword by
+default. The people rolodex lives outside =org-capture=: adding a person uses
+the dedicated =ss/people-add= command so =~/org/areas/people/people.org= stays a compact,
structured card file rather than turning into another capture target.
#+begin_src emacs-lisp
@@ -921,15 +992,15 @@ structured card file rather than turning into another capture target.
:after (org denote)
:config
(setq org-capture-templates
- `(("d" "Daily")
- ("dt" "Task" entry
- (file+headline ,#'ss/ensure-daily-note "Tasks")
+ `(("j" "Journal")
+ ("jt" "Task" entry
+ (function (lambda () (ss/journal-capture-target "Tasks")))
"* TODO %?")
- ("dn" "Note" entry
- (file+headline ,#'ss/ensure-daily-note "Notes")
+ ("jn" "Note" entry
+ (function (lambda () (ss/journal-capture-target "Notes")))
"* %?")
- ("dm" "Meeting" entry
- (file+headline ,#'ss/ensure-daily-note "Notes")
+ ("jm" "Meeting" entry
+ (function (lambda () (ss/journal-capture-target "Meetings")))
"* %<%H:%M> meeting %?")
("n" "Denote")
("nn" "Generic" plain