Simplified my org journaling code
This commit is contained in:
		
							parent
							
								
									2317cc5d37
								
							
						
					
					
						commit
						f2287c59a0
					
				
					 1 changed files with 86 additions and 50 deletions
				
			
		| 
						 | 
					@ -25,33 +25,50 @@ A literate programming configuration file for extending the Journaling capabilit
 | 
				
			||||||
  ;;; Code:
 | 
					  ;;; Code:
 | 
				
			||||||
#+end_src
 | 
					#+end_src
 | 
				
			||||||
* Introduction
 | 
					* Introduction
 | 
				
			||||||
Using the [[https://github.com/bastibe/org-journal][org-journal]] project to easily create /daily/ journal entries:
 | 
					I used to use the [[https://github.com/bastibe/org-journal][org-journal]] project to create /daily/ journal entries, but what I like is one file per journal entry, and that project did more than I needed. I made my own.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#+begin_src emacs-lisp
 | 
					My requirements are simple:
 | 
				
			||||||
  (use-package org-journal
 | 
					 | 
				
			||||||
    :after org
 | 
					 | 
				
			||||||
    :config
 | 
					 | 
				
			||||||
    (setq org-journal-dir "~/journal"
 | 
					 | 
				
			||||||
          org-journal-date-format " "
 | 
					 | 
				
			||||||
          org-journal-time-format ""
 | 
					 | 
				
			||||||
          org-journal-file-type 'daily
 | 
					 | 
				
			||||||
          org-journal-file-format "%Y%m%d")
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  1. A directory of entries, =~/journal=. Each file is based on the date, e.g. =20241228= or =20130401=.
 | 
				
			||||||
 | 
					  2. A minor mode to identify a journal entry as opposed to a regular org file.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Where do I store these?
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#+BEGIN_SRC emacs-lisp
 | 
				
			||||||
 | 
					  (defvar org-journal-dir (expand-file-name "~/journal")
 | 
				
			||||||
 | 
					    "Location of Journal entries, org files.")
 | 
				
			||||||
 | 
					#+END_SRC
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					And what identifies a Journal file?
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#+BEGIN_SRC emacs-lisp
 | 
				
			||||||
 | 
					  (defvar org-journal-rx (rx (group (= 4 digit))
 | 
				
			||||||
 | 
					                             (optional "-")
 | 
				
			||||||
 | 
					                             (group (= 2 digit))
 | 
				
			||||||
 | 
					                             (optional "-")
 | 
				
			||||||
 | 
					                             (group (= 2 digit)))
 | 
				
			||||||
 | 
					    "A regular expression that identifies journal file entries.")
 | 
				
			||||||
 | 
					  #+END_SRC
 | 
				
			||||||
 | 
					And a function to create a new entry:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#+BEGIN_SRC emacs-lisp
 | 
				
			||||||
 | 
					  (defun org-journal-new-entry ()
 | 
				
			||||||
 | 
					    "Opens today's journal entry file."
 | 
				
			||||||
 | 
					    (interactive)
 | 
				
			||||||
 | 
					    (find-file (expand-file-name (format-time-string "%Y%m%d")
 | 
				
			||||||
 | 
					                                 org-journal-dir)))
 | 
				
			||||||
 | 
					#+END_SRC
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					And connect files that /look/ like a Journal entry with =org-mode=:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#+BEGIN_SRC emacs-lisp
 | 
				
			||||||
 | 
					  (add-to-list 'auto-mode-alist `(,org-journal-rx . org-mode))
 | 
				
			||||||
 | 
					#+END_SRC
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					And pull ‘er up:
 | 
				
			||||||
 | 
					#+BEGIN_SRC emacs-lisp
 | 
				
			||||||
    (ha-leader "f j" '("journal" . org-journal-new-entry))
 | 
					    (ha-leader "f j" '("journal" . org-journal-new-entry))
 | 
				
			||||||
 | 
					#+END_SRC
 | 
				
			||||||
 | 
					 | 
				
			||||||
    ;; In normal Org file, I like large headers, but in my Journal,
 | 
					 | 
				
			||||||
    ;; where each task is a header, I want them smaller:
 | 
					 | 
				
			||||||
    (add-hook 'org-journal-mode-hook
 | 
					 | 
				
			||||||
          (lambda ()
 | 
					 | 
				
			||||||
            (set-face-attribute 'org-level-1 nil :height 1.2)
 | 
					 | 
				
			||||||
            (set-face-attribute 'org-level-2 nil :height 1.1)
 | 
					 | 
				
			||||||
            (set-face-attribute 'org-level-3 nil :height 1.0)))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    ;; But new files could use /my formatting/ (which is different
 | 
					 | 
				
			||||||
    ;; than the options available in the project):
 | 
					 | 
				
			||||||
    (ha-auto-insert-file (rx "journal/" (zero-or-more any) (= 8 digit)) "journal"))
 | 
					 | 
				
			||||||
#+end_src
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
This depends on the following [[file:~/.doom.d/snippets/org-journal-mode/__journal][snippet/template file]]:
 | 
					This depends on the following [[file:~/.doom.d/snippets/org-journal-mode/__journal][snippet/template file]]:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -59,48 +76,57 @@ This depends on the following [[file:~/.doom.d/snippets/org-journal-mode/__journ
 | 
				
			||||||
#+title: Journal Entry- `(ha-journal-file-datestamp)`
 | 
					#+title: Journal Entry- `(ha-journal-file-datestamp)`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
$0
 | 
					$0
 | 
				
			||||||
 | 
					 | 
				
			||||||
#+end_src
 | 
					#+end_src
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					And the code to connect that template to those files:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#+BEGIN_SRC emacs-lisp
 | 
				
			||||||
 | 
					  (ha-auto-insert-file (rx "journal/" (regexp org-journal-rx)) "journal"))
 | 
				
			||||||
 | 
					#+END_SRC
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Note that when I create a new journal entry, I want a title that should insert a date to match the file's name, not necessarily the current date (see below).
 | 
					Note that when I create a new journal entry, I want a title that should insert a date to match the file's name, not necessarily the current date (see below).
 | 
				
			||||||
* Journal Filename to Date
 | 
					* Journal Filename to Date
 | 
				
			||||||
Since the Journal's filename represents a date, I should be able to get the "date" associated with a file.
 | 
					Since the Journal's filename represents a date, I should be able to get the "date" associated with a file.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#+begin_src emacs-lisp
 | 
					#+begin_src emacs-lisp
 | 
				
			||||||
  (defun ha-journal-file-date (&optional datename)
 | 
					  (defun ha-journal-file-date (&optional datename)
 | 
				
			||||||
    "Returns a Lisp date-timestamp based on the format of the current filename,
 | 
					    "Return a Lisp date-timestamp from current filename.
 | 
				
			||||||
  or DATENAME if given."
 | 
					  If DATENAME is given, return that timestamp."
 | 
				
			||||||
    (unless datename
 | 
					    (unless datename
 | 
				
			||||||
      (setq datename (buffer-file-name)))
 | 
					      (setq datename (file-name-base (buffer-file-name))))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    (let* ((datename-parser (rx (group (= 4 digit))
 | 
					    (when (string-match org-journal-rx datename)
 | 
				
			||||||
                                (group (= 2 digit))
 | 
					      (let ((day (string-to-number   (match-string 3 datename)))
 | 
				
			||||||
                                (group (= 2 digit))))
 | 
					            (month (string-to-number (match-string 2 datename)))
 | 
				
			||||||
           (parsed-datename (string-match datename-parser datename))
 | 
					            (year(string-to-number   (match-string 1 datename))))
 | 
				
			||||||
           (day (string-to-number (match-string 3 datename)))
 | 
					        (encode-time 0 0 0 day month year))))
 | 
				
			||||||
           (month (string-to-number (match-string 2 datename)))
 | 
					 | 
				
			||||||
           (year(string-to-number (match-string 1 datename))))
 | 
					 | 
				
			||||||
      (encode-time 0 0 0 day month year)))
 | 
					 | 
				
			||||||
#+end_src
 | 
					#+end_src
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					And some unit tests to validate this function:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#+begin_src emacs-lisp :tangle no
 | 
				
			||||||
 | 
					  (ert-deftest ha-journal-file-date-test ()
 | 
				
			||||||
 | 
					    (should (equal (ha-journal-file-date "20240817") '(26304 19056)))
 | 
				
			||||||
 | 
					    (should (equal (ha-journal-file-date "2024-08-17") '(26304 19056))))
 | 
				
			||||||
 | 
					#+end_src
 | 
				
			||||||
Using the "date" associated with a file, we can create our standard timestamp:
 | 
					Using the "date" associated with a file, we can create our standard timestamp:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#+begin_src emacs-lisp
 | 
					#+begin_src emacs-lisp
 | 
				
			||||||
  (defun ha-journal-file-datestamp (&optional datename)
 | 
					  (defun ha-journal-file-datestamp (&optional datename)
 | 
				
			||||||
    "Return a string of the buffer's date (based on the file's name)."
 | 
					    "Return date string of DATENAME if given.
 | 
				
			||||||
 | 
					  If nil, use the buffer's filename's date."
 | 
				
			||||||
    (format-time-string "%e %b %Y (%A)" (ha-journal-file-date datename)))
 | 
					    (format-time-string "%e %b %Y (%A)" (ha-journal-file-date datename)))
 | 
				
			||||||
#+end_src
 | 
					#+end_src
 | 
				
			||||||
 | 
					 | 
				
			||||||
* Journal Capture
 | 
					* Journal Capture
 | 
				
			||||||
Capturing a task (that when uncompleted, would then spillover to following days) could go to the daily journal entry. This requires a special function that opens today's journal, but specifies a non-nil prefix argument in order to inhibit inserting the heading, as =org-capture= will insert the heading.
 | 
					Capturing a task (that when uncompleted, would then spillover to following days) could go to the daily journal entry. This requires a special function that opens today's journal, but specifies a non-nil prefix argument in order to inhibit inserting the heading, as =org-capture= will insert the heading.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#+begin_src emacs-lisp
 | 
					#+begin_src emacs-lisp
 | 
				
			||||||
  (defun org-journal-find-location ()
 | 
					  (defun org-journal-find-location ()
 | 
				
			||||||
    (org-journal-new-entry t)
 | 
					    (org-journal-new-entry)
 | 
				
			||||||
    (org-narrow-to-subtree)
 | 
					 | 
				
			||||||
    (goto-char (point-max)))
 | 
					    (goto-char (point-max)))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  (defvar org-capture-templates (list))
 | 
					  (defvar org-capture-templates (list))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  (add-to-list 'org-capture-templates
 | 
					  (add-to-list 'org-capture-templates
 | 
				
			||||||
               '("j" "Journal Task/Entry" plain
 | 
					               '("j" "Journal Task/Entry" plain
 | 
				
			||||||
                 (function org-journal-find-location)
 | 
					                 (function org-journal-find-location)
 | 
				
			||||||
| 
						 | 
					@ -111,16 +137,18 @@ Capturing a task (that when uncompleted, would then spillover to following days)
 | 
				
			||||||
Sometimes it is obvious what is the /next file/ based on the one I'm currently reading. For instance, in my journal entries, the filename is a number that can be incremented. Same with presentation files...
 | 
					Sometimes it is obvious what is the /next file/ based on the one I'm currently reading. For instance, in my journal entries, the filename is a number that can be incremented. Same with presentation files...
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#+begin_src emacs-lisp
 | 
					#+begin_src emacs-lisp
 | 
				
			||||||
  (defun split-string-with-number (string)
 | 
					  (defun split-string-with-number (str)
 | 
				
			||||||
    "Returns a list of three components of the string, the first is
 | 
					    "Return list of three components of string, STR.
 | 
				
			||||||
    the text prior to any numbers, the second is the embedded number,
 | 
					  The first is the text prior to any numbers, The second is the
 | 
				
			||||||
    and the third is the rest of the text in the string."
 | 
					  embedded number, and the third is the rest of the text in the
 | 
				
			||||||
    (let* ((start (string-match "[0-9]+" string))
 | 
					  string."
 | 
				
			||||||
           (end (string-match "[^0-9]+" string start)))
 | 
					    (let* ((ms (string-match (rx (one-or-more digit)) str)))
 | 
				
			||||||
      (if start
 | 
					      (when ms
 | 
				
			||||||
          (list (substring string 0 start)
 | 
					        (list (substring str 0 ms)
 | 
				
			||||||
                (substring string start end)
 | 
					              (match-string 0 str)
 | 
				
			||||||
                (if end  (substring string end)  "")))))
 | 
					              (substring str
 | 
				
			||||||
 | 
					                         (+ ms
 | 
				
			||||||
 | 
					                            (length (match-string 0 str))))))))
 | 
				
			||||||
#+end_src
 | 
					#+end_src
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Which means that the following defines this function:
 | 
					Which means that the following defines this function:
 | 
				
			||||||
| 
						 | 
					@ -170,6 +198,14 @@ And this allows us to create two simple functions that can load the "next" and "
 | 
				
			||||||
    (interactive)
 | 
					    (interactive)
 | 
				
			||||||
    (find-file (find-file-number-change '1-)))
 | 
					    (find-file (find-file-number-change '1-)))
 | 
				
			||||||
#+end_src
 | 
					#+end_src
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					And we could bind those:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#+BEGIN_SRC emacs-lisp
 | 
				
			||||||
 | 
					  (ha-leader "f +" '("next file" . find-file-increment)
 | 
				
			||||||
 | 
					             "f -" '("previous file" . find-file-decrement))
 | 
				
			||||||
 | 
					#+END_SRC
 | 
				
			||||||
 | 
					
 | 
				
			||||||
* Technical Artifacts                          :noexport:
 | 
					* Technical Artifacts                          :noexport:
 | 
				
			||||||
Let's =provide= a name so we can =require= this file.
 | 
					Let's =provide= a name so we can =require= this file.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue