#+TITLE: Doom Emacs Literate Config #+AUTHOR: Emmet * Table of Contents :TOC:QUOTE: #+BEGIN_QUOTE - [[#what-is-doom-emacs][What is Doom Emacs?]] - [[#configuration-for-doom-emacs][Configuration for Doom Emacs]] - [[#my-configel][My config.el]] - [[#preamble--user-configuration][Preamble + User Configuration]] - [[#registers][Registers]] - [[#org-mode-configuration][Org Mode Configuration]] - [[#org-roam-configuration][Org Roam Configuration]] - [[#org-agenda-configuration][Org Agenda Configuration]] - [[#magit-configuration][Magit Configuration]] - [[#ibuffer-configuration][Ibuffer Configuration]] - [[#dired-configuration][Dired Configuration]] - [[#ranger-configuration][Ranger Configuration]] - [[#hledger-mode-configuration][hledger-mode Configuration]] - [[#tab-bar-configuration][Tab Bar Configuration]] - [[#focus-mode-configuration][Focus Mode Configuration]] - [[#helpful-mode-configuration][Helpful Mode Configuration]] - [[#mu4e-configuration][mu4e Configuration]] - [[#eaf][EAF]] - [[#direnv][Direnv]] - [[#projectile][Projectile]] - [[#sudo-edit][sudo-edit]] - [[#lsp][LSP]] - [[#terminal][Terminal]] - [[#elfeed][Elfeed]] - [[#my-initel][My init.el]] - [[#my-packagesel][My packages.el]] - [[#nix-integration][Nix Integration]] #+END_QUOTE * What is Doom Emacs? [[https://github.com/doomemacs/doomemacs][Doom Emacs]] is a distribution of the [[https://www.gnu.org/software/emacs/][Emacs Text Editor]] designed for [[https://www.vim.org/][Vim]] users. I like to use Emacs due to its extensibility and extra features it is capable of (besides text editing). Some of these extra features include: - [[https://orgmode.org/][Org Mode]] (Hierarchical text-based document format) - [[https://www.orgroam.com/][Org Roam]] (A second brain / personal wiki) - [[https://orgmode.org/][Org Agenda]] (Calendar and todo list) - [[https://magit.vc/][Magit]] (Git Client) I have found Emacs to be incredibly efficient, and transferring my workflow to fit inside of Emacs has allowed me to get much more work done. I primarily use Emacs for writing, note-taking, task/project management and organizing information. * Configuration for Doom Emacs Doom Emacs is configured via 3 main files, written in Elisp, a dialect of the Lisp programming language designed for Emacs. These 3 main files are: - [[./config.el][config.el]] - Stores your main configuration and allows to set user variables. - [[./init.el][init.el]] - Allows quick downloads of groups of Emacs packages. These groups of Emacs packages are curated by the Doom Emacs developers. - [[./packages.el][packages.el]] - Allows you to download additional packages from Melpa (Emacs package manager). By storing your configuration in these 3 files, it allows for quick reproducible builds of Doom Emacs. You can also load separate files inside of [[./config.el][config.el]] via the =load!= function, like so: #+BEGIN_SRC emacs-lisp (load! "~/.doom.d/private.el") #+END_SRC This can be used to load private config file with non-public information, or can be used to create modular configuration. Doom Emacs is traditionally installed by cloning the repository ([[https://github.com/doomemacs/doomemacs][https://github.com/doomemacs/doomemacs]]) and running =./bin/doom install=. I instead install Doom Emacs via Nix Doom Emacs ([[https://github.com/nix-community/nix-doom-emacs][https://github.com/nix-community/nix-doom-emacs]]), which packages Doom Emacs as a Nix derivation. The advantage to this is that I get more reproducibility and the ability to rollback updates (if anything breaks), but the downside is that any time Emacs packages are changed/updated, the entire derivation must be rebuilt from scratch (this is often time-consuming). I load this as a Nix derivation in my flake using the [[./doom.nix][doom.nix]] module. * My config.el ** Preamble + User Configuration #+BEGIN_SRC emacs-lisp :tangle config.el ;;; $DOOMDIR/config.el -*- lexical-binding: t; -*- ;;;------ User configuration ------;;; ;; Import relevant system variables from flake (see doom.nix) ;; includes variables like user-full-name, user-username, user-home-directory, user-email-address, doom-font, ;; and a few other custom variables I use later (load! "~/.emacs.d/system-vars.el") ;; custom variables include: ;; dotfiles-dir, absolute path to home directory ;; user-default-roam-dir, name of default org-roam directory for the machine (relative to ~/Org) ;; system-nix-profile, profile selected from my dotfiles ("personal" "work" "wsl" etc...) ;; system-wm-type, wayland or x11? only should be considered if system-nix-profile is "personal" or "work" ;; I prefer visual lines (setq display-line-numbers-type 'visual line-move-visual t) (use-package-hook! evil :pre-init (setq evil-respect-visual-line-mode t) ;; sane j and k behavior t) ;; I also like evil mode visual movement (map! :map evil-normal-state-map :desc "Move to next visual line" "j" 'evil-next-visual-line :desc "Move to previous visual line" "k" 'evil-previous-visual-line) ;; Theme (setq custom-theme-directory "~/.emacs.d/themes") (setq doom-theme 'doom-stylix) ;; +unicode-init-fonts-h often errors out (remove-hook 'doom-init-ui-hook '+unicode-init-fonts-h) ;; Transparent background (if (string= system-nix-profile "wsl") ;; Can't be that tranparent under wsl because no blur (funcall (lambda () (set-frame-parameter nil 'alpha-background 98) (add-to-list 'default-frame-alist '(alpha-background . 98)) )) ;; On Linux I can enable blur, however (funcall (lambda () (set-frame-parameter nil 'alpha-background 65) (add-to-list 'default-frame-alist '(alpha-background . 65)) )) ) ;; Icons in completion buffers (add-hook 'marginalia-mode-hook #'all-the-icons-completion-marginalia-setup) (all-the-icons-completion-mode) ;; This makes non-main buffers dimmer, so you can focus on main buffers (solaire-global-mode +1) ;; Grammar tasing should be voluntary (setq writegood-mode nil) ;; Beacon shows where the cursor is, even when fast scrolling (setq beacon-mode t) ;; Quicker window management keybindings (bind-key* "C-j" #'evil-window-down) (bind-key* "C-k" #'evil-window-up) (bind-key* "C-h" #'evil-window-left) (bind-key* "C-l" #'evil-window-right) (bind-key* "C-q" #'evil-window-delete) (bind-key* "M-q" #'kill-current-buffer) (bind-key* "M-w" #'+workspace/close-window-or-workspace) (bind-key* "M-n" #'next-buffer) (bind-key* "M-p" #'previous-buffer) (bind-key* "M-z" #'+vterm/toggle) (bind-key* "M-e" #'+eshell/toggle) (bind-key* (kbd "M-") #'+vterm/here) (bind-key* (kbd "M-E") #'+eshell/here) ;; Buffer management (bind-key* "" #'next-buffer) (bind-key* "" #'previous-buffer) ;; Disables custom.el (setq custom-file null-device) ;; emacs-dashboard setup (require 'all-the-icons) (require 'dashboard) (setq initial-buffer-choice (lambda () (get-buffer-create "*dashboard*")) doom-fallback-buffer-name "*dashboard*") ;; emacs-dashboard variables (setq dashboard-banner-logo-title "Welcome to Nix Doom Emacs") (setq dashboard-startup-banner 2) (setq dashboard-icon-type 'all-the-icons) ;; use `all-the-icons' package (setq dashboard-set-heading-icons t) (setq dashboard-set-file-icons t) (setq dashboard-set-navigator t) (setq dashboard-items '()) (setq dashboard-center-content t) (setq dashboard-footer-messages '("Here to do customizing, or actual work?" "M-x insert-inspiring-message" "My software never has bugs. It just develops random features." "Dad, what are clouds made of? Linux servers, mostly." "There is no place like ~" "~ sweet ~" "sudo chown -R us ./allyourbase" "I’ll tell you a DNS joke but it could take 24 hours for everyone to get it." "I'd tell you a UDP joke, but you might not get it." "I'll tell you a TCP joke. Do you want to hear it?")) (setq dashboard-navigator-buttons `(;; line1 ( (,"Roam" "" "" (lambda (&rest _)) 'org-formula) (,(all-the-icons-octicon "globe" :height 1.0 :v-adjust 0.0) "Notes overview" "" (lambda (&rest _) (org-roam-default-overview)) 'org-formula) (,(all-the-icons-fileicon "org" :height 1.0 :v-adjust 0.0) "Switch roam db" "" (lambda (&rest _) (org-roam-switch-db)) 'org-formula) ) ;; line 2 ( (,"Git" "" "" (lambda (&rest _)) 'diredfl-exec-priv) (,(all-the-icons-octicon "mark-github" :height 1.0 :v-adjust 0.0) "GitHub" "" (lambda (&rest _) (browse-url "ext+container:name=Tech&url=https://github.com/librephoenix")) 'diredfl-exec-priv) (,(all-the-icons-faicon "gitlab" :height 1.0 :v-adjust 0.0) "GitLab" "" (lambda (&rest _) (browse-url "ext+container:name=Tech&url=https://gitlab.com/librephoenix")) 'diredfl-exec-priv) (,(all-the-icons-faicon "coffee" :height 1.0 :v-adjust 0.0) "Gitea" "" (lambda (&rest _) (browse-url my-gitea-domain)) 'diredfl-exec-priv) ) ;; line 3 ( (,"Agenda" "" "" (lambda (&rest _)) 'dired-warning) (,(all-the-icons-octicon "checklist" :height 1.0 :v-adjust 0.0) "Agenda todos" "" (lambda (&rest _) (org-agenda-list)) 'dired-warning) (,(all-the-icons-octicon "calendar" :height 1.0 :v-adjust 0.0) "Agenda calendar" "" (lambda (&rest _) (cfw:open-org-calendar)) 'dired-warning) ) ;; line 4 ( (,"Config" "" "" (lambda (&rest _)) 'dired-mark) (,(all-the-icons-faicon "cogs" :height 1.0 :v-adjust 0.0) "System config" "" (lambda (&rest _) (projectile-switch-project-by-name "~/.dotfiles" t)) 'dired-mark) (,(all-the-icons-material "help" :height 1.0 :v-adjust -0.2) "Doom documentation" "" (lambda (&rest _) (doom/help)) 'dired-mark) ))) (setq dashboard-footer-icon (all-the-icons-faicon "list-alt" :height 1.0 :v-adjust -0.15 :face 'font-lock-keyword-face)) (dashboard-setup-startup-hook) ;; Smooth scrolling ;; requires good-scroll.el ;;(good-scroll-mode 1) ;;(setq good-scroll-duration 0.4 ;; good-scroll-step 270 ;; good-scroll-render-rate 0.03) ;; ;;(global-set-key (kbd "") #'good-scroll-up-full-screen) ;;(global-set-key (kbd "") #'good-scroll-down-full-screen) (setq scroll-margin 30) (setq hscroll-margin 10) ;; Requires for faster loading (require 'org-agenda) (require 'dired) ;; Garbage collection to speed things up (add-hook 'after-init-hook #'(lambda () (setq gc-cons-threshold (* 100 1024 1024)))) (add-hook 'focus-out-hook 'garbage-collect) (run-with-idle-timer 5 t 'garbage-collect) ;; Enable autorevert globally so that buffers update when files change on disk. ;; Very useful when used with file syncing (i.e. syncthing) (setq global-auto-revert-mode nil) (setq auto-revert-use-notify t) ;; Neotree fun (defun neotree-snipe-dir () (interactive) (if (projectile-project-root) (neotree-dir (projectile-project-root)) (neotree-dir (file-name-directory (file-truename (buffer-name)))) ) ) (map! :leader :desc "Open neotree here" "o n" #'neotree-snipe-dir :desc "Hide neotree" "o N" #'neotree-hide) ;; For camelCase (global-subword-mode 1) #+END_SRC ** Registers #+BEGIN_SRC emacs-lisp :tangle config.el ;;;------ Registers ------;;; (map! :leader :desc "Jump to register" "r" 'jump-to-register) (if (string= system-nix-profile "personal") (set-register ?f (cons 'file (concat user-home-directory "/Org/Family.s/Notes/hledger.org")))) (set-register ?h (cons 'file user-home-directory)) (set-register ?r (cons 'file (concat dotfiles-dir "/README.org"))) #+END_SRC ** Org Mode Configuration *** Standard Org Mode Configuration #+BEGIN_SRC emacs-lisp :tangle config.el ;;;------ Org mode configuration ------;;; ;; Set default org directory (setq org-directory "~/.Org") (remove-hook 'after-save-hook #'+literate|recompile-maybe) (set-company-backend! 'org-mode nil) ;; Automatically show images but manually control their size (setq org-startup-with-inline-images t org-image-actual-width nil) (require 'evil-org) (require 'evil-org-agenda) (add-hook 'org-mode-hook 'evil-org-mode -100) ;; Top-level headings should be bigger! (custom-set-faces! '(org-level-1 :inherit outline-1 :height 1.3) '(org-level-2 :inherit outline-2 :height 1.25) '(org-level-3 :inherit outline-3 :height 1.2) '(org-level-4 :inherit outline-4 :height 1.1) '(org-level-5 :inherit outline-5 :height 1.1) '(org-level-6 :inherit outline-6 :height 1.05) '(org-level-7 :inherit outline-7 :height 1.05) ) (after! org (org-eldoc-load)) (with-eval-after-load 'org (global-org-modern-mode)) ;; Add frame borders and window dividers (modify-all-frames-parameters '((right-divider-width . 5) (internal-border-width . 5))) (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)) (setq ;; Edit settings org-auto-align-tags nil org-tags-column 0 org-catch-invisible-edits 'show-and-error org-special-ctrl-a/e t org-insert-heading-respect-content t ;; Org styling, hide markup etc. org-hide-emphasis-markers t org-pretty-entities t org-ellipsis "…") (setq-default line-spacing 0.15) ; Automatic table of contents is nice (if (require 'toc-org nil t) (progn (add-hook 'org-mode-hook 'toc-org-mode) (add-hook 'markdown-mode-hook 'toc-org-mode)) (warn "toc-org not found")) ;;---- this block from http://fgiasson.com/blog/index.php/2016/06/21/optimal-emacs-settings-for-org-mode-for-literate-programming/ ----;; ;; Tangle Org files when we save them (defun tangle-on-save-org-mode-file() (when (string= (message "%s" major-mode) "org-mode") (org-babel-tangle))) (add-hook 'after-save-hook 'tangle-on-save-org-mode-file) ;; ---- end block ---- ;; ;; Better org table editing ;; This breaks multiline visual block edits ;;(setq-default evil-insert-state-exit-hook '(org-update-parent-todo-statistics ;; t)) ;;(setq org-table-automatic-realign nil) ;; Better for org source blocks (setq electric-indent-mode nil) (setq org-src-window-setup 'current-window) (set-popup-rule! "^\\*Org Src" :side 'top' :size 0.9) ;; Horizontal scrolling tables (add-load-path! "~/.emacs.d/phscroll") (setq org-startup-truncated nil) (with-eval-after-load "org" (require 'org-phscroll)) (setq phscroll-calculate-in-pixels t) ;; Org side tree outline (add-load-path! "~/.emacs.d/org-side-tree") (require 'org-side-tree) (setq org-side-tree-persistent nil) (setq org-side-tree-fontify t) (setq org-side-tree-enable-folding t) (defun org-side-tree-create-or-toggle () (interactive) (if (or (org-side-tree-has-tree-p) (eq major-mode 'org-side-tree-mode)) (org-side-tree-toggle) (org-side-tree))) (map! :leader "O t" #'org-side-tree-create-or-toggle) (map! :map org-side-tree-mode-map "SPC" nil) #+END_SRC *** Org Download and Image Capture #+BEGIN_SRC emacs-lisp :tangle config.el (require 'org-download) ;; Drag-and-drop to `dired` (add-hook 'dired-mode-hook 'org-download-enable) ;; system-wm-type, wayland or x11? only should be considered if system-nix-profile is "personal" or "work" (if (string= system-wm-type "wayland") (setq org-download-screenshot-method "grim -g \"$(slurp)\" %s") (setq org-download-screenshot-method "flameshot gui -p %s") ) (after! org-download (setq org-download-method 'directory)) (after! org (setq-default org-download-image-dir "img/" org-download-heading-lvl nil)) (add-to-list 'display-buffer-alist '("^*Async Shell Command*" . (display-buffer-no-window))) (defun org-download-clipboard-basename () (interactive) (setq org-download-path-last-dir org-download-image-dir) (setq org-download-image-dir (completing-read "directory: " (-filter #'f-directory-p (directory-files-recursively "." "" t)) nil t)) (org-download-clipboard (completing-read "basename: " '() nil nil)) (setq org-download-image-dir org-download-path-last-dir) ) (map! :leader :desc "Insert a screenshot" "i s" 'org-download-screenshot :desc "Insert image from clipboard" "i p" 'org-download-clipboard "i P" 'org-download-clipboard-basename) #+END_SRC *** External Program File Management #+BEGIN_SRC emacs-lisp :tangle config.el (defun org-new-file-from-template() "Copy a template from ~/Templates into a time stamped unique-named file in the same directory as the org-buffer and insert a link to this file." (interactive) (setq template-file (completing-read "Template file:" (directory-files "~/Templates"))) (setq filename (concat (make-temp-name (concat (file-name-directory (buffer-file-name)) "files/" (file-name-nondirectory (buffer-file-name)) "_" (format-time-string "%Y%m%d_%H%M%S_")) ) (file-name-extension template-file t))) (copy-file (concat user-home-directory "/Templates/" template-file) filename) (setq prettyname (read-from-minibuffer "Pretty name:")) (insert (concat "[[./files/" (file-name-nondirectory filename) "][" prettyname "]]")) (org-display-inline-images)) (map! :leader :desc "Create a new file from a template and insert a link at point" "i t" 'my-org-new-file-from-template) (if (not (string= system-nix-profile "wsl")) (when (require 'openwith nil 'noerror) (setq openwith-associations (list (list (openwith-make-extension-regexp '("mpg" "mpeg" "mp3" "mp4" "avi" "wmv" "wav" "mov" "flv" "ogm" "ogg" "mkv")) "mpv" '(file)) (list (openwith-make-extension-regexp '("doc" "xls" "ppt" "odt" "ods" "odg" "odp")) "libreoffice" '(file)) '("\\.lyx" "lyx" (file)) '("\\.chm" "kchmviewer" (file)) (list (openwith-make-extension-regexp '("pdf" "ps" "ps.gz" "dvi")) "atril" '(file)) (list (openwith-make-extension-regexp '("kdenlive")) "kdenlive-accel" '(file)) (list (openwith-make-extension-regexp '("kra")) "krita" '(file)) (list (openwith-make-extension-regexp '("blend" "blend1")) "blender" '(file)) (list (openwith-make-extension-regexp '("helio")) "helio" '(file)) (list (openwith-make-extension-regexp '("svg")) "inkscape" '(file)) (list (openwith-make-extension-regexp '("flp")) "~/.local/bin/flstudio" '(file)) )) (openwith-mode 1))) #+END_SRC *** Copy Links/Files into Clipboard #+BEGIN_SRC emacs-lisp :tangle config.el (defun org-copy-link-to-clipboard-at-point () "Copy current link at point into clipboard (useful for images and links)" ;; Remember to press C-g to kill this foreground process if it hangs! (interactive) (if (eq major-mode #'org-mode) (link-hint-copy-link-at-point) ) (if (eq major-mode #'ranger-mode) (ranger-copy-absolute-file-paths) ) (if (eq major-mode #'image-mode) (image-mode-copy-file-name-as-kill) ) (shell-command "~/.emacs.d/scripts/copy-link-or-file/copy-link-or-file-to-clipboard.sh " nil nil) ) (if (string= system-nix-profile "wsl") (map! :leader :desc "Copy link at point" "y y" 'link-hint-copy-link-at-point) (map! :leader :desc "Copy link/file at point into system clipbord (C-g to escape if copying a file)" "y y" 'org-copy-link-to-clipboard-at-point)) #+END_SRC **** Copy Link/File to Clipboard Helper Script Shamelessly stolen from [[https://unix.stackexchange.com/questions/30093/copy-image-from-command-line-to-clipboard][here]] and modified for my use. #+BEGIN_SRC shell :tangle ./scripts/copy-link-or-file/copy-link-or-file-to-clipboard.sh :tangle-mode (identity #o755) #!/bin/sh if [ $(echo $XDG_SESSION_TYPE) == "wayland" ]; then FILENAME="$(wl-paste)" FILTEREDFILENAME=$(echo "$FILENAME" | sed "s+file:+./+") echo "$FILTEREDFILENAME" if [[ -f "$FILTEREDFILENAME" ]]; then wl-copy < "$FILTEREDFILENAME" fi elif [ $(echo $XDG_SESSION_TYPE) == "x11" ]; then FILENAME="$(xclip -o)" FILTEREDFILENAME=$(echo "$FILENAME" | sed "s+file:+./+") if [[ -f "$FILTEREDFILENAME" ]]; then TYPE=$(file -b --mime-type "$FILTEREDFILENAME") xclip -selection clipboard -t "$TYPE" -i "$FILTEREDFILENAME" exit fi else exit fi exit #+END_SRC *** Org Online Images #+BEGIN_SRC emacs-lisp :tangle config.el ;; Online images inside of org mode is pretty cool ;; This snippit is from Tobias on Stack Exchange ;; https://emacs.stackexchange.com/questions/42281/org-mode-is-it-possible-to-display-online-images (require 'org-yt) (defun org-image-link (protocol link _description) "Interpret LINK as base64-encoded image data." (cl-assert (string-match "\\`img" protocol) nil "Expected protocol type starting with img") (let ((buf (url-retrieve-synchronously (concat (substring protocol 3) ":" link)))) (cl-assert buf nil "Download of image \"%s\" failed." link) (with-current-buffer buf (goto-char (point-min)) (re-search-forward "\r?\n\r?\n") (buffer-substring-no-properties (point) (point-max))))) (org-link-set-parameters "imghttp" :image-data-fun #'org-image-link) (org-link-set-parameters "imghttps" :image-data-fun #'org-image-link) #+END_SRC *** Org Mermaid Diagrams #+BEGIN_SRC emacs-lisp :tangle config.el ;; Mermaid diagrams (setq ob-mermaid-cli-path "~/.nix-profile/bin/mmdc") #+END_SRC *** Org Simple Printing #+BEGIN_SRC emacs-lisp :tangle config.el ;; Print org mode (defun org-simple-print-buffer () "Open an htmlized form of current buffer and open in a web browser to print" (interactive) (htmlize-buffer) (browse-url-of-buffer (concat (buffer-name) ".html")) (sleep-for 1) (kill-buffer (concat (buffer-name) ".html"))) ;; Doesn't work yet, bc htmlize-region takes arguments BEG and END ;(defun org-simple-print-region() ; "Open an htmlized form of current region and open in a web browser to print" ; (interactive) ; (htmlize-region ) ; (browse-url-of-buffer (concat (buffer-name) ".html")) ; (sleep-for 1) ; (kill-buffer (concat (buffer-name) ".html"))) (map! :leader :prefix ("P" . "Print") :desc "Simple print buffer in web browser" "p" 'org-simple-print-buffer) (map! :leader :prefix ("P" . "Print") :desc "Simple print buffer in web browser" "b" 'org-simple-print-buffer) ;(map! :leader ; :prefix ("P" . "Print") ; :desc "Simple print region in web browser" ; "r" 'org-simple-print-region) #+END_SRC *** Org Inline Macros #+BEGIN_SRC emacs-lisp :tangle config.el ;; Display macros inline in buffers (add-to-list 'font-lock-extra-managed-props 'display) (font-lock-add-keywords 'org-mode '(("\\({{{[a-zA-Z#%)(_-+0-9]+}}}\\)" 0 `(face nil display ,(format "%s" (let* ((input-str (match-string 0)) (el (with-temp-buffer (insert input-str) (goto-char (point-min)) (org-element-context))) (text (org-macro-expand el org-macro-templates))) (if text text input-str))))))) #+END_SRC *** Org Transclusion #+BEGIN_SRC emacs-lisp :tangle config.el ;; Org transclusion (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)) (map! :leader :prefix "n" "l" #'org-transclusion-live-sync-start) (add-hook 'org-mode-hook #'org-transclusion-mode) #+END_SRC *** Org Jekyll #+begin_src emacs-lisp :tangle config.el (defun org-jekyll-new-post () (interactive) (setq new-blog-post-title (read-from-minibuffer "Post name: ")) (setq new-blog-post-date (format-time-string "%Y-%m-%d" (date-to-time (org-read-date)))) (setq new-blog-post-slug (downcase (replace-regexp-in-string "[^[:alpha:][:digit:]_-]" "" (string-replace " " "-" new-blog-post-title)))) (setq new-blog-post-file (concat (projectile-project-root) "org/_posts/" new-blog-post-date "-" new-blog-post-slug ".org")) (let ((org-capture-templates `(("p" "New Jekyll blog post" plain (file new-blog-post-file) ,(concat "#+title: " new-blog-post-title "\n#+options: toc:nil num:nil\n#+begin_export html\n---\nlayout: post\ntitle: " new-blog-post-title "\nexcerpt: %?\ntags: \npermalink: " new-blog-post-date "-" new-blog-post-slug "\n---\n#+end_export\n\n#+attr_html: :alt " new-blog-post-title " :align center\n[[../assets/" new-blog-post-date "-" new-blog-post-slug ".png]]"))) )) (org-capture)) ) (defun org-jekyll-rename-post () (interactive) (setq new-blog-post-title (read-from-minibuffer "Post name: ")) (setq new-blog-post-date (format-time-string "%Y-%m-%d" (date-to-time (org-read-date)))) (setq new-blog-post-slug (downcase (replace-regexp-in-string "[^[:alpha:][:digit:]_-]" "" (string-replace " " "-" new-blog-post-title)))) (org-roam-set-keyword "title" new-blog-post-title) (replace-regexp "permalink: .*\n" (concat "permalink: " new-blog-post-date "-" new-blog-post-slug "\n") nil (point-min) (point-max)) (replace-regexp "title: .*\n" (concat "title: " new-blog-post-title "\n") nil (point-min) (point-max)) (setq prev-blog-post-filename-base (file-name-base (buffer-file-name))) (doom/move-this-file (concat new-blog-post-date "-" new-blog-post-slug ".org")) (shell-command (concat "sed -i s/" prev-blog-post-filename-base "/" (file-name-base (buffer-file-name)) "/g *.org") nil) (replace-regexp prev-blog-post-filename-base (file-name-base (buffer-file-name)) nil (point-min) (point-max)) (save-buffer) ) (map! :leader :prefix ("N") :desc "New blog post" "p" #'org-jekyll-new-post :desc "Rename or redate blog post and update links accordingly" "e" #'org-jekyll-rename-post ) #+end_src ** Org Roam Configuration *** Standard Org Roam Configuration #+BEGIN_SRC emacs-lisp :tangle config.el ;;;------ Org roam configuration ------;;; (require 'org-roam) (require 'org-roam-dailies) (setq org-roam-directory (concat "~/Org/" user-default-roam-dir "/Notes") org-roam-db-location (concat "~/Org/" user-default-roam-dir "/Notes/org-roam.db")) (setq org-roam-node-display-template "${title:65}📝${tags:*}") (org-roam-db-autosync-mode) (setq mode-line-misc-info '((which-function-mode (which-func-mode ("" which-func-format " "))) ("" so-long-mode-line-info) (global-mode-string ("" global-mode-string)) " " org-roam-db-choice) ) #+END_SRC *** Multi Org Roam Configuration #+BEGIN_SRC emacs-lisp :tangle config.el (setq full-org-roam-db-list nil) (setq full-org-roam-db-list (directory-files "~/Org" t "\\.[p,s]$")) (dolist (item full-org-roam-db-list) (setq full-org-roam-db-list (append (directory-files item t "\\.[p,s]$") full-org-roam-db-list))) (setq org-roam-db-choice user-default-roam-dir) (setq full-org-roam-db-list-pretty (list)) (dolist (item full-org-roam-db-list) (setq full-org-roam-db-list-pretty (append (list (replace-regexp-in-string (concat "\\/home\\/" user-username "\\/Org\\/") "" item)) full-org-roam-db-list-pretty))) (defun org-roam-open-dashboard () "Open ${org-roam-directory}/dashboard.org (I use this naming convention to create dashboards for each of my org roam maps)" (interactive) (if (file-exists-p (concat org-roam-directory "/dashboard.org")) (org-open-file (concat org-roam-directory "/dashboard.org")) (dired org-roam-directory)) ) (defun org-roam-open-inbox () "Capture info in ${org-roam-directory}/inbox.org (I use this naming convention to create dashboards for each of my org roam maps)" (interactive) (if (file-exists-p (concat org-roam-directory "/inbox.org")) (org-open-file (concat org-roam-directory "/inbox.org")) (message "No inbox found, capture something with M-x org-roam-capture-inbox")) ) (defun org-roam-capture-inbox () (interactive) (org-roam-capture- :node (org-roam-node-create) :templates '(("i" "inbox" plain "* %?" :if-new (file+head "inbox.org" "#+title: Inbox\n"))))) (defun org-roam-switch-db (&optional arg silent) "Switch to a different org-roam database, arg" (interactive) (when (not arg) (setq full-org-roam-db-list nil) (setq full-org-roam-db-list (directory-files "~/Org" t "\\.[p,s]$")) (dolist (item full-org-roam-db-list) (setq full-org-roam-db-list (append (directory-files item t "\\.[p,s]$") full-org-roam-db-list))) (setq full-org-roam-db-list-pretty (list)) (dolist (item full-org-roam-db-list) (setq full-org-roam-db-list-pretty (append (list (replace-regexp-in-string (concat "\\/home\\/" user-username "\\/Org\\/") "" item)) full-org-roam-db-list-pretty))) (setq org-roam-db-choice (completing-read "Select org roam database: " full-org-roam-db-list-pretty nil t))) (when arg (setq org-roam-db-choice arg)) (setq org-roam-directory (file-truename (concat "~/Org/" org-roam-db-choice "/Notes")) org-roam-db-location (file-truename (concat "~/Org/" org-roam-db-choice "/Notes/org-roam.db")) org-directory (file-truename (concat "~/Org/" org-roam-db-choice "/Notes"))) (when (not silent) (org-roam-open-dashboard)) (org-roam-db-sync) (message (concat "Switched to " org-roam-db-choice " org-roam database!"))) (defun org-roam-default-overview () (interactive) (org-roam-switch-db user-default-roam-dir)) (defun org-roam-switch-db-id-open (arg ID &optional switchpersist) "Switch to another org-roam db and visit file with id arg" "If switchpersist is non-nil, stay in the new org-roam db after visiting file" (interactive) (setq prev-org-roam-db-choice org-roam-db-choice) (org-roam-switch-db arg 1) (org-roam-id-open ID) (when (not switchpersist) (org-roam-switch-db prev-org-roam-db-choice 1))) #+END_SRC *** Org Roam "todos" Tagging for Org Agenda #+BEGIN_SRC emacs-lisp :tangle config.el ;;;------ Org-roam-agenda configuration ------;;; (defun text-in-buffer-p (TEXT) (save-excursion (goto-char (point-min)) (search-forward TEXT nil t))) (defun apply-old-todos-tag-maybe (&optional FILE) (interactive) (if (stringp FILE) (setq the-daily-node-filename FILE) (setq the-daily-node-filename buffer-file-name)) (if (org-roam-dailies--daily-note-p the-daily-node-filename) (if (<= (nth 2 (org-roam-dailies-calendar--file-to-date the-daily-node-filename)) (nth 2 org-agenda-current-date)) (if (<= (nth 1 (org-roam-dailies-calendar--file-to-date the-daily-node-filename)) (nth 1 org-agenda-current-date)) (if (<= (nth 0 (org-roam-dailies-calendar--file-to-date the-daily-node-filename)) (nth 0 org-agenda-current-date)) (funcall (lambda () (with-current-buffer (get-file-buffer the-daily-node-filename) (org-roam-tag-add '("old-todos"))) (with-current-buffer (get-file-buffer the-daily-node-filename) (org-roam-tag-remove '("todos"))) ) ) ) ) ) ) ) (defun apply-old-todos-tag-maybe-and-save (FILE) (interactive) (find-file-noselect FILE) (apply-old-todos-tag-maybe FILE) (with-current-buffer (get-file-buffer the-daily-node-filename) (save-buffer)) (with-current-buffer (get-file-buffer the-daily-node-filename) (kill-buffer)) ) (defun org-current-buffer-has-todos () "Return non-nil if current buffer has any todo entry." (org-element-map ; (2) (org-element-parse-buffer 'headline) ; (1) 'headline (lambda (h) (eq (org-element-property :todo-type h) 'todo)) nil 'first-match)) ; (3) (defun org-has-recent-timestamps (OLD-DAYS) "Return non-nil only if current buffer has entries with timestamps more recent than OLD-DAYS days" (interactive) (if (org-element-map (org-element-parse-buffer) 'timestamp (lambda (h) (org-element-property :raw-value h))) (org-element-map ; (2) (org-element-parse-buffer) ; (1) 'timestamp (lambda (h) (time-less-p (time-subtract (current-time) (* 60 60 24 OLD-DAYS)) (date-to-time (org-element-property :raw-value h)))) nil 'first-match) nil)) (setq org-timestamps-days-for-old 21) ; This has a bug where it won't sync a new agenda file ; if I'm editing an org roam node file while set to another ; org roam db (defun add-todos-tag-on-save-org-mode-file() (interactive) (when (string= (message "%s" major-mode) "org-mode") (if (org-roam-node-p (org-roam-node-at-point)) (funcall (lambda() (if (or (org-current-buffer-has-todos) (org-has-recent-timestamps org-timestamps-days-for-old)) (org-roam-tag-add '("todos")) (org-roam-tag-remove '("todos")) ) (apply-old-todos-tag-maybe) ) ) ) ) ) (add-hook 'before-save-hook 'add-todos-tag-on-save-org-mode-file) #+END_SRC *** Setup Org Agenda from Org Roam #+BEGIN_SRC emacs-lisp :tangle config.el (defun org-roam-filter-by-tag (tag-name) (lambda (node) (member tag-name (org-roam-node-tags node)))) (defun org-roam-list-notes-by-tag (tag-name) (mapcar #'org-roam-node-file (seq-filter (org-roam-filter-by-tag tag-name) (org-roam-node-list)))) (defun org-roam-dailies-apply-old-todos-tags-to-all () ; (dolist (daily-node org-roam-dailies-files) ; (apply-old-todos-tag-maybe-and-save daily-node) ; ) (setq num 0) (while (< num (list-length (org-roam-list-notes-by-tag "todos"))) (apply-old-todos-tag-maybe-and-save (nth num (org-roam-list-notes-by-tag "todos"))) (setq num (1+ num)) ) ) (defun org-roam-append-notes-to-agenda (tag-name db) (org-roam-switch-db db t) ; (org-roam-dailies-apply-old-todos-tags-to-all) (setq org-agenda-files (append org-agenda-files (org-roam-list-notes-by-tag "todos"))) ) (defun org-roam-refresh-agenda-list () (interactive) (setq prev-org-roam-db-choice org-roam-db-choice) (setq org-agenda-files '()) (dolist (DB full-org-roam-db-list-pretty) (org-roam-append-notes-to-agenda "todos" DB) ) (setq org-agenda-files (-uniq org-agenda-files)) (org-roam-switch-db prev-org-roam-db-choice 1) ) ;; Build agenda for first time during this session (org-roam-refresh-agenda-list) (map! :leader :prefix ("o a") :desc "Refresh org agenda from roam dbs" "r" 'org-roam-refresh-agenda-list) #+END_SRC *** Org Roam Keybindings #+BEGIN_SRC emacs-lisp :tangle config.el (map! :leader :prefix ("N" . "org-roam notes") :desc "Capture new roam node" "c" 'org-roam-capture :desc "Open org roam inbox" "I o" 'org-roam-open-inbox :desc "Capture stuff in inbox" "I c" 'org-roam-capture-inbox :desc "Insert roam node link at point" "i" 'org-roam-node-insert :desc "Find roam node" "." 'org-roam-node-find :desc "Switch org-roam database" "s" 'org-roam-switch-db :desc "Update current org-roam database" "u" 'org-roam-db-sync :desc "Re-zoom on current node in org-roam-ui" "z" 'org-roam-ui-node-zoom :desc "Visualize org-roam database with org-roam-ui" "O" 'org-roam-default-overview :desc "Visualize org-roam database with org-roam-ui" "o" 'org-roam-open-dashboard) #+END_SRC *** Org Roam Capture Templates #+BEGIN_SRC emacs-lisp :tangle config.el (after! org-roam (setq org-roam-capture-templates '(("d" "default" plain "%?" :target (file+head "%<%Y%m%d%H%M%S>-${slug}.org" "#+title: ${title}\n") :unnarrowed t)))) #+END_SRC *** Org Roam Olivetti Mode #+BEGIN_SRC emacs-lisp :tangle config.el (setq olivetti-style 'fancy olivetti-margin-width 100) (setq-default olivetti-body-width 100) (defun org-roam-olivetti-mode () (interactive) (if (org-roam-file-p) (olivetti-mode)) (if (org-roam-file-p) (doom-disable-line-numbers-h))) (add-hook 'org-mode-hook 'org-roam-olivetti-mode) #+END_SRC *** Org Roam Dynamic Blocks #+BEGIN_SRC emacs-lisp :tangle config.el (add-load-path! "~/.emacs.d/org-nursery/lisp") (require 'org-roam-dblocks) (use-package org-roam-dblocks :hook (org-mode . org-roam-dblocks-autoupdate-mode)) #+END_SRC *** Org Roam Export Setup #+BEGIN_SRC emacs-lisp :tangle config.el (setq org-id-extra-files 'org-agenda-text-search-extra-files) #+END_SRC *** Org Roam UI Setup I want this to be able to automatically open ORUI in EAF Browser in a split to the right. This kinda works now? On Wayland, EAF doesn't work. #+BEGIN_SRC emacs-lisp :tangle config.el ;(add-to-list 'display-buffer-alist '("^\\ORUI" display-buffer-in-side-window ; '(side . right) ; (window-width . 50) ;)) ;(add-to-list 'display-buffer-alist '("^\\localhost:35901" display-buffer-in-side-window ; '(side . right) ; (window-width . 50) ;)) ;;(setq org-roam-ui-browser-function 'eaf-open-browser) ; xorg (setq org-roam-ui-browser-function 'browse-url) ; wayland (defun open-org-roam-ui () (interactive) (+evil/window-vsplit-and-follow) (org-roam-ui-open) (evil-window-left 1)) (defun kill-org-roam-ui () (interactive) ;; (delete-window (get-buffer-window "ORUI" t)) ; xorg ;; (kill-buffer "ORUI") ; xorg (kill-buffer "*httpd*") ) ; xorg ;;(map! :leader ;; :prefix ("N" . "org-roam notes") ;; :desc "Visualize org-roam database with org-roam-ui" ;; "v" 'open-org-roam-ui) ; wayland (map! :leader :prefix ("N" . "org-roam notes") :desc "Visualize org-roam database with org-roam-ui" "v" 'org-roam-ui-open) (map! :leader :prefix ("N" . "org-roam notes") :desc "Kill all org roam ui buffers" "V" 'kill-org-roam-ui) #+END_SRC ** Org Agenda Configuration *** Standard Org Agenda Configuration #+BEGIN_SRC emacs-lisp :tangle config.el ;;;------ Org agenda configuration ------;;; ;; Set span for agenda to be just daily (setq org-agenda-span 1 org-agenda-start-day "+0d" org-agenda-skip-timestamp-if-done t org-agenda-skip-deadline-if-done t org-agenda-skip-scheduled-if-done t org-agenda-skip-scheduled-if-deadline-is-shown t org-agenda-skip-timestamp-if-deadline-is-shown t) ;; Custom styles for dates in agenda (custom-set-faces! '(org-agenda-date :inherit outline-1 :height 1.15) '(org-agenda-date-today :inherit diary :height 1.15) '(org-agenda-date-weekend :ineherit outline-2 :height 1.15) '(org-agenda-date-weekend-today :inherit outline-4 :height 1.15) '(org-super-agenda-header :inherit custom-button :weight bold :height 1.05) ) ;; Toggle completed entries function (defun org-agenda-toggle-completed () (interactive) (setq org-agenda-skip-timestamp-if-done (not org-agenda-skip-timestamp-if-done) org-agenda-skip-deadline-if-done (not org-agenda-skip-timestamp-if-done) org-agenda-skip-scheduled-if-done (not org-agenda-skip-timestamp-if-done)) (org-agenda-redo)) (map! :map evil-org-agenda-mode-map :after org-agenda :nvmeg "s d" #'org-agenda-toggle-completed) ;; Ricing org agenda (setq org-agenda-current-time-string "") (setq org-agenda-time-grid '((daily) () "" "")) (setq org-agenda-prefix-format '( (agenda . " %?-2i %t ") (todo . " %i %-12:c") (tags . " %i %-12:c") (search . " %i %-12:c"))) (setq org-agenda-hide-tags-regexp ".*") (setq org-agenda-category-icon-alist `(("Teaching.p" ,(list (all-the-icons-faicon "graduation-cap" :height 0.8)) nil nil :ascent center) ("Family.s" ,(list (all-the-icons-faicon "home" :v-adjust 0.005)) nil nil :ascent center) ("Producer.p" ,(list (all-the-icons-faicon "youtube-play" :height 0.9)) nil nil :ascent center) ("Bard.p" ,(list (all-the-icons-faicon "music" :height 0.9)) nil nil :ascent center) ("Stories.s" ,(list (all-the-icons-faicon "book" :height 0.9)) nil nil :ascent center) ("Author.p" ,(list (all-the-icons-faicon "pencil" :height 0.9)) nil nil :ascent center) ("Gamedev.s" ,(list (all-the-icons-faicon "gamepad" :height 0.9)) nil nil :ascent center) ("Knowledge.p" ,(list (all-the-icons-faicon "database" :height 0.8)) nil nil :ascent center) ("Personal.p" ,(list (all-the-icons-material "person" :height 0.9)) nil nil :ascent center) )) #+END_SRC *** Org Agenda Convenience Functions #+BEGIN_SRC emacs-lisp :tangle config.el (defun org-categorize-by-roam-db-on-save () (interactive) (when (string= (message "%s" major-mode) "org-mode") (when (string-prefix-p (concat "/home/" user-username "/Org") (expand-file-name (buffer-file-name))) (setq categorizer-old-line (line-number-at-pos)) (evil-goto-first-line) (org-set-property "CATEGORY" (substring (string-trim-left (expand-file-name (buffer-file-name)) (concat "/home/" user-username "/Org/")) 0 (string-match "/" (string-trim-left (expand-file-name (buffer-file-name)) (concat "/home/" user-username "/Org/"))))) (evil-goto-line categorizer-old-line) ) ) ) (add-hook 'after-save-hook 'org-categorize-by-roam-db-on-save) ;; Function to be run when org-agenda is opened (defun org-agenda-open-hook () "Hook to be run when org-agenda is opened" (olivetti-mode)) ;; Adds hook to org agenda mode, making follow mode active in org agenda (add-hook 'org-agenda-mode-hook 'org-agenda-open-hook) ;; Easy refreshes on org agenda for syncthing file changes ;; adapted from https://www.reddit.com/r/orgmode/comments/mu6n5b/org_agenda_auto_updating/ ;; and https://lists.gnu.org/archive/html/help-gnu-emacs/2008-12/msg00435.html (defadvice org-agenda-list (before refresh-org-agenda-on-revert activate) (mapc (lambda (file) (unless (verify-visited-file-modtime (get-file-buffer file)) (with-current-buffer (get-file-buffer file) (when (eq major-mode 'org-mode) (revert-buffer nil 'noconfirm))))) (org-agenda-files))) (defadvice org-agenda-redo (before refresh-org-agenda-on-revert activate) (mapc (lambda (file) (unless (verify-visited-file-modtime (get-file-buffer file)) (with-current-buffer (get-file-buffer file) (when (eq major-mode 'org-mode) (revert-buffer nil 'noconfirm))))) (org-agenda-files))) (defadvice org-agenda-redo-all (before refresh-org-agenda-on-revert activate) (mapc (lambda (file) (unless (verify-visited-file-modtime (get-file-buffer file)) (with-current-buffer (get-file-buffer file) (when (eq major-mode 'org-mode) (revert-buffer nil 'noconfirm))))) (org-agenda-files))) ;; Function to list all my available org agenda files and switch to them (defun list-and-switch-to-agenda-file () "Lists all available agenda files and switches to desired one" (interactive) (setq full-agenda-file-list nil) (setq choice (completing-read "Select agenda file:" org-agenda-files nil t)) (find-file choice)) (map! :leader :desc "Switch to specific org agenda file" "o a s" 'list-and-switch-to-agenda-file) (defun org-agenda-switch-with-roam () "Switches to org roam node file and database from org agenda view" (interactive) (org-agenda-switch-to) (if (f-exists-p (concat (dir!) "/org-roam.db")) (org-roam-switch-db (replace-regexp-in-string (concat "\\/home\\/" user-username "\\/Org\\/") "" (f-parent (dir!))) t)) (if (f-exists-p (concat (f-parent (dir!)) "/org-roam.db")) (org-roam-switch-db (replace-regexp-in-string (concat "\\/home\\/" user-username "\\/Org\\/") "" (f-parent (f-parent (dir!)))) t)) (org-roam-olivetti-mode) ) (map! :map evil-org-agenda-mode-map :after org-agenda :nvmeg "" #'org-agenda-switch-with-roam :nvmeg "" #'org-agenda-switch-with-roam) (map! :map org-agenda-mode-map :after org-agenda :nvmeg "" #'org-agenda-switch-with-roam :nvmeg "" #'org-agenda-switch-with-roam) #+END_SRC *** Org Super Agenda Configuration #+BEGIN_SRC emacs-lisp :tangle config.el (require 'org-super-agenda) (setq org-super-agenda-groups '(;; Each group has an implicit boolean OR operator between its selectors. (:name " Overdue " ; Optionally specify section name :scheduled past :order 2 :face 'error) (:name "Personal " :and(:file-path "Personal.p" :not (:tag "event")) :order 3) (:name "Family " :and(:file-path "Family.s" :not (:tag "event")) :order 3) (:name "Teaching " :and(:file-path "Teaching.p" :not (:tag "event")) :order 3) (:name "Gamedev " :and(:file-path "Gamedev.s" :not (:tag "event")) :order 3) (:name "Youtube " :and(:file-path "Producer.p" :not (:tag "event")) :order 3) (:name "Music " :and(:file-path "Bard.p" :not (:tag "event")) :order 3) (:name "Storywriting " :and(:file-path "Stories.s" :not (:tag "event")) :order 3) (:name "Writing " :and(:file-path "Author.p" :not (:tag "event")) :order 3) (:name "Learning " :and(:file-path "Knowledge.p" :not (:tag "event")) :order 3) (:name " Today " ; Optionally specify section name :time-grid t :date today :scheduled today :order 1 :face 'warning) )) (org-super-agenda-mode t) (map! :desc "Next line" :map org-super-agenda-header-map "j" 'org-agenda-next-line) (map! :desc "Next line" :map org-super-agenda-header-map "k" 'org-agenda-previous-line) #+END_SRC *** Org Agenda Notifications #+BEGIN_SRC emacs-lisp (add-load-path! "~/.emacs.d/org-yaap") (require 'org-yaap) (setq org-yaap-alert-title "Org Agenda") (setq org-yaap-overdue-alerts 20) (setq org-yaap-alert-before 20) (setq org-yaap-daily-alert '(7 30)) (setq org-yaap-daemon-idle-time 30) (org-yaap-mode 1) #+END_SRC *** Org Timeblock #+begin_src emacs-lisp :tangle config.el (add-load-path! "~/.emacs.d/org-timeblock") (require 'org-timeblock) (map! :leader :desc "Open org timeblock" "O c" 'org-timeblock) (map! :desc "Next day" :map org-timeblock-mode-map :nvmeg "l" 'org-timeblock-day-later) (map! :desc "Previous day" :map org-timeblock-mode-map :nvmeg "h" 'org-timeblock-day-earlier) (map! :desc "Schedule event" :map org-timeblock-mode-map :nvmeg "m" 'org-timeblock-schedule) (map! :desc "Event duration" :map org-timeblock-mode-map :nvmeg "d" 'org-timeblock-set-duration) #+end_src ** Magit Configuration #+BEGIN_SRC emacs-lisp :tangle config.el ;;;------ magit configuration ------;;; ;; Need the following two blocks to make magit work with git bare repos (defun ~/magit-process-environment (env) "Add GIT_DIR and GIT_WORK_TREE to ENV when in a special directory. https://github.com/magit/magit/issues/460 (@cpitclaudel)." (let ((default (file-name-as-directory (expand-file-name default-directory))) (home (expand-file-name "~/"))) (when (string= default home) (let ((gitdir (expand-file-name "~/.dotfiles.git/"))) (push (format "GIT_WORK_TREE=%s" home) env) (push (format "GIT_DIR=%s" gitdir) env)))) env) (advice-add 'magit-process-environment :filter-return #'~/magit-process-environment) (require 'magit-todos) (magit-todos-mode 1) #+END_SRC ** Ibuffer Configuration #+BEGIN_SRC emacs-lisp :tangle config.el (evil-set-initial-state 'ibuffer-mode 'motion) (evil-define-key 'motion 'ibuffer-mode "j" 'evil-next-visual-line "k" 'evil-previous-visual-line "d" 'ibuffer-mark-for-delete "q" 'kill-buffer (kbd "") 'ibuffer-visit-buffer) #+END_SRC ** Dired Configuration #+BEGIN_SRC emacs-lisp :tangle config.el ;;;------ dired configuration ------;;; (add-hook 'dired-mode-hook 'all-the-icons-dired-mode) (map! :desc "Increase font size" "C-=" 'text-scale-increase :desc "Decrease font size" "C--" 'text-scale-decrease) #+END_SRC ** Ranger Configuration #+BEGIN_SRC emacs-lisp :tangle config.el ;;;------ ranger configuration ------;;; (map! :map ranger-mode-map :desc "Mark current file" "m" 'ranger-mark :desc "Toggle mark on current file" "x" 'ranger-toggle-mark :desc "Open ranger" "o d" 'ranger) #+END_SRC ** hledger-mode Configuration #+BEGIN_SRC emacs-lisp :tangle config.el ;;;-- hledger-mode configuration ;;;-- ;;; Basic configuration (require 'hledger-mode) ;; To open files with .journal extension in hledger-mode (add-to-list 'auto-mode-alist '("\\.journal\\'" . hledger-mode)) ;; The default journal location is too opinionated. (setq hledger-jfile (concat user-home-directory "/Org/Family.s/Notes/hledger.journal")) ;;; Auto-completion for account names ;; For company-mode users: (add-to-list 'company-backends 'hledger-company) (evil-define-key* 'normal hledger-view-mode-map "q" 'kill-current-buffer) (evil-define-key* 'normal hledger-view-mode-map "[" 'hledger-prev-report) (evil-define-key* 'normal hledger-view-mode-map "]" 'hledger-next-report) (map! :leader :prefix ("l" . "hledger") :desc "Exec hledger command" "c" 'hledger-run-command :desc "Generate hledger balancesheet" "b" 'hledger-balancesheet* :desc "Exec hledger command" "d" 'hledger-daily-report*) (map! :localleader :map hledger-mode-map :desc "Reschedule transaction at point" "d s" 'hledger-reschedule :desc "Edit amount at point" "t a" 'hledger-edit-amount) #+END_SRC ** Tab Bar Configuration I don't have this active right now since it's kinda weird with pgtk... #+BEGIN_SRC emacs-lisp ;;;-- tab-bar-mode configuration ;;;-- ;; Kbd tab navigation (map! :map evil-normal-state-map "H" #'tab-bar-switch-to-prev-tab "L" #'tab-bar-switch-to-next-tab "C-" #'tab-bar-switch-to-prev-tab "C-" #'tab-bar-switch-to-next-tab) (evil-global-set-key 'normal (kbd "C-w") 'tab-bar-close-tab) (evil-global-set-key 'normal (kbd "C-t") 'tab-bar-new-tab) (setq tab-bar-new-tab-choice "*doom*") (tab-bar-mode t) #+END_SRC ** Focus Mode Configuration #+BEGIN_SRC emacs-lisp :tangle config.el (require 'focus) (map! :leader :prefix ("F" . "Focus mode") :desc "Toggle focus mode" "t" 'focus-mode :desc "Pin focused section" "p" 'focus-pin :desc "Unpin focused section" "u" 'focus-unpin) (add-to-list 'focus-mode-to-thing '(org-mode . org-element)) (add-to-list 'focus-mode-to-thing '(python-mode . paragraph)) (add-to-list 'focus-mode-to-thing '(lisp-mode . paragraph)) ;(add-hook 'org-mode-hook #'focus-mode) #+END_SRC ** Helpful Mode Configuration #+BEGIN_SRC emacs-lisp :tangle config.el ;;;------ helpful configuration ------;;; (evil-set-initial-state 'helpful-mode 'normal) (evil-define-key 'normal helpful-mode-map "j" 'evil-next-visual-line "k" 'evil-previous-visual-line "q" 'helpful-kill-buffers) #+END_SRC ** mu4e Configuration #+BEGIN_SRC emacs-lisp :tangle config.el ;;;------ helpful configuration ------;;; (add-load-path! "~/.nix-profile/share/emacs/site-lisp/elpa/mu4e-1.10.7") (require 'mu4e) (require 'mu4e-contrib) (require 'mu4e-actions) (after! mu4e (setq mu4e-sent-folder (lambda (msg) (concat "/" (nth 1 (split-string (mu4e-message-field msg :maildir) "/" )) "/Sent"))) (setq mu4e-drafts-folder (lambda (msg) (concat "/" user-mail-address "/Drafts"))) (setq mu4e-trash-folder (lambda (msg) (concat "/" (nth 1 (split-string (mu4e-message-field msg :maildir) "/" )) "/Trash"))) (setq mu4e-refile-folder (lambda (msg) (concat "/" (nth 1 (split-string (mu4e-message-field msg :maildir) "/" )) "/Archive"))) (setq mu4e-index-lazy-check t) (setq mu4e-index-cleanup t) (define-key mu4e-main-mode-map (kbd "") #'doom/leader) (define-key mu4e-headers-mode-map (kbd "") #'doom/leader) (define-key mu4e-view-mode-map (kbd "") #'doom/leader) (define-key mu4e-main-mode-map (kbd "g g") #'evil-goto-first-line) (define-key mu4e-main-mode-map (kbd "G") #'evil-goto-line) (define-key mu4e-main-mode-map (kbd "h") #'evil-backward-char) (define-key mu4e-main-mode-map (kbd "l") #'evil-forward-char) (define-key mu4e-main-mode-map (kbd "w") #'evil-forward-word-begin) (unbind-key "g" mu4e-headers-mode-map) (define-key mu4e-headers-mode-map (kbd "g g") #'evil-goto-first-line) (define-key mu4e-headers-mode-map (kbd "G") #'evil-goto-line) (define-key mu4e-headers-mode-map (kbd "h") #'evil-backward-char) (define-key mu4e-headers-mode-map (kbd "l") #'evil-forward-char) (define-key mu4e-headers-mode-map (kbd "w") #'evil-forward-word-begin) (unbind-key "g" mu4e-view-mode-map) (define-key mu4e-view-mode-map (kbd "g g") #'evil-goto-first-line) (define-key mu4e-view-mode-map (kbd "G") #'evil-goto-line) (define-key mu4e-view-mode-map (kbd "h") #'evil-backward-char) (define-key mu4e-view-mode-map (kbd "l") #'evil-forward-char) (define-key mu4e-view-mode-map (kbd "w") #'evil-forward-word-begin) (map! :map 'mu4e-main-mode-map :desc "Jump to maildir" :ge "J" #'mu4e-search-maildir) (map! :map 'mu4e-main-mode-map :desc "Next line" :ge "j" #'evil-next-visual-line) (map! :map 'mu4e-main-mode-map :desc "Prev line" :ge "k" #'evil-previous-visual-line) (map! :map 'mu4e-headers-mode-map :desc "Jump to maildir" :ge "J" #'mu4e-search-maildir) (map! :map 'mu4e-headers-mode-map :desc "Next line" :ge "j" #'evil-next-visual-line) (map! :map 'mu4e-headers-mode-map :desc "Prev line" :ge "k" #'evil-previous-visual-line) (map! :map 'mu4e-headers-mode-map :desc "Next char" :ge "l" #'evil-forward-char) (map! :map 'mu4e-headers-mode-map :desc "Update mail and index" :ge "U" #'mu4e-update-mail-and-index) (map! :map 'mu4e-headers-mode-map :desc "Compose reply" :ge "r" #'mu4e-compose-reply) (map! :map 'mu4e-headers-mode-map :desc "Archive message" :ge "e" #'mu4e-headers-mark-for-refile) (map! :map 'mu4e-view-mode-map :desc "Jump to maildir" :ge "J" #'mu4e-search-maildir) (map! :map 'mu4e-view-mode-map :desc "Next line" :ge "j" #'evil-next-visual-line) (map! :map 'mu4e-view-mode-map :desc "Prev line" :ge "k" #'evil-previous-visual-line) (map! :map 'mu4e-view-mode-map :desc "Update mail and index" :ge "U" #'mu4e-update-mail-and-index) (map! :map 'mu4e-view-mode-map :desc "Compose reply" :ge "r" #'mu4e-compose-reply) (map! :map 'mu4e-view-mode-map :desc "Archive message" :ge "e" #'mu4e-view-mark-for-refile) (add-to-list 'mu4e-header-info-custom '(:maildir-folder-no-account . ( :name "Maildir folder without account" ;; long name, as seen in the message-view :shortname "Folder" ;; short name, as seen in the headers view :help "Name of the subfolder without the maildir" ;; tooltip :function (lambda (msg) (substring (mu4e-message-field msg :maildir) (+ 2 (length (nth 1 (split-string (mu4e-message-field msg :maildir) "/" ))))))))) (add-to-list 'mu4e-bookmarks '( :name "Unified inbox" :query "maildir://.*/INBOX/" :key ?i)) (setq mu4e-headers-fields '((:account-stripe . 1) (:account . 25) (:human-date . 12) (:flags . 6) (:from-or-to . 20) (:maildir-folder-no-account . 30) (:subject))) (add-hook 'mu4e-compose-mode-hook #'(lambda () (auto-save-mode -1))) (setq mu4e-sent-messages-behavior 'delete) (setq sendmail-program "~/.nix-profile/bin/msmtp") (setq send-mail-function 'smtpmail-send-it) (setq message-sendmail-f-is-evil t) (setq message-sendmail-extra-arguments '("--read-envelope-from")) (setq message-send-mail-function 'message-send-mail-with-sendmail) (if (file-exists-p "~/.emacs.d/mu4e-private.el") (load! "~/.emacs.d/mu4e-private.el")) ;;(setq mu4e-contexts ;; `( ;; ,(my-make-mu4e-context "example1" "user@example1.com" "user@example1.com" "John Doe" "Example Company" "John Doe\nThis is my signature" "Personal.p") ;; ,(my-make-mu4e-context "example2" "user@example1.com" "user@example2.com" "Johnny" "Example Organization" "John Doe\nThis is my other signature" "Personal.p") ;; )) ;;(mu4e-context-switch t "example1") (org-msg-mode 0) ;; https://emacs.stackexchange.com/questions/3061/how-to-stop-mu4e-from-inserting-line-breaks (defun no-auto-fill () "Turn off auto-fill-mode." (auto-fill-mode -1)) (add-hook 'mu4e-compose-mode-hook #'no-auto-fill) ) ;; TODO fix my make-mu4e-context wrapper ;;(defun my-make-mu4e-context (context-name address catch-address full-name organization-name signature org-roam-db) ;; (make-mu4e-context ;; :name context-name ;; :enter-func `(lambda () ,(mu4e-message (concat "Entering " context-name " context")) ;; (org-roam-switch-db org-roam-db t) ;; ,(setq user-mail-address address) ;; ,(setq user-full-name full-name) ;; ,(setq message-user-organization organization-name) ;; ,(setq mu4e-maildir (concat "~/.mail/" address)) ;; ,(setq mu4e-compose-signature signature) ;; ) ;; :leave-func `(lambda () ,(mu4e-message (concat "Leaving " context-name " context"))) ;; ;; we match based on the contact-fields of the message ;; :match-func `(lambda (msg) ;; (when msg ;; (mu4e-message-contact-field-matches msg ;; :to ,catch-address))))) #+END_SRC ** EAF EAF doesn't work on Wayland :( #+BEGIN_SRC emacs-lisp ;;;-- Load emacs application framework;;;-- (use-package! eaf :load-path "~/.emacs.d/eaf/" :init :custom (eaf-browser-continue-where-left-off t) (eaf-browser-enable-adblocker t) (browse-url-browser-function 'eaf-open-browser) ;; Make EAF Browser my default browser :config (defalias 'browse-web #'eaf-open-browser) (require 'eaf-browser) (require 'eaf-evil) (define-key key-translation-map (kbd "SPC") (lambda (prompt) (if (derived-mode-p 'eaf-mode) (pcase eaf--buffer-app-name ("browser" (if (string= (eaf-call-sync "eval_function" eaf--buffer-id "is_focus") "True") (kbd "SPC") (kbd eaf-evil-leader-key))) (_ (kbd "SPC"))) (kbd "SPC"))))) (setq browse-url-browser-function 'browse-url-default-browser) (map! :leader :desc "Open web browser" "o w" #'eaf-open-browser-with-history) #+END_SRC ** Direnv #+BEGIN_SRC emacs-lisp :tangle config.el ;;;-- Load emacs direnv;;;-- (require 'direnv) (direnv-mode) #+END_SRC ** Projectile #+BEGIN_SRC emacs-lisp :tangle config.el ;;;-- projectile wrapper commands ;;;-- (defun projectile-goto-project () (interactive) (projectile-switch-project t) ;;(neotree-dir (projectile-project-root)) ) (map! :leader :desc "Open project" "p p" #'projectile-goto-project) (map! :leader :desc "Projectile commander" "p @" #'projectile-commander) (map! :leader :desc "Projectile grep" "/" #'projectile-grep) #+END_SRC ** sudo-edit #+BEGIN_SRC emacs-lisp :tangle config.el ;;;-- projectile wrapper commands ;;;-- (require 'sudo-edit) (setq sudo-edit-local-method "su") (map! :leader :desc "Open current file as root" "f U" #'sudo-edit-current-file) (map! :leader :desc "Find a file and open as root" "f u" #'sudo-edit-find-file) #+END_SRC ** LSP #+BEGIN_SRC emacs-lisp :tangle config.el ;;;-- LSP stuff ;;;-- (use-package lsp-mode :ensure t) (use-package nix-mode :hook (nix-mode . lsp-deferred) :ensure t) (setq lsp-java-workspace-dir (concat user-home-directory "/.local/share/doom/java-workspace")) (require 'gdscript-mode) (use-package gdscript-mode :hook (gdscript-mode . lsp-deferred) :ensure t) (setq lsp-treemacs-deps-position-params '((side . right) (slot . 1) (window-width . 35))) (setq lsp-treemacs-symbols-position-params '((side . right) (slot . 2) (window-width . 35))) (map! :leader :desc "Open treemacs symbol outliner" "o s" #'lsp-treemacs-symbols :desc "Hide neotree" "o S" #'treemacs-quit) (setq +format-on-save-enabled-modes '(not emacs-lisp-mode sql-mode tex-mode latex-mode org-msg-edit-mode nix-mode)) #+END_SRC ** Terminal #+BEGIN_SRC emacs-lisp :tangle config.el #+END_SRC ** Elfeed #+BEGIN_SRC emacs-lisp :tangle config.el ;; I source my rss from my freshrss instance ;; I login with a private elisp file: ~/.emacs.d/freshrss-elfeed.el ;; freshrss-elfeed.el looks like this: ;;(elfeed-protocol-enable) ;;(setq elfeed-use-curl t) ;;(setq elfeed-set-timeout 36000) ;;(setq elfeed-log-level 'debug) ;;(setq freshrss-hostname "https://freshrss.example.com") ;;(setq elfeed-feeds (list ;; (list "fever+https://user@freshrss.example.com" ;; :api-url "https://user@freshrss.example.com/api/fever.php" ;; :password "mYsUpErCoMpLiCaTeDp@s$w0rD")))) ;;(setq main-elfeed-feed "https://user@freshrss.example.com/api/fever.php") (if (file-exists-p "~/.emacs.d/freshrss-elfeed.el") (load! "~/.emacs.d/freshrss-elfeed.el")) (setq elfeed-search-filter "@6-months-ago +unread") (setq browse-url-chromium-program "mpv") (setq browse-url-chrome-program "mpv") (setq browse-url-handlers '(("youtube.com" . browse-url-chrome) ("odcyn.com" . browse-url-chrome) ("odysee.com" . browse-url-chrome) ("tilvids.com" . browse-url-chrome))) (map! :leader :desc "Open elfeed" "O n" #'elfeed) (map! :map 'elfeed-search-mode-map :desc "Open url" :n "g o" #'elfeed-search-browse-url) (defun freshrss-network-connection-p () (not (condition-case nil (delete-process (make-network-process :name freshrss-hostname :host "elpa.gnu.org" :service 443)) (error t)))) (defun elfeed-full-update () (interactive) (if (freshrss-network-connection-p) (delete-directory "~/.cache/doom/elfeed" t)) (setq elfeed-db nil) (elfeed-protocol-fever-update main-elfeed-feed) (elfeed-update)) (map! :map 'elfeed-search-mode-map :desc "Update elfeed" :n "g R" #'elfeed-full-update) #+END_SRC * My init.el This section is the [[./init.el][init.el]] section, which controls which Doom modules are loaded. =SPC h d h= (vim) or =C-h d h= (non-vim) can be used to access Doom's documentation (including a "Module Index"). =K= (vim) or =C-c c k= (non-vim) can be used to view a module's documentation (this can help you discover module flags as well). =gd= (vim) or =C-c c d= (non-vim) will let you browse a module's directory (source code). #+BEGIN_SRC emacs-lisp :tangle init.el (doom! :input ;;chinese ;;japanese ;;layout ; auie,ctsrnm is the superior home row :completion company ; 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 ; 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 ; 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 +ranger) ; making dired pretty [functional] electric ; smarter, keyword-based electric-indent ibuffer ; interactive buffer management undo ; 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 ; 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 ; 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 ; C > C++ == 1 ;;clojure ; 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 +lsp) ; the language you waited for ;;(go +lsp) ; the hipster dialect (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 ; all(hope(abandon(ye(who(enter(here)))))) ;;julia ; 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 +lsp) ; I hereby declare "nix geht mehr!" ;;ocaml ; an objective camel (org +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 ; 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 ; Fe2O3.unwrap().unwrap().unwrap().unwrap() ;;scala ; java, but good ;;(scheme +guile) ; a fully conniving family of lisps sh ; 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 ; the tubes yaml ; JSON, but readable ;;zig ; C, but simpler :email (mu4e +org) ;;notmuch ;;(wanderlust +gmail) :app ;;calendar ;;emms ;;everywhere ; *leave* Emacs!? You must be joking ;;irc ; how neckbeards socialize rss ; emacs as an RSS reader ;;twitter ; twitter client https://twitter.com/vnought :config ;;literate (default +bindings +smartparens)) #+END_SRC * My packages.el The [[./packages.el][packages.el]] file allows extra packages to be configured outside of the typical Doom modules from [[./init.el][init.el]]. Packages are declared via =(package! some-package)= where =some-package= is from MELPA, ELPA, or emacsmirror. There are other ways to install packages outside of Emacs package archives, including directly from git. Installing a package directly from git requires a =:recipe=. Here is [[https://github.com/raxod502/straight.el#the-recipe-format][a full documentation of the recipe format]]. Doom's built-in packages can also be modified here: - =(package! builtin-package :disable t)= to disable - =(package! builtin-package-2 :recipe (:repo "myfork/package"))= to override the recipe - Side-note: the full recipe for built-in packages does not need specification, as the override will inherit the unspecified properties directly from Doom Any git package can be configured for a particular commit or branch: - =(package! builtin-package :recipe (:branch "develop")= for a particular branch - =(package! builtin-package :pin "1a2b3c4d5e")= for a particular commit - =(unpin! pinned-package another-pinned-package)= to get bleeding edge instead of Doom's stability #+BEGIN_SRC emacs-lisp :tangle packages.el (package! embark :pin "0908eea") (package! dashboard) (package! direnv) (package! org-modern) (package! org-super-agenda) (package! emacsql :pin "c1a4407") (package! org-roam-ui) (package! org-transclusion) (package! org-download) (package! org-yt) (package! toc-org) (package! lister) (package! all-the-icons-dired) (package! all-the-icons-completion) (package! ox-reveal) (package! magit-todos) (package! hledger-mode) (package! rainbow-mode) (package! crdt) (package! ess) (package! openwith) (package! ob-mermaid) (package! focus) (package! olivetti) (package! async) (package! centered-cursor-mode) (package! elfeed) (package! elfeed-protocol) (package! docker-tramp :disable t) (package! org-ql) (package! persist) (package! sudo-edit) #+END_SRC * Nix Integration In order to have Nix load my Doom Emacs configuration [[./doom.nix][doom.nix]], which I source in the =imports= block of my [[../../../profiles/work/home.nix][home.nix]]. #+BEGIN_SRC nix :tangle doom.nix { config, lib, pkgs, userSettings, systemSettings, eaf, eaf-browser, org-nursery, org-yaap, org-side-tree, org-timeblock, phscroll, ... }: let themePolarity = lib.removeSuffix "\n" (builtins.readFile (./. + "../../../../themes"+("/"+userSettings.theme)+"/polarity.txt")); dashboardLogo = ./. + "/nix-" + themePolarity + ".png"; in { programs.doom-emacs = { enable = true; emacsPackage = pkgs.emacs29-pgtk; doomPrivateDir = ./.; # This block from https://github.com/znewman01/dotfiles/blob/be9f3a24c517a4ff345f213bf1cf7633713c9278/emacs/default.nix#L12-L34 # Only init/packages so we only rebuild when those change. doomPackageDir = let filteredPath = builtins.path { path = ./.; name = "doom-private-dir-filtered"; filter = path: type: builtins.elem (baseNameOf path) [ "init.el" "packages.el" ]; }; in pkgs.linkFarm "doom-packages-dir" [ { name = "init.el"; path = "${filteredPath}/init.el"; } { name = "packages.el"; path = "${filteredPath}/packages.el"; } { name = "config.el"; path = pkgs.emptyFile; } ]; # End block }; home.file.".emacs.d/themes/doom-stylix-theme.el".source = config.lib.stylix.colors { template = builtins.readFile ./themes/doom-stylix-theme.el.mustache; extension = ".el"; }; home.packages = with pkgs; [ nil nixfmt git file nodejs wmctrl jshon aria hledger hunspell hunspellDicts.en_US-large pandoc nodePackages.mermaid-cli (pkgs.mu.override { emacs = emacs29-pgtk; }) emacsPackages.mu4e isync msmtp (python3.withPackages (p: with p; [ pandas requests pyqt6 sip qtpy qt6.qtwebengine epc lxml pyqt6-webengine pysocks pymupdf markdown ])) ]; nixpkgs.overlays = [ (self: super: { mu = super.mu.overrideAttrs (oldAttrs: rec { pname = "mu"; version = "1.10.7"; src = super.fetchFromGitHub { owner = "djcb"; repo = "mu"; rev = "v1.10.7"; hash = "sha256-x1TsyTOK5U6/Y3QInm+XQ7T32X49iwa+4UnaHdiyqCI="; }; }); } ) ]; services.mbsync = { enable = true; package = pkgs.isync; frequency = "*:0/5"; }; home.file.".emacs.d/eaf" = { source = "${eaf}"; recursive = true; }; home.file.".emacs.d/org-yaap" = { source = "${org-yaap}"; recursive = true; }; home.file.".emacs.d/org-side-tree" = { source = "${org-side-tree}"; recursive = true; }; home.file.".emacs.d/org-timeblock" = { source = "${org-timeblock}"; recursive = true; }; home.file.".emacs.d/eaf/app/browser" = { source = "${eaf-browser}"; recursive = true; onChange = " pushd ~/.emacs.d/eaf/app/browser; rm package*.json; npm install darkreader @mozilla/readability && rm package*.json; popd; "; }; home.file.".emacs.d/org-nursery" = { source = "${org-nursery}"; }; home.file.".emacs.d/dashboard-logo.png".source = dashboardLogo; home.file.".emacs.d/scripts/copy-link-or-file/copy-link-or-file-to-clipboard.sh" = { source = ./scripts/copy-link-or-file/copy-link-or-file-to-clipboard.sh; executable = true; }; home.file.".emacs.d/phscroll" = { source = "${phscroll}"; }; home.file.".emacs.d/system-vars.el".text = '' ;;; ~/.emacs.d/config.el -*- lexical-binding: t; -*- ;; Import relevant variables from flake into emacs (setq user-full-name "''+userSettings.name+''") ; name (setq user-username "''+userSettings.username+''") ; username (setq user-mail-address "''+userSettings.email+''") ; email (setq user-home-directory "/home/''+userSettings.username+''") ; absolute path to home directory as string (setq user-default-roam-dir "''+userSettings.defaultRoamDir+''") ; absolute path to home directory as string (setq system-nix-profile "''+systemSettings.profile+''") ; what profile am I using? (setq system-wm-type "''+userSettings.wmType+''") ; wayland or x11? (setq doom-font (font-spec :family "''+userSettings.font+''" :size 20)) ; import font (setq dotfiles-dir "''+userSettings.dotfilesDir+''") ; import location of dotfiles directory ''; } #+END_SRC