#+Title: Phil's Doom Emacs Config #+STARTUP: indent #+auto_tangle: t * Intro :PROPERTIES: :ID: de888450-40a6-4255-81dc-e6e65a9cf07c :END: This is my personal [[https://github.com/doomemacs/doomemacs][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 [[https://gitlab.com/dwt1/configuring-emacs/][DT's Configuring Emacs config files]], as well as [[https://github.com/novoid/dot-emacs][Karl Voit's Emacs config.]] * config.el ** Basic settings *** Author/ personal info #+begin_src emacs-lisp :tangle config.el (setq user-full-name "Phil Bajsicki") #+end_src *** 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. #+begin_src emacs-lisp :tangle config.el (setq-default backup-inhibited t) (setq global-auto-revert-mode t) (setq-default indent-tabs-mode t) #+end_src Ensure visited files are called by their true names. Kinda insignificant but nice. #+begin_src emacs-lisp :tangle config.el (setq find-file-visit-truename t) #+end_src **** Auth #+begin_src emacs-lisp :tangle config.el (setq auth-sources '("~/.authinfo")) #+end_src **** Locale #+begin_src elisp :tangle config.el (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) #+end_src *** Langtool Note that for this functionality you do need some resources, namely: - some kind of Java runtime (OpenJRE for instance) - [[https://languagetool.org/][LanguageTool]] This command only sets up the path to your java runtime binary. #+begin_src emacs-lisp :tangle config.el (setq langtool-java-bin "/usr/bin/java") #+end_src *** Theming and prettifying #+begin_src emacs-lisp :tangle config.el (after! counsel (setq counsel-outline-display-style 'title)) #+end_src **** Doom Theme ¯\_(ツ)_/¯ #+begin_src emacs-lisp :tangle config.el (load-theme 'doom-one t) (doom-themes-neotree-config) (doom-themes-org-config) #+end_src **** org-modern Just some bits here that affect the entirety of Emacs; the parts relevant to org-mode specifically are in [[*Appearance and style][org's appearance section.]] This part removes all the unnecessary bits that take up screen space and add clutter. #+begin_src elisp :tangle config.el (menu-bar-mode -1) (tool-bar-mode -1) (scroll-bar-mode -1) #+end_src Then fixing up some borders and dividers. It's a very clean look, imo. #+begin_src elisp :tangle config.el (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)) #+end_src **** Transparency ¯\_(ツ)_/¯ #+begin_src emacs-lisp :tangle config.el (set-frame-parameter nil 'alpha-background 85) (add-to-list 'default-frame-alist '(alpha-background . 85)) #+end_src **** Fonts To be entirely fair, I pretty much exclusively use Iosevka. Such a good font. #+begin_src emacs-lisp :tangle config.el (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") #+end_src ***** 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. #+begin_src emacs-lisp :results value format: pp :tangle no (print (font-family-list)) #+end_src ***** Ligature.el #+begin_src emacs-lisp :tangle config.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) #+end_src **** Helpers for text editing #+begin_src emacs-lisp :tangle config.el (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) #+end_src ** Global Keybinds Setting this here because I experiment with these occasionally and want them reset properly eaach time. #+begin_src emacs-lisp :tangle config.el (global-set-key "\C-g" 'keyboard-quit) (global-set-key "\C-cu" 'browse-url-chrome) #+end_src ** Package settings *** Straight Living on the edge. Honestly I probably should not... but then I do find joy in fixing up my config... #+begin_src emacs-lisp :tangle config.el (setq straight-repository-branch "develop") #+end_src *** 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 #+begin_src emacs-lisp :tangle config.el ;; must be set before `org` is loaded (add-to-list 'auto-mode-alist '("\\.org\\'" . org-mode)) (setq-default calendar-week-start-day 1) #+end_src ****** Directories and structure Basic directory set-up for org-mode #+begin_src elisp :tangle config.el (setq org-contacts-files '("~/enc/org/people.org")) (setq org-directory "~/enc/org/") #+end_src Agenda files #+begin_src elisp :tangle config.el (setq org-agenda-files (directory-files-recursively "~/enc/org/" ".org$"))1 #+end_src =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. #+begin_src emacs-lisp :tangle config.el (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) #+end_src ****** Appearance and style Keeps images contained on the screen. #+begin_src elisp :tangle config.el (setq org-image-actual-width '(0.8)) #+end_src Pretty! #+begin_src emacs-lisp config.el (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) #+end_src Code highlighting in code blocks! #+begin_src emacs-lisp (setq org-src-fontify-natively t) #+end_src Naturally, I prefer to have a consistent look in my numbers. #+begin_src emacs-lisp config.el (setq org-table-duration-hour-zero-padding t) #+end_src Tags flush right to the 80th column, and realign them when the length/ indentation of the heading changes. #+begin_src emacs-lisp config.el (setq org-tags-column -80 org-auto-align-tags t) #+end_src And, enable org-modern-mode by default, since it's nice. #+begin_src emacs-lisp :tangle config.el (global-org-modern-mode) #+end_src ****** Editing and comfort It's preferable to have org guess dates in the future when scheduling. #+begin_src elisp :tangle config.el (setq org-read-date-prefer-future t) #+end_src 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. #+begin_src elisp :tangle config.el (setq org-reverse-note-order nil) #+end_src 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. #+begin_src elisp :tangle config.el (setq org-blank-before-new-entry (quote ((heading . nil) (plain-list-item . nil)))) #+end_src 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? #+begin_src elisp :tangle config.el (setq org-catch-invisible-edits "smart") #+end_src Special functions for headings. #+begin_src elisp :tangle config.el (setq org-special-ctrl-a/e t) (setq org-special-ctrl-k t) #+end_src This fits the yanked subtree into the appropriate level in the structure it's yanked into. #+begin_src elisp :tangle config.el (setq org-yank-adjusted-subtrees t) #+end_src I like being able to split lines sometimes, especially when cleaning up large pieces of text. #+begin_src elisp :tangle config.el (setq org-M-RET-may-split-line '((headline . t) (item . t) (default . nil))) #+end_src 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. #+begin_src elisp :tangle config.el (setq org-insert-heading-respect-content nil) #+end_src 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. #+begin_src elisp :tangle config.el (setq org-footnote-section nil) #+end_src ****** Logging and Properties Logging into a drawer. #+begin_src elisp :tangle config.el (setq org-log-done (quote time) org-log-into-drawer t org-clock-into-drawer t) #+end_src Do not log inserting the TODO heading for the first time; only when further changes are made to the heading. #+begin_src elisp :tangle config.el (setq org-treat-insert-todo-heading-as-state-change nil) #+end_src 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. #+begin_src elisp :tangle config.el (setq org-use-property-inheritance nil) ;;(setq org-use-property-inheritance '(category columns archive logging)) #+end_src ****** 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. #+begin_src emacs-lisp :tangle config.el (setq-default org-enforce-todo-dependencies t) (setq org-enforce-todo-checkbox-dependencies t) #+end_src I want to know when my deadlines are approaching. #+begin_src emacs-lisp :tangle config.el (setq org-deadline-warning-days 7) #+end_src I like my statistics. #+begin_src emacs-lisp :tangle config.el (setq org-provide-todo-statistics t org-hierarchical-todo-statistics t) #+end_src #+begin_src emacs-lisp :tangle config.el (setq org-todo-repeat-to-state "LOOP") #+end_src ****** Todo keywords I got these from... I frankly don't even know where. They're not bad, imo. #+begin_src emacs-lisp :tangle config.el (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))) #+end_src Change font for DONE tasks - https://lists.gnu.org/archive/html/emacs-orgmode/2007-03/msg00179.html #+BEGIN_SRC emacs-lisp :tangle config.el (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))))) #+END_SRC **** Keybinds Pretty self-explanatory. #+begin_src emacs-lisp :tangle config.el (global-set-key "\C-cl" 'org-store-link) (global-set-key "\C-cnn" 'org-capture) #+end_src ***** 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. #+begin_src emacs-lisp :tangle config.el (global-set-key "\C-cia" '(lambda ()(interactive) (org-time-stamp '(16)))) (global-set-key "\C-cii" '(lambda () (interactive) (org-time-stamp-inactive '(16)))) #+end_src **** Capture templates #+begin_src emacs-lisp :tangle config.el (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:"))) #+end_src #+RESULTS: | 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%? | **** Functions ***** my-id-get-or-generate Straight from Karl Voit's config. #+BEGIN_SRC emacs-lisp :tangle no (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 ) #+END_SRC ***** 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. #+begin_src elisp :tangle config.el (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))) #+end_src ***** my-org-tree-to-indirect-buffer #+begin_quote This beautiful piece of code was done by [[https://www.reddit.com/user/github-alphapapa][alphapapa]] and published on [[https://www.reddit.com/r/orgmode/comments/dbsngi/finally_solving_the_lack_of_a_treeview_navigation/f26qpzr/][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. #+end_quote --Karl Voit #+BEGIN_SRC emacs-lisp :tangle config.el (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) #+END_SRC ***** preserving all heading levels when archiving #+begin_quote Preserve the hierarchy when archiving: [[https://fuco1.github.io/2017-04-20-Archive-subtrees-under-the-same-hierarchy-as-original-in-the-archive-files.html][blog article]], [[https://gist.github.com/Fuco1/e86fb5e0a5bb71ceafccedb5ca22fcfb][source code (GitHub gist)]] --Karl Voit #+end_quote #+BEGIN_SRC emacs-lisp :tangle config.el (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 don’t 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)))))))) #+END_SRC ***** my-dired-insert-lfile-link-list-to-other-org-window() #+begin_quote | 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 [[https://emacs.stackexchange.com/questions/60359/is-there-a-quicker-way-to-create-links-to-attachments][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]] #+end_quote #+begin_src emacs-lisp :results none :tangle no (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))) #+end_src **** org-roam #+begin_src emacs-lisp :tangle config.el (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) (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))) #+end_src ***** Keybinds #+begin_src emacs-lisp :tangle config.el (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) #+end_src #+RESULTS: : org-roam-capture **** org-agenda These are settings specifically for org-agenda, that don't overlap with any other settings. #+begin_src emacs-lisp :tangle config.el (setq org-agenda-start-day nil) (setq org-agenda-start-on-weekday nil) (setq org-agenda-span 'day) #+end_src Dim blocked tasks to clearly see that their prerequisites are not met. Make the agenda blocks more compact by skipping certain elements. #+begin_src emacs-lisp :tangle config.el (setq org-agenda-dim-blocked-tasks t) (setq org-agenda-compact-blocks t) #+end_src Non-nil means skip timestamp line if same entry shows because of deadline. #+BEGIN_SRC emacs-lisp :tangle config.el (setq org-agenda-skip-timestamp-if-deadline-is-shown t) #+END_SRC Remove completed deadline and scheduled tasks from the agenda view #+BEGIN_SRC emacs-lisp :tangle config.el (setq org-agenda-skip-deadline-if-done t) (setq org-agenda-skip-scheduled-if-done t) #+END_SRC Remove completed items from search results #+BEGIN_SRC emacs-lisp :tangle no (setq org-agenda-skip-timestamp-if-done t) #+END_SRC Include agenda archive files when searching for things #+BEGIN_SRC emacs-lisp :tangle config.el (setq org-agenda-text-search-extra-files (quote (agenda-archives))) #+END_SRC Do not search for time in heading when displaying a date-stamp #+BEGIN_SRC emacs-lisp :tangle config.el (setq org-agenda-search-headline-for-time nil) #+END_SRC Show all agenda dates - even if they are empty #+BEGIN_SRC emacs-lisp :tangle config.el (setq org-agenda-show-all-dates t) #+END_SRC Show the following items in log mode. #+begin_src emacs-lisp :tangle config.el (setq org-agenda-log-mode-items '(closed clock state)) #+end_src #+begin_src emacs-lisp :tangle config.el (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)))) #+end_src Ensuring that tag inheritance is applied in the agenda view. #+begin_src emacs-lisp :tangle config.el (setq org-agenda-use-tag-inheritance (quote (agenda))) #+end_src Agenda prefixes and org-modern agenda styling. #+begin_src emacs-lisp :tangle config.el (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 ─────────────────────────────────────────────────") #+end_src Two to choose from, I'm not sure which one is better here. I don't know where I got this one from. #+begin_src emacs-lisp :tangle config.el (setq org-agenda-time-grid '((daily today remove-match) (800 1000 1200 1400 1600 1800 2000) " ┄┄┄┄┄ " "┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄")) #+end_src Add hook into the agenda mode for highlighting. #+begin_src emacs-lisp :tangle config.el (add-hook 'org-agenda-mode-hook '(lambda () (hl-line-mode 1))) #+end_src **** 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. #+begin_src emacs-lisp :tangle config.el (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) #+end_src Some keybinds and a hook. #+begin_src emacs-lisp :tangle config.el (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) #+end_src **** 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. #+begin_src emacs-lisp :tangle config.el (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) #+end_src **** [disabled] copilot.el #+begin_src emacs-lisp :tangle no ;; accept completion from copilot and fallback to company (use-package! copilot :hook (prog-mode . copilot-mode) :bind (:map copilot-completion-map ("" . 'copilot-accept-completion) ("TAB" . 'copilot-accept-completion) ("C-TAB" . 'copilot-accept-completion-by-word) ("C-" . 'copilot-accept-completion-by-word))) #+end_src **** 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. #+begin_src emacs-lisp :tangle config.el (require 'org-auto-tangle) (add-hook 'org-mode-hook 'org-auto-tangle-mode) #+end_src ***** Automated timestamps in headings I need this because hitting the [[*Timestamp keybinds][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- C-i i~ into just ~C-~. Much easier, and I don't have to think about this any more. #+begin_src emacs-lisp :tangle config.el (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))))) #+end_src *** org-mode expansions **** org-babel This is really important for me since I tend to use PlantUML to generate charts, graphs and diagrams. #+begin_src emacs-lisp :tangle config.el (add-hook 'org-babel-after-execute-hook 'org-display-inline-images) #+end_src **** 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. #+begin_src emacs-lisp :tangle config.el (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) #+end_src **** org-expiry :PROPERTIES: :CREATED: <2024-09-18 Wed 23:03> :END: I want my entries to have a real expiry date sometimes, so this is here. It's quite neat! I am then hooking it into #+begin_src emacs-lisp :tangle config.el (use-package! org-expiry) #+end_src **** 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. #+begin_src emacs-lisp :tangle config.el (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}")))) #+end_src Testing function, not tangled. #+begin_src emacs-lisp :tangle no (print org-latex-classes) #+end_src I have not settled on this. Meh. #+begin_src elisp :tangle no (setq org-latex-default-class "tufte-handout" org-latex-pdf-process '("latexmk -pdf -bibtex-cond -f -outdir=%o %f")) #+end_src **** 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. #+begin_src emacs-lisp :tangle config.el (use-package! org-transclusion :after org :init (map! :map global-map "" #'org-transclusion-add :leader :prefix "n" :desc "Org Transclusion Mode" "t" #'org-transclusion-mode)) #+end_src **** Org-wild-notifier This lets me get desktop notifications for TODO items. #+begin_src emacs-lisp :tangle config.el (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) #+end_src *** mu4e Email in Emacs... what more can a man want? #+begin_src elisp :tangle config.el (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) #+end_src #+RESULTS: *** pdf-tools Gotta read in Emacs, sometimes. Usually in the browser, but when I have to take notes there's nothing more convenient. #+begin_src emacs-lisp :tangle config.el (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)))) #+end_src *** yasnippets #+begin_src emacs-lisp :tangle config.el (setq doom-snippets-enable-short-helpers t) #+end_src *** csv-mode Just making sure it loads when I load up csv files. #+begin_src emacs-lisp :tangle config.el (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) #+end_src *** sly Basic settings for Common Lisp development. #+begin_src emacs-lisp :tangle config.el ;; (load (expand-file-name "~/.roswell/helper.el")) (setq inferior-lisp-program "sbcl --dynamic-space-size 8192 -Q -l ~/.sbclrc") #+end_src *** 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. #+begin_src emacs-lisp :tangle config.el (use-package! gptel :config (setq! gptel-api-key "thisisanapikey") (setq! gptel-max-tokens 8192) (setq gptel-model "model" gptel-backend (gptel-make-openai "llama-cpp" :key "thisisanapikey" :stream t :protocol "http" :host "localhost:6666" :models '("model")))) (gptel-make-openai "llama-cpp" ;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 (setq gptel--debug t) #+end_src #+RESULTS: : t *** elfeed RSS is not dead. RSS is not dead. RSS is not dead. #+begin_src emacs-lisp :tangle config.el (setq-default elfeed-search-filter "@1-week-ago +unread ") #+end_src * 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. #+begin_src emacs-lisp :tangle no (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. ) #+end_src * init.el #+begin_src emacs-lisp :tangle 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)) #+end_src #+RESULTS: * packages.el *** Core #+begin_src emacs-lisp :tangle packages.el ;; -*- no-byte-compile: t; -*- ;;; $DOOMDIR/packages.el (unpin! straight) (package! beacon) (package! counsel) (package! deft) #+end_src *** Themes #+begin_src emacs-lisp :tangle packages.el (package! all-the-icons) (package! all-the-icons-dired) (package! doom-themes) #+end_src *** Modes: #+begin_src emacs-lisp :tangle packages.el (package! battle-haxe) (package! fish-mode) (package! typescript-mode) (package! terraform-mode) (package! wc-mode) (package! plantuml-mode) (package! csv-mode) #+end_src *** dired #+begin_src emacs-lisp :tangle packages.el (package! dired-open) #+end_src *** pdf-tools #+begin_src emacs-lisp :tangle packages.el (package! pdf-tools) #+end_src *** Org #+begin_src emacs-lisp :tangle packages.el ;; Fix for org-roam link issue (package! org-auto-tangle) (package! ox-slack) (package! ox-tufte) (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) #+end_src **** org-expiry #+begin_src emacs-lisp :tangle packages.el (package! org-contrib :recipe (:host sourcehut :type git :repo "~bzg/org-contrib" :files ("lisp/*.el"))) #+end_src *** LLM Some packages for dealing with LLM integrations. **** copilot.el #+begin_src emacs-lisp :tangle no (package! copilot :recipe (:host github :repo "zerolfx/copilot.el" :files ("*.el" "dist"))) #+end_src **** 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. #+begin_src emacs-lisp :tangle packages.el (package! gptel :recipe (:host github :repo "karthink/gptel" :files ("*.el"))) #+end_src *** Better Internet **** elpher Gopher and Gemini browser in Emacs! #+begin_src emacs-lisp :tangle packages.el (package! elpher) #+end_src