Little Elisp Workflow Enhancements

Published November 12, 2024 · 588 words · 3 minute read

Every week at work, I type a line in my org notes like so:

*** 2024-W46 [2024-11-11 Mon]--[2024-11-15 Fri]:

Clicking this date range opens the five-day agenda view for the week, and allows me to visualize all the meetings and date-stamped events I’ve recorded for the week in question.

Engineering and computer science types of people love to spend hours automating away minor inconveniences. Living in a LISP interpreter enables these automations to be written quickly, re-used, and improved over time without the crazy hassle of writing personal extensions in other popular text editors.

Now, rather than typing the line above, I can type M-x r/new-week or C-c n w and have this line appear with no effort at all, saving twenty or so keystrokes a week. C-c n m runs r/new-meeting which adds a heading with the current time - enabling me to use the calendar view in Emacs to jump to my notes for a particular time.

Running new week now adds the following to my buffer:

** 2024-W48 [2024-11-25 Mon]--[2024-11-29 Fri]:

  *** Monday Morning Standup
      At: <2024-11-25 Mon 09:00>

      - =( the cursor will end up here )=

Running new meeting now adds the following to my buffer:

   *** =( the cursor will end up here )=
       At: <2024-11-26 Tue 12:12>

…by using the save-excursion function, I can ensure my cursor ends up right where I would write the title of the meeting, saving a bit of navigation time.

Here’s the full source code:

;;; work.el --- Work related Elisp    -*- lexical-binding: t; -*-
;;; Commentary:
;; Some simple functions to hack on for work at IBM.
;;; Code:

;; Libraries
(require 'cl-lib)
(require 'org)
(require 's)

(defun get-day (time day-of-week)
  "Given the current TIME and DAY-OF-WEEK, return the 'day-shifted' time."
  (let ((weekday (decoded-time-weekday (decode-time time))))
    (message "Weekday: %s" weekday)
    (cond
     ((= weekday day-of-week) time)
     ((> weekday day-of-week) (time-subtract time (days-to-time (- weekday day-of-week))))
     ((< weekday day-of-week) (time-add time (days-to-time (- day-of-week weekday))))
     (t (error "Error! Imaginary time")))))

(defun get-monday (time)
  "Given the current TIME, return the same time on Monday."
  (get-day time 1))

(defun get-friday (time)
  "Given the current TIME, return the same time on Friday."
  (get-day time 5))

(defun r/new-meeting ()
  "Prints a header for a new meeting to the org buffer."
  (interactive)
  (org-insert-heading)

  ;; Return to location where we'll enter the meeting title.
  (save-excursion
    (let ((now (current-time)))
      (insert (format-time-string "\nAt: <%Y-%m-%d %a %H:%M>\n\n" now)))))

(defun r/new-week ()
  "Prints a header for the current week's notes to the org file."
  (interactive)

  ;; I usually organize my file into week-long headers,
  ;; so this action moves the weekly header left once.
  (org-insert-heading)
  (org-metaleft)

  ;; Write the current-week heading based on today's date.
  (let ((now (current-time)))
    (insert (format-time-string "%Y-W%W " now))
    ;; Org Timestamp Format: [2024-11-12 Tue 10:00]
    (insert (format-time-string "[%Y-%m-%d %a]--" (get-monday now)))
    (insert (format-time-string "[%Y-%m-%d %a]:\n" (get-friday now))))
  
  ;; Insert Monday Standup meeting
  (org-insert-heading)
  (org-metaright)
  (insert "Monday Morning Standup\n")
  (let ((now (current-time)))
    (insert (format-time-string "At: <%Y-%m-%d %a 09:00>" (get-monday now)))
    ;; The cursor will now start ready at this first bullet point
    (insert "\n\n- ")))

(provide 'work)
;;; work.el ends here

In the part of your configuration files where you set keybindings, add the following:

(require 'work)
(global-set-key (kbd "C-c n w") 'r/new-week)
(global-set-key (kbd "C-c n m") 'r/new-meeting)

In the future, I think I’ll update this script to snap the meeting time to the nearest previous 15-minute mark. If the meeting was scheduled for 10:15, chances are I won’t be writing notes until 10:17 or maybe even 10:28.

You’ve gotta love Emacs.

Comments