“I’m rarely happier than when spending an entire day programming my computer to perform automatically a task that would otherwise take me a good ten seconds to do by hand.” - Douglas Adams
This is the .doom.d
submodule of neurosys, my computing environment.
I use Emacs as the primary interface to my machine and remote machines. In many situations, it replaces CLIs or GUIs with well-designed keyboard-driven interfaces (e.g. magit). There’s no going back.
I use Doom Emacs as a base Emacs configuration. This is a literate org file, which specifies and documents the entirety of my Doom configuration. If you link this file to ~/.doom.d/config.org
, Doom will automatically tangle it on startup and whenever it changes.
If you’re reading this in a browser, consider opening it in Emacs Org mode for the full experience.
- Jethro Kuan’s dotfiles
- bauer: an Emacs+Nix IDE
- Pierre Neidhardt: Emacs Everywhere
- Ryan Rix’s Complete Computing Environment (CCE)
- LemonBreezes’ Literate Doom Config
- Diego Zamboni’s Literate Emacs Config
- Justin Abrahms’ Literate Emacs Config
- About
- Doom Module Declarations
- Package Configuration
- Header
- Global Constants
- Load helper functions
- Visual Settings
- Key Chord Config
- Hardware Settings
- Org
- Remote Machine Interfaces
- Effective Editing
- Haskell
- Rust
- Jupyter
- Selectrum etc…
- Dired
- Search Utilities
- Version Control
- Searching + Annotating PDFs
- Lauching External Programs
- Window Management
- Autosave
- Logview
- Better Expansions with Fancy Dabbrev
- Registers
- Load Untracked Elisp (work-specific)
- Misc Global Keybindings
- Avoid Long-line Performance Hit
- Misc
- Utility functions.
- Neurosys Module
- Package declarations
- Future
This file controls what Doom modules are enabled and what order they load in.
Remember to run doom sync
or doom/reload
after modifying it.
;;; init.el -*- lexical-binding: t; -*-
(doom! :input
:personal
neurosys
:completion
(company +childframe)
:ui
doom
hl-todo
modeline
nav-flash
zen
:editor
lispy
multiple-cursors
word-wrap
format
snippets
:emacs
;; dired
electric
vc
:term
vterm
:checkers
syntax
:tools
(eval +overlay)
direnv
docker
lookup
(magit +forge)
lsp
pass
pdf
tree-sitter
:lang
;; cc
common-lisp
data
emacs-lisp
go
;; javascript
(haskell +dante)
;; (julia +lsp)
;; julia
(latex +latexmk +cdlatex)
markdown
nix
(org +hugo
+jupyter
+roam2)
python
(rust +lsp)
sh
yaml
:config
literate
(default +bindings))
lexical-binding
for this file.
;;; $DOOMDIR/config.el -*- lexical-binding: t; -*-
Some functionality uses this to identify you, e.g. GPG configuration, email clients, file templates and snippets.
(setq user-full-name "Dan Girshovich"
user-mail-address (rot13 "[email protected]"))
(setq my/home-dir "/home/dan/")
(setq my/sync-base-dir (concat my/home-dir "Sync/"))
(setq my/work-base-dir (concat my/home-dir "Work/"))
(setq my/media-base-dir (concat my/home-dir "Media/"))
(setq org-directory my/sync-base-dir
org-roam-directory "/home/dan/Sync/org-roam2/"
org-roam-db-location (concat org-roam-directory "org-roam.db")
my/org-roam-todo-file (concat org-roam-directory "orgzly/todo.org"))
(save-window-excursion
(find-file my/org-roam-todo-file)
(save-buffer))
(load-file (concat doom-private-dir "funcs.el"))
(setq
doom-font (font-spec :family "Iosevka" :size 28)
doom-variable-pitch-font (font-spec :family "Libre Baskerville")
doom-serif-font (font-spec :family "Libre Baskerville"))
(setq display-line-numbers-type nil)
;; Thin grey line separating windows
(set-face-background 'vertical-border "grey")
(set-face-foreground 'vertical-border (face-background 'vertical-border))
(use-package! doom-themes
:config
;; Global settings (defaults)
(setq doom-themes-enable-bold t ; if nil, bold is universally disabled
doom-themes-enable-italic t) ; if nil, italics is universally disabled
;; (load-theme 'doom-vibrant t)
;; (load-theme 'leuven t)
;; (load-theme 'doom-dark+ t)
;; (load-theme 'doom-solarized-light t)
(load-theme 'doom-one t)
;; (load-theme 'doom-one-light t)
;; (load-theme 'doom-nord-light t)
;; Enable flashing mode-line on errors
(doom-themes-visual-bell-config)
;; Corrects (and improves) org-mode's native fontification.
(doom-themes-org-config))
;; Waiting on https://github.com/hlissner/emacs-doom-themes/issues/252
;; Currently, some things like italics and some links in org fail to render correctly.
;; (use-package! poet-theme
;; :config
;; (load-theme 'poet))
;; (use-package! almost-mono-themes
;; :config
;; ;; (load-theme 'almost-mono-black t)
;; (load-theme 'almost-mono-white t))
I don’t use Evil (Vim emulation), which would add an extra layer of complexity to everything. Instead, I heavily leverage key-chord.el, which enables binding simultaneous key presses (chords) to commands.
I have some custom code to bind chords to Doom’s leaders. Many commonly used commands are bound in these “key chord maps”.
Set hardware-specific delay. Tweak this if:
- there are false keychords triggered when typing fast (delay too large)
- if expected keychords don’t register (delay too small)
- there’s a noticable lag when typing normally (delay too large)
(use-package! key-chord
:config
(key-chord-mode 1)
(setq key-chord-one-key-delay 0.20 ; same key (e.g. xx)
key-chord-two-keys-delay 0.075))
(defun simulate-seq (seq)
(setq unread-command-events (listify-key-sequence seq)))
(defun send-doom-leader ()
(interactive)
(simulate-seq "\C-c"))
(setq doom-localleader-alt-key "M-c")
(defun send-doom-local-leader ()
(interactive)
(simulate-seq "\M-c"))
One of my proudest moments.... https://gist.github.com/dangirsh/86c001351c02b42321d20f462a66da6b
(after! key-chord
(key-chord-define-global "fj" 'send-doom-leader)
(key-chord-define-global "gh" 'send-doom-local-leader)
(setq dk-keymap (make-sparse-keymap))
(setq sl-keymap (make-sparse-keymap))
(key-chord-define-global "dk" dk-keymap)
(key-chord-define-global "sl" sl-keymap)
(defun add-to-keymap (keymap bindings)
(dolist (binding bindings)
(define-key keymap (kbd (car binding)) (cdr binding))))
(defun add-to-dk-keymap (bindings)
(add-to-keymap dk-keymap bindings))
(defun add-to-sl-keymap (bindings)
(add-to-keymap sl-keymap bindings))
(add-to-dk-keymap
'(("." . jump-to-register)
("/" . org-recoll-search)
("<SPC>" . rgrep)
("a" . my/org-agenda)
("b" . my/set-brightness)
("c" . my/open-literate-private-config-file)
("d" . dired-jump)
("k" . doom/kill-this-buffer-in-all-windows)
("m" . my/mathpix-screenshot-to-clipboard)
("n" . narrow-or-widen-dwim)
("o" . ibuffer)
("p" . my/publish-dangirsh.org)
("r" . my/set-redshift)
("s" . save-buffer)
("t" . +vterm/here)
("T" . google-translate-at-point)
("v" . neurosys/open-config-file)
("w" . google-this-noconfirm)
("x" . sp-splice-sexp)))
(key-chord-define-global ",." 'end-of-buffer)
;; FIXME: accidentally triggered too often
(key-chord-define-global "zx" 'beginning-of-buffer)
(key-chord-define-global "qw" 'delete-window)
(key-chord-define-global "qp" 'delete-other-windows)
(key-chord-define-global ",," 'doom/open-scratch-buffer)
(key-chord-define-global "fk" 'other-window)
(key-chord-define-global "jd" 'rev-other-window)
;; (key-chord-define-global "hh" 'helpful-at-point)
(key-chord-define-global "hk" 'helpful-key)
(key-chord-define-global "hv" 'helpful-variable)
;; no bueno: e.g. "pathfinder", "highfidelity"
;; (key-chord-define-global "hf" 'helpful-function)
(key-chord-define-global "vn" 'split-window-vertically-and-switch)
(key-chord-define-global "vm" 'split-window-vertically-and-switch) ; ergodox
(key-chord-define-global "hj" 'split-window-horizontally-and-switch)
(key-chord-define-global "jm" 'my/duplicate-line-or-region)
(key-chord-define-global "fv" 'comment-line)
(key-chord-define-global "kl" 'er/expand-region)
(key-chord-define-global "xx" 'execute-extended-command)
(key-chord-define-global "xf" 'ffap)
(key-chord-define-global "jp" 'my/insert-jupyter-python-block))
Sets caps to control and sets a snappy key repeat / delay.
xset r rate <delay> <rate>
(defun fix-keyboard ()
(interactive)
(shell-command "setxkbmap -option 'ctrl:nocaps'")
(shell-command "xset r rate 160 100"))
Occassionally, the touchpad gets triggered accidentally while typing. This is a quick way to disable/enable it.
(defun toggle-touchpad ()
(interactive)
(shell-command "/home/dan/my-config/scripts/toggle_trackpad.sh"))
Set brightness by writing directly to system brightness file.
(setq my/brightness-min 1)
(setq my/brightness-max 100)
(setq my/brightness-step 5)
(defun my/get-brightness ()
(* my/brightness-step (round (string-to-number
(shell-command-to-string "xbacklight -get"))
my/brightness-step)))
(defun my/set-brightness (level)
(interactive "nBrightness level: ")
(let ((safe-level
(cond ((< level my/brightness-min) my/brightness-min)
((> level my/brightness-max) my/brightness-max)
(t level))))
(save-window-excursion
(shell-command
(format "xbacklight -set %s &" safe-level) nil nil))))
(defun my/brightness-step-change (delta)
(my/set-brightness (+ delta (my/get-brightness))))
(defun my/brightness-increase ()
(interactive)
(my/brightness-step-change my/brightness-step))
(defun my/brightness-decrease ()
(interactive)
(my/brightness-step-change (- my/brightness-step)))
(map! "<XF86MonBrightnessDown>" 'my/brightness-decrease)
(map! "<XF86MonBrightnessUp>" 'my/brightness-increase)
(defun my/set-brightness-lg-5k (level)
(interactive "nBrightness level: ")
(save-window-excursion
(shell-command
(format "echo \"0i%s\n\" | sudo /home/dan/repos/LG-ultrafine-brightness/build/LG_ultrafine_brightness" level) nil nil)))
(setq my/redshift-min 500)
(setq my/redshift-max 6000)
(setq my/redshift-step 250)
;; Since get-redshift is slow
(setq my/redshift-val-cache nil)
;; (defun my/query-redshift ()
;; (string-to-number (save-window-excursion
;; (with-temp-buffer
;; (insert (shell-command-to-string "redshift -p"))
;; (beginning-of-buffer)
;; (re-search-forward "Color temperature")
;; (forward-char)
;; (forward-char)
;; (set-mark-command nil)
;; (re-search-forward "K")
;; (backward-char)
;; (buffer-substring (mark) (point))))))
;; (defun my/get-redshift-cache ()
;; (if my/redshift-val-cache
;; my/redshift-val-cache
;; (let ((val (my/query-redshift)))
;; (setq my/redshift-val-cache val)
;; val)))
;; (defun my/get-redshift ()
;; (* my/redshift-step (round (my/get-redshift-cache)
;; my/redshift-step)))
(defun my/set-redshift (redness brightness-percent)
(interactive "nRedshift level: \nnBrightess percent: ")
(let* ((safe-redness
(cond ((< redness my/redshift-min) my/redshift-min)
((> redness my/redshift-max) my/redshift-max)
(t redness)))
(safe-brightness-percent
(cond ((< brightness-percent 10) 10)
((> brightness-percent 100) 100)
(t brightness-percent)))
(redshift-command (format "redshift -P -O %s -b %s" safe-redness (/ safe-brightness-percent 100.0))))
(message redshift-command)
(save-window-excursion
(shell-command redshift-command nil nil))))
;; (defun my/redshift-step-change (delta)
;; (let ((new-val (+ delta (my/get-redshift-cache))))
;; (my/set-redshift new-val)
;; (setq my/redshift-val-cache new-val)))
;; (defun my/redshift-increase ()
;; (interactive)
;; (my/redshift-step-change my/redshift-step))
;; (defun my/redshift-decrease ()
;; (interactive)
;; (my/redshift-step-change (- my/redshift-step)))
;; (map! "S-<f5>" 'my/redshift-decrease)
;; (map! "S-<f6>" 'my/redshift-increase)
(setq my/volume-min 1)
(setq my/volume-max 100)
(setq my/volume-step 5)
(defun my/get-volume ()
(* my/volume-step (round (string-to-number
(shell-command-to-string "awk -F\"[][]\" '/dB/ { print $2 }' <(amixer sget Master)"))
my/volume-step)))
(defun my/set-volume (level)
(interactive "nVolume level: ")
(let ((clipped-level
(cond ((< level my/volume-min) my/volume-min)
((> level my/volume-max) my/volume-max)
(t level))))
(save-window-excursion
(shell-command
(format "amixer set Master %s%% &" clipped-level) nil nil))))
(defun my/volume-step-change (delta)
(my/set-volume (+ delta (my/get-volume))))
(defun my/volume-increase ()
(interactive)
(my/volume-step-change my/volume-step))
(defun my/volume-decrease ()
(interactive)
(my/volume-step-change (- my/volume-step)))
(map! "<XF86AudioRaiseVolume>" 'my/volume-increase)
(map! "<XF86AudioLowerVolume>" 'my/volume-decrease)
(defun my/connect-to-bose-700s ()
(interactive)
(shell-command "bluetoothctl -- connect 4C:87:5D:27:B8:63")
(shell-command "pacmd set-card-profile 3 headset_head_unit"))
(defun my/disconnect-to-bose-700s ()
(interactive)
(shell-command "bluetoothctl -- disconnect 4C:87:5D:27:B8:63"))
(defun my/connect-to-pixel-buds ()
(interactive)
(shell-command "bluetoothctl -- connect E4:5E:1B:C8:B2:9F"))
(defun my/disconnect-to-pixel-buds ()
(interactive)
(shell-command "bluetoothctl -- disconnect E4:5E:1B:C8:B2:9F"))
“Notes aren’t a record of my thinking process. They are my thinking process.” – Richard Feynman
I largely live inside Org. It currently manages:
- My second brain with org-roam & org-journal
- literate programming with babel and emacs-jupyter (e.g. this file)
- tasks + calendar with org-agenda and calfw
- Writing / blogging with ox-hugo, pandoc, etc…
- Has nice inline rendering of LaTeX
- Managing references + pdfs with org-ref
- Annotating PDFs with notes via org-noter
(use-package! org
:mode ("\\.org\\'" . org-mode)
:init
(add-hook 'org-src-mode-hook #'(lambda () (flycheck-mode 0)))
(add-hook 'org-mode-hook #'(lambda () (flycheck-mode 0)))
(map! :map org-mode-map
"M-n" #'outline-next-visible-heading
"M-p" #'outline-previous-visible-heading
"C-c ;" nil)
(setq org-src-window-setup 'current-window
org-return-follows-link t
org-confirm-elisp-link-function nil
org-confirm-shell-link-function nil
org-use-speed-commands t
org-catch-invisible-edits 'show
;; Use with consel-org-goto (gh .)
org-goto-interface 'outline-path-completion)
(setq org-file-apps '((auto-mode . emacs)
(directory . emacs)
("\\.mm\\'" . default)
("\\.x?html?\\'" . default)
("\\.pdf\\'" . (lambda (file link) (org-pdftools-open link))))))
(after! org
;; FIXME: Don't know why this isn't loaded automatically...
(require 'ob-async)
;; Clear Doom's default templates
(setq org-capture-templates '())
(add-to-list 'org-capture-templates `("l" "Listen" entry (file ,(concat org-directory "org-roam2/orgzly/listen.org"))
"* TODO %?\n%i"))
(add-to-list 'org-capture-templates `("i" "Incoming" entry (file ,(concat org-directory "org-roam2/orgzly/incoming.org"))
"* %?\n%i"))
;; (add-to-list 'org-latex-packages-alist "\\usepackage{braket}")
;; http://kitchingroup.cheme.cmu.edu/blog/2015/01/04/Redirecting-stderr-in-org-mode-shell-blocks/
;; NOTE: This will affect (break) tangled output. Use directly on top of code blocks when needed instead.
;; TODO: Figure out how to keep this without adding it to tangled output.
;; (setq org-babel-default-header-args:sh
;; '((:prologue . "exec 2>&1") (:epilogue . ":")))
(setq org-babel-default-header-args:jupyter-julia '((:kernel . "julia-1.6")
(:display . "text/plain")
(:async . "yes")))
(setq org-confirm-babel-evaluate nil
org-use-property-inheritance t
org-export-use-babel nil
org-pretty-entities nil
org-use-speed-commands t
org-return-follows-link t
org-outline-path-complete-in-steps nil
org-ellipsis ""
org-fontify-whole-heading-line t
org-fontify-done-headline t
org-fontify-quote-and-verse-blocks t
org-image-actual-width nil
org-src-fontify-natively t
org-src-tab-acts-natively t
org-startup-indented t
org-src-preserve-indentation t
org-edit-src-content-indentation 0
org-adapt-indentation nil
org-hide-emphasis-markers t
org-special-ctrl-a/e t
org-special-ctrl-k t
org-yank-adjusted-subtrees t
org-src-window-setup 'reorganize-frame
org-src-ask-before-returning-to-edit-buffer nil
org-insert-heading-respect-content nil)
;; (add-hook 'org-babel-after-execute-hook 'org-display-inline-images 'append)
;; (add-hook 'org-babel-after-execute-hook 'org-toggle-latex-fragment 'append)
(add-to-list 'org-structure-template-alist '("el" . "src emacs-lisp"))
(add-to-list 'org-structure-template-alist '("sh" . "src sh"))
(add-to-list 'org-structure-template-alist '("jl" . "src jupyter-julia"))
(add-to-list 'org-structure-template-alist '("r" . "src rust"))
(add-to-list 'org-structure-template-alist '("py" . "src jupyter-python"))
(setq org-refile-use-outline-path 'file
org-outline-path-complete-in-steps nil
org-refile-allow-creating-parent-nodes 'confirm)
;; (setq org-format-latex-options
;; (quote (:foreground default
;; :background default
;; :scale 2.0
;; :matchers ("begin" "$1" "$" "$$" "\\(" "\\["))))
;; Colorize org babel output. Without this color codes are left in the output.
(defun my/display-ansi-colors ()
(interactive)
(let ((inhibit-read-only t))
(ansi-color-apply-on-region (point-min) (point-max))))
(add-hook 'org-babel-after-execute-hook #'my/display-ansi-colors)
(advice-add 'org-meta-return :override #'my/org-meta-return)
(setq org-tags-match-list-sublevels 'indented)
(setq org-image-actual-width nil)
(setq org-agenda-files '())
(setq org-todo-keywords
'((sequence
"TODO(t)"
"WAIT(w)"
"HOLD(h)"
"IDEA(i)"
"DELEGATED(e)"
"|"
"DONE(d)"
"KILL(k)")
)
org-todo-keyword-faces
'(("WAIT" . +org-todo-onhold)
("HOLD" . +org-todo-onhold)
("DELEGATED" . +org-todo-onhold)
("KILL" . +org-todo-cancel)))
;; Update parent TODO state when all children TODOs are done
;; NOTE: Only works if the parent has a "[/]" or "[%]" in the heading!!
;; https://orgmode.org/manual/Breaking-Down-Tasks.html#Breaking-Down-Tasks
(defun org-summary-todo (n-done n-not-done)
"Switch entry to DONE when all subentries are done, to TODO otherwise."
(let (org-log-done org-log-states) ; turn off logging
(org-todo (if (= n-not-done 0) "DONE" "TODO"))))
(add-hook 'org-after-todo-statistics-hook 'org-summary-todo)
;; (add-to-list 'org-agenda-files "~/Sync/org-roam/orgzly/boox-incoming.org")
(add-to-list 'org-agenda-files "~/Sync/org-roam2/orgzly/pixel-incoming.org")
(add-to-list 'org-agenda-files "~/Sync/org-roam2/orgzly/incoming.org")
(add-to-list 'org-latex-default-packages-alist "\\PassOptionsToPackage{hyphens}{url}")
(require 'ox-latex))
;; Setup syntax highlighting for code block pdf exports
(after! ox-latex
(setq org-latex-pdf-process
'("pdflatex -shell-escape -interaction nonstopmode -output-directory %o %f")
org-latex-listings 'minted
org-latex-packages-alist '(("" "minted"))))
(use-package! toc-org
:hook (org-mode . toc-org-mode))
(use-package! org-noter
:after org
:config
;; helpful in EXWM, where there are no frames
(customize-set-variable 'org-noter-always-create-frame t)
(customize-set-variable 'org-noter-notes-window-behavior '(start))
(customize-set-variable 'org-noter-notes-window-location 'horizontal-split)
(setq org-noter-notes-window-location 'other-frame
org-noter-notes-search-path '("~/Sync")
org-noter-auto-save-last-location t
org-noter-default-notes-file-names '("~/Sync/pdf_notes.org"))
;; This works for assigning PDF paths, but then breaks when trying to find the tpath later.
;; (defadvice! better-org-noter--get-or-read-document-property (orig-fn &rest args)
;; :around 'org-noter--get-or-read-document-property
;; (let ((default-directory (if (boundp 'my/noter-default-directory)
;; my/noter-default-directory
;; default-directory) ))
;; (apply orig-fn args)))
)
;; Note that this pulls in Helm :/
;; https://github.com/jkitchin/org-ref/issues/202
(use-package! org-ref
:after (org bibtex)
:init
(setq org-ref-default-bibliography '("~/Sync/references.bib"))
(setq bibtex-completion-bibliography org-ref-default-bibliography)
:config
(setq org-latex-pdf-process
'("pdflatex -shell-escape -interaction nonstopmode -output-directory %o %f"
"bibtex %b"
"pdflatex -shell-escape -interaction nonstopmode -output-directory %o %f"
"pdflatex -shell-escape -interaction nonstopmode -output-directory %o %f")
org-ref-bibliography-notes "~/Sync/pdf_notes.org"
org-ref-pdf-directory "~/Sync/pdf/"
org-ref-notes-function #'org-ref-notes-function-one-file)
(defun get-pdf-filename (key)
(let ((results (bibtex-completion-find-pdf key)))
(if (equal 0 (length results))
(org-ref-get-pdf-filename key)
(car results))))
(add-hook 'org-ref-create-notes-hook
(lambda ()
(org-entry-put
nil
"NOTER_DOCUMENT"
(get-pdf-filename (org-entry-get
(point) "Custom_ID")))) )
(defun my/org-ref-noter-at-point ()
(interactive)
(let* ((results (org-ref-get-bibtex-key-and-file))
(key (car results))
(pdf-file (funcall org-ref-get-pdf-filename-function key))
(orig-bibtex-dialect bibtex-dialect))
(if (file-exists-p pdf-file)
(save-window-excursion
;; using the local flag for bibtex-set-dialect doesn't work
;; likely because org-ref-open-notes-at-point loses the buffer context
(bibtex-set-dialect 'BibTeX)
(org-ref-open-notes-at-point)
(bibtex-set-dialect orig-bibtex-dialect)
(find-file-other-window pdf-file)
(org-noter))
(message "no pdf found for %s" key))))
(map! :leader
:map org-mode-map
:desc "org-noter from ref"
"n p" 'my/org-ref-noter-at-point))
aka my exocortex
(defun my/org-roam-capture-new-node-hook ()
(org-entry-put (point) "header-args" ":noweb yes"))
(after! org-roam
(setq +org-roam-open-buffer-on-find-file nil
org-id-link-to-org-use-id t
org-roam-mode-section-functions (list #'org-roam-backlinks-section
#'org-roam-reflinks-section
#'org-roam-unlinked-references-section))
(add-hook 'org-roam-capture-new-node-hook 'my/org-roam-capture-new-node-hook))
(after! org-roam-dailies
(setq org-roam-dailies-directory "daily/")
(setq org-roam-dailies-capture-templates
'(("d" "default" entry
"* %?"
:if-new (file+head "%<%Y-%m-%d>.org"
"#+TITLE: %<%Y-%m-%d>\n#+FILETAGS: daily")))))
(add-to-dk-keymap
'(("J" . org-roam-dailies-goto-today)))
;; leader-n-r-d-t also works, but this muscle-memory from the org-journal days is easier to type
(map! :leader
(:prefix-map ("n" . "notes")
(:prefix ("j" . "journal")
:desc "Today" "j" #'my/today)))
(use-package! websocket
:after org-roam)
(use-package! org-roam-ui
:after org-roam
:config
(setq org-roam-ui-sync-theme t
org-roam-ui-follow t
org-roam-ui-update-on-save t
org-roam-ui-open-on-start t))
https://org-roam.discourse.group/t/using-consult-ripgrep-with-org-roam-for-searching-notes/1226
(defun my/org-dir-search (dir)
"Search an org directory using consult-ripgrep. With live-preview."
(let ((consult-ripgrep-command "rg --null --ignore-case --type org --line-buffered --color=always --max-columns=1000 --no-heading --line-number . -e ARG OPTS"))
(consult-ripgrep dir)))
(map! "<f8>" #'(lambda () (interactive) (my/org-dir-search "/home/dan/Sync/org-roam-old")))
In real Roam, TODO tags can be conveniently interspersed in any file. Then, filtering backlinks on the TODO page is the agenda view.
Unfortunately, this workflow doesn’t work for org-roam, since org-agenda is implemented too ineffeciently to handle thousands of agenda files.
My fix, as recommended here, is to put capture todos to a single file, but auto-insert links back to the context of the todo. Then, any TODOs for a page should be visible in the backlinks of that page. This is an inversion of the setup available in Roam.
Jethro mentions a better solution potentially coming soon (org-roam-agenda )at the bottom of this post.
The org-capture-templates
templates used here:
Template | Doc |
---|---|
%? | Initial cursor position |
%F | File path of original buffer |
%i | Body |
%a | Link back to context |
(after! org
(add-to-list 'org-agenda-files my/org-roam-todo-file)
(add-to-list 'org-capture-templates '("t" "Todo" entry (file my/org-roam-todo-file)
"* TODO %?"))
(add-to-list 'org-capture-templates '("T" "Todo with Context" entry (file my/org-roam-todo-file)
"* TODO %? #[[%F][%(my/org-get-title \"%F\")]]\n%i\n%a"))
)
(use-package! org-download
:config
;; take an image that is already on the clipboard
(customize-set-variable 'org-download-screenshot-method "xclip -selection clipboard -t image/png -o > %s"))
Automatically pulls the titles from pages from a URL, then inserts a corresponding org-link.
(use-package! org-cliplink)
(defun my/org-insert-image ()
"Select and insert an image at point."
(interactive)
(let* ((file-name (format "%s.png" (cl-random (expt 2 31))))
(path (format "%s%s/%s" org-directory "images" file-name)))
(let ((maim-exit (call-process "maim" nil nil nil "-s" path)))
(when (= maim-exit 0)
(insert (format "[[%s]]" path))))))
(setq org-agenda-start-day "+0d" ; start today
org-agenda-show-current-time-in-grid nil
org-agenda-timegrid-use-ampm t
org-agenda-use-time-grid nil ; Toggle it with 'G' in agenda view
org-agenda-span 3
org-agenda-skip-timestamp-if-done t
org-agenda-skip-deadline-if-done t
org-agenda-overriding-header "⚡ Agenda"
org-agenda-prefix-format '((agenda . " %i %-12:c%?-12t% s")
(todo . " %i %b")
(tags . " %i %-12:c %b")
(search . " %i %-12:c %b"))
org-agenda-category-icon-alist
`(("Personal" ,(list (all-the-icons-material "home" :height 1.2)) nil nil :ascent center)
("Incoming" ,(list (all-the-icons-material "move_to_inbox" :height 1.2)) nil nil :ascent center))
org-agenda-todo-keyword-format "%-1s"
org-agenda-scheduled-leaders '("" "")
org-agenda-deadline-leaders '("Deadline: " "In %3d d.: " "%2d d. ago: "))
(defun my/org-agenda ()
(interactive)
(org-agenda nil "n"))
(use-package! org-super-agenda
:after org-agenda
:config
(setq org-super-agenda-groups
'((:discard (:todo "HOLD" :todo "IDEA"))
(:name "WIP"
:todo "[-]")
(:name "High Priority"
:priority "A")
(:name "Med Priority"
:priority "B")
(:name "Low Priority"
:priority "C")
(:name "Today"
;; :time-grid t
:scheduled today
:deadline today)
(:auto-todo t)))
(org-super-agenda-mode))
(after! tramp
(add-to-list 'tramp-remote-path 'tramp-own-remote-path)
(setq tramp-use-scp-direct-remote-copying t)
(customize-set-variable 'tramp-default-method "scp"))
(setq password-cache-expiry nil)
(defun teleport-tramp-add-method ()
"Add teleport tramp method."
;; For debugging remove the old method
(setf tramp-methods (assoc-delete-all "tsh" tramp-methods))
(add-to-list 'tramp-methods `("tsh"
(tramp-login-program "tsh ssh")
(tramp-login-args
(("-l" "%u")
("%h")))
(tramp-copy-program "tsh")
(tramp-copy-args (("scp")))
(tramp-copy-recursive t)
(tramp-remote-shell "/bin/sh")
(tramp-remote-shell-args ("-i" "-c")))))
;;;###autoload
(eval-after-load 'tramp
'(progn
(teleport-tramp-add-method)))
To eventually make everything else in this project obsolete…
dangirsh/openai-api.el · GitHub
(use-package! openai-api
:config
(setq openai-api-secret-key (password-store-get (rot13 "bcranv/[email protected]/pbqrk-ncv-xrl")))
(setq openai-api-engine "text-davinci-001")
;; (setq openai-api-engine "davinci")
(setq openai-api-completion-params '((max_tokens . 100)
(temperature . 0.3)
(frequency_penalty . 0.1)
(presence_penalty . 0.1)
(n . 6)))
(defun my/openai-complete-region ()
(interactive)
(let ((selectrum-max-window-height nil)
(selectrum-fix-vertical-window-height nil))
(openai-api-consult-complete-region)))
(add-to-dk-keymap
'(("TAB" . my/openai-complete-region))))
(require 'openai-api)
(use-package! copilot)
FIXME: This pulls in ivy/swiper/counsel :/
(use-package! lispy
:config
(advice-add 'delete-selection-pre-hook :around 'lispy--delsel-advice)
;; FIXME: magit-blame still fails to all "ret" when lispy is on
;; the compat code isn't even getting hit!
(setq lispy-compat '(edebug magit-blame-mode))
;; this hook leaves lispy mode off, but that's not as bad as breaking blame!
(add-hook 'magit-blame-mode-hook #'(lambda () (lispy-mode 0)))
:hook
((emacs-lisp-mode common-lisp-mode lisp-mode) . lispy-mode)
:bind (:map lispy-mode-map
("'" . nil) ; leave tick behaviour alone
("M-n" . nil)
("C-M-m" . nil)))
;; (use-package! smartparens
;; :init
;; (map! :map smartparens-mode-map
;; "C-M-f" #'sp-forward-sexp
;; "C-M-b" #'sp-backward-sexp
;; "C-M-u" #'sp-backward-up-sexp
;; "C-M-d" #'sp-down-sexp
;; "C-M-p" #'sp-backward-down-sexp
;; "C-M-n" #'sp-up-sexp
;; "C-M-s" #'sp-splice-sexp
;; ;; conflicts with mc
;; ;; "C-)" #'sp-forward-slurp-sexp
;; "C-}" #'sp-forward-barf-sexp
;; ;; conflicts with mc
;; ;; "C-(" #'sp-backward-slurp-sexp
;; "C-M-)" #'sp-backward-slurp-sexp
;; "C-M-)" #'sp-backward-barf-sexp))
(use-package! wrap-region
:hook
(org-mode . wrap-region-mode)
(latex-mode . wrap-region-mode)
:config
(wrap-region-add-wrappers
'(("*" "*" nil (org-mode))
("~" "~" nil (org-mode))
("/" "/" nil (org-mode))
("=" "=" nil (org-mode))
("_" "_" nil (org-mode))
("$" "$" nil (org-mode latex-mode)))))
(use-package! aggressive-indent
:hook
(emacs-lisp-mode . aggressive-indent-mode)
(common-lisp-mode . aggressive-indent-mode))
The mathpix.el package is failing when using the standard package!
/ use-package!
setup.
Loading manually from mathpix.el for now.
(defun setup-mathpix ()
(load-file (concat doom-private-dir "mathpix.el"))
(require 'mathpix)
(customize-set-variable 'mathpix-app-id "dan_girsh_gmail_com_5d68dc")
(customize-set-variable 'mathpix-app-key "600336b7b2b932549ce4")
(customize-set-variable 'mathpix-screenshot-method "scrot -s %s"))
(setup-mathpix)
(defun my/mathpix-screenshot-to-clipboard ()
(interactive)
(with-temp-buffer
(mathpix-screenshot)
(kill-new
(format "$$\n%s\n$$" (buffer-string)))))
(use-package! multiple-cursors
:init
(setq mc/always-run-for-all t)
:config
(add-to-list 'mc/unsupported-minor-modes 'lispy-mode)
:bind (("C-S-c" . mc/edit-lines)
("C-M-g" . mc/mark-all-like-this-dwim)
("C->" . mc/mark-next-like-this)
("C-<" . mc/mark-previous-like-this)
("C-)" . mc/skip-to-next-like-this)
("C-M->" . mc/skip-to-next-like-this)
("C-(" . mc/skip-to-previous-like-this)
("C-M-<" . mc/skip-to-previous-like-this)))
(use-package! iedit
:init
(map! "C-;" 'company-complete)
(map! "M-i" 'iedit-mode))
(use-package! undo-tree
:init
(setq undo-tree-auto-save-history nil
undo-tree-visualizer-timestamps t
undo-tree-visualizer-diff t)
:config
;; stolen from layers/+spacemacs/spacemacs-editing/package.el
(progn
;; restore diff window after quit. TODO fix upstream
(defun my/undo-tree-restore-default ()
(setq undo-tree-visualizer-diff t))
(advice-add 'undo-tree-visualizer-quit :after #'my/undo-tree-restore-default))
(global-undo-tree-mode 1))
(use-package! string-inflection)
(setq haskell-mode-stylish-haskell-path "brittany")
(after! rustic-flycheck
(customize-set-variable 'rustic-flycheck-clippy-params-stable
(concat rustic-flycheck-clippy-params-stable " --target x86_64-unknown-linux-gnu"))
(add-to-list 'flycheck-checkers 'rustic-clippy)
(delete 'rust-clippy flycheck-checkers)
(delete 'rust-cargo flycheck-checkers)
(delete 'rust flycheck-checkers))
(after! lsp-rust
(setq lsp-rust-analyzer-cargo-watch-command "check"))
Config thanks to: Configuring Emacs for Rust development | Robert Krahn
(after! rustic
(map! :map rustic-mode-map
"M-j" #'lsp-ui-imenu
"M-?" #'lsp-find-references
"C-c C-c C-c" #'rustic-compile
"C-c C-c l" #'flycheck-list-errors
"C-c C-c a" #'lsp-execute-code-action
"C-c C-c r" #'lsp-rename
"C-c C-c q" #'lsp-workspace-restart
"C-c C-c Q" #'lsp-workspace-shutdown
"C-c C-c s" #'lsp-rust-analyzer-status)
(setq lsp-enable-symbol-highlighting nil)
(setq rustic-format-trigger nil)
(add-hook 'rustic-mode-hook 'my/rustic-mode-hook)
(setq lsp-rust-analyzer-server-display-inlay-hints nil)
(customize-set-variable 'lsp-ui-doc-enable nil)
(add-hook 'lsp-ui-mode-hook #'(lambda () (lsp-ui-sideline-enable nil))))
(defun my/rustic-mode-hook ()
;; so that run C-c C-c C-r works without having to confirm, but don't try to
;; save rust buffers that are not file visiting. Once
;; https://github.com/brotzeit/rustic/issues/253 has been resolved this should
;; no longer be necessary.
(when buffer-file-name
(setq-local buffer-save-without-query t)))
- cargo-edite
(use-package! jupyter
:init
(setq jupyter-eval-use-overlays t)
(map!
:map org-mode-map
:localleader
(:desc "Jupyter Org Hydra" "j" #'jupyter-org-hydra/body))
(defun my/insert-julia-src-block ()
(interactive)
(jupyter-org-insert-src-block t current-prefix-arg))
;; I locally modified jupyter-completion-at-point to check for this,
;; since completions regularly crash the julia kernel for me :/
(setq my/jupyter-enable-completions nil)
;; Better than `M-c C-, j` or `M-c j =`
(key-chord-define-global "jq" #'my/insert-julia-src-block)
(map!
:map julia-mode-map
:localleader
(:prefix ("j" . "jupyter")
:desc "Run REPL" "o" #'jupyter-run-repl
:desc "Eval function" "f" #'jupyter-eval-defun
:desc "Eval buffer" "b" #'jupyter-eval-buffer
:desc "Eval region" "r" #'jupyter-eval-region
:desc "Restart REPL" "R" #'jupyter-repl-restart-kernel
:desc "Interrupt REPL" "i" #'jupyter-repl-interrup-kernel
:desc "Scratch buffer" "s" #'jupyter-repl-scratch-buffer
:desc "Remove overlays" "O" #'jupyter-eval-remove-overlays
:desc "Eval string" "w" #'jupyter-eval-string
:desc "Inspect at point" "d" #'jupyter-inspect-at-point)))
(use-package! selectrum
:config
(selectrum-mode +1)
(setq selectrum-max-window-height 30)
(setq selectrum-fix-vertical-window-height t)
(setq selectrum-group-format nil)
(setq magit-completing-read-function #'selectrum-completing-read))
(use-package! orderless
:custom (completion-styles '(orderless)))
(use-package! selectrum-prescient
:after (selectrum)
:config
(setq selectrum-prescient-enable-filtering nil)
(selectrum-prescient-mode +1)
(prescient-persist-mode +1))
(use-package! ctrlf
:init
(ctrlf-mode +1))
(use-package! consult
:init
(setq xref-search-program 'ripgrep
xref-show-xrefs-function #'consult-xref
xref-show-definitions-function #'consult-xref)
(map! :localleader
:map org-mode-map
;; override default binding for org-goto
"." 'consult-outline)
:config
(setq consult-async-split-style 'nil)
(autoload 'projectile-project-root "projectile")
(setq consult-project-root-function #'projectile-project-root)
(setq consult-ripgrep-command "rg --null --ignore-case --line-buffered --color=ansi --max-columns=1000 --no-heading --line-number . -e ARG OPTS")
:bind
(;; C-c bindings (mode-specific-map)
("M-g M-g" . consult-goto-line) ;; orig. goto-line
("M-g m" . consult-mark)
("M-g k" . consult-global-mark)
("M-s l" . consult-line)
("M-s m" . consult-multi-occur)
("M-s k" . consult-keep-lines)
("M-s u" . consult-focus-lines)
;; Isearch integration
("M-s e" . consult-isearch)
:map isearch-mode-map
("M-s e" . consult-isearch) ;; orig. isearch-edit-string
("M-s l" . consult-line)) ;; needed by consult-line to detect isearch
)
(use-package! consult-flycheck
:bind (:map flycheck-command-map
("!" . consult-flycheck)))
(use-package! consult-projectile)
(consult-customize
consult-ripgrep consult-git-grep consult-grep
consult-bookmark consult-recent-file consult-xref
consult--source-bookmark consult--source-recent-file
consult--source-project-recent-file
;; :preview-key '(:debounce 0.2 any) ;; Option 1: Delay preview
:preview-key (kbd "M-."))
;; (consult-customize
;; consult--source-file consult--source-project-file consult--source-bookmark
;; :preview-key (kbd "M-."))
(add-to-dk-keymap
'(("<SPC>" . deadgrep)
;; Project content search. ripgrep automatically understands .gitignore
("g" . consult-ripgrep)
;; Project file search.
("h" . consult-projectile)
("i" . consult-imenu)
("l" . consult-locate)
("j" . consult-buffer)))
(global-set-key [remap yank-pop] 'consult-yank-pop)
(use-package! marginalia
:init (marginalia-mode)
:bind
(("M-A" . marginalia-cycle)
:map minibuffer-local-map
("M-A" . marginalia-cycle)))
(after! dired
(setq dired-listing-switches "-aBhlv --group-directories-first"
dired-dwim-target t
dired-recursive-copies (quote always)
dired-recursive-deletes (quote top)
;; Directly edit permisison bits!
wdired-allow-to-change-permissions t))
(use-package! dired-x)
;; Directly edit permission bits!
(setq wdired-allow-to-change-permissions t)
(use-package! deadgrep)
Edit results with deadgrep-edit-mode
(replaces wgrep). Save changes with save-some-buffers
(C-x s !
).
This is one of my primary ways of navigating next: jump through other occurances of the text currently under the cursor.
(use-package! smartscan
:init (global-smartscan-mode 1)
:bind (("M-N" . smartscan-symbol-go-forward)
("M-P" . smartscan-symbol-go-backward)
:map smartscan-map
("M-p" . nil)
("M-n" . nil)))
Disable version control when using TRAMP to avoid extra delays
(setq vc-ignore-dir-regexp
(format "\\(%s\\)\\|\\(%s\\)"
vc-ignore-dir-regexp
tramp-file-name-regexp))
Stunningly useful.
(use-package! magit
:config
(set-default 'magit-stage-all-confirm nil)
(set-default 'magit-unstage-all-confirm nil)
(remove-hook 'magit-mode-hook 'turn-on-magit-gitflow)
;; Restores "normal" behavior in branch view (when hitting RET)
(setq magit-visit-ref-behavior '(create-branch checkout-any focus-on-ref))
(setq git-commit-finish-query-functions nil)
(setq magit-visit-ref-create 1)
(setq magit-revision-show-gravatars nil))
(after! (magit key-chord)
(add-to-sl-keymap
'(("k" . magit-dispatch-popup)
("s" . magit-status)
("o" . magit-log)
("u" . magit-submodule-update)
("l" . magit-show-refs-head))))
(after! pdf-tools
(map! :map pdf-isearch-minor-mode-map
"C-s" 'isearch-forward-regexp))
(use-package! dmenu)
Here we set the window labels to homerow keys (they are numbers by default)
Would use the window-select Doom module, but that (unwantedly in EXWM) binds other-window to ace-window.
(use-package! ace-window
:config
(map! "C-M-SPC" #'ace-window)
(setq aw-keys '(?a ?s ?d ?f ?g ?h ?j ?k ?l)))
;; prevents horizontal splits when split-window-sensibly is used
(setq split-width-threshold nil)
(use-package! real-auto-save
:hook
(prog-mode . real-auto-save-mode)
(org-mode . real-auto-save-mode))
(use-package! logview)
(use-package! fancy-dabbrev
:hook
(prog-mode . fancy-dabbrev-mode)
(org-mode . fancy-dabbrev-mode)
:config
;; (setq fancy-dabbrev-preview-delay 0.1)
(setq fancy-dabbrev-preview-context 'before-non-word)
;; Let dabbrev searches ignore case and expansions preserve case:
(setq dabbrev-case-distinction nil)
(setq dabbrev-case-fold-search t)
(setq dabbrev-case-replace nil)
(add-hook 'minibuffer-setup-hook (lambda () (fancy-dabbrev-mode 0)))
(add-hook 'minibuffer-exit-hook (lambda () (fancy-dabbrev-mode 1))))
(delete 'register-alist savehist-additional-variables)
(set-register ?h '(file . "~/Sync/home/config.org"))
(set-register ?r '(file . "~/Sync/resume/resume.tex"))
Load extra work config if the environment variable EMACS_WORK_MODE
is set.
(unless (getenv "EMACS_NON_WORK_MODE")
(load-file "/home/dan/Work/w/emacs/work-config.el")
(require 'work-config))
(map!
"M-p" (lambda () (interactive) (scroll-down 4))
"M-n" (lambda () (interactive) (scroll-up 4))
"C-h h" 'helpful-at-point
"C-h f" 'helpful-function
"C-h v" 'helpful-variable
"C-h k" 'helpful-key
"M-SPC" 'avy-goto-word-or-subword-1
"C-S-d" 'my/duplicate-line-or-region
"C-c <left>" 'winner-undo
"C-c <right>" 'winner-redo
"C-+" 'text-scale-increase
"C--" 'text-scale-decrease
"C-<f5>" 'my/night-mode
"C-<f6>" 'my/day-mode
"C-z" 'undo-fu-only-undo
"C-S-z" 'undo-fu-only-redo
"C-/" 'undo-fu-only-undo
"C-?" 'undo-fu-only-redo
"C-x C-z" nil)
;; remove binding for suspend-frame
;; (global-set-key [remap goto-line] 'goto-line-with-feedback)
;; (global-set-key [remap goto-line] 'goto-line-with-feedback)
When a file has lines longer than so-long-threshold, so-long mode is enabled. This prevents files with long lines from slowing down emacs. Doom sets this to 400, which is too small for me.
(after! so-long
(setq so-long-threshold 10000))
(doom/open-scratch-buffer nil nil t)
(set-company-backend! 'text-mode nil)
(defun my/file-local-p (f)
(not (file-remote-p f)))
(after! recentf
(add-to-list 'recentf-keep 'my/file-local-p))
;; (setq warning-minimum-level :emergency)
;; (when doom-debug-p
;; (require 'benchmark-init)
;; (add-hook 'doom-first-input-hook #'benchmark-init/deactivate))
(setq isearch-allow-scroll t)
(setq async-shell-command-buffer 'new-buffer)
(setq direnv-always-show-summary nil)
(add-to-list 'auto-mode-alist '("\\.eps\\'" . doc-view-minor-mode))
;; all backup and autosave files in the tmp dir
(setq backup-directory-alist
`((".*" . ,temporary-file-directory)))
(setq auto-save-file-name-transforms
`((".*" ,temporary-file-directory t)))
;; Coordinate between kill ring and system clipboard
(setq save-interprogram-paste-before-kill t)
(setq eshell-history-file-name (concat doom-private-dir "eshell-history"))
;; This is dangerous, but reduces the annoying step of confirming local variable settings each time
;; a file with a "Local Variables" clause (like many Org files) is opened.
(setq-default enable-local-variables :all)
;; This is usually just annoying
(setq compilation-ask-about-save nil)
;; No confirm on exit
(setq confirm-kill-emacs nil)
;; Alternative to calling save-buffers-kill-emacs, since
;; a) Muscle memory sends me to "kill-emacs" via fj-q-q
;; b) save-buffers-kill-emacs sometimes fails
;; This way, we try to save things, but quit in any case.
(defun my/save-ignore-errors ()
(ignore-errors
(save-some-buffers)))
(add-hook 'kill-emacs-hook 'my/save-ignore-errors)
;; Help out Projectile for remote files via TRAMP
;; https://sideshowcoder.com/2017/10/24/projectile-and-tramp/
(defadvice projectile-on (around exlude-tramp activate)
"This should disable projectile when visiting a remote file"
(unless (--any? (and it (file-remote-p it))
(list
(buffer-file-name)
list-buffers-directory
default-directory
dired-directory))
mad-do-it))
(setq projectile-mode-line "Projectile")
(setq password-store-password-length 20)
;; Truncate compiilation buffers, otherwise Emacs gets slow
;; https://stackoverflow.com/questions/11239201/can-i-limit-the-length-of-the-compilation-buffer-in-emacs
(add-hook 'compilation-filter-hook 'comint-truncate-buffer)
(setq comint-buffer-maximum-size 2000)
(setq recentf-max-saved-items 10000)
(after! vterm
(setq vterm-max-scrollback 100000
vterm-copy-exclude-prompt t))
(customize-set-variable 'vterm-buffer-name-string nil)
;; Emacs 28: Hide commands in M-x which do not work in the current mode.
;; Vertico commands are hidden in normal buffers.
(setq read-extended-command-predicate
#'command-completion-default-include-p)
(defun crm-indicator (args)
(cons (concat "[CRM] " (car args)) (cdr args)))
(advice-add #'completing-read-multiple :filter-args #'crm-indicator)
(defun my-compilation-mode-hook ()
(visual-line-mode 1))
(add-hook 'compilation-mode-hook 'my-compilation-mode-hook)
;;; ~/.doom.d/funcs.el -*- lexical-binding: t; -*-
(defun my/open-literate-private-config-file ()
"Open the private config.org file."
(interactive)
(find-file (expand-file-name "config.org" doom-private-dir)))
(defun my/rot13-and-kill-region ()
(interactive)
(kill-new (rot13
(buffer-substring (region-beginning) (region-end)))))
(defun my/org-export-subtree-as-markdown-and-copy ()
(interactive)
(save-window-excursion
(let ((export-buffer (org-md-export-as-markdown nil t nil)))
(with-current-buffer export-buffer
(clipboard-kill-ring-save (point-min) (point-max)))
(kill-buffer export-buffer))))
(defun goto-line-with-feedback ()
"Show line numbers temporarily, while prompting for the line number input"
(interactive)
(unwind-protect
(progn
(linum-mode 1)
(call-interactively 'goto-line))
(linum-mode -1)))
(defun split-window-horizontally-and-switch ()
(interactive)
(split-window-horizontally)
(other-window 1))
(defun split-window-vertically-and-switch ()
(interactive)
(split-window-vertically)
(other-window 1))
(defun my-increment-number-decimal
(&optional
arg)
"Increment the number forward from point by 'arg'."
(interactive "p*")
(save-excursion
(save-match-data
(let (inc-by field-width answer)
(setq inc-by
(if arg
arg
1))
(skip-chars-backward "0123456789")
(when (re-search-forward "[0-9]+" nil t)
(setq field-width (- (match-end 0)
(match-beginning 0)))
(setq answer (+ (string-to-number (match-string 0) 10) inc-by))
(when (< answer 0)
(setq answer (+ (expt 10 field-width) answer)))
(replace-match (format (concat "%0" (int-to-string field-width) "d") answer)))))))
(defun rev-other-window ()
(interactive)
(other-window -1))
(defun eshell-here ()
"Opens up a new shell in the directory associated with the
current buffer's file. The eshell is renamed to match that
directory to make multiple eshell windows easier."
(interactive)
(let* ((parent (if (buffer-file-name)
(file-name-directory (buffer-file-name))
default-directory))
(name (car (last (split-string parent "/" t)))))
(eshell "new")
(rename-buffer (concat "*eshell: " name "*"))
(insert (concat "ls"))
(eshell-send-input)))
;; https://www.emacswiki.org/emacs/CopyingWholeLines
(defun my/duplicate-line-or-region (&optional n)
"Duplicate current line, or region if active.
With argument N, make N copies.
With negative N, comment out original line and use the absolute value."
(interactive "*p")
(let ((use-region (use-region-p)))
(save-excursion
(let ((text (if use-region ; Get region if active, otherwise line
(buffer-substring (region-beginning) (region-end))
(prog1 (thing-at-point 'line)
(end-of-line)
(if (< 0 (forward-line 1)) ; Go to beginning of next line, or make a new one
(newline))))))
(dotimes (i (abs (or n 1))) ; Insert N times, or once if not specified
(insert text))))
(if use-region nil ; Only if we're working with a line (not a region)
(let ((pos (- (point) (line-beginning-position)))) ; Save column
(if (> 0 n) ; Comment out original with negative arg
(comment-region (line-beginning-position) (line-end-position)))
(forward-line 1)
(forward-char pos)))))
(defun my/org-ref-noter-link-from-arxiv (arxiv-number)
"Retrieve a pdf for ARXIV-NUMBER and save it to the default PDF dir.
Then, add a bibtex entry for the new file in the default bib
file. Then, create a new org-ref note heading for it (see
org-ref-create-notes-hook in packages.el to see it also creates
a property for org-noter). Finally, insert a descriptive link to
the note heading at point, using the paper title as the link
text.
"
(interactive "sarxiv number: ")
(let ((bibtex-dialect 'BibTeX))
(org-ref-save-all-bibtex-buffers)
(save-window-excursion
(arxiv-get-pdf-add-bibtex-entry arxiv-number
(car org-ref-default-bibliography)
org-ref-pdf-directory)
(org-ref-save-all-bibtex-buffers))
(let* ((parsed-entry (save-excursion
(with-temp-buffer
;; In case of dir-local path to references.bib
(hack-dir-local-variables-non-file-buffer)
(insert-file-contents (car org-ref-default-bibliography))
(bibtex-set-dialect (parsebib-find-bibtex-dialect) t)
(search-forward (format "{%s}" arxiv-number))
(bibtex-narrow-to-entry)
(bibtex-beginning-of-entry)
(bibtex-parse-entry)))))
(org-insert-heading)
(let* ((raw-ref-title (cdr (assoc "title" parsed-entry)))
(ref-title (s-replace-regexp (rx (sequence "\n" (+ space))) " "
(car (cdr (s-match (rx "{" (group (+ anything)) "}") raw-ref-title)))))
(ref-key (cdr (assoc "=key=" parsed-entry))))
(insert ref-title)
(insert "\n\n")
(insert (format "cite:%s" ref-key))))))
(defun my/night-mode ()
(interactive)
(load-theme 'doom-dark+ t)
(doom/reload-theme)
(my/set-redshift 1500 30))
(defun my/day-mode ()
(interactive)
(load-theme 'doom-nord-light t)
(doom/reload-theme)
(my/set-redshift 5500 100))
(defun narrow-or-widen-dwim (p)
"If the buffer is narrowed, it widens. Otherwise, it narrows intelligently.
Intelligently means: region, subtree, or defun, whichever applies
first.
With prefix P, don't widen, just narrow even if buffer is already
narrowed."
(interactive "P")
(declare (interactive-only))
(cond ((and (buffer-narrowed-p) (not p)) (widen))
((region-active-p)
(narrow-to-region (region-beginning) (region-end)))
((derived-mode-p 'org-mode) (org-narrow-to-subtree))
(t (narrow-to-defun))))
;; https://stackoverflow.com/questions/28727190/org-babel-tangle-only-one-code-block
(defun my/org-babel-tangle-block()
(interactive)
(let ((current-prefix-arg '(4)))
(call-interactively 'org-babel-tangle)))
(defun my/open-org-files-list ()
(delq nil
(mapcar (lambda (buffer)
(buffer-file-name buffer))
(org-buffer-list 'files t))))
(defun my/org-latex-toggle-recent ()
(when (looking-back (rx "$ "))
(save-excursion
(backward-char 1)
(org-toggle-latex-fragment))))
(add-hook 'org-mode-hook
(lambda ()
(org-cdlatex-mode)
(add-hook 'post-self-insert-hook #'my/org-latex-toggle-recent 'append 'local)))
(defun my/save-shebanged-file-as-executable ()
(and (save-excursion
(save-restriction
(widen)
(goto-char (point-min))
(save-match-data
(looking-at "^#!"))))
(not (file-executable-p buffer-file-name))
(shell-command (concat "chmod +x " buffer-file-name))
(message
(concat "Saved as script: " buffer-file-name))))
(add-hook 'after-save-hook #'my/save-shebanged-file-as-executable)
;; https://llazarek.com/2018/10/images-in-org-mode.html
(defun my/org-link-file-path-at-point ()
"Get the path of the file referred to by the link at point."
(let* ((org-element (org-element-context))
(is-subscript-p (equal (org-element-type org-element) 'subscript))
(is-link-p (equal (org-element-type org-element) 'link))
(is-file-p (equal (org-element-property :type org-element) "file")))
(when is-subscript-p
(user-error "Org thinks you're in a subscript. Move the point and try again."))
(unless (and is-link-p is-file-p)
(user-error "Not on file link"))
(expand-file-name (org-element-property :path org-element))))
(defun my/org-resize-image-at-point (&optional arg)
"Resize the image linked at point."
(interactive)
(let ((img (my/org-link-file-path-at-point))
(percent (read-number "Resize to what percentage of current size? ")))
(start-process "mogrify" nil "/usr/bin/mogrify"
"-resize"
(format "%s%%" percent)
img)))
(defun my/run-in-fresh-compilation (cmd dir)
(defun local-compile-buffer-namer (ignored)
(generate-new-buffer-name cmd))
(let* ((compilation-buffer-name-function #'local-compile-buffer-namer)
(compilation-ask-about-save nil)
(default-directory (if dir dir default-directory)))
(compile cmd)))
(defun my/publish-dangirsh.org ()
(interactive)
(let ((neurosys-org-file "/home/dan/repos/dangirsh.org/site/projects/neurosys.org")
(doom-org-file "/home/dan/repos/dangirsh.org/site/projects/doom-config.org"))
;; Hack: copy in the files - had issues hardlinking it.
(copy-file (concat neurosys/base-dir "README.org") neurosys-org-file t)
(copy-file (concat doom-private-dir "config.org") doom-org-file t)
(my/run-in-fresh-compilation "./publi.sh" "/home/dan/repos/dangirsh.org/")))
(defun my/org-get-title (path)
(save-window-excursion
;; A simple find-file didn't work when the original was narrowed
(with-temp-buffer
(insert-file-contents path)
(org-mode)
(cadr (assoc "TITLE" (org-collect-keywords '("title"))
#'string-equal)))))
(defun my/set-timezone ()
(interactive)
;; (shell-command "sudo timedatectl set-timezone America/Los_Angeles")
;; (shell-command "sudo timedatectl set-timezone America/New_York")
;; (shell-command "sudo timedatectl set-timezone Europe/Paris")
(shell-command "sudo timedatectl set-timezone Europe/Berlin")
)
;; (my/set-timezone)
(defun my/insert-jupyter-julia-block ()
(interactive)
(org-insert-structure-template "src jupyter-julia"))
(defun my/insert-jupyter-python-block ()
(interactive)
(org-insert-structure-template "src jupyter-python"))
;; https://emacs.stackexchange.com/questions/10091/sentence-in-text-is-read-only-even-though-the-buffer-is-not-how-to-fix-this/10093#10093
(defun my/set-region-read-only (begin end)
"Sets the read-only text property on the marked region.
Use `set-region-writeable' to remove this property."
;; See https://stackoverflow.com/questions/7410125
(interactive "r")
(with-silent-modifications
(put-text-property begin end 'read-only t)))
(defun my/set-region-writeable (begin end)
"Removes the read-only text property from the marked region.
Use `set-region-read-only' to set this property."
;; See https://stackoverflow.com/questions/7410125
(interactive "r")
(with-silent-modifications
(remove-text-properties begin end '(read-only t))))
(defun my/copy-yubikey-token (account-name)
"Expects ykman to be installed."
(interactive (list (completing-read "Account: " '("yubi" "yubi3") nil t)))
(kill-new (my/get-yubikey-token account-name)))
(defun my/get-yubikey-token (account-name)
"Expects ykman to be installed."
(format "%s"
(with-temp-buffer
(message "Touch Yubikey!")
(call-process-region (point-min) (point-max) "ykman" t t nil "oath" "code" account-name)
(let* ((output (buffer-string))
(cells (split-string output)))
(car (last cells))))))
(defun my/save-yubikey-token (account-name)
(let ((yubikey-token-file (format "/tmp/current-yubi-token/%s" account-name)))
(save-window-excursion
(find-file yubikey-token-file)
(erase-buffer)
(insert (my/get-yubikey-token account-name))
(save-buffer))
yubikey-token-file))
(defun my/run-in-vterm-kill (process event)
"A process sentinel. Kills PROCESS's buffer if it is live."
(let ((b (process-buffer process)))
(and (buffer-live-p b)
(kill-buffer b))))
;; https://www.reddit.com/r/emacs/comments/ft84xy/run_shell_command_in_new_vterm/
(defun my/run-in-vterm (command dir &optional term-name)
"Execute string COMMAND in a new vterm.
Like `async-shell-command`, but run in a vterm for full terminal features.
The new vterm buffer is named in the form `*foo bar.baz*`, the
command and its arguments in earmuffs.
When the command terminates, the shell remains open, but when the
shell exits, the buffer is killed."
(interactive)
;; Ensure the vterm is opened in the right directory
(let ((default-directory dir))
(with-current-buffer (vterm (if term-name term-name (format "*%s*" command)))
(set-process-sentinel vterm--process #'my/run-in-vterm-kill)
(vterm-send-string command)
(vterm-send-return))))
;; https://github.com/org-roam/org-roam/wiki/Hitchhiker's-Rough-Guide-to-Org-roam-V2#hiding-the-properties-drawer
(defun org-hide-properties ()
"Hide all org-mode headline property drawers in buffer. Could be slow if it has a lot of overlays."
(interactive)
(save-excursion
(goto-char (point-min))
(while (re-search-forward
"^ *:properties:\n\\( *:.+?:.*\n\\)+ *:end:\n" nil t)
(let ((ov_this (make-overlay (match-beginning 0) (match-end 0))))
(overlay-put ov_this 'display "")
(overlay-put ov_this 'hidden-prop-drawer t))))
(put 'org-toggle-properties-hide-state 'state 'hidden))
(defun org-show-properties ()
"Show all org-mode property drawers hidden by org-hide-properties."
(interactive)
(remove-overlays (point-min) (point-max) 'hidden-prop-drawer t)
(put 'org-toggle-properties-hide-state 'state 'shown))
(defun org-toggle-properties ()
"Toggle visibility of property drawers."
(interactive)
(if (eq (get 'org-toggle-properties-hide-state 'state) 'hidden)
(org-show-properties)
(org-hide-properties)))
(defun alist-get-nested (alist path)
(let ((result alist))
(dolist (key path)
(setq result (alist-get key result)))
result))
(defun my/edit-resume ()
(interactive)
(find-file "~/Sync/resume/resume.tex"))
(defun my/org-split-block ()
"Sensibly split the current Org block at point."
(interactive)
(if (my/org-in-any-block-p)
(save-match-data
(save-restriction
(widen)
(let ((case-fold-search t)
(at-bol (bolp))
block-start
block-end)
(save-excursion
(re-search-backward "^\\(?1:[[:blank:]]*#\\+begin_.+?\\)\\(?: .*\\)*$" nil nil 1)
(setq block-start (match-string-no-properties 0))
(setq block-end (replace-regexp-in-string
"begin_" "end_" ;Replaces "begin_" with "end_", "BEGIN_" with "END_"
(match-string-no-properties 1))))
;; Go to the end of current line, if not at the BOL
(unless at-bol
(end-of-line 1))
(insert (concat (if at-bol "" "\n")
block-end
"\n\n"
block-start
(if at-bol "\n" "")))
;; Go to the line before the inserted "#+begin_ .." line
(beginning-of-line (if at-bol -1 0)))))
(message "Point is not in an Org block")))
(defun my/org-in-any-block-p ()
"Return non-nil if the point is in any Org block.
The Org block can be *any*: src, example, verse, etc., even any
Org Special block.
This function is heavily adapted from `org-between-regexps-p'."
(save-match-data
(let ((pos (point))
(case-fold-search t)
(block-begin-re "^[[:blank:]]*#\\+begin_\\(?1:.+?\\)\\(?: .*\\)*$")
(limit-up (save-excursion (outline-previous-heading)))
(limit-down (save-excursion (outline-next-heading)))
beg end)
(save-excursion
;; Point is on a block when on BLOCK-BEGIN-RE or if
;; BLOCK-BEGIN-RE can be found before it...
(and (or (org-in-regexp block-begin-re)
(re-search-backward block-begin-re limit-up :noerror))
(setq beg (match-beginning 0))
;; ... and BLOCK-END-RE after it...
(let ((block-end-re (concat "^[[:blank:]]*#\\+end_"
(match-string-no-properties 1)
"\\( .*\\)*$")))
(goto-char (match-end 0))
(re-search-forward block-end-re limit-down :noerror))
(> (setq end (match-end 0)) pos)
;; ... without another BLOCK-BEGIN-RE in-between.
(goto-char (match-beginning 0))
(not (re-search-backward block-begin-re (1+ beg) :noerror))
;; Return value.
(cons beg end))))))
(defun my/org-meta-return (&optional arg)
"Insert a new heading or wrap a region in a table.
Calls `org-insert-heading', `org-insert-item',
`org-table-wrap-region', or `my/org-split-block' depending on
context. When called with an argument, unconditionally call
`org-insert-heading'."
(interactive "P")
(org-check-before-invisible-edit 'insert)
(or (run-hook-with-args-until-success 'org-metareturn-hook)
(call-interactively (cond (arg #'org-insert-heading)
((org-at-table-p) #'org-table-wrap-region)
((org-in-item-p) #'org-insert-item)
((my/org-in-any-block-p) #'my/org-split-block)
(t #'org-insert-heading)))))
;; https://emacs.stackexchange.com/questions/50649/jumping-from-a-source-block-to-the-tangled-file
(defun my/org-babel-tangle-jump ()
"Jump to tangle file for the source block at point."
(interactive)
(let (file org-babel-pre-tangle-hook org-babel-post-tangle-hook)
(cl-letf (((symbol-function 'write-region) (lambda (start end filename &rest _ignore)
(setq file filename)))
((symbol-function 'delete-file) #'ignore))
(org-babel-tangle '(4)))
(when file
(setq file (expand-file-name file))
(if (file-readable-p file)
(find-file file)
(error "Cannot open tangle file %S" file)))))
;; https://sachachua.com/blog/2019/07/tweaking-emacs-on-android-via-termux-xclip-xdg-open-syncthing-conflicts/
(defun my/org-archive-done-tasks (&optional scope)
"Archive finished or cancelled tasks.
SCOPE can be 'file or 'tree."
(interactive)
(beginning-of-buffer)
(org-map-entries
(lambda ()
(org-archive-subtree)
(setq org-map-continue-from (outline-previous-heading)))
"TODO=\"DONE\"|TODO=\"KILL\"" (or scope (if (org-before-first-heading-p) 'file 'tree))))
(defun my/org-titlify-link-or-noop ()
(interactive)
(org-beginning-of-line)
(kill-line)
(condition-case nil
(progn
(org-cliplink)
(sleep-for 5))
(error (yank))))
(defun my/org-jupyter-execute-subtree-by-id (id)
(save-window-excursion
(org-id-goto id)
(save-excursion
(org-narrow-to-subtree)
(end-of-buffer)
(jupyter-org-execute-to-point nil)
(widen))))
Elisp related to my neurosys.
(setq neurosys/base-dir "/home/dan/repos/neurosys/")
(defun neurosys/deploy-to-host (host host-home-raw)
(interactive "sHost: \nsHost home: ")
(let ((host-root (format "/ssh:%s:/" host))
;; mind the trailing slash, since we're passing it to rsync
(host-home (file-name-as-directory host-home-raw)))
(save-window-excursion
(org-babel-tangle)
(my/run-in-fresh-compilation
(format (concat neurosys/base-dir "rsync.sh %s %s") host host-home) neurosys/base-dir)
;; TODO: Is there cleaner way to compile over TRAMP?
(find-file host-root)
(compile "nixos-rebuild switch --show-trace")))
(switch-to-buffer-other-window "*compilation*"))
(defun neurosys/deploy-to-nixos-dev ()
(interactive)
(neurosys/deploy-to-host "root@nixos-dev" "/home/dan/"))
- [ ] Update channels with
nix-channel --update
- [ ] Rebuild packages with
nixos-rebuild switch
NOTE: These can be combined with nixos-rebuild switch --update
(defun neurosys/open-config-file ()
(interactive)
(find-file (concat neurosys/base-dir "README.org")))
(map!
:leader
:prefix ("j" . "neurosys")
:desc "deploy" "D" #'neurosys/deploy-to-host
:desc "deploy to nixos-dev" "d" #'neurosys/deploy-to-nixos-dev)
Any desired package not declared in a Doom module must be declared here. This seems redundant given the corresponding use-package!
declarations, but required by Doom (presumably for lazy loading).
;; -*- no-byte-compile: t; -*-
;;; $DOOMDIR/packages.el
(package! ace-window)
(package! aggressive-indent)
;; (package! benchmark-init)
;; (package! burly :recipe (:host github :repo "alphapapa/burly.el"))
;; (package! company-org-block)
;; (package! company-posframe)
(package! copilot
:recipe (:host github :repo "zerolfx/copilot.el" :files ("*.el" "dist")))
;; (package! dap-mode)
(package! deadgrep)
(package! dired-narrow)
(package! dmenu)
(package! elegant-agenda-mode :recipe (:host github :repo "justinbarclay/elegant-agenda-mode"))
;; (package! evxcr-mode :recipe (:host github :repo "serialdev/evcxr-mode"))
(package! google-this)
;; (package! google-translate)
(package! helpful)
;; (package! jest)
(package! key-chord)
;; (package! mathpix :recipe (:host github :repo "dangirsh/mathpix"))
;; (package! nano-emacs
;; :recipe (:host github :repo "rougier/nano-emacs"))
(package! ob-graphql)
(package! openai-api :recipe (:host github :repo "dangirsh/openai-api.el"))
(package! org-cliplink)
(package! org-download)
;; (package! org-drill)
;; (package! org-gcal)
(package! org-noter)
;; (package! org-recoll :recipe (:host github :repo "alraban/org-recoll"))
(package! org-ref)
(package! org-roam :recipe (:host github :repo "jethrokuan/org-roam"))
;; (package! org-roam-bibtex)
(package! websocket)
(package! org-roam-ui :recipe (:host github :repo "org-roam/org-roam-ui" :files ("*.el" "out")))
(package! org-super-agenda)
;; (package! org-transclusion :recipe (:host github :repo "nobiot/org-transclusion"))
(package! phi-search)
;; (package! ob-rust)
(package! real-auto-save)
(package! rust-mode)
;; (package! s3ed)
(package! smartscan)
(package! string-inflection)
(package! toc-org)
(package! undo-tree)
(package! wrap-region)
;; (package! almost-mono-themes)
(package! selectrum)
(package! orderless)
(package! selectrum-prescient)
(package! ctrlf)
(package! mini-frame)
(package! consult)
(package! consult-flycheck)
(package! consult-projectile :recipe (:host gitlab :repo "OlMon/consult-projectile"))
(package! marginalia)
;; (package! embark)
;; (package! embark-consult)
(package! logview)
(package! fancy-dabbrev)
;; Julia
;; (package! julia-mode)
;; (package! julia-snail)
;; (package! julia-repl
;; :recipe (:host github :repo "tpapp/julia-repl"))
;; (package! julia-formatter
;; :recipe (:host github :repo "ki-chi/julia-formatter"))
;; (package! eglot-jl)
;; (unpin! dirvish)
- [ ] Setup dirvish!
- [ ] try notebook mode
- [ ] GitHub - takaxp/org-tree-slide: A presentation tool for org-mode based on the…
- [ ] GitHub - minad/bookmark-view: bookmark-view.el - Use bookmarks to persist the…
- [ ] jao/consult-recoll: recoll queries in emacs using consult - consult-recoll - …
- [ ] GitHub - gagbo/consult-lsp: LSP-mode and consult.el helping each other
- [ ] look through GNU Emacs integrated computing environment | Protesilaos Stavrou