dot/.config/doom/README.org
2024-11-15 00:08:06 +01:00

54 KiB
Raw Blame History

Phil's Doom Emacs Literate Config

Intro

This is my personal Doom Emacs config. The important bit is that I have some additional keybinds. This file is a catch-all for all the files in $DOOMDIR - you can use org-babel-tangle to tangle them into their respective files.

Some of the comments are from the default config.el file that ships with Doom Emacs.

You can extract all the source/ config files from here by running Emacs and hitting C-c C-v t.

A lot of these are swiped from DT's Configuring Emacs config files, as well as Karl Voit's Emacs config.

Header

This will generate a header, clarifying that the resulting Doom Emacs config.el is not to be modified directly.

;; -*- lexical-binding: t -*-
;; DO NOT EDIT THIS FILE
;; This file was generated from the .config/doom/README.org file
;; in the following repo: https://git.bajsicki.com/phil/dot/

config.el

Basic settings

Author/ personal info

(setq user-full-name "Phil Bajsicki")

Global settings

  • backup-inhibited is true because I use git for the vast majority of my work.
  • global-auto-revert-mode is true because I sometimes use external tools on my org-files, and don't want to have to manually revert-buffer when these changes happen. Mild inconvenience but it's nice to have.
  • indent-tabs-mode because that's what tabs are for.
(setq-default backup-inhibited t)
(setq global-auto-revert-mode t)
(setq-default indent-tabs-mode t)

Ensure visited files are called by their true names. Kinda insignificant but nice.

