#+title:  Org Journaling
#+author: Howard X. Abrams
#+date:   2020-09-24
#+tags: emacs org

A literate programming configuration file for extending the Journaling capabilities.

#+begin_src emacs-lisp :exports none
  ;;; org-journaling --- Configuring journals in org. -*- lexical-binding: t; -*-
  ;;
  ;; © 2020-2023 Howard X. Abrams
  ;;   This work is licensed under a Creative Commons Attribution 4.0 International License.
  ;;   See http://creativecommons.org/licenses/by/4.0/
  ;;
  ;; Author: Howard X. Abrams <http://gitlab.com/howardabrams>
  ;; Maintainer: Howard X. Abrams
  ;; Created: September 24, 2020
  ;;
  ;; This file is not part of GNU Emacs.
  ;;
  ;; *NB:* Do not edit this file. Instead, edit the original literate file at:
  ;;            ~/other/hamacs/org-journaling.org
  ;;       And tangle the file to recreate this one.
  ;;
  ;;; Code:
#+end_src
* Introduction
Using the [[https://github.com/bastibe/org-journal][org-journal]] project to easily create /daily/ journal entries:

#+begin_src emacs-lisp
(use-package org-journal
  :init
  (setq org-journal-dir "~/journal"
        org-journal-date-format "TODO "
        org-journal-time-format ""
        org-journal-file-type 'daily
        org-journal-file-format "%Y%m%d")
  :config
#+end_src
Notice that the rest of this file's contents is /contained/ in this =config= section!

And let's put a /leader key/ sequence for it (Doom-specific):

#+begin_src emacs-lisp
(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:

#+begin_src emacs-lisp
(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)))
#+end_src

But new files could use /my formatting/ (which is different than the options available in the project):

#+begin_src emacs-lisp
(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]]:

#+begin_src snippet :tangle ~/other/hamacs/templates/journal
#+TITLE: Journal Entry- `(ha-journal-file-datestamp)`

$0

#+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).
* Journal Filename to Date
Since the Journal's filename represents a date, I should be able to get the "date" associated with a file.

#+begin_src emacs-lisp
(defun ha-journal-file-date (&optional datename)
  "Returns a Lisp date-timestamp based on the format of the current filename,
or DATENAME if given."
  (unless datename
    (setq datename (buffer-file-name)))

  (let* ((datename-parser (rx (group (= 4 digit))
                              (group (= 2 digit))
                              (group (= 2 digit))))
         (parsed-datename (string-match datename-parser datename))
         (day (string-to-number (match-string 3 datename)))
         (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

Using the "date" associated with a file, we can create our standard timestamp:

#+begin_src emacs-lisp
(defun ha-journal-file-datestamp (&optional datename)
  "Return a string of the buffer's date (based on the file's name)."
  (format-time-string "%e %b %Y (%A)" (ha-journal-file-date datename)))
#+end_src

Close the =use-package= call:
#+begin_src emacs-lisp
)
#+end_src
* 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.

#+begin_src emacs-lisp
(defun org-journal-find-location ()
  (org-journal-new-entry t)
  (org-narrow-to-subtree)
  (goto-char (point-max)))

(defvar org-capture-templates (list))
(add-to-list 'org-capture-templates
             '("j" "Journal Task/Entry" plain
               (function org-journal-find-location)
               "* %?\n\n  %i\n\n  From: %a"
               :empty-lines 1 :jump-to-captured t :immediate-finish t))
#+end_src
* Next and Previous File
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
(defun split-string-with-number (string)
  "Returns a list of three components of the string, the first is
  the text prior to any numbers, the second is the embedded number,
  and the third is the rest of the text in the string."
  (let* ((start (string-match "[0-9]+" string))
         (end (string-match "[^0-9]+" string start)))
    (if start
        (list (substring string 0 start)
              (substring string start end)
              (if end  (substring string end)  "")))))
#+end_src

Which means that the following defines this function:

#+begin_src emacs-lisp :tangle no
(ert-deftest split-string-with-number-test ()
  (should (equal (split-string-with-number "abc42xyz") '("abc" "42" "xyz")))
  (should (equal (split-string-with-number "42xyz")    '("" "42" "xyz")))
  (should (equal (split-string-with-number "abc42")    '("abc" "42" "")))
  (should (equal (split-string-with-number "20140424") '("" "20140424" "")))
  (should (null  (split-string-with-number "abcxyz"))))
#+end_src

Given this splitter function, we create a function that takes some sort of operator and return a new filename based on the conversion that happens:

#+begin_src emacs-lisp
(defun find-file-number-change (f)
  (let* ((filename (buffer-file-name))
         (parts    (split-string-with-number
                    (file-name-base filename)))
         (new-name (number-to-string
                    (funcall f (string-to-number (nth 1 parts))))))
    (concat (file-name-directory filename)
            (nth 0 parts)
            new-name
            (nth 2 parts))))
#+end_src

And this allows us to create two simple functions that can load the "next" and "previous" files:

#+begin_src emacs-lisp
(defun find-file-increment ()
  "Takes the current buffer, and loads the file that is 'one
  more' than the file contained in the current buffer. This
  requires that the current file contain a number that can be
  incremented."
  (interactive)
  (find-file (find-file-number-change '1+)))
#+end_src

#+begin_src emacs-lisp
(defun find-file-decrement ()
  "Takes the current buffer, and loads the file that is 'one
  less' than the file contained in the current buffer. This
  requires that the current file contain a number that can be
  decremented."
  (interactive)
  (find-file (find-file-number-change '1-)))
#+end_src
* Technical Artifacts                                :noexport:
Let's =provide= a name so we can =require= this file.

#+begin_src emacs-lisp :exports none
(provide 'ha-org-journaling)
;;; ha-org-journaling.el ends here
#+end_src

Before you can build this on a new system, make sure that you put the cursor over any of these properties, and hit: ~C-c C-c~

#+DESCRIPTION: A literate programming configuration file for extending the Journaling capabilities.

#+PROPERTY:    header-args:sh :tangle no
#+PROPERTY:    header-args:emacs-lisp :tangle yes
#+PROPERTY:    header-args    :results none :eval no-export :comments no mkdirp yes

#+OPTIONS:     num:nil toc:t todo:nil tasks:nil tags:nil date:nil
#+OPTIONS:     skip:nil author:nil email:nil creator:nil timestamp:nil
#+INFOJS_OPT:  view:nil toc:t ltoc:t mouse:underline buttons:0 path:http://orgmode.org/org-info.js
