config.org (38185B)
1 #+Startup: overview 2 #+Title:My emacs config 3 #+Author:Ethan Long 4 * What is this document/config/file? 5 This is a literate config for emacs, using the built-in ~org~ package for Emacs. 6 * Elpaca 7 The Elpaca package manager is an alternative to ~use-package~ that works asynchronously in the background. Beyond the initial set-up, it is faster and more reliable than using ~package.el~. 8 9 Its asynchronous nature is also what makes package initialisation a little more involved; packages that need to be set up after others must explicitly specify this. This is mostly a non-issue for my setup, and I try to avoid issues with variable declarations by using ~use-package~ whenever possible. 10 11 Alternatively, if you already have a setup with extensive use of ~use-package~ with some form of synchronous package manager, then you might want to use the ~elpaca-wait~ function, which forces it to complete all package evaluation up until that point. Using this function too often will defeat the purpose of elpaca, as the asynchronicity is exactly what makes it faster than alternatives. 12 13 Another thing of note, if you ever need to use ~after-init-hook~, then make sure to use ~elpaca-after-init-hook~ instead, as the regular ~after-init-hook~ can be triggered before Elpaca has finished its evaluation unless you use the afforementioned ~elpaca-wait~ function. 14 15 Elpaca is installed in =init.el=, as we need to install the latest version of org before we enter here. 16 ** ~init.el~ 17 #+include: "./init.el" src elisp :tangle no 18 * Configuration functions 19 Here I define all of my helper functions in the one place just for convenience. Unfortunately this can have the effect of breaking up some of my configuration, especially for things like ~org~. 20 ** General programming configuration 21 Firstly, here are some convenience functions that I find useful for general programming, making the editor act the way that I want it to. 22 *** Auto buffer formatting 23 I quite like how the LSP (or some other kind of parser/prettifier) can automatically format the buffer. In other editors, I typically like to have this happen whenever I save. 24 25 This functionality is especially useful for languages like Rust or Haskell where the formatting is handled quite well by the LSP. 26 #+begin_src emacs-lisp 27 (defun ethandl/format-buffer () 28 (when (and eglot--managed-mode 29 (eglot-server-capable :documentFormattingProvider)) 30 (eglot-format-buffer))) 31 #+end_src 32 In the future, I may extend this function to utilise prettifiers, but I don't really have the need to at the moment. 33 *** Line numbers 34 Line numbering in emacs is still a bit of a third class citizen; the primary reason I say this is because the width of the line number column is prone to change for seemingly no good reason. Example: scrolling any file below 80 lines will increase the size to accomodate line numbers greater than 1oo for no reason; the same thing happens around 850 lines for numbers greater than 1000. 35 36 I find that currently I am mostly satisfied by using the variable ~display-line-numbers-grow-only~. This effectively stops most of the annoyance around the width changing when scrolling up and down. 37 38 Following is a function that sets up the requisite variables for the behaviour that I like: 39 #+begin_src emacs-lisp 40 (defun ethandl/config-line-numbers () 41 ;; Set line numbers to relative 42 (setq display-line-numbers 'relative 43 display-line-numbers-width 2 44 display-line-numbers-current-absolute t 45 display-line-numbers-grow-only t)) 46 #+end_src 47 I would recommend adding this to a hook, which I have done in [[*General Emacs/Editor settings]], specifically the ~hook~ section of the ~use-package~ declaration. 48 *** Code fonts 49 For convenience, I have defined a helper function that can be called to configure the code fonts. 50 In typical one-frame setups not using the daemon functionality of emacs, you only need to use this once with the ~default~ parameter set as ~t~. 51 52 With daemon usage, it is not so simple. When using emacs as a daemon, emacs will initially read over this config file in terminal mode, which will stop it from setting the fonts correctly; the only solution to this is to set this function to run every time you create a new frame. I have this exact functionality set up in [[*Font & Ligature Definitions]]. 53 #+begin_src emacs-lisp 54 (defun ethandl/set-fonts (fontname &optional default) 55 (set-face-attribute 'default default :font fontname) 56 (set-face-attribute 'font-lock-comment-face default :slant 'italic) 57 (set-face-attribute 'font-lock-keyword-face default :slant 'italic) 58 (set-face-attribute 'mode-line default :font fontname)) 59 #+end_src 60 *** Tree sitter grammar compilation 61 I wanted a function that, given an ~alist~ of tree sitter grammars and their associated sources, would clone, build, and set up those grammars. 62 This function avoids recompiling grammars that are already installed. 63 #+begin_src emacs-lisp 64 (defun ethandl/install-treesit-grammars (lang-alist) 65 (require 'cl-lib) 66 (when (treesit-available-p) 67 (mapc #'treesit-install-language-grammar 68 (cl-remove-if #'treesit-language-available-p (mapcar #'car lang-alist))))) 69 #+end_src 70 I use this function in [[*Tree Sitter Setup]]. 71 ** Org mode configuration 72 Org mode is quite ugly out of the box, at least in my opinion. I use this config, which was inspired by a config that I found online. 73 74 I have used the following guides in informing this setup; it is largely based on the work of Diego Zamboni: 75 * [[https://zzamboni.org/post/beautifying-org-mode-in-emacs/][Beautifying Org Mode in Emacs by Diego Zamboni]] 76 * [[https://lepisma.xyz/2017/10/28/ricing-org-mode/][Ricing up Org Mode]] 77 78 I think that the latter guide is by far the prettier, more /"aesthetically pleasing"/ setup deserving of Unixporn or something, but personally I like it slightly less minimalistic. 79 80 *** Basic behavioral configuration 81 For starters, I define the function ~ethandl/org-base~ as the function to set up org in the way that I generally like. Of primary concern: it sets org to indent on section depth, sets the font to be variable pitch, and turns on visual lines for wrapped lines. 82 #+begin_src emacs-lisp 83 (defun ethandl/org-base () 84 (require 'org) 85 (org-indent-mode t) 86 (variable-pitch-mode t) 87 (visual-line-mode t) 88 (setq org-src-fontify-natively t 89 org-src-tab-acts-natively t 90 org-hide-leading-stars nil 91 org-indent-mode-turns-on-hiding-stars nil 92 org-hide-emphasis-markers t) 93 (font-lock-add-keywords 'org-mode ;; HACK to fix the catppuccin theme 94 '(("^ *\\([-]\\) " 95 (0 (prog1 () (compose-region (match-beginning 1) (match-end 1) "•"))))))) 96 #+end_src 97 This function should be called when you are setting up org mode, personally I do it when I'm [[* 98 *** Fonts 99 The following function is the config for org to set all the fonts. It is still a bit rough around the edges, I'd like to programatically set the heading sizes. 100 #+begin_src emacs-lisp 101 (defun ethandl/org-font () 102 (require 'org) 103 (let* 104 ;; Variable bindings 105 ((variable-font (if (x-list-fonts "P052") 106 '(:font "P052") 107 '(:family "Serif"))) 108 (mono-font (if (x-list-fonts ethandl/code-font) 109 `(:font ,ethandl/code-font) 110 '(:family "Mono"))) 111 (base-font-color (face-foreground 'default nil 'default)) 112 (headline `(:inherit default :weight bold :foreground ,base-font-color)) 113 (body `(:inherit default :weight thin :foreground ,base-font-color :height 200)) ;; 20 pt 114 (code `(:weight regular :height 0.8 :inherit t))) 115 116 ;; Actual function body 117 (custom-theme-set-faces 118 'user 119 `(variable-pitch ((t (,@variable-font ,@body))) t "Variable width font") 120 `(fixed-pitch ((t (,@mono-font ,@code))) t "Fixed width font") 121 `(org-level-8 ((t (,@variable-font ,@headline :height 1.1))) t "Heading level 8") 122 `(org-level-7 ((t (,@variable-font ,@headline :height 1.2))) t "Heading level 7") 123 `(org-level-6 ((t (,@variable-font ,@headline :height 1.3))) t "Heading level 6") 124 `(org-level-5 ((t (,@variable-font ,@headline :height 1.4))) t "Heading level 5") 125 `(org-level-4 ((t (,@variable-font ,@headline :height 1.5))) t "Heading level 4") 126 `(org-level-3 ((t (,@variable-font ,@headline :height 1.6))) t "Heading level 3") 127 `(org-level-2 ((t (,@variable-font ,@headline :height 1.7))) t "Heading level 2") 128 `(org-level-1 ((t (,@variable-font ,@headline :height 1.8))) t "Heading level 1") 129 `(org-document-title ((t (,@variable-font ,@headline :height 2.0 :underline nil))) t "Document title") 130 '(org-block ((t (:inherit fixed-pitch))) t "Verbatim block") 131 '(org-code ((t (:inherit (shadow fixed-pitch)))) t "Code block") 132 '(org-document-info ((t (:foreground "dark orange"))) t "Document info") 133 '(org-document-info-keyword ((t (:inherit (shadow fixed-pitch)))) t "Document info keys") 134 '(org-indent ((t (:inherit (org-hide fixed-pitch)))) t "Trailing Org Indentation") 135 '(org-link ((t (:foreground "royal blue" :underline t))) t "Links") 136 '(org-meta-line ((t (:inherit (font-lock-comment-face fixed-pitch)))) t "Metadata") 137 '(org-property-value ((t (:inherit fixed-pitch))) t "Org value") 138 '(org-special-keyword ((t (:inherit (font-lock-comment-face fixed-pitch)))) t "Org keyword") 139 '(org-table ((t (:inherit fixed-pitch :foreground "#83a598"))) t "Org table") 140 '(org-tag ((t (:inherit (shadow fixed-pitch) :weight bold :height 0.8))) t "Org tag") 141 '(org-verbatim ((t (:inherit (shadow fixed-pitch)))) t "Verbatim")))) 142 #+end_src 143 *** LaTeX 144 Some configuration for the LaTeX that appears in Org mode. We want to make sure that it's SVG, and also if we have the ability to, we should auto-render it. 145 #+begin_src emacs-lisp 146 (defun ethandl/org-latex () 147 (setq org-preview-latex-default-process 'dvisvgm)) 148 #+end_src 149 ** Hooks 150 *** Before saving 151 I like to format my buffers every time that I save in other editors, for now this function just calls my other ~format-buffer~ function. Any other action that you might like to do whenever you save can be put here too. 152 #+begin_src emacs-lisp 153 (defun ethandl/before-save-hook () 154 (ethandl/format-buffer)) 155 #+end_src 156 A good example of something that you might want to put here would be a ~git~ commit and push every time that you save within an Overleaf git project. This can be useful for when you're trying to avoid actually using the god-forsaken web editor of Overleaf. 157 * Theme 158 There are many themes for Emacs that you can use. It can be nice to spice things up every once in a while. 159 One day I might make my own theme, only if I get too lost in the ricing. 160 *** Catppuccin 161 I use the Catppuccin theme normally. 162 Unfortunately, this theme has some issues and I'm not sure whether they will ever be fixed; I have the fixes all here. 163 #+begin_src emacs-lisp 164 ;; Catppuccin Mocha theme 165 (use-package catppuccin-theme 166 :config 167 (load-theme 'catppuccin t) 168 (setq catppuccin-flavor 'mocha) 169 ;;(setq catppuccin-flavor 'latte) 170 (catppuccin-reload) 171 (add-to-list 'org-src-block-faces 172 (list "" (list :foreground (catppuccin-get-color 'green)))) 173 ;; HACK FIX: https://github.com/catppuccin/emacs/issues/61 174 (defun ctp/text-org-blocks () 175 (face-remap-add-relative 'org-block (list :foreground (catppuccin-get-color 'text)))) 176 ;; FIXME: Move this hook to the Org mode configuration so that it is obvious that we are adding this hook. 177 (add-hook 'org-mode-hook #'ctp/text-org-blocks) 178 (setq pdf-view-midnight-colors (cons (catppuccin-get-color 'text) 179 (catppuccin-get-color 'base)))) 180 #+end_src 181 *** Gruber darker 182 Sometimes I like to use Gruber Darker, following is an example snippet that is not tangled into my actual config. 183 #+begin_src emacs-lisp :tangle no 184 (use-package gruber-darker-theme 185 :config 186 (load-theme 'gruber-darker t)) 187 #+end_src 188 *** Emacs titlebar colour 189 FIXME: Move all configuration of the titlebar colour here for all versions of emacs like the mac port and gtk+. 190 It's nice to have the titlebar blend for the NS port of emacs: 191 #+begin_src emacs-lisp 192 (add-to-list 'default-frame-alist '(ns-transparent-titlebar . t)) 193 (add-to-list 'default-frame-alist '(ns-appearance . dark)) 194 #+end_src 195 #+begin_src emacs-lisp 196 (add-to-list 'default-frame-alist '(mac-transparent-titlebar . t)) 197 #+end_src 198 199 * Font & Ligature Definitions 200 FIXME: Bring in the ~org~ and variable font definitions here! 201 *** Code fonts 202 Here I pick the code font and declare it as the variable ~ethandl/code-font~. 203 #+begin_src emacs-lisp 204 (setq ethandl/code-font "Codelia Ligatures-16") 205 #+end_src 206 Currently I use Codelia, but I also recommend Comic Code, Julia Mono, or Victor Mono. In the end this is entirely personal preference. 207 Some more examples: 208 #+begin_src emacs-lisp :tangle no 209 (setq ethandl/code-font "Comic Code Ligatures-16") 210 (setq ethandl/code-font "JuliaMono-16") 211 (setq ethandl/code-font "Victor Mono-16") 212 #+end_src 213 214 Now we use [[*Code fonts][the font helper function that I defined earlier]] to actually set the fonts. 215 #+begin_src emacs-lisp 216 ;; Set default font 217 (ethandl/set-fonts ethandl/code-font t) 218 (add-hook 'elpaca-after-init-hook (apply-partially #'ethandl/set-fonts ethandl/code-font)) 219 #+end_src 220 221 We also want this to run after we make a new frame, in case we are running emacs as a daemon. 222 #+begin_src emacs-lisp 223 (add-hook 'after-make-frame-functions (apply-partially #'ethandl/set-fonts ethandl/code-font)) 224 (add-hook 'after-make-frame-functions 225 #'(lambda (frame) (run-with-timer 1 nil #'meow--prepare-face))) 226 #+end_src 227 **** Font supported ligatures for ~ligature.el~ 228 Each font has its own set of supported ligatures. 229 Unfortunately on Linux systems you must use ~ligature.el~ to set ligatures, and this requires manually defining which ligatures are supported. This is either really cool or a pain in the ass. 230 231 Here are some examples: 232 #+begin_src emacs-lisp 233 (setq 234 comic-code-ligs 235 '(("-" (rx (+ "-"))) ("-" (rx (* "-") ">")) 236 ("+" (rx (+ "+"))) ("<" (rx (+ "="))) 237 ("<" (rx (+ "=") ">")) ("<" (rx (+ "~"))) 238 ("<" (rx (+ "~") ">")) ("<" (rx "!" (+ "-"))) 239 ("<" (rx (+ "-"))) ("<" (rx (+ "-") ">")) ("<" (rx "|")) 240 (">" (rx (+ "="))) (">" (rx ">" (+ "="))) 241 (">" (rx ">" (+ "=") ">")) (">" (rx (+ "-"))) 242 (">" (rx (+ "-") "<")) ("~" (rx (+ "~"))) 243 ("~" (rx (+ "~") ">")) ("=" (rx (* "=") ">")) 244 ("=" (rx (+ (or ">" "<" "|" "/" "~" ":" "!" "=")))) 245 "!=" "!==" "[|" "|]" "{|" "|}" "|>" "||" "&&") 246 247 victor-mono-ligs 248 '("</" "</>" "/>" "~-" "-~" "~@" "<~" "<~>" "<~~" "~>" "~~" "~~>" ">=" "<=" 249 "<!--" "##" "###" "####" "|-" "-|" "|->" "<-|" ">-|" "|-<" "|=" "|=>" 250 ">-" "<-" "<--" "-->" "->" "-<" ">->" ">>-" "<<-" "<->" "->>" "-<<" "<-<" 251 "==>" "=>" "=/=" "!==" "!=" "<==" ">>=" "=>>" ">=>" "<=>" "<=<" 252 "=<=" "=>=" "<<=" "=<<" ".-" ".=" "=:=" "=!=" "==" "===" "::" ":=" ":>" 253 ":<" ">:" ";;" "<|" "<|>" "|>" "<>" "<$" "<$>" "$>" "<+" 254 "<+>" "+>" "?=" "/=" "/==" "/\\" "\\/" "__" "&&" "++" "+++") 255 256 julia-mono-ligs 257 '("->" "=>" "|>" "<|" "::" "<--" "-->" "<-->" 258 ("=" (rx (+ "="))))) 259 #+end_src 260 In my configuration, I declare the variable ~ethandl/ligs~ to use in the ~ligature.el~ setup. 261 #+begin_src emacs-lisp 262 (setq ethandl/ligs julia-mono-ligs) 263 #+end_src 264 265 All of this configuration is unnecessary if you don't want ligatures, or if you are using ~emacs-mac~ by Mitsuharu Yamamoto. 266 * Custom Keybinds 267 Here I have made a little section for setting up some additional keybinds. 268 ** Vim-style window navigation 269 When navigating windows, I find the binding ~C-x o~ to be rather slow when you have many buffers open in different arrangements, so I have adopted a set of bindings for the ~windmove-*~ functions that are left unused in the default configuration. These binds fit in quite nicely with the ~vim~-like keybinds that I use with ~meow~. 270 271 This is mostly just the work of [[https://dev.to/rajasegar/vim-style-repeatable-key-bindings-for-navigating-windows-in-emacs-5c4l][Rajasegar Chandran]]. 272 #+begin_src emacs-lisp 273 (global-set-key (kbd "C-x w h") 'windmove-left) 274 (global-set-key (kbd "C-x w j") 'windmove-down) 275 (global-set-key (kbd "C-x w k") 'windmove-up) 276 (global-set-key (kbd "C-x w l") 'windmove-right) 277 (repeat-mode t) 278 (defvar-keymap windmove-repeat-map 279 :repeat t 280 "h" #'windmove-left 281 "j" #'windmove-down 282 "k" #'windmove-up 283 "l" #'windmove-right) 284 #+end_src 285 ** Super as meta 286 I like having the super key also function as a meta key, as I frequently switch between MacOS and Linux with different window managers and keyboards. 287 #+begin_src emacs-lisp 288 (setq x-super-keysym 'meta) 289 #+end_src 290 * General Emacs/Editor settings 291 FIXME: Continue from here (remembering that I have other FIXMEs above) 292 293 FIXME: Bring as many of these changes into standalone functions as possible to reduce fragmentation. 294 We can use ~use-package~ to configure emacs at startup. 295 #+begin_src emacs-lisp 296 ;; Emacs init config 297 (use-package emacs 298 :ensure nil 299 :hook 300 (prog-mode . display-line-numbers-mode) 301 (display-line-numbers-mode . ethandl/config-line-numbers) 302 (before-save . ethandl/before-save-hook) 303 :init 304 ;; Get rid of default crud 305 (setq inhibit-startup-screen t) 306 (if (eq system-type 'darwin) 307 (menu-bar-mode 1) 308 (menu-bar-mode 0)) 309 (tool-bar-mode -1) 310 (setq-default tool-bar-mode -1) 311 (add-to-list 'default-frame-alist '(tool-bar-lines . 0)) 312 ;; (add-to-list 'after-make-frame-functions 'ethandl/tool-bar-padding-remove) 313 (when (fboundp 'scroll-bar-mode) 314 (scroll-bar-mode 0)) 315 ;; Note, the following two are already set in early_init.el, 316 ;; so the initial frame has good resizing 317 (setq frame-resize-pixelwise t) 318 (setq window-resize-pixelwise t) 319 ;; Modeline 320 (line-number-mode 1) ;; Line no. 321 (column-number-mode 1) ;; Col. no. 322 ;; Indentation 323 (setq-default indent-tabs-mode nil) 324 (setq-default tab-width 4) 325 ;; windmove wraps around 326 (setq windmove-wrap-around t) 327 ;; Get rid of the bell 328 (setq ring-bell-function 'ignore) 329 ;; Fuck Control+Scroll to zoom, that's terrible and seems to be bound by something in emacs-plus? 330 (global-unset-key (kbd "<C-wheel-up>")) 331 (global-unset-key (kbd "<C-wheel-down>")) 332 ;; Autosave files need to piss off 333 (setq backup-directory-alist 334 `((".*" . ,temporary-file-directory))) 335 (setq auto-save-file-name-transforms 336 `((".*" ,temporary-file-directory t))) 337 ;; Ensure that the command key is the emacs meta key 338 (when (eq system-type 'darwin) 339 (setq mac-option-modifier nil 340 mac-command-modifier 'meta)) 341 ;; Emacs frame title format default is bad: 342 (setq frame-title-format "%b")) 343 #+end_src 344 * Packages 345 ** Ivy and Counsel (Better Text Navigation) 346 [[https://github.com/abo-abo/swiper][Ivy and Counsel]] are replacements for the default ~find-file~ and =M-x= menus. 347 #+begin_src emacs-lisp 348 ;; ivy mode instead of ido mode: 349 (use-package ivy 350 :hook (elpaca-after-init . ivy-mode)) 351 ;; counsel extends ivy: 352 (use-package counsel 353 :hook (elpaca-after-init . counsel-mode)) 354 #+end_src 355 ** Ligature.el / Ligature set up 356 Ligatures are native on =emacs-mac=, so we just call the built in helper function if we are using that. If not, we will use [[https://github.com/mickeynp/ligature.el][ligature.el]] to give ligatures with Harfbuzz. 357 #+begin_src emacs-lisp 358 ;; Font ligatures: 359 (if (eq window-system 'mac) 360 ;; We must be in emacs-mac 361 (mac-auto-operator-composition-mode) 362 ;; Else, we're in a vanilla emacs 363 (use-package ligature 364 :config 365 (ligature-set-ligatures 'prog-mode ethandl/ligs) 366 (global-ligature-mode t))) 367 #+end_src 368 ** Rainbow Delimiters 369 Rainbow delimiters are essential for working with LISP, and are just nice to have elsewhere. This package has apparently got a very small footprint, and I can't be arsed actually benchmarking anything in this emacs config so I trust them. 370 #+begin_src emacs-lisp 371 ;; Rainbow delimiters: 372 (use-package rainbow-delimiters 373 :hook (prog-mode . rainbow-delimiters-mode)) 374 #+end_src 375 ** Doom Modeline 376 This modeline is supposedly sexier than the original, honestly I don't mind the original either, it's also very nice. If there's ever a reason to ditch this because of some bug or performance issue, etc. then don't be afraid to. 377 #+begin_src emacs-lisp 378 ;; Doom modeline: 379 (use-package doom-modeline 380 :hook (elpaca-after-init . doom-modeline-mode) 381 :config 382 ;; simpc-mode icon 383 (push '(simpc-mode nerd-icons-sucicon "nf-custom-c" 384 :face nerd-icons-blue) 385 nerd-icons-mode-icon-alist)) 386 #+end_src 387 ** Which Key? 388 Fix my ineptitude in this keyboard chord hell. 389 #+begin_src emacs-lisp 390 ;; Which key (this is the thing responsible for coming up with the minibuffer of keys that you can pick): 391 (use-package which-key 392 :init (which-key-mode) 393 :diminish which-key-mode 394 :config 395 (setq which-key-idle-delay 0.3)) 396 #+end_src 397 ** Meow 398 Meow takes some getting used to, but I want to try. 399 The beauty is that I have full control explicitly over every binding in a really simple interface, and the rest of the binds are just emacs' default with some enhancement: 400 #+begin_src emacs-lisp 401 ;; meow :D 402 (use-package meow 403 :config 404 ;; General meow config: 405 (setq meow-cheatsheet-layout meow-cheatsheet-layout-qwerty) 406 (meow-motion-overwrite-define-key 407 '("j" . meow-next) 408 '("k" . meow-prev) 409 '("<escape>" . ignore)) 410 (meow-leader-define-key 411 ;; SPC j/k will run the original command in MOTION state. 412 '("j" . "H-j") 413 '("k" . "H-k") 414 ;; Use SPC (0-9) for digit arguments. 415 '("1" . meow-digit-argument) 416 '("2" . meow-digit-argument) 417 '("3" . meow-digit-argument) 418 '("4" . meow-digit-argument) 419 '("5" . meow-digit-argument) 420 '("6" . meow-digit-argument) 421 '("7" . meow-digit-argument) 422 '("8" . meow-digit-argument) 423 '("9" . meow-digit-argument) 424 '("0" . meow-digit-argument) 425 '("/" . meow-keypad-describe-key) 426 '("?" . meow-cheatsheet)) 427 (meow-normal-define-key 428 '("0" . meow-expand-0) 429 '("9" . meow-expand-9) 430 '("8" . meow-expand-8) 431 '("7" . meow-expand-7) 432 '("6" . meow-expand-6) 433 '("5" . meow-expand-5) 434 '("4" . meow-expand-4) 435 '("3" . meow-expand-3) 436 '("2" . meow-expand-2) 437 '("1" . meow-expand-1) 438 '("-" . negative-argument) 439 '(";" . meow-reverse) 440 '("," . meow-inner-of-thing) 441 '("." . meow-bounds-of-thing) 442 '("[" . meow-beginning-of-thing) 443 '("]" . meow-end-of-thing) 444 '("a" . meow-append) 445 '("A" . meow-open-below) 446 '("b" . meow-back-word) 447 '("B" . meow-back-symbol) 448 '("c" . meow-change) 449 '("d" . meow-delete) 450 '("D" . meow-backward-delete) 451 '("e" . meow-next-word) 452 '("E" . meow-next-symbol) 453 '("f" . meow-find) 454 '("g" . meow-cancel-selection) 455 '("G" . meow-grab) 456 '("h" . meow-left) 457 '("H" . meow-left-expand) 458 '("i" . meow-insert) 459 '("I" . meow-open-above) 460 '("j" . meow-next) 461 '("J" . meow-next-expand) 462 '("k" . meow-prev) 463 '("K" . meow-prev-expand) 464 '("l" . meow-right) 465 '("L" . meow-right-expand) 466 '("m" . meow-join) 467 '("n" . meow-search) 468 '("o" . meow-block) 469 '("O" . meow-to-block) 470 '("p" . meow-yank) 471 '("q" . meow-quit) 472 '("Q" . meow-goto-line) 473 '("r" . meow-replace) 474 '("R" . meow-swap-grab) 475 '("s" . meow-kill) 476 '("t" . meow-till) 477 '("u" . meow-undo) 478 '("U" . meow-undo-in-selection) 479 '("v" . meow-visit) 480 '("w" . meow-mark-word) 481 '("W" . meow-mark-symbol) 482 '("x" . meow-line) 483 '("X" . meow-goto-line) 484 '("y" . meow-save) 485 '("Y" . meow-sync-grab) 486 '("z" . meow-pop-selection) 487 '("'" . repeat) 488 '(">" . indent-rigidly-right-to-tab-stop) 489 '("<" . indent-rigidly-left-to-tab-stop) 490 '("<escape>" . ignore)) 491 (setq meow-keypad-leader-dispatch "C-x") 492 (meow-global-mode t)) 493 #+end_src 494 ** Corfu & Cape (Completion) 495 Based completion. This is an overhaul of the autocomplete. Company mode sucks because when you resize a buffer with C-x-+ everything breaks. 496 #+begin_src emacs-lisp 497 ;; Cape 498 (use-package cape) 499 500 ;; Completion & Modernisation 501 (use-package corfu 502 :after cape 503 :hook 504 (meow-insert-exit . corfu-quit) 505 :custom 506 (corfu-cycle t) 507 (corfu-auto t) 508 (corfu-preselect 'prompt) 509 (corfu-scroll-margin 5) 510 (completion-cycle-threshold 3) 511 :init 512 (global-corfu-mode)) 513 #+end_src 514 ** Scrolling Patches 515 JDT makes a nice scroll package, this should be good regardless of the emacs build that you are using. 516 #+begin_src emacs-lisp 517 (use-package ultra-scroll 518 :ensure `(ultra-scroll 519 :host github 520 :repo "jdtsmith/ultra-scroll") 521 :init 522 (setq scroll-conservatively 10 523 scroll-margin 0) 524 :config 525 (ultra-scroll-mode 1)) 526 #+end_src 527 ** Exec path from shell (Fix Path issues) 528 When running emacs as a daemon, we have a notable lack of things in our ~PATH~ because daemons are started in a minimal environment, at least on MacOS. 529 This solution will increase startup time, but will fix any path issues for most shells. May need tinkering. This will also only be activated when using a daemon. 530 #+begin_src emacs-lisp 531 (use-package exec-path-from-shell 532 :config 533 (exec-path-from-shell-initialize)) 534 #+end_src 535 ** PDF-tools 536 #+begin_src emacs-lisp 537 (use-package pdf-tools 538 :mode ("\\.[pP][dD][fF]\\'" . pdf-view-mode) 539 :hook 540 (pdf-view-mode . auto-revert-mode) 541 (pdf-view-mode . pdf-view-midnight-minor-mode) 542 :config 543 (setq-default pdf-view-display-size 'fit-page) 544 (setq pdf-annot-activate-created-annotations t)) 545 #+end_src 546 ** Emacs vterm 547 In emacs' included packages, there are only 2 shells that are good to use: ~eshell~ and ~shell~. 548 I have had poor experiences with ~term~, as it doesn't properly emulate all escape sequences and is a bit slow. 549 550 The solution to this is the ~vterm~ package, which is a package written mostly in C with a much better terminal emulation. It is fast and more reliable. 551 #+begin_src emacs-lisp 552 (use-package vterm) 553 #+end_src 554 * Org Mode 555 My org mode is based on [[https://orgmode.org/guide/Hyperlinks.html][a post by Diego Zamboni]]. The general idea is that we want headings to be bigger and more noticable than text, all regular text should be non-monospace, and all code should be in the regular monospace font. 556 The org configuration uses a lot of custom functions, see the 557 #+begin_src emacs-lisp 558 (use-package org 559 :ensure nil 560 :hook 561 (org-mode . ethandl/org-base) 562 (org-mode . ethandl/org-font) 563 (org-mode . ethandl/org-latex)) 564 #+end_src 565 Other auxillary packages for Org mode: 566 #+begin_src emacs-lisp 567 (use-package org-superstar ;; Nicer bullet fonts 568 :hook (org-mode . org-superstar-mode) 569 :config (setq org-superstar-leading-bullet ?\s)) 570 (use-package org-autolist ;; Automatic bulleting 571 :hook (org-mode . org-autolist-mode)) 572 (use-package org-download ;; Seamless image pasting 573 :after org 574 :defer nil 575 :custom 576 (org-download-method 'directory) 577 (org-download-image-dir "pasted-images") 578 (org-download-heading-lvl nil) 579 (org-download-timestamp "%Y%m%d-%H%M%S_") 580 (org-image-actual-width t) 581 (org-download-screenshot-method "/opt/homebrew/bin/pngpaste %s") 582 :bind 583 ("M-p" . org-download-screenshot) 584 :config 585 (require 'org-download)) 586 #+end_src 587 * Languages 588 ** LSP Setup 589 LSP, the Language Server Protocol. Very nice for debugging code live as you write it. It depends on the language as to how useful this really is. 590 591 *Warning:* Some LSPs are godawful slow and can chew through CPU and memory. Be careful, tinker, and don't be afraid to disable the training wheels. 592 We use the built-in package eglot (requires emacs 29) if possible as there seems to occasionally be issues with installing eglot. 593 #+begin_src emacs-lisp 594 (when (>= emacs-major-version 29) 595 (use-package eglot 596 :ensure nil)) 597 (use-package markdown-mode) ; needed for formatting the stuff in the eldoc buffers 598 #+end_src 599 ** Tree Sitter Setup 600 Since Emacs 29, we don't need to install tree sitter separately anymore, it comes with Emacs! 601 #+begin_src emacs-lisp 602 (setq treesit-language-source-alist 603 '((bash "https://github.com/tree-sitter/tree-sitter-bash") 604 (css "https://github.com/tree-sitter/tree-sitter-css") 605 (go "https://github.com/tree-sitter/tree-sitter-go") 606 (gomod "https://github.com/camdencheek/tree-sitter-go-mod") 607 (html "https://github.com/tree-sitter/tree-sitter-html") 608 (javascript "https://github.com/tree-sitter/tree-sitter-javascript" "master" "src") 609 (json "https://github.com/tree-sitter/tree-sitter-json") 610 (yaml "https://github.com/ikatyang/tree-sitter-yaml") 611 (python "https://github.com/tree-sitter/tree-sitter-python") 612 (toml "https://github.com/tree-sitter/tree-sitter-toml") 613 (tsx "https://github.com/tree-sitter/tree-sitter-typescript" "master" "tsx/src") 614 (typescript "https://github.com/tree-sitter/tree-sitter-typescript" "master" "typescript/src") 615 (rust "https://github.com/tree-sitter/tree-sitter-rust") 616 (java "https://github.com/tree-sitter/tree-sitter-java") 617 ;;(haskell "https://github.com/tree-sitter/tree-sitter-haskell") ; There is no haskell-ts-mode yet 618 ;;(ocaml "https://github.com/tree-sitter/tree-sitter-ocaml" "master" "ocaml/src") ; There is no ocaml-ts-mode 619 (c "https://github.com/tree-sitter/tree-sitter-c") 620 (cpp "https://github.com/tree-sitter/tree-sitter-cpp") 621 (zig "https://github.com/maxxnino/tree-sitter-zig"))) 622 623 ;; Fuck windows, this won't work on there and I don't care 624 (ethandl/install-treesit-grammars treesit-language-source-alist) 625 #+end_src 626 ** Eldoc Setup 627 I like to have eldoc appear as a box below where I'm typing, rather than having it appear in the minibuffer. This is done with =eldoc-box=: 628 #+begin_src emacs-lisp 629 (use-package eldoc-box 630 :hook 631 (eglot-managed-mode . eldoc-box-hover-mode)) 632 #+end_src 633 ** C 634 I was using the C treesitter mode, but that mode is still based on C-mode and is incredibly slow for large files. 635 #+begin_src emacs-lisp :tangle no 636 (push '(c-mode . c-ts-mode) major-mode-remap-alist)) 637 #+end_src 638 639 Instead, I now use Alexey Kutepov's ~simp-c~ mode, which performs far better. 640 #+begin_src emacs-lisp 641 (use-package simpc-mode 642 :ensure '(simpc-mode 643 :host github 644 :repo "rexim/simpc-mode") 645 :config 646 (push '(c-mode . simpc-mode) major-mode-remap-alist)) 647 #+end_src 648 ** Haskell 649 This setup is just a combination of =haskell-mode= and the Haskell Language Server. 650 Haskell mode is really good for the indenting and overall behaviour of the editor, and the Haskell language server is definitely there... (It can be slow, so can be turned off on larger projects) 651 #+begin_src emacs-lisp 652 (executable-find "haskell-language-server-wrapper") 653 ;; Haskell setup 654 (use-package haskell-mode) 655 (use-package eglot 656 :ensure nil 657 :after eglot 658 :hook (haskell-mode . eglot-ensure) 659 :config 660 (setq-default eglot-workplace-configuration 661 '((haskell 662 (plugin 663 (stan 664 (globalOn . :json-false)))))) 665 :custom 666 (eglot-autoshutdown t) 667 (eglot-confirm-server-initiated-edits nil)) 668 #+end_src 669 NOTE: This is not using tree sitter, as there is no haskell-ts-mode yet or probably for a while into the future. 670 ** Rust 671 Rust mode alongside LSP again. The rust LSP is very good as far as LSPs go, very helpful. Though sometimes it's better to compile and see the rustc errors as they tend to be more verbose. 672 #+begin_src emacs-lisp 673 (use-package eglot 674 :ensure nil 675 :after eglot 676 :hook (rust-ts-mode . eglot-ensure) 677 :config 678 (add-to-list 'eglot-server-programs 679 `(rust-mode . ("rust-analyzer" :initializationOptions 680 (:procmacro (:enable t))))) 681 (push '("\\.rs\\'" . rust-ts-mode) auto-mode-alist)) 682 #+end_src 683 ** Go 684 This basic LSP setup is based on the golang guide: https://cs.opensource.google/go/x/tools/+/refs/tags/gopls/v0.14.2:gopls/doc/emacs.md 685 #+begin_src emacs-lisp 686 (push '("\\.go\\'" . go-ts-mode) auto-mode-alist) 687 (push '("\\.mod\\'" . go-mod-ts-mode) auto-mode-alist) 688 (defun golang/project-find-go-module (dir) 689 (when-let ((root (locate-dominating-file dir "go.mod"))) 690 (cons 'go-module root))) 691 (cl-defmethod project-root ((project (head go-module))) 692 (cdr project)) 693 694 (use-package project 695 :ensure nil 696 :config 697 (add-hook 'project-find-functions #'golang/project-find-go-module)) 698 699 (use-package eglot 700 :ensure nil 701 :after eglot 702 :hook (go-ts-mode . eglot-ensure) 703 :config 704 (setq-default eglot-workspace-configuration 705 '((:gopls . 706 ((staticcheck . t) 707 (matcher . "CaseSensitive"))))) 708 (push '("\\.go\\'" . go-ts-mode) auto-mode-alist) 709 (push '("\\.mod\\'" . go-mod-ts-mode) auto-mode-alist)) 710 #+end_src 711 ** Java 712 OO hell 😌 713 If you want a language server, maybe just use IntelliJ? I don't use Java and the ~eglot-java~ package has broken for my config, complaining about the eglot version. 714 #+begin_src emacs-lisp 715 ;; Java setup 716 (use-package emacs 717 :ensure nil 718 :config 719 (push '(java-mode . java-ts-mode) major-mode-remap-alist)) 720 #+end_src 721 ** JavaScript/TypeScript 722 JavaScript and TypeScript are easy thanks to tree sitter! 723 #+begin_src emacs-lisp 724 (use-package eglot 725 :ensure nil 726 :after eglot 727 :hook 728 (js-ts-mode . eglot-ensure) 729 (typescript-ts-mode . eglot-ensure) 730 (tsx-ts-mode . eglot-ensure) 731 :config 732 (setq typescript-ts-mode-indent-offset tab-width) 733 (push '(js-mode . js-ts-mode) major-mode-remap-alist) 734 (push '(javascript-mode . js-ts-mode) major-mode-remap-alist) 735 (push '("\\.ts\\'" . typescript-ts-mode) auto-mode-alist) 736 (push '("\\.tsx\\'" . tsx-ts-mode) auto-mode-alist)) 737 #+end_src 738 ** Python 739 A.K.A. the most overused and overhyped language. This language is incredibly slow, which is why its language server is not written in Python LMAO. Anywho the =pyright= LSP is made by Microshit so maybe this is proprietary software or telemetry, idk. 740 #+begin_src emacs-lisp 741 (use-package eglot 742 :ensure nil 743 :after eglot 744 :hook ((python-mode python-ts-mode) . eglot-ensure) 745 :config 746 (add-to-list 'eglot-server-programs 747 `(python-mode . ("pyright-langserver" "--stdio"))) 748 (add-to-list 'eglot-server-programs 749 `(python-ts-mode . ("pyright-langserver" "--stdio"))) 750 ;(push ".dir-locals.el" project-vc-extra-root-markers) 751 (push '(python-mode . python-ts-mode) major-mode-remap-alist)) 752 #+end_src 753 The following lets me set up a venv for use with pyright (https://robbmann.io/posts/emacs-eglot-pyrightconfig/): 754 #+begin_src emacs-lisp 755 (defun pyrightconfig-write (virtualenv) 756 (interactive "DEnv: ") 757 758 (let* (;; file-truename and tramp-file-local-name ensure that neither `~' nor 759 ;; the Tramp prefix (e.g. "/ssh:my-host:") wind up in the final 760 ;; absolute directory path. 761 (venv-dir (tramp-file-local-name (file-truename virtualenv))) 762 763 ;; Given something like /path/to/.venv/, this strips off the trailing `/'. 764 (venv-file-name (directory-file-name venv-dir)) 765 766 ;; Naming convention for venvPath matches the field for 767 ;; pyrightconfig.json. `file-name-directory' gets us the parent path 768 ;; (one above .venv). 769 (venvPath (file-name-directory venv-file-name)) 770 771 ;; Grabs just the `.venv' off the end of the venv-file-name. 772 (venv (file-name-base venv-file-name)) 773 774 ;; Eglot demands that `pyrightconfig.json' is in the project root 775 ;; folder. 776 (base-dir (vc-git-root default-directory)) 777 (out-file (expand-file-name "pyrightconfig.json" base-dir)) 778 779 ;; Finally, get a string with the JSON payload. 780 (out-contents (json-encode (list :venvPath venvPath :venv venv)))) 781 782 ;; Emacs uses buffers for everything. This creates a temp buffer, inserts 783 ;; the JSON payload, then flushes that content to final `pyrightconfig.json' 784 ;; location 785 (with-temp-file out-file (insert out-contents)))) 786 #+end_src 787 ** LaTeX 788 LaTeX isn't really a language, but we should set up stuff for it. 789 Firstly, we should get CDLaTeX: 790 #+begin_src emacs-lisp 791 (use-package cdlatex 792 :hook ((latex-mode LaTeX-mode) . turn-on-cdlatex) 793 :hook (latex-mode . (lambda () (setq tab-width 2)))) 794 #+end_src 795 * Native Comp 796 Supress all warnings: 797 #+begin_src emacs-lisp 798 (setq native-comp-async-report-warnings-errors 'silent) 799 #+end_src 800 801 I used to always try to compile all the emacs packages in our config, I find that this just results in a build job running forever, even when we're done. Not sure what it's doing or what package it's for, but I'm just going to make this compilation process manual. 802 #+begin_src emacs-lisp :tangle no 803 (when (fboundp 'native-comp-available-p) 804 (add-hook 'elpaca-after-init-hook (lambda () (native-compile-async user-emacs-directory t)))) 805 #+end_src 806 807 Manual compile function: 808 #+begin_src emacs-lisp 809 (defun ethandl/nativecomp-all () 810 (interactive) 811 (native-compile-async user-emacs-directory 'recursively)) 812 #+end_src