#+title Ian's Emacs Config #+PROPERTY: header-args:emacs-lisp :tangle (if (eq system-type 'darwin) "~/dotfiles/guix/init.el" "~/.config/emacs/init.el") * 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 #+begin_src emacs-lisp ;; Initialize Package Sources (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) ;; Persist history over Emacs restarts. Vertico sorts by history position. (use-package savehist :init (savehist-mode)) #+end_src ** Environment-specific setup #+begin_src emacs-lisp (setq IS-MACOS (eq system-type 'darwin)) (setq openai-key-string (if IS-MACOS "self/openai-alt" "openai-alt")) #+end_src ** Secrets #+begin_src emacs-lisp (use-package pinentry :ensure t) (use-package pass :ensure t) (use-package password-store) (pinentry-start) (setq gptel-api-key (password-store-get openai-key-string)) ;; TODO if-macos #+end_src ** Global variables ** Handle config file #+begin_src emacs-lisp (setq user-init-file (expand-file-name "~/.config/emacs/init.el")) (defun reload-config () "Reload the Emacs configuration." (interactive) (load-file user-init-file)) #+end_src ** Required directories for emacs setup #+begin_src emacs-lisp (defun ensure-directory (dir) "Ceate a dir if it doesn't exist." (unless (file-directory-p dir) (make-directory dir t))) (ensure-directory "~/.config/emacs/backups/") (ensure-directory "~/.config/emacs/autosaves") (ensure-directory "~/notes/roam") (ensure-directory "~/notes/deft") (ensure-directory "~/notes/code") (ensure-directory "~/.config/emacs/video") (ensure-directory "~/.config/emacs/audio") (setq deft-directory "~/notes/deft" org-roam-directory "~/notes/roam" 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 custom/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 custom/conditional-imenu () "Call `consult-org-heading` in Org mode, otherwise `consult-imenu`." (interactive) (if (eq major-mode 'org-mode) (consult-org-heading) (consult-imenu))) #+end_src * One-Line Includes #+begin_src emacs-lisp (use-package treemacs) #+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")) (use-package org-make-toc :hook (org-mode . org-make-toc-mode)) (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)) #+end_src * Basic Appearance and Behaviors #+begin_src emacs-lisp (setq inhibit-startup-message t) (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 ;; 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 solaire-mode :config (solaire-global-mode +1)) (use-package doom-themes :ensure t :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-one t) ;; 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 14") (use-package simple-modeline :hook (after-init . simple-modeline-mode)) (use-package base16-theme) (load-theme 'base16-oceanicnext t) (global-display-line-numbers-mode t) (dolist (mode '(org-mode-hook term-mode-hook eshell-mode-hook)) (add-hook mode (lambda () (display-line-numbers-mode 0)))) (column-number-mode) (use-package default-text-scale :defer 1 :config (default-text-scale-mode)) (use-package rainbow-delimiters :hook (prog-mode . rainbow-delimiters-mode)) (use-package helpful) ; Slightly more helpful help (setq tab-always-indent 'complete) (setq tab-first-completion 'word) ;; Generate buffers in last window (setq display-buffer-base-action '(display-buffer-reuse-mode-window display-buffer-reuse-window display-buffer-same-window)) ;; If a popup does happen, don't resize windows to be equal-sized (setq even-window-sizes 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 ** Direct keymaps #+begin_src emacs-lisp ;; (global-set-key (kbd "s-c") 'delete-window) ;; (global-set-key (kbd "s-h") 'windmove-left) ;; (global-set-key (kbd "s-j") 'windmove-down) ;; (global-set-key (kbd "s-k") 'windmove-up) ;; (global-set-key (kbd "s-l") 'windmove-right) ; (define-key evil-normal-state-map (kbd "s-d") 'kill-this-buffer) ; (define-key evil-normal-state-map (kbd "s-n") 'projectile-next-project-buffer) ; (define-key evil-normal-state-map (kbd "s-p") 'projectile-previous-project-buffer) ; (define-key evil-normal-state-map (kbd "s-J") 'split-and-follow-horizontally) ; (define-key evil-normal-state-map (kbd "s-L") 'split-and-follow-vertically) ; (define-key evil-normal-state-map (kbd "s-b") 'buffer-menu) ; (define-key evil-normal-state-map (kbd "s-x") 'execute-extended-command) ;; (global-set-key (kbd "s-SPC") 'tab-next) (global-set-key (kbd "") 'keyboard-escape-quit) (use-package winner :after evil :config (winner-mode)) #+end_src ** Windows and Workspaces #+begin_src emacs-lisp (use-package persp-mode :diminish persp-mode) (unless (equal persp-mode t) (persp-mode)) (use-package ace-window) (setq aw-keys '(?a ?s ?d ?f ?g ?h ?j ?k ?l)) (defvar 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) ;;(?u aw-switch-buffer-other-window "Switch Buffer Other Window") (?u aw-switch-buffer-other-window 'winner-undo) (?U aw-switch-buffer-other-window 'winner-redo) (?c aw-split-window-fair "Split Fair Window") (?v aw-split-window-vert "Split Vert Window") (?b aw-split-window-horz "Split Horz Window") (?o delete-other-windows "Delete Other Windows") (?? aw-show-dispatch-help)) "List of actions for `aw-dispatch-default'.") ;; TODO: maybe put workspace controls in aw-dispatch? #+end_src ** Dired #+begin_src emacs-lisp (setq ring-bell-function 'ignore) (setq dired-listing-switches "-al") (setq dired-dwim-target t) ; opening 'other window' on a subdir enters 2 window dired mode for copy/paste (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) ;; we're good to go; just add our bindings (my-dired-init) ;; it's not loaded yet, so add our bindings to the load-hook (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 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 - map spc W for split and winner-undo / redo operations on 2 windows - bind persp-mode - bind lispy for colemak-dh - bind lispy doc features and ide-like features - bind embark - bind commentary #+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") "" '(treemacs-find-file :which-key "Find current file in sidebar") "," '(+ivy/switch-workspace-buffer :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") ;; "*" '(counsel-locate :which-key "Fuzzy find file") ;; find-file? consult-locate? "d" '(docker :which-key "Docker") "i" '(custom/conditional-imenu :which-key "Imenu") ;; consult-outline? "w" '(ace-window :which-key "Window") ;; 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" '(custom/eval-region-or-buffer :which-key "Eval buffer/region") ;; "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") "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" '(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" '(+vc-gutter/previous-hunk :which-key "jump to previous hunk") "ghp" '(+vc-gutter/next-hunk :which-key "jump to next hunk") "ghr" '(+vc-gutter/revert-hunk :which-key "revert hunk at point") "ghs" '(+vc-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") "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-graph :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") ;; 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") ;; 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 * 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) ;; Different scroll margin ;; (setq vertico-scroll-margin 0) ;; Show more candidates ;; (setq vertico-count 20) ;; Grow and shrink the Vertico minibuffer ;; (setq vertico-resize t) ;; Optionally enable cycling for `vertico-next' and `vertico-previous'. ;; (setq vertico-cycle t) ) #+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) ;; 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) ;; Enable recursive minibuffers (setq enable-recursive-minibuffers t)) (setq completion-styles '(basic substring partial-completion flex)) #+end_src ** Orderless #+begin_src emacs-lisp (use-package orderless :init ;; Configure a custom style dispatcher (see the Consult wiki) ;; (setq orderless-style-dispatchers '(+orderless-consult-dispatch orderless-affix-dispatch) ;; orderless-component-separator #'orderless-escapable-split-on-space) (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 `marginalia-cycle' locally in the minibuffer. To make the binding ;; available in the *Completions* buffer, add it to the ;; `completion-list-mode-map'. :bind (:map minibuffer-local-map ("M-A" . marginalia-cycle)) ;; The :init section is always executed. :init ;; Marginalia must be activated in the :init section of use-package such that ;; the mode gets enabled right away. Note that this forces loading the ;; package. (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)) ; Automatically format rust files on save (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 #+begin_src emacs-lisp (use-package markdown-mode :mode ("\\.md\\'" . markdown-mode)) ;;(use-package evil-markdown ;; :mode ("\\.md\\'" . evil-markdown-mode)) (use-package json-mode) (use-package yaml-mode) #+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 * Meow #+begin_src emacs-lisp ; (use-package 'meow) ; (defun meow-setup () ; (setq meow-cheatsheet-layout meow-cheatsheet-layout-colemak) ; (meow-motion-overwrite-define-key ; ;; Use e to move up, n to move down. ; ;; Since special modes usually use n to move down, we only overwrite e here. ; '("e" . meow-prev) ; '("" . ignore)) ; (meow-leader-define-key ; '("?" . meow-cheatsheet) ; ;; To execute the originally e in MOTION state, use SPC e. ; '("e" . "H-e") ; '("1" . meow-digit-argument) ; '("2" . meow-digit-argument) ; '("3" . meow-digit-argument) ; '("4" . meow-digit-argument) ; '("5" . meow-digit-argument) ; '("6" . meow-digit-argument) ; '("7" . meow-digit-argument) ; '("8" . meow-digit-argument) ; '("9" . meow-digit-argument) ; '("0" . meow-digit-argument)) ; (meow-normal-define-key ; '("0" . meow-expand-0) ; '("1" . meow-expand-1) ; '("2" . meow-expand-2) ; '("3" . meow-expand-3) ; '("4" . meow-expand-4) ; '("5" . meow-expand-5) ; '("6" . meow-expand-6) ; '("7" . meow-expand-7) ; '("8" . meow-expand-8) ; '("9" . meow-expand-9) ; '("-" . negative-argument) ; '(";" . meow-reverse) ; '("," . meow-inner-of-thing) ; '("." . meow-bounds-of-thing) ; '("[" . meow-beginning-of-thing) ; '("]" . meow-end-of-thing) ; '("/" . meow-visit) ; '("a" . meow-append) ; '("A" . meow-open-below) ; '("b" . meow-back-word) ; '("B" . meow-back-symbol) ; '("c" . meow-change) ; '("d" . meow-delete) ; '("e" . meow-prev) ; '("E" . meow-prev-expand) ; '("f" . meow-find) ; '("g" . meow-cancel-selection) ; '("G" . meow-grab) ; '("m" . meow-left) ; '("M" . meow-left-expand) ; '("i" . meow-right) ; '("I" . meow-right-expand) ; '("j" . meow-join) ; '("k" . meow-kill) ; '("l" . meow-line) ; '("L" . meow-goto-line) ; '("h" . meow-mark-word) ; '("H" . meow-mark-symbol) ; '("n" . meow-next) ; '("N" . meow-next-expand) ; '("o" . meow-block) ; '("O" . meow-to-block) ; '("p" . meow-yank) ; '("q" . meow-quit) ; '("r" . meow-replace) ; '("s" . meow-insert) ; '("S" . meow-open-above) ; '("t" . meow-till) ; '("u" . meow-undo) ; '("U" . meow-undo-in-selection) ; '("v" . meow-search) ; '("w" . meow-next-word) ; '("W" . meow-next-symbol) ; '("x" . meow-delete) ; '("X" . meow-backward-delete) ; '("y" . meow-save) ; '("z" . meow-pop-selection) ; '("'" . repeat) ; '("" . ignore))) ; ; (require 'meow) ; (meow-setup) ; (meow-global-mode 1) #+end_src * Evil #+begin_src emacs-lisp (use-package evil :ensure t :config (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)) ; :config ; (require 'evil-org-agenda) ; (evil-org-agenda-set-keys) ) (use-package evil-collection :after evil :ensure t :diminish evil-collection-unimpaired-mode :config (evil-collection-init) (setq evil-want-C-i-jump t evil-respect-visual-line-mode t)) #+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") )) ;; Todo: lainchan? adhd music stream from youtube? wuog? wrekFM? does freeside have streaming radio? (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 * 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 ** 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 - define global meow-left and vim-left, swich contextually - fix c-u in evil mode - fix tab key - window size functions, winner undo/redo - map default-text-scale operations - 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]]