Last active
November 19, 2022 17:50
-
-
Save redblobgames/ca9d0808f13a42f9c6e64c913e2a5894 to your computer and use it in GitHub Desktop.
my journal code
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
;;; my-diary.el --- | |
;;; Commentary: | |
;; My daily diary, inspired by org-journal, but customized for my needs. | |
;; | |
;; My keybindings: H-j to open the diary file (global binding), then | |
;; H-j to add an entry (local binding). C-c C-b, C-c C-f to move days | |
;; (like org-journal). H-i to search previous headings for completion, | |
;; so that I can reuse headings and then analyze them. | |
;;; Code: | |
(require 'org) | |
;;; Configuration variables | |
(defvar my-diary-directory "~/Documents/journal/") | |
(defvar my-diary-filename | |
(expand-file-name (concat my-diary-directory "%Y-%m-%d.org"))) | |
(defvar my-diary-filename-regexp | |
(concat "\\`" | |
(s-replace "%Y-%m-%d" "\\(....-..-..\\)" | |
(regexp-quote my-diary-filename)) | |
"\\'")) | |
(add-to-list 'auto-mode-alist (cons my-diary-filename-regexp 'my-diary-mode)) | |
;;; Helper functions | |
(defun my-diary-filename-to-date (filename) | |
(let ((str (cadr (s-match my-diary-filename-regexp (expand-file-name filename))))) | |
(when str | |
(let* ((time (parse-time-string str)) | |
(date (list (nth 4 time) (nth 3 time) (nth 5 time)))) | |
date)))) | |
(defun my-diary-calendar-day-to-time (calendar-day) | |
(encode-time 0 0 0 (nth 1 calendar-day) (nth 0 calendar-day) (nth 2 calendar-day))) | |
(defun my-diary-change-day (dir) | |
"Construct filename 'dir' days from current filename" | |
(let* ((day (calendar-absolute-from-gregorian (my-diary-filename-to-date (buffer-file-name)))) | |
(newday (calendar-gregorian-from-absolute (+ day dir)))) | |
(format-time-string | |
my-diary-filename | |
(my-diary-calendar-day-to-time newday)))) | |
;;; Commands | |
(defun my-diary-today () | |
"Open today's diary file" | |
(interactive) | |
(find-file (format-time-string my-diary-filename)) | |
(when (equal (point-max) 1) | |
(let ((calendar-date (my-diary-filename-to-date (buffer-file-name)))) | |
(insert (format-time-string | |
(read-file-into-string | |
(concat my-diary-directory "/diary-template.org")) | |
(my-diary-calendar-day-to-time calendar-date))))) | |
(goto-char (point-max))) | |
(defun my-diary-new-entry () | |
"Make a new entry, rounded to the nearest 5 minutes" | |
(interactive) | |
(my-diary-today) | |
(insert (format-time-string "** %H:%M " (org-current-time 5)))) | |
(defun my-diary-search-headings () | |
"Search through previous headings for completion" | |
(interactive) | |
(let ((headings (split-string | |
(shell-command-to-string | |
(concat "rg --no-filename '^[*][*] \\d\\d:\\d\\d (.*)$' --replace '$1' " my-diary-directory " | sort | uniq -c | sort -n -r | perl -pe 's/^ *\\d* *//'")) | |
"\n"))) | |
(insert (concat (completing-read "Headings: " headings) "\n")))) | |
(defun my-diary-next-day () | |
"Move to the next day's diary file" | |
(interactive) | |
(find-file (my-diary-change-day 1))) | |
(defun my-diary-prev-day () | |
"Move to the previous day's diary file" | |
(interactive) | |
(find-file (my-diary-change-day -1))) | |
(define-derived-mode my-diary-mode org-mode "Journal" | |
"Mode for writing diary entries" | |
(face-remap-add-relative 'default :family "Iosevka Aile" | |
:weight 'medium :height 1.1) | |
(turn-on-visual-line-mode) | |
(run-mode-hooks)) | |
(provide 'my-diary) | |
;;; my-diary.el ends here |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment