#+PROPERTY: header-args:emacs-lisp :tangle (if (eq system-type 'darwin) "~/dotfiles/guix/init.el" "~/.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/guix/init.org")) (let ((org-confirm-babel-evaluate nil)) (org-babel-tangle)))) (add-hook 'org-mode-hook (lambda () (add-hook 'after-save-hook #'dotfiles/org-babel-tangle-config))) #+end_src ** 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) #+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 "~/.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))) #+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)) #+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") ;; (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/guix/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)) (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 #+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 * 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 ** 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) (use-package dired-single) (defun my-dired-init () "Bunch of stuff to run for dired, either immediately or when it's loaded." (define-key dired-mode-map [remap dired-find-file] 'dired-single-buffer) (define-key dired-mode-map [remap dired-mouse-find-file-other-window] 'dired-single-buffer-mouse) (define-key dired-mode-map [remap dired-up-directory] 'dired-single-up-directory)) ;; 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")))) (use-package all-the-icons-dired :hook (dired-mode . all-the-icons-dired-mode)) #+end_src ** Treemacs #+begin_src emacs-lisp (use-package treemacs) ;; 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) #+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 :config (general-create-definer general-definition :keymaps '(normal insert visual emacs) :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") "," '(prochectile-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)") "x" '(scratch-buffer :which-key "Scratch popup") "-" '(dired :which-key "Find Directory") "d" '(docker :which-key "Docker") "i" '(ian/conditional-imenu :which-key "Imenu") "w" '(ace-window :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" '(consult-recent-file :which-key "Recent files") "fR" '(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") "hl" '(view-lossage :which-key "View actions log") "hm" '(describe-mode :which-key "Describe mode") "ho" '(helpful-symbol :which-key "Describe symbol") "hp" '(explain-pause-top :which-key "Processes") "hs" '(yas-desrcibe-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-insert :which-key "Insert node at point") ;; Org mode "o" '(:ignore t :which-key "org") "ol" '(org-store-link :which-key "Org store link") "oc" '(org-capture :which-key "Org Capture") "oC" '(org-capture-goto-target :which-key "Goto Capture") "ot" '(org-babel-tangle :which-key "Org Tangle") "oy" '(+org/export-to-clipboard :which-key "Org export to clipboard") "oY" '(+org/export-to-clipboard-as-rich-text :which-key "Org export to clipboard (rich)") "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") ;; 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)) (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 #+end_src * 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))) #+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 :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) :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)) #+end_src ** 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) :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 * 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 * 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 git-gutter+ :diminish) (global-git-gutter+-mode t) (use-package magit) (use-package magit-todos) (setq magit-display-buffer-function 'magit-display-buffer-same-window-except-diff-v1) #+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) (evil-mode 1)) (use-package undo-tree :ensure t :after evil :diminish :config (evil-set-undo-system 'undo-tree) (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 * 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 * 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") :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)= ** 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 ** Lisp stuff - paredit - lispy ** One-offs - 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 ** 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 - 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 - 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 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]] ** Clean up Org Roam - Major mode notes master node ** Create yasnippets repo as per [[https://github.com/joaotavora/yasnippet#where-are-the-snippets][The docs]]