(setq find-file-visit-truename t)
Auth
(setq auth-sources '("~/.authinfo"))
Locale
(setq locale-coding-system 'utf-8)
(set-terminal-coding-system 'utf-8)
(set-keyboard-coding-system 'utf-8)
(set-clipboard-coding-system 'utf-8)
(prefer-coding-system 'utf-8)

Langtool

Note that for this functionality you do need some resources, namely:

  • some kind of Java runtime (OpenJRE for instance)
  • LanguageTool

This command only sets up the path to your java runtime binary.

(setq langtool-java-bin "/usr/bin/java")

Theming and prettifying

(after! counsel
  (setq counsel-outline-display-style 'title))
Doom Theme

¯\_(ツ)_/¯

(load-theme 'doom-one t)
(doom-themes-neotree-config)
(doom-themes-org-config)
org-modern

Just some bits here that affect the entirety of Emacs; the parts relevant to org-mode specifically are in org's appearance section.

This part removes all the unnecessary bits that take up screen space and add clutter.

(menu-bar-mode -1)
(tool-bar-mode -1)
(scroll-bar-mode -1)

Then fixing up some borders and dividers. It's a very clean look, imo.

(modify-all-frames-parameters
 '((right-divider-width . 0)
   (internal-border-width . 0)))
(dolist (face '(window-divider
                window-divider-first-pixel
                window-divider-last-pixel))
  (face-spec-reset-face face)
  (set-face-foreground face (face-attribute 'default :background)))
(set-face-background 'fringe (face-attribute 'default :background))
Transparency

¯\_(ツ)_/¯

(set-frame-parameter nil 'alpha-background 85)
(add-to-list 'default-frame-alist '(alpha-background . 85))
Fonts

To be entirely fair, I pretty much exclusively use Iosevka. Such a good font.

  (setq doom-themes-enable-bold t
        doom-themes-enable-italic t
        doom-font (font-spec :family "Iosevka" :size 14)
        doom-big-font (font-spec :family "Iosevka" :size 16)
        ;; doom-variable-pitch-font (font-spec :family "Iosevka" :size 14)
        doom-unicode-font (font-spec :family "Iosevka"))
        ;; doom-serif-font (font-spec :family "IBM Plex Mono" :size 10 :weight 'light))

;; (set-face-attribute 'default nil :family "Iosevka")
;; (set-face-attribute 'variable-pitch nil :family "Iosevka Aile")
;; (set-face-attribute 'org-modern-symbol nil :family "Iosevka")
Font Family List

This is a simple command that outputs the fonts you have available in Emacs. Not really a config thing, but it's useful when trying to find out why that one specific thing isn't showing correctly.

(print (font-family-list))
Ligature.el
(ligature-set-ligatures 't '("www"))
;; Enable traditional ligature support in eww-mode, if the
;; `variable-pitch' face supports it
(ligature-set-ligatures 'eww-mode '("ff" "fi" "ffi"))
;; Enable all Cascadia Code ligatures in programming modes
(ligature-set-ligatures 'org-mode '("|||>" "<|||" "<==>" "<!--" "####" "~~>" "***" "||=" "||>"
                                     ":::" "::=" "=:=" "===" "==>" "=!=" "=>>" "=<<" "=/=" "!=="
                                     "!!." ">=>" ">>=" ">>>" ">>-" ">->" "->>" "-->" "---" "-<<"
                                     "<~~" "<~>" "<*>" "<||" "<|>" "<$>" "<==" "<=>" "<=<" "<->"
                                     "<--" "<-<" "<<=" "<<-" "<<<" "<+>" "</>" "###" "#_(" "..<"
                                     "..." "+++" "/==" "///" "_|_" "www" "&&" "^=" "~~" "~@" "~="
                                     "~>" "~-" "**" "*>" "*/" "||" "|}" "|]" "|=" "|>" "|-" "{|"
                                     "[|" "]#" "::" ":=" ":>" ":<" "$>" "==" "=>" "!=" "!!" ">:"
                                     ">=" ">>" ">-" "-~" "-|" "->" "--" "-<" "<~" "<*" "<|" "<:"
                                     "<$" "<=" "<>" "<-" "<<" "<+" "</" "#{" "#[" "#:" "#=" "#!"
                                     "##" "#(" "#?" "#_" "%%" ".=" ".-" ".." ".?" "+>" "++" "?:"
                                     "?=" "?." "??" ";;" "/*" "/=" "/>" "//" "__" "~~" "(*" "*)"
                                     "\\\\" "://"))
;; Enables ligature checks globally in all buffers.  You can also do it
;; per mode with `ligature-mode'.
(global-ligature-mode t)
Helpers for text editing
(setq display-line-numbers-type 'relative) ;; best honestly
(setq-default global-visual-line-mode t)
(setq column-number-mode t)
(setq next-screen-context-lines 4)
(setq x-stretch-cursor t)

Global Keybinds

Setting this here because I experiment with these occasionally and want them reset properly eaach time.

(global-set-key "\C-g" 'keyboard-quit)
(global-set-key "\C-cu" 'browse-url-chrome)

Package settings

Straight

Living on the edge. Honestly I probably should not… but then I do find joy in fixing up my config…

(setq straight-repository-branch "develop")

org-mode

I am including pretty much everything here, mostly sorted by package, but I'm keeping org-mode and org-agenda together since they're virtually inseparable in my mind.

Basic settings
;; must be set before `org` is loaded

(add-to-list 'auto-mode-alist
           '("\\.org\\'" . org-mode))

(setq-default calendar-week-start-day 1)
Directories and structure

Basic directory set-up for org-mode

(setq org-contacts-files '("~/enc/org/people.org"))
(setq org-directory "~/enc/org/")

Agenda files

(setq org-agenda-files (directory-files-recursively "~/enc/org/" ".org$"))1

org-refile targets. I just want to see nearly everything. If something is more than 9 levels deep then I should start questioning my sanity. I do want to go step by step on these (org-outline-path-complete-in-steps controls this), since I have a lot of information collected.

(setq org-refile-targets '((nil :maxlevel . 9)
                                (org-agenda-files :maxlevel . 9)))
(setq org-outline-path-complete-in-steps nil)
(setq org-refile-use-outline-path 'file)
Appearance and style

Keeps images contained on the screen.

(setq org-image-actual-width '(0.8))

Footnote positioning and style.

(setq org-footnote-auto-adjust t)
(setq org-footnote-define-inline t)

Pretty!

(setq org-superstar-headline-bullets-list
      '("⁖" "◉" "○" "✸" "✿")
      org-hide-emphasis-markers t
      org-pretty-entities t
      org-fontify-todo-headline t
      org-hide-leading-stars t)

Code highlighting in code blocks!

(setq org-src-fontify-natively t)

Naturally, I prefer to have a consistent look in my numbers.

(setq org-table-duration-hour-zero-padding t)

Tags flush right to the 80th column, and realign them when the length/ indentation of the heading changes.

(setq org-tags-column -80
      org-auto-align-tags t)

And, enable org-modern-mode by default, since it's nice.

(global-org-modern-mode)
Editing and comfort

It's preferable to have org guess dates in the future when scheduling.

(setq org-read-date-prefer-future t)

This makes the notes I take read like a book. I can imagine there's folks who enjoy reversing their notes and having the most recent at the top but… no. Just no.

(setq org-reverse-note-order nil)

This one really annoyed me for a long time, until I just gave up. There is no better way to have more vertical space in my files than by just… not wasting more space between headings and list items.

(setq org-blank-before-new-entry (quote ((heading . nil)
					 (plain-list-item . nil))))

This is something I struggled with, particularly when dealing with lots of nested headings; ultimately I have settled on 'smart' as 'good enough'. May move to 'nil' at some point?

(setq org-catch-invisible-edits "smart")

Special functions for headings.

(setq org-special-ctrl-a/e t)
(setq org-special-ctrl-k t)

This fits the yanked subtree into the appropriate level in the structure it's yanked into.

(setq org-yank-adjusted-subtrees t)

I like being able to split lines sometimes, especially when cleaning up large pieces of text.

(setq org-M-RET-may-split-line '((headline . t)
				 (item . t)
				 (default . nil)))

This ensures that I can insert my headings anywhere without having to consider structure; particularly useful when I'm breaking large pieces of text into headings, and don't want to jiggle things around much.

(setq org-insert-heading-respect-content nil)

Keep the footnotes per heading, instead of per file; when t, it'll create a footnote heading at the end of the file and that's a pain when dealing with large files.

(setq org-footnote-section nil)
Logging and Properties

Logging into a drawer.

(setq org-log-done (quote time)
      org-log-into-drawer t
      org-clock-into-drawer t)

Do not log inserting the TODO heading for the first time; only when further changes are made to the heading.

(setq org-treat-insert-todo-heading-as-state-change nil)

Property inheritance is… difficult. I don't believe it has a place in my world, but I can see specific scenarios where it would. Haven't found one myself yet, despite experimenting.

(setq org-use-property-inheritance nil)
;;(setq org-use-property-inheritance '(category columns archive logging))
Tasking and Dependencies

Forcing myself to acknowledge and address dependencies has been of great help for me, especially on more involved projects; I am occasionally prone to being lazy and leaving tasks I set for myself unaddressed, but these little settings have really helped me maintain my files over time.

(setq-default org-enforce-todo-dependencies t)
(setq org-enforce-todo-checkbox-dependencies t)

I want to know when my deadlines are approaching.

(setq org-deadline-warning-days 7)

I like my statistics.

(setq org-provide-todo-statistics t
      org-hierarchical-todo-statistics t)
(setq org-todo-repeat-to-state "LOOP")
Todo keywords

I got these from… I frankly don't even know where. They're not bad, imo.

(setq org-todo-keywords
      '((sequence
         "INBOX(i!)"
         "TASK(t!)"  ; A task that needs doing & is ready to do
         "PROJ(p!)"  ; A project, which usually contains other tasks
         "LOOP(r!)"  ; A recurring task
         "WAIT(w!)"  ; Something external is holding up this task
         "HOLD(h!)"  ; This task is paused/on hold because of me
         "|"
         "DONE(d!@)"  ; Task successfully completed
         "KILL(k!@)") ; Task was cancelled, aborted or is no longer applicable
        (sequence
         "DECIDE()"   ; for making decisions
         "|"
         "OKAY(o!)"    ; okay as-is
         "YES(y!)"     ; take action
         "NO(n!)"))    ; don't take action
      org-todo-keyword-faces
      '(
        ("INBOX"     :foreground "cyan"   :weight bold)
        ("TASK"      :foreground "purple"   :weight bold)
        ("PROJ"      :foreground "violet"         :weight bold)
        ("LOOP"      :foreground "magenta"      :weight bold)
        ("WAIT"      :foreground "yellow"       :weight bold)
        ("HOLD"      :foreground "orange"       :weight bold)
        ("DONE"      :foreground "green" :weight bold)
        ("KILL"      :foreground "grey"   :weight bold)))

Change font for DONE tasks

(setq org-fontify-done-headline t)
(custom-set-faces
 '(org-done ((t (:foreground "PaleGreen"
                 :weight normal
                 :strike-through t))))
 '(org-headline-done
            ((((class color) (min-colors 16) (background dark))
               (:foreground "LightSalmon" :strike-through t)))))
Capture templates
(setq org-capture-templates '(("t" "inbox" entry (file+headline "~/enc/org/agenda.org" "Inbox") "* %i%?")
                              ("i" "idea" entry (file+headline "~/enc/org/agenda.org" "Ideas") "* %?")
                              ("d" "reminder" entry (file+headline "~/enc/org/agenda.org" "Reminders") "* %i%? \n %U")
                              ("p" "person" entry (file+headline "~/enc/org/people.org" "Sort")
                               "* %(org-contacts-template-name)
:PROPERTIES:
:EMAIL: %(org-contacts-template-email)
:PHONE:
:ALIAS:
:NICKNAME:
:IGNORE:
:ICON:
:NOTE:
:ADDRESS:
:BIRTHDAY:
:END:")))
t inbox entry (file+headline ~/enc/org/agenda.org Inbox) * %i%?
i idea entry (file+headline ~/enc/org/agenda.org Ideas) * %?
d reminder entry (file+headline ~/enc/org/agenda.org Reminders) * %i%?
Keybinds

Pretty self-explanatory.

(global-set-key "\C-cl" 'org-store-link)
(global-set-key "\C-cnn" 'org-capture)
Timestamp keybinds

Inserts timestamps in the proper format. '(16) stands for two universal arguments, keeping the command from prompting for the time. Two keybinds here, which insert an active or inactive timestamp.

(global-set-key "\C-cia"  '(lambda ()(interactive)
                               (org-time-stamp '(16))))
(global-set-key "\C-cii"  '(lambda () (interactive)
                               (org-time-stamp-inactive '(16))))
org-roam
(setq org-roam-v2-ack t)
(setq org-roam-completion-everywhere t)
(setq org-roam-directory
      (file-truename "~/enc/org/roam"))
(org-roam-db-autosync-mode)
(org-roam-db-autosync-enable)
Capture templates
(setq org-roam-capture-templates
      '(("n" "default" plain
         "%?"
         :if-new (file+head "${slug}.org" "#+title: ${title}\n#+category: ${title}\n#+filetags: \n")
         :empty-lines 1
         :unnarrowed t)
        ("t" "Therapy" plain
         "#+title: ${title}\n"
         :if-new (file+head "therapy/therapy-${slug}.org" "#+title: ${title}\n#+category: 📗 ${title}\n#+filetags: 📗\n")
         :empty-lines 1
         :unnarrowed)))
Keybinds
(define-prefix-command 'org-roam-map)
(global-set-key "\C-r" 'org-roam-map)
(define-key org-roam-map "o" 'org-roam-buffer-toggle)
(define-key org-roam-map "f" 'org-roam-node-find)
(define-key org-roam-map "i" 'org-roam-node-insert)
(define-key org-roam-map "n" 'org-roam-capture)
Functions
my-id-get-or-generate

Straight from Karl Voit's config.

(defun my-id-get-or-generate()
"Returns the ID property if set or generates and returns a new one if not set.
 The generated ID is stripped off potential progress indicator cookies and
 sanitized to get a slug. Furthermore, it is prepended with an ISO date-stamp
 if none was found before."
    (interactive)
        (when (not (org-id-get))
            (progn
               (let* (
                      (my-heading-text (nth 4 (org-heading-components)));; retrieve heading string
                      (my-heading-text (replace-regexp-in-string "\\(\\[[0-9]+%\\]\\)" "" my-heading-text));; remove progress indicators like "[25%]"
                      (my-heading-text (replace-regexp-in-string "\\(\\[[0-9]+/[0-9]+\\]\\)" "" my-heading-text));; remove progress indicators like "[2/7]"
                      (my-heading-text (replace-regexp-in-string "\\(\\[#[ABC]\\]\\)" "" my-heading-text));; remove priority indicators like "[#A]"
                      (my-heading-text (replace-regexp-in-string "\\[\\[\\(.+?\\)\\]\\[" "" my-heading-text t));; removes links, keeps their description and ending brackets
;;                      (my-heading-text (replace-regexp-in-string "[<\\[][12][0-9]\\{3\\}-[0-9]\\{2\\}-[0-9]\\{2\\}\\( .*?\\)[>\\]]" "" my-heading-text t));; removes day of week and time from date- and time-stamps (doesn't work somehow)
                      (my-heading-text (replace-regexp-in-string "<[12][0-9]\\{3\\}-[0-9]\\{2\\}-[0-9]\\{2\\}\\( .*?\\)>" "" my-heading-text t));; removes day of week and time from active date- and time-stamps
                      (my-heading-text (replace-regexp-in-string "\\[[12][0-9]\\{3\\}-[0-9]\\{2\\}-[0-9]\\{2\\}\\( .*?\\)\\]" "" my-heading-text t));; removes day of week and time from inactive date- and time-stamps
                      (new-id (my-generate-sanitized-alnum-dash-string my-heading-text));; get slug from heading text
                      (my-created-property (assoc "CREATED" (org-entry-properties))) ;; nil or content of CREATED time-stamp
                     )
                   (when (not (string-match "[12][0-9][0-9][0-9]-[01][0-9]-[0123][0-9]-.+" new-id))
                           ;; only if no ISO date-stamp is found at the beginning of the new id:
                           (if my-created-property (progn
                               ;; prefer date-stamp of CREATED property (if found):
                               (setq my-created-datestamp (substring (org-entry-get nil "CREATED" nil) 1 11)) ;; returns "2021-12-16" or nil (if no CREATED property)
                               (setq new-id (concat my-created-datestamp "-" new-id))
                           )
                           ;; use today's date-stamp if no CREATED property is found:
                           (setq new-id (concat (format-time-string "%Y-%m-%d-") new-id))))
                   (org-set-property "ID" new-id)
                   )
                 )
        )
        (kill-new (concat "id:" (org-id-get)));; put ID in kill-ring
        (org-id-get);; retrieve the current ID in any case as return value
)
Directory to org

Frankly I don't know where I got this from, it's been a long time, and I don't recall ever using it but… it's so nice that I don't dare remove this just in case I need it at some point in the future.

(defun my-dir-to-org (dir org-file)
  "Create a file ORG-FILE which has all txt files in DIR as linked headlines
and the contents of the files below the headlines."
  (interactive "DDirectory to convert: \nFFilename: ")
  (let ((files (directory-files
                dir t ".*\\.txt\\'")))
    (with-temp-file org-file
      (dolist (file files)
        (insert (concat "* " (file-name-nondirectory file) "\n\n"))
        (insert-file-contents file)
        (goto-char (point-max))
        (insert "\n")))))

(defun my-dir-to-org-with-links (dir org-file)
  "Create a file ORG-FILE which has all txt files in DIR as linked headlines
and the contents of the files below the headlines."
  (interactive "DDirectory to convert: \nFFilename: ")
  (let ((files (directory-files
                dir t ".*\\.txt\\'")))
    (with-temp-file org-file
      (dolist (file files)
        (insert (concat "* " "[[" file "][" (file-name-nondirectory file) "]]\n\n"))
        (insert-file-contents file)
        (goto-char (point-max))
        (insert "\n")))))


(defun my-mass-conversion (source-dir target-dir)
  "Create one org file per directory of SOURCE-DIR inside TARGET-DIR."
  (interactive "DDirectory to convert: \nDTarget Directory:")
  (let ((dirs-full
         (remove-if-not #'file-directory-p
                        (directory-files
                         source-dir t
                         directory-files-no-dot-files-regexp))))

    (mapc (lambda (dir)
            (my-dir-to-org dir
                           (concat target-dir
                                   (file-name-base dir) ".org")))
          dirs-full)))
my-org-tree-to-indirect-buffer

This beautiful piece of code was done by alphapapa and published on reddit. Its purpose is to provide more than one indirect buffer when using org-tree-to-indirect-buffer() (via C-c C-x b). Further more, it has a different way of naming these buffers.

Using an advice, the original function gets overwritten.

Karl Voit

(defun my-org-tree-to-indirect-buffer (&optional arg)
  "Create indirect buffer and narrow it to current subtree.
The buffer is named after the subtree heading, with the filename
appended.  If a buffer by that name already exists, it is
selected instead of creating a new buffer."
  (interactive "P")
  (let* ((new-buffer-p)
         (pos (point))
w         (buffer-name (let* ((heading (org-get-heading t t))
                             (level (org-outline-level))
                             (face (intern (concat "outline-" (number-to-string level))))
                             (heading-string (propertize (org-link-display-format heading)
                                                         'face face)))
                        (concat heading-string "::" (buffer-name))))
         (new-buffer (or (get-buffer buffer-name)
                         (prog1 (condition-case nil
                                    (make-indirect-buffer (current-buffer) buffer-name 'clone)
                                  (error (make-indirect-buffer (current-buffer) buffer-name)))
                           (setq new-buffer-p t)))))
    (switch-to-buffer new-buffer)
    (when new-buffer-p
      ;; I don't understand why setting the point again is necessary, but it is.
      (goto-char pos)
      (rename-buffer buffer-name)
      (org-narrow-to-subtree))))

(advice-add 'org-tree-to-indirect-buffer :override 'my-org-tree-to-indirect-buffer)
preserving all heading levels when archiving

Preserve the hierarchy when archiving: blog article, source code (GitHub gist) Karl Voit

(setq org-archive-default-command #'org-archive-subtree-hierarchically)

(defun org-archive-subtree-hierarchically (&optional prefix)
  (interactive "P")
  (let* ((fix-archive-p (and (not prefix)
                             (not (use-region-p))))
         (afile  (car (org-archive--compute-location
                       (or (org-entry-get nil "ARCHIVE" 'inherit) org-archive-location))))
         (buffer (or (find-buffer-visiting afile) (find-file-noselect afile))))
    (org-archive-subtree prefix)
    (when fix-archive-p
      (with-current-buffer buffer
        (goto-char (point-max))
        (while (org-up-heading-safe))
        (let* ((olpath (org-entry-get (point) "ARCHIVE_OLPATH"))
               (path (and olpath (split-string olpath "/")))
               (level 1)
               tree-text)
          (when olpath
            (org-mark-subtree)
            (setq tree-text (buffer-substring (region-beginning) (region-end)))
            (let (this-command (inhibit-message t)) (org-cut-subtree)) ; we dont want to see "Cut subtree" messages
            (goto-char (point-min))
            (save-restriction
              (widen)
              (-each path
                (lambda (heading)
                  (if (re-search-forward
                       (rx-to-string
                        `(: bol (repeat ,level "*") (1+ " ") ,heading)) nil t)
                      (org-narrow-to-subtree)
                    (goto-char (point-max))
                    (unless (looking-at "^")
                      (insert "\n"))
                    (insert (make-string level ?*)
                            " "
                            heading
                            "\n"))
                  (cl-incf level)))
              (widen)
              (org-end-of-subtree t t)
              (org-paste-subtree level tree-text))))))))
my-dired-insert-lfile-link-list-to-other-org-window()
2022-06-20 I had this idea and implemented it

Development task: id:2022-06-20-implement-add-lfile-links-to-buffer-with-marked-dired-files

This stackexchange snippet had the almost exactly perfect code which I adapted.

The idea of the process is:

  1. I have an Org-mode buffer and a dired buffer side-by-side (which is my usual setup).
  2. I place the cursor in the Org-mode buffer so that I may add a list.
  3. I switch to the dired buffer and mark one or more files.
  4. I invoke this function.

This results in a list that gets added to the Org-mode buffer similar to:

- [[lfile:This is an example.odt][This is an example.odt]]
- [[lfile:2022-06-20 an image.png][2022-06-20 an image.png]]
  (defun my-dired-insert-lfile-link-list-to-other-org-window (files)
    ;; adapted by Karl Voit from https://emacs.stackexchange.com/a/60369
    (interactive
     (list (dired-get-marked-files)))
    (unless (eq major-mode 'dired-mode)
      (user-error "This command must be triggered in a dired buffer"))
    (let ((dired-win (selected-window))
          (orgmode-win
           (get-window-with-predicate
            (lambda (window)
              (with-current-buffer (window-buffer window)
                (eq major-mode 'org-mode))))))
      (unless orgmode-win
        (user-error
         "Can't attach to subtree.  No window displaying an Org buffer"))
      (select-window orgmode-win)
      (dolist (file files)
        (let* ((fname (file-name-nondirectory file))
               (link (format "lfile:%s" fname))
               (desc fname))
          ;;(push (list link desc) org-stored-links) ;; original idea was to insert to this buffer in order to paste via C-c C-l
          (insert (format "%s" (concat "- [[" link "][" desc "]]\n")))
      ))
      (select-window dired-win)))
org-agenda

These are settings specifically for org-agenda, that don't overlap with any other settings.

(setq org-agenda-start-day nil)
(setq org-agenda-start-on-weekday nil)
(setq org-agenda-span 'day)

Dim blocked tasks to clearly see that their prerequisites are not met. Make the agenda blocks more compact by skipping certain elements.

(setq org-agenda-dim-blocked-tasks t)
(setq org-agenda-compact-blocks t)

Non-nil means skip timestamp line if same entry shows because of deadline.

(setq org-agenda-skip-timestamp-if-deadline-is-shown t)

Remove completed deadline and scheduled tasks from the agenda view

(setq org-agenda-skip-deadline-if-done t)
(setq org-agenda-skip-scheduled-if-done t)

Remove completed items from search results

(setq org-agenda-skip-timestamp-if-done t)

Include agenda archive files when searching for things

(setq org-agenda-text-search-extra-files (quote (agenda-archives)))

Do not search for time in heading when displaying a date-stamp

(setq org-agenda-search-headline-for-time nil)

Show all agenda dates - even if they are empty

(setq org-agenda-show-all-dates t)

Show the following items in log mode.

(setq org-agenda-log-mode-items '(closed clock state))
(setq org-agenda-sorting-strategy
		(quote ((agenda time-up user-defined-up priority-down category-keep)
				(todo priority-down category-keep)
				(tags priority-down category-keep)
				(search category-keep))))

Ensuring that tag inheritance is applied in the agenda view.

(setq org-agenda-use-tag-inheritance (quote (agenda)))

Agenda prefixes and org-modern agenda styling.

(setq org-agenda-prefix-format '((agenda . " %l %i %c %s %t")
				 (todo . " %i %-12:c")
				 (tags . " %i $-12:c")
				 (search . " %i %-12:c")))

(setq org-agenda-tags-column -80
      org-agenda-block-separator ?─
      org-agenda-current-time-string "◀── now ─────────────────────────────────────────────────")

Two to choose from, I'm not sure which one is better here. I don't know where I got this one from.

(setq org-agenda-time-grid
      '((daily today remove-match)
	(800 1000 1200 1400 1600 1800 2000)
	" ┄┄┄┄┄ "
	"┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄"))

Add hook into the agenda mode for highlighting.

(add-hook 'org-agenda-mode-hook '(lambda () (hl-line-mode 1)))
org-habits

I try to run a reasonable routine, and it doesn't always work. This helps me review if I'm sticking to it well (or, reasonably well) over time.

(add-to-list 'org-modules 'habit)
(setq org-habit-following-days 2
      org-habit-preceding-days 7
      org-habit-show-all-today nil
      org-habit-show-habits-only-for-today t
      org-habit-show-habits t)

Some keybinds and a hook.

(define-key org-mode-map (kbd "C-c h") 'org-habit-stats-view-habit-at-point)
(add-hook 'org-after-todo-state-change-hook 'org-habit-stats-update-properties)
multiple-cursors

I rarely use these, since I don't edit much structured data, and when I do it's less like this and more like massive articles or books or whatnot. Still, it does come in handy occasionally.

(global-set-key (kbd "C-S-c C-S-c") 'mc/edit-lines)
(global-set-key (kbd "C->") 'mc/mark-next-like-this)
(global-set-key (kbd "C-<") 'mc/mark-previous-like-this)
(global-set-key (kbd "C-c C-<") 'mc/mark-all-like-this)
[disabled] copilot.el
;; accept completion from copilot and fallback to company
(use-package! copilot
  :hook (prog-mode . copilot-mode)
  :bind (:map copilot-completion-map
              ("<tab>" . 'copilot-accept-completion)
              ("TAB" . 'copilot-accept-completion)
              ("C-TAB" . 'copilot-accept-completion-by-word)
              ("C-<tab>" . 'copilot-accept-completion-by-word)))
Hooks
org-auto-tangle

By adding #+auto_tangle: t to the frontmatter of an org-mode file, this enables automatic tangling upon the file being saved.

(require 'org-auto-tangle)
(add-hook 'org-mode-hook 'org-auto-tangle-mode)
Automated timestamps in headings

I need this because hitting the timestamp keybinds is tedious.

For the files whose paths match the strings in the function, it will advise the org-insert-heading function to insert an inactive timestamp into the new heading.

This turns making new entries from C-<return> C-i i into just C-<return>. Much easier, and I don't have to think about this any more.

Additionally, outside of the structured files where I am tracking time linearly, I want org-expiry-insert-created, which fits in neatly into this little hook, thus allowing me to inspect my workflows more carefully.

(use-package! org-expiry)
(after! org
  (add-hook! 'org-insert-heading-hook
          (if (or
	       (string-match-p "journal.org" buffer-file-name)
	       (string-match-p "money.org" buffer-file-name)
	       (string-match-p "therapy.org" buffer-file-name))
              (progn
		(org-time-stamp-inactive '(16))
		(newline))
	    (org-expiry-insert-created))))

org-mode expansions

org-babel

This is really important for me since I tend to use PlantUML to generate charts, graphs and diagrams.

(add-hook 'org-babel-after-execute-hook 'org-display-inline-images)
org-crypt

This is nice, since it lets me easily encrypt parts of my notes using my GPG key, which I have set up with my NitroKey. It's some really really cool tech.

(require 'org-crypt)
(require 'epa-file)
(epa-file-enable)
(org-crypt-use-before-save-magic)
(setq org-tags-exclude-from-inheritance (quote ("crypt")))
(setq org-crypt-key "phil@bajsicki.com")
(setenv "GPG_AGENT_INFO" nil)
org-export

Just a catch-all category for this… I honestly should split things up better instead of this, but it is what it is.

LaTeX

Adding the tufte-handout and the memoir classes.

(with-eval-after-load 'ox-latex
   (add-to-list 'org-latex-classes
		'("tufte-handout"
                  "\\documentclass[nobib]{tufte-handout}
                   \\usepackage{nicefrac}
                   \\usepackage{units}
                   [NO-DEFAULT-PACKAGES]
                   [EXTRA]"
                  ("\\section{%s}" . "\\section*{%s}")
                  ("\\subsection{%s}" . "\\subsection*{%s}")
                  ("\\subsubsection{%s}" . "\\subsubsection*{%s}")
                  ("\\paragraph{%s}" . "\\paragraph*{%s}")
                  ("\\subparagraph{%s}" . "\\subparagraph*{%s}"))
		'("memoir"
                  "\\documentclass{memoir}"
                  ("\\chapter{%s}" . "\\chapter*{%s}")
                  ("\\section{%s}" . "\\section*{%s}")
                  ("\\subsection{%s}" . "\\subsection*{%s}")
                  ("\\subsubsection{%s}" . "\\subsubsection*{%s}"))))

Testing function, not tangled.

(print org-latex-classes)

I have not settled on this. Meh.

(setq org-latex-default-class "tufte-handout"
      org-latex-pdf-process '("latexmk -pdf -bibtex-cond -f -outdir=%o %f"))
ox-hugo
(use-package! ox-hugo
  :ensure t
  :after ox)
org-transclusion

I don't use this enough, and hopefully I'll find happiness with this if I do end up working on larger projects.

(use-package! org-transclusion
             :after org
              :init
              (map!
               :map global-map "<f12>" #'org-transclusion-add
               :leader
               :prefix "n"
               :desc "Org Transclusion Mode" "t" #'org-transclusion-mode))
Org-wild-notifier

This lets me get desktop notifications for TODO items.

  (org-wild-notifier-mode)
  (setq alert-default-style 'libnotify
        org-wild-notifier-alert-time '(0 5 15 60)
        org-wild-notifier-keyword-whitelist nil
        ;; good for testing
        org-wild-notifier--alert-severity 'high
        alert-fade-time 50)

mu4e

Email in Emacs… what more can a man want?

(add-to-list 'load-path "/usr/share/emacs/site-lisp/mu4e/")

(setq mu4e-change-filenames-when-moving t)
(setq mu4e-update-interval (* 10 60))
(setq mu4e-get-mail-command "mbsync -a")
(setq mu4e-maildir "~/enc/.mail")

(setq mu4e-drafts-folder "/Drafts")
(setq mu4e-sent-folder "/Sent")
(setq mu4e-refile-folder "/Refile")
(setq mu4e-trash-folder "/Trash")

(mu4e t)

circe

Doesn't work very well. I guess it "works", but I still need to auth manually; not sure what the issue is - my best guess is that my passwords use unusual unicode characters and that screws with the (read) instruction.

(setq my-credentials-file "~/enc/keys/emacs/circe.el")

(defun my-nickserv-password (server)
  (with-temp-buffer
    (insert-file-contents-literally my-credentials-file)
    (plist-get (read (buffer-string)) :nickserv-password)))

(setq circe-network-options
      '(("Libera Chat"
         :nick "phil_bb"
         :channels ("#emacs" "#emacs-circe")
         :nickserv-password my-nickserv-password)))

pdf-tools

Gotta read in Emacs, sometimes. Usually in the browser, but when I have to take notes there's nothing more convenient.

(use-package! pdf-tools
  :defer t
  :commands (pdf-loader-install)
  :mode "\\.pdf\\'"
  :bind (:map pdf-view-mode-map
	      ("n" . pdf-view-next-line-or-next-page)
	      ("p" . pdf-view-previous-line-or-previous-page)
	      ("C-=" . pdf-view-enlarge)
	      ("C--" . pdf-view-shrink))
  :init (pdf-loader-install)
  :config (add-to-list 'revert-without-query ".pdf"))

(add-hook 'pdf-view-mode-hook #'(lambda () (interactive (display-line-numbers-mode))))

yasnippets

(setq doom-snippets-enable-short-helpers t)

csv-mode

Just making sure it loads when I load up csv files.

(add-to-list 'auto-mode-alist '("\\.[Cc][Ss][Vv]\\'" . csv-mode))
(autoload 'csv-mode "csv-mode"
    "Major mode for editing comma-separated value files." t)

sly

Basic settings for Common Lisp development.

;; (load (expand-file-name "~/.roswell/helper.el"))

(setq inferior-lisp-program "sbcl --dynamic-space-size 8192 -Q -l ~/.sbclrc")

gptel

This is exclusively local, as I am not entirely comfortable letting third parties into my journals and personal notes. I usually run LLMs as they come, using them largely for brainstorming when I'm trying to plan out projects or consider my habits.

With their context size only increasing as time goes by, this is turning into a very easy way to get feedback on the ideas I have.

(use-package! gptel)
(gptel-make-openai "ooba"          ;Any name
  :key "thisisanapikey"
  :stream t                             ;Stream responses
  :protocol "http"
  :host "localhost:6666"                ;Llama.cpp server location
  :models '("model")) ;Any names, doesn't matter for Llama

(gptel-make-openai "OpenRouter"
  :host "openrouter.ai"
  :endpoint "/api/v1/chat/completions"
  :key (getenv "GPTEL_OPENROUTER_API")
  :stream t                             ;Stream responses
  :models '(qwen/qwen-2.5-coder-32b-instruct))

(setq gptel--debug t)

elfeed

RSS is not dead. RSS is not dead. RSS is not dead.

(setq-default elfeed-search-filter "@1-week-ago +unread ")

custom.el

Custom variables. Note that this file is generally set up automatically by Emacs" so I'm not exporting this block. I'm keeping the default warning comments in just for completion here.

(custom-set-variables)
 ;; custom-set-variables was added by Custom.
 ;; If you edit it by hand"  you could mess it up"  so be careful.
 ;; Your init file should contain only one such instance.
 ;; If there is more than one"  they won't work right.
(custom-set-faces
 ;; custom-set-faces was added by Custom.
 ;; If you edit it by hand"  you could mess it up"  so be careful.
 ;; Your init file should contain only one such instance.
 ;; If there is more than one"  they won't work right.
 )

init.el

;;; init.el -*- lexical-binding: t; -*-

;; This file controls what Doom modules are enabled and what order they load
;; in. Remember to run 'doom sync' after modifying it!

;; NOTE Press 'SPC h d h' (or 'C-h d h' for non-vim users) to access Doom's
;;      documentation. There you'll find a link to Doom's Module Index where all
;;      of our modules are listed"  including what flags they support.

;; NOTE Move your cursor over a module's name (or its flags) and press 'K' (or
;;      'C-c c k' for non-vim users) to view its documentation. This works on
;;      flags as well (those symbols that start with a plus).
;;
;;      Alternatively"  press 'gd' (or 'C-c c d') on a module to browse its
;;      directory (for easy access to its source code).

(doom! :input
       ;;bidi              ; (tfel ot) thgir etirw uoy gnipleh
       ;;chinese
       ;;japanese
       ;;layout            ; auie" ctsrnm is the superior home row

       :completion
       (company +childframe)             ; the ultimate code completion backend
       ;;helm                ; the *other* search engine for love and life
       ;;ido               ; the other *other* search engine...
       ;;ivy               ; a search engine for love and life
       vertico           ; the search engine of the future

       :ui
       ;;deft              ; notational velocity for Emacs
       doom              ; what makes DOOM look the way it does
       doom-dashboard    ; a nifty splash screen for Emacs
       doom-quit         ; DOOM quit-message prompts when you quit Emacs
       (emoji +unicode)  ; 🙂
       ;;hl-todo           ; highlight TODO/FIXME/NOTE/DEPRECATED/HACK/REVIEW
       hydra
       indent-guides     ; highlighted indent columns
       (ligatures +iosevka +extra)         ; ligatures and symbols to make your code pretty again
       minimap           ; show a map of the code on the side
       modeline          ; snazzy"  Atom-inspired modeline"  plus API
       nav-flash         ; blink cursor line after big motions
       ;;neotree           ; a project drawer"  like NERDTree for vim
       ophints           ; highlight the region an operation acts on
       (popup +defaults)   ; tame sudden yet inevitable temporary windows
       ;;tabs              ; a tab bar for Emacs
       treemacs          ; a project drawer"  like neotree but cooler
       unicode           ; extended unicode support for various languages
       (vc-gutter +pretty) ; vcs diff in the fringe
       vi-tilde-fringe   ; fringe tildes to mark beyond EOB
       ;;window-select     ; visually switch windows
       workspaces        ; tab emulation"  persistence & separate workspaces
       ;;zen               ; distraction-free coding or writing

       :editor
       ;;(evil +everywhere); come to the dark side"  we have cookies
       file-templates    ; auto-snippets for empty files
       fold              ; (nigh) universal code folding
       (format +onsave)  ; automated prettiness
       ;;god               ; run Emacs commands without modifier keys
       ;;lispy             ; vim for lisp"  for people who don't like vim
       ;;multiple-cursors  ; editing in many places at once
       ;;objed             ; text object editing for the innocent
       ;;parinfer          ; turn lisp into python"  sort of
       ;;rotate-text       ; cycle region at point between text candidates
       snippets          ; my elves. They type so I don't have to
       word-wrap         ; soft wrapping with language-aware indent

       :emacs
       dired             ; making dired pretty [functional]
       electric          ; smarter"  keyword-based electric-indent
       ;;ibuffer         ; interactive buffer management
       (undo +tree)              ; persistent"  smarter undo for your inevitable mistakes
       vc                ; version-control and Emacs"  sitting in a tree

       :term
       ;;eshell            ; the elisp shell that works everywhere
       ;;shell             ; simple shell REPL for Emacs
       ;;term              ; basic terminal emulator for Emacs
       vterm             ; the best terminal emulation in Emacs

       :checkers
       syntax              ; tasing you for every semicolon you forget
       (spell +flyspell) ; tasing you for misspelling mispelling
       ;;grammar           ; tasing grammar mistake every you make

       :tools
       ansible
       ;;biblio            ; Writes a PhD for you (citation needed)
       debugger          ; FIXME stepping through code"  to help you add bugs
       ;;direnv
       docker
       editorconfig      ; let someone else argue about tabs vs spaces
       ;;ein               ; tame Jupyter notebooks with emacs
       (eval +overlay)     ; run code"  run (also"  repls)
       ;;gist              ; interacting with github gists
       lookup              ; navigate your code and its documentation
       lsp               ; M-x vscode
       magit             ; a git porcelain for Emacs
       ;;make              ; run make tasks from Emacs
       ;;pass              ; password manager for nerds
       pdf               ; pdf enhancements
       ;;prodigy           ; FIXME managing external services & code builders
       rgb               ; creating color strings
       ;;taskrunner        ; taskrunner for all your projects
       terraform         ; infrastructure as code
       ;;tmux              ; an API for interacting with tmux
       ;;upload            ; map local to remote projects via ssh/ftp

       :os
       (:if IS-MAC macos)  ; improve compatibility with macOS
       ;;tty               ; improve the terminal Emacs experience

       :lang
       ;;agda              ; types of types of types of types...
       ;;beancount         ; mind the GAAP
       (cc +lsp)         ; C > C++ == 1
       ;;(clojure +lsp)           ; java with a lisp
       common-lisp       ; if you've seen one lisp"  you've seen them all
       ;;coq               ; proofs-as-programs
       ;;crystal           ; ruby at the speed of c
       ;;csharp            ; unity"  .NET"  and mono shenanigans
       data              ; config/data formats
       ;;(dart +flutter)   ; paint ui and not much else
       ;;dhall
       ;;elixir            ; erlang done right
       ;;elm               ; care for a cup of TEA?
       emacs-lisp        ; drown in parentheses
       ;;erlang            ; an elegant language for a more civilized age
       ;;ess               ; emacs speaks statistics
       ;;factor
       ;;faust             ; dsp"  but you get to keep your soul
       ;;fortran           ; in FORTRAN"  GOD is REAL (unless declared INTEGER)
       ;;fsharp            ; ML stands for Microsoft's Language
       ;;fstar             ; (dependent) types and (monadic) effects and Z3
       ;;gdscript          ; the language you waited for
       (go +lsp)         ; the hipster dialect
       ;;(graphql +lsp)    ; Give queries a REST
       (haskell +lsp)    ; a language that's lazier than I am
       ;;hy                ; readability of scheme w/ speed of python
       ;;idris             ; a language you can depend on
       json              ; At least it ain't XML
       ;;(java +lsp)       ; the poster child for carpal tunnel syndrome
       (javascript +lsp)        ; all(hope(abandon(ye(who(enter(here))))))
       ;;(julia +lsp)             ; a better"  faster MATLAB
       ;;kotlin            ; a better"  slicker Java(Script)
       latex             ; writing papers in Emacs has never been so fun
       ;;lean              ; for folks with too much to prove
       ;;ledger            ; be audit you can be
       ;;lua               ; one-based indices? one-based indices
       markdown          ; writing docs for people to ignore
       ;;nim               ; python + lisp at the speed of c
       ;;nix               ; I hereby declare "nix geht mehr!"
       ;;ocaml             ; an objective camel
       (org +dragndrop +pandoc +pretty +gnuplot +roam2)               ; organize your plain life in plain text
       ;;php               ; perl's insecure younger brother
       plantuml          ; diagrams for confusing people more
       ;;purescript        ; javascript"  but functional
       (python +lsp)            ; beautiful is better than ugly
       ;;qt                ; the 'cutest' gui framework ever
       ;;racket            ; a DSL for DSLs
       ;;raku              ; the artist formerly known as perl6
       ;;rest              ; Emacs as a REST client
       ;;rst               ; ReST in peace
       ;;(ruby +rails)     ; 1.step {|i| p "Ruby is #{i.even? ? 'love' : 'life'}"}
       ;;(rust +lsp)       ; Fe2O3.unwrap().unwrap().unwrap().unwrap()
       ;;scala             ; java"  but good
       ;;(scheme +guile)   ; a fully conniving family of lisps
       (sh +lsp)                ; she sells {ba" z" fi}sh shells on the C xor
       ;;sml
       ;;solidity          ; do you need a blockchain? No.
       ;;swift             ; who asked for emoji variables?
       ;;terra             ; Earth and Moon in alignment for performance.
       (web +lsp)               ; the tubes
       yaml              ; JSON"  but readable
       ;;(zig +lsp)               ; C"  but simpler

       :email
       (mu4e +org +gmail)
       ;;notmuch
       ;;(wanderlust +gmail)

       :app
       calendar
       emms
       everywhere        ; *leave* Emacs!? You must be joking
       irc               ; how neckbeards socialize
       (rss +org)        ; emacs as an RSS reader
       ;;twitter           ; twitter client https://twitter.com/vnought

       :config
       ;;literate
       (default +bindings))

packages.el

Core

;; -*- no-byte-compile: t; -*-
;;; $DOOMDIR/packages.el

(unpin! straight)
(package! beacon)
(package! counsel)
(package! deft)

Themes

(package! all-the-icons)
(package! all-the-icons-dired)
(package! doom-themes)

Modes:

(package! battle-haxe)
(package! fish-mode)
(package! typescript-mode)
(package! terraform-mode)
(package! wc-mode)
(package! plantuml-mode)
(package! csv-mode)

dired

(package! dired-open)

pdf-tools

(package! pdf-tools)

Org

;; Fix for org-roam link issue
(package! org-auto-tangle)
(package! ox-slack)
(package! ox-tufte)
(package! ox-hugo)
(package! ox-gemini
  :recipe (
	   :host sourcehut
		 :repo "abrahms/ox-gemini"))
(package! org-special-block-extras)
(package! org-transclusion)
(package! org-modern)
(package! org-ql)
(package! org-sidebar
  :recipe (
           :host github
                 :repo "alphapapa/org-sidebar"
           ))
(package! org-contacts)
(package! org-bullets)
(package! org-download)
(package! org-cliplink)
(package! org-roam)
;; (package! org-super-agenda)
(package! org-wild-notifier)
(package! org-habit-stats)
org-contrib
(package! org-contrib
  :recipe (:host sourcehut :type git
	   :repo "~bzg/org-contrib"
	   :files ("lisp/*.el")))

LLM

Some packages for dealing with LLM integrations.

copilot.el
(package! copilot
  :recipe (:host github :repo "zerolfx/copilot.el" :files ("*.el" "dist")))
gptel

I mostly use this for my locally hosted LLM solutions. It's pretty neat since large-context models are coming out at an increasing pace.

(package! gptel
  :recipe (:host github
		 :repo "karthink/gptel"
		 :files ("*.el")))

Better Internet

elpher

Gopher and Gemini browser in Emacs!

(package! elpher)