#+PROPERTY: header-args:emacs-lisp :tangle "~/.config/emacs/init.el" #+OPTIONS: toc:nil title:nil #+EXPORT_FILE_NAME: ~/code/website/src/content/dotfiles/emacs.md #+BEGIN_EXPORT markdown +++ title = "Emacs Configuration" author = ["Ian Keane"] date = 2023-02-09 tags = ["Config", "Text editing"] description = 'My emacs configuration.' +++ #+END_EXPORT * Preamble My emacs configuration. It tangles to =.emacs.d/init.el= and exports to this markdown file on save. If you're viewing this in a repo, it's better to visit the website at . If you are viewing this on the website and want the repo, you can find it at . To see the hugo front-matter configuration, you'll have to view the raw code. #+TOC: headlines 2 * First things first ** Literate Config Setup To get started, run =C-c C-v t= #+begin_src emacs-lisp (defun dotfiles/org-babel-tangle-config () (when (string-equal (buffer-file-name) (expand-file-name "~/.dotfiles/emacs-config.org")) (let ((org-confirm-babel-evaluate nil)) (org-babel-tangle) (load-file (expand-file-name "~/.config/emacs/init.el"))))) (add-hook 'org-mode-hook (lambda () (add-hook 'after-save-hook #'dotfiles/org-babel-tangle-config nil t))) #+end_src #+RESULTS: | (lambda nil (add-hook 'after-save-hook #'dotfiles/org-babel-tangle-config nil t)) | org-appear-mode | org-tempo-setup | yas-minor-mode | (lambda nil evil-org-mode) | #[0 \300\301\302\303\304$\207 [add-hook change-major-mode-hook org-fold-show-all append local] 5] | #[0 \300\301\302\303\304$\207 [add-hook change-major-mode-hook org-babel-show-result-all append local] 5] | org-babel-result-hide-spec | org-babel-hide-all-hashes | #[0 \301\211\207 [imenu-create-index-function org-imenu-get-tree] 2] | (lambda nil (display-line-numbers-mode 0)) | ** Package initialization =TODO:= savehist mode doesn't seem to save the history correctly #+begin_src emacs-lisp (require 'package) (setq package-archives '(("melpa" . "https://melpa.org/packages/") ("org" . "https://orgmode.org/elpa/") ("elpa" . "https://elpa.gnu.org/packages/"))) (package-initialize) ;; Initialize use-package on non-linux platforms (unless (package-installed-p 'use-package) (package-install 'use-package)) (require 'use-package) (setq use-package-always-ensure t) (package-refresh-contents) (use-package savehist :init (savehist-mode)) #+end_src ** Straight I don't use straight for much currently, but needed it in order to install beancount-mode and intend to migrate all my packages to it eventually. #+begin_src emacs-lisp (defvar bootstrap-version) (let ((bootstrap-file (expand-file-name "straight/repos/straight.el/bootstrap.el" (or (bound-and-true-p straight-base-dir) user-emacs-directory))) (bootstrap-version 7)) (unless (file-exists-p bootstrap-file) (with-current-buffer (url-retrieve-synchronously "https://raw.githubusercontent.com/radian-software/straight.el/develop/install.el" 'silent 'inhibit-cookies) (goto-char (point-max)) (eval-print-last-sexp))) (load bootstrap-file nil 'nomessage)) (setq package-enable-at-startup nil) #+end_src ** Password Retrieval =password-store= integrations require you to have =pass= and =pinentry= configured on your local system outside of emacs. #+begin_src emacs-lisp (use-package pinentry) (use-package pass) (use-package password-store) (pinentry-start) (auth-source-pass-enable) #+end_src ** Variables Things referenced throughout the config which are specific to me #+begin_src emacs-lisp (setq user-init-file (expand-file-name "~/.config/emacs/init.el")) (setq IS-MACOS (eq system-type 'darwin)) (setq openai-key-string (if IS-MACOS "self/openai-alt" "openai-alt")) (setq gptel-api-key (password-store-get openai-key-string)) #+end_src ** Required directories for emacs setup Eventually I'll set this up so that all these directories are set in the config of their respective packages; I'll still run ensure-directory on all of them beforehand though. #+begin_src emacs-lisp (defun ian/ensure-directory (dir) "Ceate a dir if it doesn't exist." (unless (file-directory-p dir) (make-directory dir t))) (ian/ensure-directory "~/.config/emacs/backups/") (ian/ensure-directory "~/.config/emacs/autosaves") (ian/ensure-directory "~/notes/roam") (ian/ensure-directory "~/notes/deft") (ian/ensure-directory "~/notes/code") (ian/ensure-directory "~/notes/work") (ian/ensure-directory "~/.config/emacs/video") (ian/ensure-directory "~/.config/emacs/audio") (setq projectile-project-search-path '("~/code/") empv-video-dir "~/.config/emacs/video" empv-audio-dir "~/.config/emacs/audio" backup-directory-alist `(("." . "~/.config/emacs/backups/")) auto-save-file-name-transforms `((".*" "~/.config/emacs/autosaves/" t))) ;; (projectile-mode) #+end_src ** Helper Functions #+begin_src emacs-lisp (defun ian/eval-region-or-buffer () "Eval the region if anything is selected, otherwise eval the whole buffer." (interactive) (if mark-active (eval-region (region-beginning) (region-end)) (eval-buffer))) (defun ian/conditional-imenu () "Call `consult-org-heading` in Org mode, otherwise `consult-imenu`." (interactive) (if (eq major-mode 'org-mode) (consult-org-heading) (consult-imenu))) (defun ian/reload-config () "Reload the Emacs configuration." (interactive) (load-file user-init-file)) (defun ian/open-from-project-root (filename) "Open a file from the root of the current Projectile project." (interactive) (find-file (expand-file-name filename (projectile-project-root)))) #+end_src ** Evil-want-keybinding Setting this in the :init of evil doesn't work for some reason. It has to be early in the file =TODO:= find a better solution #+begin_src emacs-lisp (setq evil-want-keybinding nil) #+end_src * Basic Appearance and Behaviors ** Font and Theme #+begin_src emacs-lisp (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 ;; Enable flashing mode-line on errors (setq doom-themes-treemacs-theme "doom-atom") ; use "doom-colors" for less minimal icon theme (doom-themes-treemacs-config) ;; Corrects (and improves) org-mode's native fontification. (doom-themes-org-config)) ;; (set-frame-font "DejaVu Sans Mono 16") (add-to-list 'default-frame-alist '(font . "Fira Code Mono 16")) ;; (load-theme 'doom-oceanic-next t) (use-package base16-theme) (load-theme 'base16-oceanicnext t) (use-package default-text-scale :defer 1 :config (default-text-scale-mode)) #+end_src ** Cosmetic #+begin_src emacs-lisp (setq fancy-splash-image "~/.dotfiles/sink.png") ;; the best emacs logo (setq lsp-lens-enable nil) ;; gets rid of the '0 references' note from lsp ;; remove visual noise (menu-bar-mode -1) (tool-bar-mode -1) (scroll-bar-mode -1) (recentf-mode 1) (savehist-mode 1) ; remember previous commands in minibuffer (save-place-mode 1) ; put cursor in last place when opening a file (global-display-line-numbers-mode t) (use-package rainbow-delimiters :hook (prog-mode . rainbow-delimiters-mode)) (use-package solaire-mode :config (solaire-global-mode +1)) (use-package simple-modeline :hook (after-init . simple-modeline-mode)) ;; turn off number mode in some contexts (dolist (mode '(org-mode-hook term-mode-hook eshell-mode-hook treemacs-mode-hook vterm-mode-hook nov-mode-hook)) (add-hook mode (lambda () (display-line-numbers-mode 0)))) (column-number-mode) #+end_src ** Buffers =TODO:= Make this use currently selected buffer #+begin_src emacs-lisp ;; Generate buffers in last window (setq display-buffer-base-action '(display-buffer-reuse-mode-window display-buffer-reuse-window display-buffer-same-window)) #+end_src ** Behavioral Tweaks #+begin_src emacs-lisp (when IS-MACOS (setq mac-pass-command-to-system nil)) ;; Avoid customization UI auto-variables in init.el (setq custom-file (locate-user-emacs-file "custom-vars.el")) (load custom-file 'noerror 'nomessage) ;; Don't show popup UI when prompting (setq use-dialog-box nil) ;; Update files when changed on disk (global-auto-revert-mode 1) (use-package helpful) ; Slightly more helpful help ;; If a popup does happen, don't resize windows to be equal-sized (setq even-window-sizes nil) (setq whitespace-style '(trailing tabs newline tab-mark )) ; show tab characters (setq tab-always-indent 'complete) (setq tab-first-completion 'word) (setq indent-tabs-mode nil) ; tabs not spaces (visual-line-mode) ; wrap long lines visually (whitespace-mode) (setq-default indent-tabs-mode nil) #+end_src ** Tab bar #+begin_src emacs-lisp (use-package tab-bar-echo-area :ensure :config (tab-bar-echo-area-mode 1) (setq tab-bar-show nil)) #+end_src * Evil #+begin_src emacs-lisp (use-package evil :ensure t :config (global-set-key (kbd "") 'keyboard-escape-quit) (define-key evil-normal-state-map (kbd "j") 'evil-next-visual-line) (define-key evil-normal-state-map (kbd "k") 'evil-previous-visual-line) (define-key evil-normal-state-map (kbd "ghp") 'git-gutter-previous-hunk) (define-key evil-normal-state-map (kbd "ghn") 'git-gutter-next-hunk) (define-key evil-normal-state-map (kbd "ghr") 'git-gutter-revert-hunk) (define-key evil-normal-state-map (kbd "ghs") 'git-gutter-popup-hunk) (define-key evil-normal-state-map (kbd "ghS") 'git-gutter-stage-hunk) (define-key evil-normal-state-map (kbd "gp") nil) (define-key evil-normal-state-map (kbd "gpn") 'popper-cycle) (define-key evil-normal-state-map (kbd "gpp") 'popper-cycle-backwards) (define-key evil-normal-state-map (kbd "gpq") 'popper-kill-latest-popup) (define-key evil-normal-state-map (kbd "gpt") 'popper-toggle-type) (define-key evil-normal-state-map (kbd "gbn") 'projectile-next-project-buffer) (define-key evil-normal-state-map (kbd "gbp") 'projectile-previous-project-buffer) (evil-mode 1)) (use-package undo-tree :ensure t :after evil :diminish :config (evil-set-undo-system 'undo-tree) (setq undo-tree-history-directory-alist '(("." . "~/.config/emacs/undo"))) (global-undo-tree-mode 1)) (use-package evil-org :ensure t :after org :hook (org-mode . (lambda () evil-org-mode))) (use-package evil-collection :after evil :ensure t :diminish evil-collection-unimpaired-mode :init :config (setq evil-respect-visual-line-mode t) (evil-collection-init)) (use-package evil-commentary :config (evil-commentary-mode)) #+end_src * Navigation ** Helper Functions #+begin_src emacs-lisp (defun split-and-follow-horizontally () (interactive) (split-window-below) (balance-windows) (other-window 1)) (defun split-and-follow-vertically () (interactive) (split-window-right) (balance-windows) (other-window 1)) #+end_src ** Windows and Workspaces [[https://github.com/abo-abo/ace-window/issues/216][Credit]] for manual dispatch function. =TODO:= Window width controls #+begin_src emacs-lisp (use-package winner :after evil :config (winner-mode)) (use-package ace-window) (setq aw-keys '(?a ?s ?d ?f ?g ?h ?j ?k ?l)) (setq aw-dispatch-alist '( (?x aw-delete-window "Delete Window") (?m aw-swap-window "Swap Windows") (?M aw-move-window "Move Window") ;; (?c aw-copy-window "Copy Window") ;; (?j aw-switch-buffer-in-window "Select Buffer") ;; (?n aw-flip-window) ;; ;; (?b aw-switch-buffer-other-window "Switch Buffer Other Window") (?u winner-undo) (?U winner-redo) (?c aw-split-window-fair "Split Fair Window") (?v aw-split-window-vert "Split Vert Window") (?H aw-split-window-horz "Split Horz Window") (?o delete-other-windows "Delete Other Windows") (?? aw-show-dispatch-help))) (setq aw-scope 'frame) (defun ace-window-manual-dispatch (arg) "Calls `ace-window' with ARG asking for the dispatch, even if `aw-dispatch-always' is nil. This could be useful to use the advanced commands" (interactive "p") (let ((aw-dispatch-always t)) (ace-window arg) )) #+end_src ** Shackle #+begin_src emacs-lisp (use-package shackle :config (shackle-mode)) (setq shackle-rules '( (helpful-mode :align right :select t :size 0.3 :popup t) (help-mode :align right :select t :size 0.3 :popup t) (compilation-mode :align right :select t :size 0.3 :popup t) ("*shell*" :align below :select t :size 0.3 :popup t) ("*eshell*" :align below :select t :size 0.3 :popup t) ("*vterm*" :align below :select t :size 0.3 :popup t) ("*scratch*" :align left :select t :size 0.25 :popup t) (treemacs-mode :align left :select t :size 0.40 :popup t) ("*Messages*" :align right :select t :size 0.25 :popup t)) default-shackle-rule '(:select t)) ;; Always select newly created windows #+end_src ** Popper #+begin_src emacs-lisp (use-package popper :after (shackle projectile) :init (setq popper-reference-buffers '(("\\*Messages\\*" . hide) "\\*Error\\*" "Output\\*$" ("\\*Warnings\\*" . hide) "\\*scratch*\\*" ;; "\\*lsp-bridge\\*" "\\*Async Shell Command\\*" "^\\*eshell.*\\*$" eshell-mode ;eshell as a popup "^\\*shell.*\\*$" shell-mode ;shell as a popup "^\\*term.*\\*$" term-mode ;term as a popup "^\\*vterm.*\\*$" vterm-mode ;vterm as a popup helpful-mode compilation-mode inferior-python-mode consult-flymake-mode)) :config (setq popper-display-control nil) (popper-mode +1) (popper-echo-mode +1)) (setq popper-group-function #'popper-group-by-projectile) #+end_src ** Dired #+begin_src emacs-lisp (setq ring-bell-function 'ignore) (setq dired-listing-switches "-al") ;; opening 'other window' on a subdir enters 2 window dired mode for copy/paste (setq dired-dwim-target t) ;; if dired's already loaded, then the keymap will be bound (if (boundp 'dired-mode-map) (my-dired-init) (add-hook 'dired-load-hook 'my-dired-init)) (use-package dired-open :config (setq dired-open-extensions '(("png" . "sxiv") ("mkv" . "mpv") ("avi" . "mpv")))) ;; (eval-after-load 'evil ;; '(evil-define-key 'normal dired-mode-map (kbd "SPC") nil)) (use-package all-the-icons-dired :hook (dired-mode . all-the-icons-dired-mode)) #+end_src ** Treemacs #+begin_src emacs-lisp (use-package treemacs :config (setq treemacs-width 45)) ;; Follow project buffers instantly (setq treemacs--project-follow-delay 0) (defun ian/treemacs-open-current-or-jump () "Find the current file and open treemacs if it's not open, otherwise jump to the treemacs window" (interactive) (if (not(eq (treemacs-current-visibility) 'visible)) (treemacs-find-file)) (treemacs-select-window)) (use-package all-the-icons) (use-package treemacs-all-the-icons) (use-package treemacs-evil) #+end_src ** Which-key #+begin_src emacs-lisp (use-package which-key :init (which-key-mode) :diminish which-key-mode :config (setq which-key-idle-delay 0.3)) #+end_src ** General I know these could be bound on a per-package basis, but since this is my primary interface with emacs I'd rather keep all keymaps in one place, both for reference and to discourage myself from organizing my top-level bindings on a per-plugin basis rather than keeping the focus on functionality. =TODO:= - bind lispy for colemak-dh - bind lispy doc features and ide-like features - bind embark #+begin_src emacs-lisp (use-package general :ensure t :after nov evil evil-collection treemacs :config (general-create-definer general-definition ;; :keymaps '(normal insert visual emacs nov-mode-map nov-button-map dired-mode-map) :states '(normal visual) :keymaps 'override :prefix "SPC" :global-prefix "C-SPC") (general-definition ;; Top level bindings "SPC" '(projectile-find-file :which-key "Find project file") "" '(ian/treemacs-open-current-or-jump :which-key "Find current file in sidebar") "TAB" '(popper-toggle :which-key "Toggle popup") "," '(projectile-ibuffer :which-key "Buffers (workspace)") "/" '(consult-ripgrep :which-key "Search project") ":" '(execute-extended-command :which-key "M-x") ";" '(eval-expression :which-key "Eval") "<" '(consult-buffer :which-key "Buffers (all)") "-" '(dired :which-key "Find Directory") "d" '(docker :which-key "Docker") "i" '(ian/conditional-imenu :which-key "Imenu") "w" '(acewindow :which-key "Window") "W" '(ace-window-manual-dispatch :which-key "Window (dispatch)") ;; Agenda "a" '(:ignore t :which-key "Agenda") "aa" '(org-agenda :which-key "Open Agenda") "a/" '(consult-org-agenda :which-key "Search agenda headlines") "ac" '(:ignore t :which-key "Clock") "acc" '(org-clock-goto :which-key "Active clock") "ack" '(org-clock-cancel :which-key "Cancel current clock") "act" '(+org/toggle-last-clock :which-key "Toggle last clock") ;; Buffers / bookmarks "b" '(:ignore t :which-key "Buffers") "bb" '(consult-bookmark :which-key "Goto Bookmark") ;; consult-bookmark "bk" '(kill-current-buffer :which-key "Kill buffer") "bm" '(bookmark-set :which-key "Set bookmark") "bM" '(bookmark-delete :which-key "Delete bookmark") ;; "bo" '(NEEDS CUSTOM FUNCTION :which-key "Kill other buffers") "br" '(revert-buffer :which-key "Revert buffer") "bR" '(rename-buffer :which-key "Rename buffer") "bz" '(bury-buffer :which-key "Bury buffer") ;; "bZ" '(NEEDS CUSTOM FUNCTION :which-key "Kill buried buffers") "bj" '(+ivy/jump-list :which-key "Jump list") "bu" '(vundo :which-key "Undo history") ;; Code "c" '(:ignore t :which-key "Code") "cc" '(compile :which-key "Compile") "cC" '(recompile :which-key "Recompile") "cd" '(+lookup/definition :which-key "Goto definition") "cr" '(+lookup/references :which-key "Goto references") "ce" '(ian/eval-region-or-buffer :which-key "Eval buffer/region") "cE" '(consult-flymake :which-key "Errors") ;; "cf" '(NOT A COMMAND (re-do) :which-key "Format buffer/region") "ci" '(+lookup/implementations :which-key "Find implementations") "cj" '(lsp-ivy-workspace-symbol :which-key "Goto symbol (curr. workspace)") "cJ" '(lsp-ivy-global-workspace-symbol :which-key "Goto symbol (any workspace)") "ck" '(+lookup/documentation :which-key "Jump to documentation") "cl" '(+default/lsp-command-map :which-key "LSP") "co" '(lsp-organize-imports :which-key "LSP organize imports") "cp" '(completion-at-point :which-key "Completion at point") "cR" '(lsp-rename :which-key "LSP rename") "cs" '(+eval/send-region-to-repl :which-key "Send to repl") "ct" '(+lookup/type-definition :which-key "Find type definition") "cw" '(delete-trailing-whitespace :which-key "Delete trailing whitespace") ;; "cn" '(doom/delete-trailing-newlines :which-key "Delete trailing newlines") "cx" '(+default/diagnostics :which-key "List errors") ;; File "f" '(:ignore t :which-key "File") ;; "fp" '(doom/open-private-config :which-key "Browse private config") "fr" '(projectile-recentf :which-key "Recent files") "fR" '(consult-recent-file :which-key "Recent files") "fc" '(ian/reload-config :which-key "Reload config") ;; "fm" '(doom/move-this-file :which-key "Move/rename file") ;; "fS" '(doom/sudo-find-file :which-key "Sudo find file") ;; "fs" '(doom/sudo-this-file :which-key "Sudo this file") "fy" '(+default/yank-buffer-path :which-key "yank file path") "fY" '(+default/yank-buffer-path-relative-to-project :which-key "Yank file path from project") ;; Git "g" '(:ignore t :which-key "git") "gb" '(magit-branch-checkout :which-key "magit switch branch") "gB" '(magit-blame-addition :which-key "magit blame") "gF" '(magit-fetch :which-key "magit fetch") "gg" '(magit-status :which-key "magit status") "gG" '(magit-status-here :which-key "magit status here") "gL" '(magit-log-buffer-file :which-key "magit buffer log") "gt" '(git-timemachine-toggle :which-key "git time machine") "gd" '(:ignore t :which-key "dispatch") "gdF" '(forge-dispatch :which-key "Forge dispatch") "gdd" '(magit-dispatch :which-key "Magit dispatch") "gdf" '(magit-file-dispatch :which-key "Magit file dispatch") "gf" '(:ignore t :which-key "find") "gfc" '(magit-show-commit :which-key "find commit") "gff" '(magit-find-file :which-key "find file") "gfg" '(magit-find-git-config-file :which-key "find gitconfig file") "gfi" '(forge-visit-issue :which-key "find issue") "gfp" '(forge-visit-pullreq :which-key "find pull request") "gh" '(:ignore t :which-key "hunk") "ghn" '(git-gutter-previous-hunk :which-key "jump to previous hunk") "ghp" '(git-gutter-next-hunk :which-key "jump to next hunk") "ghr" '(git-gutter-revert-hunk :which-key "revert hunk at point") "ghs" '(git-gutter-popup-hunk :which-key "show hunk") "ghS" '(git-gutter-stage-hunk :which-key "stage hunk at point") "gl" '(:ignore t :which-key "list") "gli" '(forge-list-issues :which-key "list issues") "gln" '(forge-list-notifications :which-key "list notifications") "glp" '(forge-list-pullreqs :which-key "list pull requests") "glr" '(forge-list-issues :which-key "list repositories") "gls" '(magit-list-submodules :which-key "list submodules") "go" '(:ignore t :which-key "open") "goI" '(forge-browse-issues :which-key "Browse issues") "goP" '(forge-browse-pullreqs :which-key "Browse pull requests") "goc" '(forge-browse-commit :which-key "Browse commit") "goh" '(+vc/browse-at-remote-homepage :which-key "Browse homepage") "goi" '(forge-browse-issue :which-key "Browse an issue") "goo" '(+vc/browse-at-remote :which-key "Browse file or region") "gop" '(forge-browse-pullreq :which-key "Browse a pull request") "gor" '(forge-browse-remote :which-key "Browse remote") ;; Help "h" '(:ignore t :which-key "help") "h" '(info-emacs-manual :which-key "Emacs manual") "h'" '(describe-char :which-key "Describe character") "ha" '(apropos :which-key "Apropos") "hb" '(embark-bindings :which-key "Describe bindings") "he" '(view-echo-area-messages :which-key "View echo area messages") "hf" '(helpful-function :which-key "Describe function") "hi" '(info :which-key "Info") "hk" '(helpful-key :which-key "Describe key") "hm" '(describe-mode :which-key "Describe mode") "ho" '(helpful-symbol :which-key "Describe symbol") "hp" '(explain-pause-top :which-key "Processes") "hs" '(yas-describe-tables :which-key "Describe symbol") "hv" '(helpful-variable :which-key "Describe variable") "hx" '(helpful-command :which-key "Describe command") "hA" '(apropos-documentation :which-key "Apropos(documentation)") "hF" '(describe-face :which-key "Describe Face") "hM" '(popwin:messages :which-key "View system messages") "hw" '(:ignore t :which-key "which-key") "hwf" '(which-key-show-full-keymap :which-key "Full keymap") "hwi" '(which-key-show-minor-mode-keymap :which-key "Minor mode keymap") "hwk" '(which-key-show-keymap :which-key "Show keymap") "hwm" '(which-key-show-major-mode :which-key "Show major mode") "hwt" '(which-key-show-top-level :which-key "Show top-level") "m" '(:ignore t :which-key "media") "my" '(empv-youtube :which-key "youtube") "mt" '(empv-toggle :which-key "toggle") "mT" '(empv-toggle-video :which-key "toggle-video") "mq" '(empv-exit :which-key "quit") "ms" '(empv-display-current :which-key "show currently playing") "mr" '(:ignore t :which-key "radio") "mrr" '(empv-play-radio :which-key "play") "mrR" '(empv-play-random-channel :which-key "play random") "mrl" '(empv-log-current-radio-song-name :which-key "log song name") "mp" '(:ignore t :which-key "playlist") "mpP" '(empv-playlist :which-key "playlist") "mps" '(empv-playlist-select :which-key "select") "mpn" '(empv-playlist-next :which-key "next") "mpp" '(empv-playlist-prev :which-key "prev") "mpc" '(empv-playlist-clear :which-key "clear") "mpS" '(empv-playlist-shuffle :which-key "shuffle") "mf" '(:ignore t :which-key "file") "mff" '(empv-play-file :which-key "play file") "mfd" '(empv-play-directory :which-key "play directory") "mv" '(:ignore t :which-key "volume") "mvd" '(empv-volume-down :which-key "down") "mvu" '(empv-volume-up :which-key "up") "mc" '(:ignore t :which-key "chapter") "mcp" '(empv-chapter-prev :which-key "prev") "mcn" '(empv-chapter-next :which-key "next") "mcs" '(empv-chapter-select :which-key "select") ;; Notes "nd" '(deft :which-key "Deft") "nt" '(org-todo-list :which-key "Todo list") "nf" '(org-roam-node-find :which-key "Find node") "ng" '(org-roam-ui-open :which-key "Show graph") "nr" '(org-roam-buffer-toggle :which-key "Toggle roam buffer") "nb" '(org-roam-buffer-display-dedicated :which-key "Launch roam buffer") "ns" '(org-roam-db-sync :which-key "Sync database") "nc" '(org-roam-capture :which-key "Capture to node") "ni" '(org-roam-node-insert :which-key "Insert node at point") ;; Org mode "o" '(:ignore t :which-key "org") "ol" '(org-store-link :which-key "Store link") "oC" '(org-capture-goto-target :which-key "Goto Capture") "oo" '(org-open-at-point :which-key "Open link") "ot" '(org-babel-tangle :which-key "Tangle") "oy" '(+org/export-to-clipboard :which-key "Export to clipboard") "oY" '(+org/export-to-clipboard-as-rich-text :which-key "Export to clipboard (rich)") "oc" '(:ignore t :which-key "Capture") "ocn" '(ian/capture-to-notes-org :which-key "Capture to local notes") "oct" '(ian/capture-to-todo-org :which-key "Capture to local todo") "oe" '(:ignore t :which-key "export") "oeh" '(org-html-export-to-html :which-key "Export Org to HTML") "oa" '(:ignore t :which-key "attach") "oaa" '(org-attach :which-key "Attach") "oac" '(org-download-clipboard :which-key "Org download clipboard") "oad" '(org-attach-delete-one :which-key "Delete one attachment") "oaD" '(org-attach-delete-all :which-key "Delete all attachments") "oas" '(org-attach-sync :which-key "Sync attachments") "oay" '(org-download-yank :which-key "Org download yank") ;; Project "p" '(:ignore t :which-key "project") "ps" '(+neotree/open :which-key "Open project sidebar") "pa" '(projectile-add-known-project :which-key "Add new project") "pc" '(+ivy/project-compile :which-key "Compile in project") "pd" '(projectile-remove-known-project :which-key "Remove known project") "ps" '(projectile-switch-project :which-key "Switch projects") "pC" '(projectile-configure-project :which-key "Configure project") "pr" '(projectile-run-project :which-key "Run project") "pt" '(magit-todos-list :which-key "List project todos") "pT" '(projectile-test-project :which-key "Test project") "pz" '(+taskrunner/project-tasks :which-key "List project tasks") ;; Reference buffers "r" '(:ignore t :which-key "reference buffers") "rs" '(scratch-buffer :which-key "Scratch") "rm" '(view-echo-area-messages :which-key "Messages") "rc" '(view-lossage :which-key "Commands History") "rn" '((lambda () (interactive) (ian/open-from-project-root "notes.org")) :which-key "Notes") "rt" '((lambda () (interactive) (ian/open-from-project-root "todo.org")) :which-key "Todo") "rl" '((lambda () (interactive) (find-file "~/notes/work/time.org")) :which-key "Time Log") ;; Shell "s" '(:ignore t :which-key "shell") "se" '(+eshell/toggle :which-key "Toggle eshell popup") "sE" '(+eshell/here :which-key "Open eshell here") "sr" '(+eval/open-repl-other-window :which-key "Repl") "st" '(+vterm/toggle :which-key "Toggle vterm popup") "sT" '(+vterm/here :which-key "Open vterm here") ;; Toggle "t" '(:ignore t :which-key "toggle") "tc" '(global-display-fill-column-indicator-mode :which-key "Fill Column Indicator") "tf" '(flycheck-mode :which-key "Flycheck") "tm" '(consult-minor-mode-menu :which-key "Minor modes") "tp" '(org-tree-slide-mode :which-key "Org-tree-slide-mode") "tw" '(+word-wrap-mode :which-key "Soft line wrapping") "tz" '(+zen/toggle :which-key "Zen mode") ;; "tl" '(doom/toggle-line-numbers :which-key "Line numbers") ;; Visual / appearance "v" '(:ignore t :which-key "visual/appearance") "vt" '(load-theme :which-key "load theme") ;; TODO: maybe make this mode-specific stuff, not using workspaces ;; Workspaces ;; "TAB TAB" '(+workspace/display :which-key "Display tab bar") ;; "TAB d" '(+workspace/delete :which-key "Delete this workspace") ;; "TAB l" '(+workspace/load :which-key "Load workspace from file") ;; "TAB n" '(+workspace/new :which-key "New workspace") ;; "TAB N" '(+workspace/new-named :which-key "New named workspace") ;; "TAB r" '(+workspace/rename :which-key "Rename workspace") ;; "TAB R" '(+workspace/restore-last-session :which-key "Restore last session") ;; "TAB s" '(+workspace/save :which-key "Save workspace") ;; "TAB x" '(+workspace/kill-session :which-key "Delete session") )) #+end_src * Notes #+begin_src emacs-lisp (use-package deft) (setq deft-recursive t deft-extensions '("org" "txt")) #+end_src * AI #+begin_src emacs-lisp (use-package gptel) (setq gptl-default-mode 'org-mode) #+end_src * Org Mode #+begin_src emacs-lisp (use-package org) (add-hook 'org-mode-hook 'yas-minor-mode) (org-babel-do-load-languages 'org-babel-load-languages '((emacs-lisp . t) (python . t))) (setq org-confirm-babel-evaluate nil) (require 'org-tempo) (add-to-list 'org-structure-template-alist '("sh" . "src shell")) (add-to-list 'org-structure-template-alist '("el" . "src emacs-lisp")) (add-to-list 'org-structure-template-alist '("py" . "src python")) (setq org-hide-emphasis-markers t) (use-package org-appear :hook (org-mode . org-appear-mode)) (use-package org-roam :custom (org-roam-directory "~/notes/roam") :config (org-roam-db-autosync-mode) (setq org-link-frame-setup '((file . find-file)))) (use-package deft :commands (deft) :config (setq deft-directory "~/notes/deft" deft-extensions '("org" "txt") deft-recursive t)) (use-package ox-hugo :after ox) (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)) (use-package ox-gfm) ; github-flavored-markdown exporter (use-package org-download) #+end_src ** Agenda #+begin_src emacs-lisp (setq org-agenda-start-with-log-mode t) (setq org-agenda-files '("~/notes/deft/tasks.org" "~/notes/roam/daily")) (setq org-agenda-span 10) (setq org-todo-keywords '((sequence "TODO(t)" "NEXT(n)" "EVENT(e)" "|" "DONE(d!)" "CANCELLED(c@)"))) #+end_src ** Capture templates #+begin_src emacs-lisp (defun ian/capture-to-notes-org () "Capture the current region (if selected) or a link to the point into 'notes.org' at the top of the Projectile project directory." (interactive) (let* ((selected-text (if (use-region-p) (buffer-substring-no-properties (mark) (point)) nil)) (file-path (buffer-file-name)) (project-root (projectile-project-root)) (notes-file (expand-file-name "notes.org" project-root)) (link (format "[[file:%s::%d][Link to %s::%d]]\n\n" file-path (line-number-at-pos) (file-name-nondirectory file-path) (line-number-at-pos))) (template (if selected-text (concat "* %?\n:PROPERTIES:\n:CAPTURED: %U\n:END:\n#+BEGIN_SRC\n" selected-text "\n#+END_SRC\n\n" link) (concat "* %?\n:PROPERTIES:\n:CAPTURED: %U\n:END:\n" link))) (org-capture-entry `("r" "Capture" entry (file ,notes-file) ,template))) (org-capture nil "r") (with-current-buffer (find-file-noselect notes-file) (save-buffer)))) (defun ian/capture-to-todo-org () "Capture the current region (if selected) or a link to the point into 'todo.org' at the top of the Projectile project directory." (interactive) (let* ((selected-text (if (use-region-p) (buffer-substring-no-properties (mark) (point)) nil)) (file-path (buffer-file-name)) (project-root (projectile-project-root)) (notes-file (expand-file-name "todo.org" project-root)) (link (format "[[file:%s::%d][Link to %s::%d]]\n\n" file-path (line-number-at-pos) (file-name-nondirectory file-path) (line-number-at-pos))) (template (if selected-text (concat "* %?\n:PROPERTIES:\n:CAPTURED: %U\n:END:\n#+BEGIN_SRC\n" selected-text "\n#+END_SRC\n\n" link) (concat "* %?\n:PROPERTIES:\n:CAPTURED: %U\n:END:\n" link))) (org-capture-entry `("r" "Capture" entry (file ,notes-file) ,template))) (org-capture nil "r") (with-current-buffer (find-file-noselect notes-file) (save-buffer)))) (defun checklist-daily-capture () "Generates daily checklist content." (concat "* Daily Checklist\n" "- [ ] Brush teeth\n" "- [ ] Stretch\n" "- [ ] Clean 20m\n")) (defun weekday-specific-daily-capture (day-of-week) "Generate checklist content which is specific to the weekday" (cond ((string= day-of-week "Monday") (concat "")) ((string= day-of-week "Tuesday") (concat "* Tuesday Checklist\n" "- [ ] Rollout trash\n")) ((string= day-of-week "Thursday") (concat "- [ ] Water Houseplants\n")) ((string= day-of-week "Friday") (concat "")) ((string= day-of-week "Saturday") (concat "")) ((string= day-of-week "Sunday") (concat "* Sunday Checklist\n" "- [ ] Start Sourdough\n")) )) (defun workout-daily-capture (day-of-week) "Generate workout table content based on DAY-OF-WEEK." (concat "* Workout\n" "| Exercise | Weight | Sets | Reps | Notes |\n" "|----------+--------+------+------+-------|\n" (cond ((string= day-of-week "Monday") (concat "| VSQ | | | | |\n" "| CGB | | | | |\n" "| BTN | | | | |\n" "| OHP | | | | |\n" "| SC | | | | |\n")) ((string= day-of-week "Tuesday") (concat "| RDL | | | | |\n" "| ROW | | | | |\n" "| WCHP | | | | |\n" "| CU | | | | |\n")) ((string= day-of-week "Thursday") (concat "| BP | | | | |\n" "| JMP | | | | |\n" "| SQ | | | | |\n" "| SC | | | | |\n")) ((string= day-of-week "Friday") (concat "| DL | | | | |\n" "| WPU | | | | |\n" "| CU | | | | |\n")) (t "Rest Day\n")))) (defun diet-daily-capture () "Capture for calorie tracking" (concat "* Diet\n" "- Weight :: \n" "| Food | Calories | Total |\n" "|------|----------|-------|\n" "| | | |\n")) (defun spending-daily-capture () "Capture for spending" (concat "* Spending\n" "| Expense | Price | Total |\n" "|---------|-------|-------|\n" "| | | |\n")) (setq org-roam-dailies-capture-templates `(("d" "Daily Routine" entry ,(concat "* Scheduled Today\n\n" "%(weekday-specific-daily-capture \"%<%A>\")\n" "%(checklist-daily-capture)\n" "%(workout-daily-capture \"%<%A>\")\n" "%(diet-daily-capture)\n" "%(spending-daily-capture)\n") :target (file+head "%<%Y-%m-%d>.org" "#+title: %<%Y-%m-%d>\n")))) #+end_src #+RESULTS: | d | Daily Routine | entry | * Scheduled Today | * Project management #+begin_src emacs-lisp (use-package projectile) ; todo config inside use-package (use-package treemacs-projectile) #+end_src * Autocomplete ** Vertico #+begin_src emacs-lisp (use-package vertico :init (vertico-mode) ) #+end_src ** Consult #+begin_src emacs-lisp (use-package consult :bind (:map minibuffer-local-map ("C-r" . consult-history))) (setq consult-ripgrep-args "rg --null --line-buffered --color=never --max-columns=1000 --path-separator / --smart-case --no-heading --with-filename --line-number --search-zip --hidden") #+end_src ** Generic completion Idk I think this came from the vertico readme #+begin_src emacs-lisp (use-package emacs :init ;; Add prompt indicator to `completing-read-multiple'. ;; We display [CRM], e.g., [CRM,] if the separator is a comma. (defun crm-indicator (args) (cons (format "[CRM%s] %s" (replace-regexp-in-string "\\`\\[.*?]\\*\\|\\[.*?]\\*\\'" "" crm-separator) (car args)) (cdr args))) (advice-add #'completing-read-multiple :filter-args #'crm-indicator) ;; Do not allow the cursor in the minibuffer prompt (setq minibuffer-prompt-properties '(read-only t cursor-intangible t face minibuffer-prompt)) (add-hook 'minibuffer-setup-hook #'cursor-intangible-mode) (setq enable-recursive-minibuffers t)) (setq completion-styles '(basic substring partial-completion flex)) #+end_src ** Orderless #+begin_src emacs-lisp (use-package orderless :init (setq completion-styles '(orderless basic) completion-category-defaults nil completion-category-overrides '((file (styles partial-completion))))) #+end_src ** Marginalia #+begin_src emacs-lisp (use-package marginalia :bind (:map minibuffer-local-map ("M-A" . marginalia-cycle)) :init (marginalia-mode)) #+end_src ** Company-mode #+begin_src emacs-lisp (use-package company :ensure t :hook (prog-mode . company-mode) :diminish :bind (:map company-active-map ("" . company-select-next) ("TAB" . company-select-next) ("" . company-select-previous) ("" . company-select-previous)) (:map lsp-mode-map ; more general mode than this? ("" . company-indent-or-complete-common)) :config (global-company-mode 1) :init (setq company-idle-delay nil)) #+end_src ** Embark #+begin_src emacs-lisp (use-package embark :ensure t :after evil evil-collection evil-org :diminish eldoc-mode :bind (("C-." . embark-act) ;; pick some comfortable binding ("C-;" . embark-dwim) ;; good alternative: M-. ("C-h B" . embark-bindings)) ;; alternative for `describe-bindings' :init ;; Show the Embark target at point via Eldoc. You may adjust the Eldoc ;; strategy, if you want to see the documentation from multiple providers. ;; (add-hook 'eldoc-documentation-functions #'embark-eldoc-first-target) (define-key evil-normal-state-map (kbd "C-.") 'embark-act) (evil-define-key 'normal evil-normal-state-map (kbd "C-.") embark-act) :config ;; Hide the mode line of the Embark live/completions buffers (add-to-list 'display-buffer-alist '("\\`\\*Embark Collect \\(Live\\|Completions\\)\\*" nil (window-parameters (mode-line-format . none))))) ;; Consult users will also want the embark-consult package. (use-package embark-consult :ensure t ; only need to install it, embark loads it after consult if found :hook (embark-collect-mode . consult-preview-at-point-mode)) ;; https://github.com/oantolin/embark/wiki/Additional-Configuration#use-which-key-like-a-key-menu-prompt (defun embark-which-key-indicator () "An embark indicator that displays keymaps using which-key. The which-key help message will show the type and value of the current target followed by an ellipsis if there are further targets." (lambda (&optional keymap targets prefix) (if (null keymap) (which-key--hide-popup-ignore-command) (which-key--show-keymap (if (eq (plist-get (car targets) :type) 'embark-become) "Become" (format "Act on %s '%s'%s" (plist-get (car targets) :type) (embark--truncate-target (plist-get (car targets) :target)) (if (cdr targets) "…" ""))) (if prefix (pcase (lookup-key keymap prefix 'accept-default) ((and (pred keymapp) km) km) (_ (key-binding prefix 'accept-default))) keymap) nil nil t (lambda (binding) (not (string-suffix-p "-argument" (cdr binding)))))))) (setq embark-indicators '(embark-which-key-indicator embark-highlight-indicator embark-isearch-highlight-indicator)) (defun embark-hide-which-key-indicator (fn &rest args) "Hide the which-key indicator immediately when using the completing-read prompter." (which-key--hide-popup-ignore-command) (let ((embark-indicators (remq #'embark-which-key-indicator embark-indicators))) (apply fn args))) (advice-add #'embark-completing-read-prompter :around #'embark-hide-which-key-indicator) #+end_src #+RESULTS: ** Snippets #+begin_src emacs-lisp (use-package yasnippet :diminish yas-minor-mode) (use-package yasnippet-snippets :after lsp-mode) (yas-global-mode) #+end_src * Languages ** LSP #+begin_src emacs-lisp (use-package lsp-mode :commands (lsp lsp-deferred) :init (setq lsp-keymap-prefix "C-c l") :config (lsp-enable-which-key-integration t) (setq lsp-headerline-breadcrumb-enable nil) :hook (terraform-mode . lsp-deferred) :hook (rust-mode . lsp-deferred)) (use-package lsp-ui) (use-package lsp-treemacs) (use-package flycheck :ensure t :diminish :init (global-flycheck-mode)) #+end_src ** Rust #+begin_src emacs-lisp (use-package rust-mode :ensure t :mode "\\.rs\\'" :config (setq rust-format-on-save t)) (use-package cargo :ensure t :hook (rust-mode . cargo-minor-mode)) #+end_src ** Terraform #+begin_src emacs-lisp (use-package terraform-mode :ensure t) #+end_src ** Lisp All lisp-family languages #+begin_src emacs-lisp (use-package lispy) (use-package lispyville :init (general-add-hook '(emacs-lisp-mode-hook lisp-mode-hook) #'lispyville-mode) :config (lispyville-set-key-theme '(operators c-w additional))) #+end_src ** Go #+begin_src emacs-lisp (use-package go-mode) (add-hook 'go-mode-hook 'lsp-deferred) #+end_src * Markups ** Markdown #+begin_src emacs-lisp (use-package markdown-mode) (use-package evil-markdown :after evil :straight (evil-markdown :type git :host github :repo "somelauw/evil-markdown") :mode ("\\.md\\'" . evil-markdown-mode)) (use-package json-mode) (use-package yaml-mode) #+end_src ** Beancount This is mostly lifted from the doom emacs config. Beancount-mode by default has a pretty borked tab function. #+begin_src emacs-lisp (defun beancount-tab-function () "Improved beancount tab ripped off from doom emacs" (interactive) (if (and outline-minor-mode (outline-on-heading-p)) (beancount-outline-cycle) (indent-according-to-mode))) (use-package beancount :straight (beancount :type git :host github :repo "beancount/beancount-mode") :mode ("\\.beancount\\'" . beancount-mode) :hook (beancount-mode . outline-minor-mode) :config (evil-define-key 'normal 'beancount-mode-map (kbd "TAB") 'beancount-tab-function)) ;; Bind the TAB key (add-hook 'beancount-mode-hook #'flymake-bean-check-enable) #+end_src ** Epub #+begin_src emacs-lisp (use-package nov :after evil evil-collection :config ;; (define-key nov-button-map (kbd "SPC") nil) ;; (evil-define-key 'normal nov-mode-map (kbd "SPC") nil) ;; (evil-define-key 'normal nov-button-map (kbd "SPC") nil) ;; (define-key nov-mode-map (kbd "SPC") nil) (setq nov-text-width 80)) (add-to-list 'auto-mode-alist '("\\.epub\\'" . nov-mode)) #+end_src * Containers ** Docker #+begin_src emacs-lisp (use-package dockerfile-mode) (use-package docker-compose-mode) ;; (use-package docker) ;; Todo: lsp-docker? docker-tramp? docker-cli? #+end_src ** Kubernetes #+begin_src emacs-lisp (use-package k8s-mode) ;; kubernetes ;; kubernetes-evil ;; kubernetes-helm ;; kubernetes-tramp #+end_src * Shells ** Enable fish completions Uses the external fish program to provide fish-style completions to eshell etc #+begin_src emacs-lisp (use-package fish-completion) (when (and (executable-find "fish") (require 'fish-completion nil t)) (global-fish-completion-mode)) #+end_src * Git #+begin_src emacs-lisp (use-package magit) (use-package magit-todos) (use-package git-gutter :diminish) (global-git-gutter-mode t) (setq magit-display-buffer-function 'magit-display-buffer-same-window-except-diff-v1) (use-package git-timemachine) #+end_src * Web browsing and youtube #+begin_src emacs-lisp ;; Using straight: ;;(use-package empv ;; :straight (:host github :repo "isamert/empv.el")) (use-package empv) (setq empv-radio-channels '(("SomaFM - Groove Salad" . "http://www.somafm.com/groovesalad.pls") ("SomaFM - Drone Zone" . "http://www.somafm.com/dronezone.pls") ("SomaFM - Sonic Universe" . "https://somafm.com/sonicuniverse.pls") ("SomaFM - Metal" . "https://somafm.com/metal.pls") ("SomaFM - Vaporwaves" . "https://somafm.com/vaporwaves.pls") ("ADHD 1" . "https://www.youtube.com/watch?v=CmMrm4BpQHU") ("WREK FM" . "http://streaming.wrek.org:8000/wrek_live-128kb.m3u") )) (with-eval-after-load 'embark (empv-embark-initialize-extra-actions)) (add-to-list 'empv-mpv-args "--ytdl-format=best") (add-to-list 'empv-mpv-args "--save-position-on-quit") (add-hook 'empv-init-hook #'empv-override-quit-key) (setq empv-invidious-instance "https://invidious.projectsegfau.lt/api/v1") #+end_src * Email, rss, newsgroups Oh, boy. Here we go. [[https://www.gnu.org/software/emacs/manual/html_node/auth][This]] will come in handy. (=TODO=: smtp header) #+begin_src emacs-lisp (setq user-mail-address "ian@keane.sh" user-full-name "Ian Keane") ;; Assuming your passwords are stored in Password Store with names like: ;; "email/fastmail" and "email/gmail" ;; IMAP configuration for Fastmail (setq gnus-select-method '(nnimap "Fastmail-emacs" (nnimap-user "ian@keane.sh") (nnimap-address "imap.fastmail.com") (nnimap-server-port 993) (nnimap-stream ssl))) ;; Additional secondary IMAP account for Gmail ;; (add-to-list 'gnus-secondary-select-methods ;; '(nnimap "Gmail" ;; (nnimap-address "imap.gmail.com") ;; (nnimap-server-port 993) ;; (nnimap-stream ssl) ;; (nnimap-authinfo-file nil) ; Not using .authinfo for Gmail ;; (nnir-search-engine imap) ;; (nnimap-authenticator login) ;; (nnimap-login "your-gmail-username") ; Replace with your Gmail username ;; (nnimap-password (password-store-get "email/gmail")))) (setq send-mail-function 'smtpmail-send-it message-send-mail-function 'smtpmail-send-it smtpmail-default-smtp-server "smtp.fastmail.com" smtpmail-smtp-server "smtp.fastmail.com" smtpmail-smtp-service 587 smtpmail-stream-type 'starttls smtpmail-smtp-user "ian@keane.sh" smtpmail-debug-info t) ;; You may also want to add a conditional to choose the SMTP server based on the current 'From' address. ;; RSS Feeds ;; (add-to-list 'gnus-secondary-select-methods '(nnrss "")) ;; Configure RSS feed subscriptions ;; (setq gnus-secondary-sources ;; '((nnrss "http://example.com/rss") ; replace with actual RSS URL ;; ;; Add more RSS feeds here ;; )) ;; Use Gnus for composing email (setq mail-user-agent 'gnus-user-agent) ;; Set up HTML email rendering (setq mm-text-html-renderer 'shr) (require 'all-the-icons-gnus) (all-the-icons-gnus-setup) #+end_src * Emacs Meta ** Explain-Pause Scrutinize which processes are gumming up emacs #+begin_src emacs-lisp ;; (use-package explain-pause-mode ;; :straight (explain-pause-mode :type git :host github :repo "lastquestion/explain-pause-mode") ;; :diminish explain-pause-mode ;; :config ;; (explain-pause-mode)) #+end_src * Todo ** General - Refactor to use use-package more effectively - Use :mode and :config like [[https://ianyepan.github.io/posts/setting-up-use-package/][here]] - Set things which should be set before package install in :init - Disable source editing issue - Goes away when I run =(defun org-edit-src-code nil)= - Go through AWB's notes about using gnus - TODO aggregation - Suppress evilmarkdown mode and org-roam-ui minor mode ** Terminals - More terminals - emacs-fish-completions - setup terminals to complete to vertico - starship prompts ** New functions - Git-time-machine-or-vc-region-history ** Note taking - deft - org : roam2, hugo, pretty, dragndrop, bullet - meetlog reference buffer - work roam directory - [[https://www.youtube.com/watch?v=3-sLBaJAtew][Dalies]] for scheduling things - Fix org indentation stuff ** Lisp stuff - paredit - lispy - no tabs for yaml-mode (wtf?) ** One-offs - 'ex' snippet for the most common example of a thing I do per filetype - docker-compose example - hl-todo - persistent undo - commentary - highlight tabs and newlines - [[https://youtu.be/UtqE-lR2HCA?t=5027][Vertico backwards delete]] - alphabetical keybindings - brighter modeline - surpress global minor modes - Undo-Tree, company, flycheck, which-key - ignore case in imenu - improve which-key visibility - gpt popup - org-roam-buffer popup - conflicts with global popup buffers - init popup buffer binding? spc r i? - org-roam buffer in popup (follow) - [[https://old.reddit.com/r/emacs/comments/o04it0/share_your_prettifysymbolsalist/][prettify-symbols-mode]] - create 'context' keybinding - map smerge mode ** Embark - open file in other window ** NFS stuff - map music from nfs - map books from nfs with nov.el ** LSP stuff - look into treemacs integrations - consider eglot - dap-mode ** Completion - dabbrev-expand or company on c-n c-p - c-N c-P for expand full line - yasnippet - company-mode to corfu (or vertico completions? or cofu-in-vertico?) - get vertico as completion box ** Keybindings - bind (custom?) git-view-from-other-branch - want to be able to view a file as it is in another branch - bind (custom?) git diff from other branch - bind capture to init todo - bind capture to project todo - bind org-set-property - treemacs-open-other-window - treemacs | to open in split - create-tab-with-name function - buffer to spc b b local, spc b B global - do somthing useful with ',' - custom function for toggle between last 2 windows - custom function to scroll-other-window using last 2 windows - evil-define-key instead of define-key everywhere - bind something to create file in dired / treemacs - fix general prefix in treemacs mode - fix vim-surround - snippets help =spc h y=, helpful-symbol =spc h s= - put general bindings in separate keymaps in separate sections - map hyper bindings for buffer nav and jumping - evil-org - map alignment functions in 'code'section - fix c-u in evil mode - fix tab key - window size functions, winner undo/redo - map default-text-scale operations - org-capture from string and org-ripgrep - move spc p s back to spc p p - org eval block - explain-pause spc h p - Want this for org-roam, don't want to rebind tab here - empv - map - configure - empv-radio-log-file - empv-radio-log-format - spc m y(outube) - spc m l(ocal) - spc m r(adio) - empv-video-dir empv-audio-dir? - empv-play-file - Set display-buffer-alist values for how I want windows treated (integrates with popper), e.g. #+begin_src emacs-lisp :tangle no (add-to-list 'display-buffer-alist '("\\*ielm\\*" (display-buffer-in-side-window) (side . left) (window-width . 50))) #+end_src selected radio (See empv-radio-log-file and empv-radio-log-format variables and their documentations). ** New plugins - tramp - k8s - docker - terraform - straight? - embark? - emms, emms-play-url binding (youtube view) - [[https://youtu.be/UtqE-lR2HCA?t=5134][consult-lsp]] (better for errors than treemacs integrations probably) - srht.el - affe - gnus ** Appearance switches - fonts - random theme - org mode bullets / pretty / etc ** Research - What does C-d do when in a minibuffer for vertico? - embark - ace-window / embark integration ** System crafters videos - [[https://www.youtube.com/watch?v=CUkuyW6hr18][5 Hacks to improve org roam]] - [[https://www.youtube.com/watch?v=C1kwStlEick][Improving the IRC experience]] - [[https://www.youtube.com/watch?v=J0OaRy85MOo][Streamlined completions with vertico]] - [[https://www.youtube.com/watch?v=XZjyJG-sFZI][Keeping your folders clean while using emacs]] - [[https://www.youtube.com/watch?v=zMzkorlfqLA][Static site generator from org mode]] - [[https://www.youtube.com/watch?v=za99DwdZEyg][Automated website publishing w/ org and sourcehut]] - [[https://www.youtube.com/watch?v=SCPoF1PTZpI][Emacs presentations]] - [[https://www.youtube.com/watch?v=0C16LLHGYzk&t=1882s][Converting a literate config to guix home]] - [[https://www.youtube.com/playlist?list=PLEoMzSkcN8oM-kA19xOQc8s0gr0PpFGJQ][Emacs mail playlist]] - [[https://www.youtube.com/watch?v=qk2Is_sC8Lk][Embark]] ** Annoyances - set require-final-newline = nil - fix gitgutter behavior - remove extra line file modifying behavior - fix missing snippets in note-taking mode - always open treemacs from most recent window - prevent :wq from killing frame *** Ediff - vertical - no new frame - bind magit-ediff-compare #+begin_src emacs-lisp (setq ediff-window-setup-function #'ediff-setup-windows-plain) #+end_src - bind ediff two files - fix fuzzy searching for functions - bind =SPC -= to dired-jump - fix markdown-mode (doesn't start with .md files automatically) - bind magit-log-buffer-file (handles selection-based history) - adaptive wrap (plus fix visual-line-mode to always load) - [[https://elpa.gnu.org/packages/adaptive-wrap.html]] - install / configure consult-org-roam - map default-text-scale-increase/decrease (better than regular text scaling) - set default-text-scale-amount to 5 instead of 10 - map outline-toggle-children in tf mode - map ripgrep in parent dir - map ripgrep in (dired select) - add .git to ripgrep ignore - fix vterm - make the popup frame-wide - fix spc v t - maybe just make spc tab open shell and exclude it from ace managed windows - make eshell pretty - when toggling shell, enter insert mode - migrate to wezterm, impelement popup term - look into letting org fold blocks or folding bracket blocks in general cases - try (add-hook 'magit-post-refresh-hook 'git-gutter:refresh) - make treemacs enter always open in most recent buffer - add meeting log to reference reaches - install ini-mode plugin - install lua-mode plugin - install fish-mode plugin