Files
emacs/init.el
2026-08-15 23:06:21 -06:00

431 lines
17 KiB
EmacsLisp

;;; init.el --- Rawley Fowler's Emacs Configuration
;;; Commentary:
;;; My Emacs configuration for ergonomic UNIX oriented code-editing.
;;; Code:
(make-directory "~/.emacs_backups/" t)
(make-directory "~/.emacs_autosave/" t)
(setq auto-save-file-name-transforms '((".*" "~/.emacs_autosave/" t)))
(setq backup-directory-alist '(("." . "~/.emacs_backups/")))
(setq visible-bell nil)
(setq ring-bell-function 'ignore)
(setq shell-file-name "/bin/bash")
(setq shell-command-switch "-c")
(setq indent-tabs-mode nil)
(setq require-final-newline t)
(setq frame-inhibit-implied-resize t)
(setq pixel-scroll-precision-mode t)
(setq show-trailing-whitespace t)
(setq-default indent-tabs-mode nil)
(setq-default tab-width 4)
(tool-bar-mode -1)
(scroll-bar-mode -1)
(menu-bar-mode -1)
(show-paren-mode 1)
(electric-pair-mode +1)
(recentf-mode 1)
(global-display-line-numbers-mode 1)
(add-to-list 'image-types 'svg)
(setq require-final-newline t)
(setq warning-minimum-level :error) ; Don't show *warnings*
(add-to-list 'default-frame-alist '(fullscreen . maximized))
(set-frame-font "ZedMono Nerd Font-16" nil t)
(setq create-lockfiles nil)
(setq gc-cons-threshold 100000000) ; ~100 MB
(setq read-process-output-max (* 1024 1024)) ; 1 MB read buffer chunk
;; Stupid bold font for no reason, BEGONE!
(mapc
(lambda (face)
(when (eq (face-attribute face :weight) 'bold)
(set-face-attribute face nil :weight 'normal)))
(face-list))
;; Don't allow C-z or C-x C-z if GUI mode
(when (display-graphic-p)
(global-unset-key (kbd "C-z"))
(global-unset-key (kbd "C-x C-z")))
;;
;; PACKAGES
;;
;; Straight.el
(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))
(straight-use-package 'use-package) ; use-package install
(setq straight-use-package-by-default t) ; always use straight to install packages
(setq use-package-always-ensure t) ; always auto-install packages
;; UTILS
;; Dired
(global-set-key (kbd "S-w") #'dired-jump)
;; Pull correct path from dir
(use-package direnv
:config
(direnv-mode))
;; Evil mode
(use-package evil
:init (evil-mode +1))
;; Shell stuff
(use-package exec-path-from-shell
:ensure t
:config
(exec-path-from-shell-initialize))
;; Project management
(use-package projectile
:init (projectile-mode +1)
:config
(define-key projectile-mode-map (kbd "C-c p") 'projectile-command-map))
;; Searching with ack
(use-package ack
:config
(global-set-key (kbd "C-c C-g") #'ack))
;; Dynamic tabbing
(use-package dtrt-indent
:config
(dtrt-indent-global-mode t))
;; M-x crux-rename-file-and-buffer, etc.
(use-package crux
:config
(global-set-key (kbd "C-c r") #'crux-rename-file-and-buffer))
;; Need this for some reason??
(use-package flymake-jsts
:straight '(flymake-jsts :type git :host github :repo "orzechowskid/flymake-jsts" :branch "main"))
;; The best linter/code checker ever made
(use-package flycheck
:init (global-flycheck-mode))
;; Generic completion
(use-package ivy
:defer 0.1
:diminish
:bind (("C-c C-r" . ivy-resume)
("C-x B" . ivy-switch-buffer-other-window))
:custom
(ivy-count-format "(%d/%d) ")
(ivy-use-virtual-buffers t)
:config (ivy-mode))
;; Extensions for ivy
(use-package ivy-rich
:after ivy
:custom
(ivy-virtual-abbreviate 'full
ivy-rich-switch-buffer-align-virtual-buffer t
ivy-rich-path-style 'abbrev))
;; Git frontend
(use-package magit)
;; Upgraded searching
(use-package swiper
:after ivy
:bind (("C-s" . swiper)
("C-r" . swiper)))
;; Debug adapter
(use-package dap-mode
:hook
(lsp-mode . dap-mode)
(lsp-mode . dap-ui-mode))
;;
(use-package counsel
:after ivy
:config (counsel-mode))
;; Positional frames
(use-package posframe)
;; Perltidy
(straight-use-package ; we have to use straight here because its not on MELPA/ELPA
'(perltidy
:type git
:host github
:repo "perl-ide/perltidy.el"
:branch "master"))
;; MODES
;;; No config use-packages
(use-package apache-mode)
(use-package yaml-mode)
(use-package raku-mode)
(use-package caddyfile-mode)
(use-package json-mode)
(use-package dockerfile-mode)
(use-package nix-mode)
(use-package cmake-mode)
(use-package meson-mode)
;;; With config
;;;; BEGIN theming
(use-package all-the-icons)
(use-package nerd-icons)
(use-package doom-modeline
:init
(setq doom-modeline-height 25)
(setq doom-modeline-major-mode-icon t)
(setq doom-modeline-major-mode-color-icon t)
(setq doom-modeline-lsp-icon t)
(doom-modeline-mode +1))
(use-package doom-themes
:custom
;; Global settings (defaults)
(doom-themes-enable-bold nil) ; if nil, bold is universally disabled
(doom-themes-enable-italic nil) ; if nil, italics is universally disabled
:config
(load-theme 'doom-gruvbox t)
;; Enable flashing mode-line on errors
(doom-themes-visual-bell-config)
;; Enable custom neotree theme (nerd-icons must be installed!)
(doom-themes-neotree-config)
;; Corrects (and improves) org-mode's native fontification.
(doom-themes-org-config))
;;;;
;;;; BEGIN: web-mode
(use-package web-mode
:ensure t
:config
(add-to-list 'auto-mode-alist '("\\.tmpl\\'" . web-mode)) ; Go, OCaml templates
(add-to-list 'auto-mode-alist '("\\.html.ep\\'" . web-mode)) ; Mojolicious
(add-to-list 'auto-mode-alist '("\\.ep\\'" . web-mode)) ; Mojolicious
(add-to-list 'auto-mode-alist '("\\.tt2\\'" . web-mode)) ; Template::Toolkit
(add-to-list 'auto-mode-alist '("\\.html.tt2\\'" . web-mode)) ; Template::Toolkit
(add-to-list 'auto-mode-alist '("\\.tt\\'" . web-mode)) ; Template::Toolkit
(add-to-list 'auto-mode-alist '("\\.html.tt\\'" . web-mode)) ; Template::Toolkit
(add-to-list 'auto-mode-alist '("\\.mc\\'" . web-mode)) ; Mason
(add-to-list 'auto-mode-alist '("\\.tx\\'" . web-mode)) ; Text::Xslate
(add-to-list 'auto-mode-alist '("\\.ts\\'" . web-mode)) ; Typescript
(add-to-list 'auto-mode-alist '("\\.js\\'" . web-mode)) ; Javascript
(add-to-list 'auto-mode-alist '("\\.tsx\\'" . web-mode)) ; React
(add-to-list 'auto-mode-alist '("\\.jsx\\'" . web-mode)) ; React
)
(defun enable-minor-mode (my-pair)
"Enable minor mode if filename match the regexp. MY-PAIR is a cons cell (regexp . minor-mode)."
(if (buffer-file-name)
(if (string-match (car my-pair) buffer-file-name)
(funcall (cdr my-pair)))))
(use-package prettier-js
:ensure t)
(add-hook 'web-mode-hook #'(lambda ()
(enable-minor-mode
'("\\.jsx?\\'" . prettier-js-mode))
(enable-minor-mode
'("\\.tsx?\\'" . prettier-js-mode))))
;;;; END: web-mode
;;;; BEGIN: cperl-mode
(require 'perl-mode)
(require 'cperl-mode)
(setq cperl-set-style "linux")
(setq cperl-highlight-variables-indiscriminately t)
(defalias 'perl-mode 'cperl-mode)
(setq cperl-indent-parens-as-block t)
(add-to-list 'auto-mode-alist '("\\.pm$" . cperl-mode))
(add-to-list 'auto-mode-alist '("\\.pl$" . cperl-mode))
(add-to-list 'auto-mode-alist '("\\.psgi$" . cperl-mode))
(setq cperl-basic-offset 4)
(add-hook 'cperl-mode-hook
(lambda ()
(add-hook 'before-save-hook #'perltidy-buffer nil t)))
(setq flycheck-perl-include-path '())
(when (file-directory-p "~/perl5/perlbrew")
(let ((rf-perl-version (shell-command-to-string "source ~/.bashrc && perl -e 'print($^V =~ s/v//r)' 2> /dev/null")))
;; Strip any trailing newlines from shell command output
(setq rf-perl-version (string-trim rf-perl-version))
(when (not (string-empty-p rf-perl-version))
(add-to-list 'flycheck-perl-include-path
(expand-file-name (format "~/perl5/perlbrew/perls/perl-%s/lib/%s" rf-perl-version rf-perl-version))))))
(require 'projectile)
(defun flycheck-perllib-init ()
"Dynamically add local project lib path to Flycheck without overwriting global paths."
(let ((root (or (and (fboundp 'projectile-project-root) (projectile-project-root))
(and (fboundp 'project-current) (project-current) (project-root (project-current))))))
(when root
(let ((local-lib (expand-file-name "lib" root)))
(when (file-directory-p local-lib)
(make-local-variable 'flycheck-perl-include-path)
(add-to-list 'flycheck-perl-include-path local-lib))))))
(add-hook 'cperl-mode-hook #'flycheck-perllib-init)
;;; cperl-mode does some ugly stuff
(eval-after-load 'cperl-mode
'(progn
(set-face-attribute 'cperl-array-face nil
:foreground 'unspecified
:background 'unspecified
:weight 'normal
:slant 'italic
)
(set-face-attribute 'cperl-hash-face nil
:foreground 'unspecified
:background 'unspecified
:weight 'normal
:slant 'italic
)
))
;;;; END cperl-mode
;;;; BEGIN common-lisp-mode
(use-package sly
:config
(setq inferior-lisp-program "sbcl"))
;;;; END common-lisp
;;;; BEGIN clojure-mode
(use-package clojure-mode)
(use-package cider
:config
(setq cider-repl-result-prefix ";; => "
cider-eval-result-prefix ""))
;;;;
;;;; BEGIN go-mode
(use-package go-mode
:config
(add-to-list 'auto-mode-alist '("\\.tmpl\\'" . web-mode)))
;;;; END go-mode
;;;; BEGIN c++-mode
(add-hook 'c++-mode-hook (lambda () (c-set-offset 'innamespace 0)))
;;;; END c++-mode
;;;; BEGIN company
(use-package company
:init (global-company-mode)
:config
(setq company-minimum-prefix-length 1
company-idle-delay 0.0))
;;;; END company
;;;; BEGIN lsp
(use-package yasnippet)
(use-package which-key)
(use-package lsp-mode
:custom
(lsp-keymap-prefix "C-c l") ; Prefix for LSP actions
(lsp-diagnostics-provider :flycheck)
(lsp-session-file (locate-user-emacs-file ".lsp-session"))
(lsp-log-io nil) ; IMPORTANT! Use only for debugging! Drastically affects performance
(lsp-keep-workspace-alive nil) ; Close LSP server if all project buffers are closed
(lsp-idle-delay 0.5) ; Debounce timer for `after-change-function'
;; core
(lsp-enable-xref t) ; Use xref to find references
(lsp-auto-configure t) ; Used to decide between current active servers
(lsp-eldoc-enable-hover t) ; Display signature information in the echo area
(lsp-enable-dap-auto-configure t) ; Debug support
(lsp-enable-file-watchers nil)
(lsp-enable-folding nil) ; I disable folding since I use origami
(lsp-enable-imenu t)
(lsp-enable-links nil) ; No need since we have `browse-url'
(lsp-enable-suggest-server-download t) ; Useful prompt to download LSP providers
(lsp-enable-symbol-highlighting t) ; Shows usages of symbol at point in the current buffer
(lsp-enable-text-document-color nil) ; This is Treesitter's job
(lsp-ui-sideline-show-hover nil) ; Sideline used only for diagnostics
(lsp-ui-sideline-diagnostic-max-lines 20) ; 20 lines since typescript errors can be quite big
;; completion
(lsp-completion-enable t)
(lsp-completion-enable-additional-text-edit t) ; Ex: auto-insert an import for a completion candidate
(lsp-completion-show-kind t) ; Optional
;; headerline
(lsp-headerline-breadcrumb-enable t) ; Optional, I like the breadcrumbs
(lsp-headerline-breadcrumb-enable-diagnostics nil) ; Don't make them red, too noisy
(lsp-headerline-breadcrumb-enable-symbol-numbers nil)
(lsp-headerline-breadcrumb-icons-enable nil)
;; modeline
(lsp-modeline-code-actions-enable nil) ; Modeline should be relatively clean
(lsp-modeline-diagnostics-enable nil) ; Already supported through `flycheck'
(lsp-modeline-workspace-status-enable nil) ; Modeline displays "LSP" when lsp-mode is enabled
(lsp-signature-doc-lines 1) ; Don't raise the echo area. It's distracting
(lsp-ui-doc-use-childframe t) ; Show docs for symbol at point
(lsp-eldoc-render-all nil) ; This would be very useful if it would respect `lsp-signature-doc-lines', currently it's distracting
;; lens
(lsp-lens-enable nil) ; Optional, I don't need it
;; semantic
(lsp-semantic-tokens-enable nil) ; Related to highlighting, and we defer to treesitter
:init
(setq lsp-use-plists t)
(setq lsp-format-buffer-on-save-list '(c++-mode c-mode go-mode clojure-mode))
(setq lsp-warn-no-matched-clients nil) ; Don't warn on unsupported modes
(setq lsp-clients-clangd-executable "clangd")
(setq lsp-completion-provider :capf)
(setopt backup-by-copying t)
:config
(add-hook 'web-mode 'lsp)
(add-hook 'clojure-mode-hook 'lsp)
(add-hook 'go-mode-hook 'lsp)
(add-hook 'c++-mode-hook 'lsp)
(add-hook 'lsp-mode-hook 'lsp-diagnostics-mode)
(add-hook 'lsp-mode-hook 'lsp-enable-which-key-integration)
(add-hook 'lsp-mode-hook (lambda ()
(setq-local completion-styles '(basic partial-completion orderless)
completion-category-defaults nil))))
(use-package lsp-ui
:commands
(lsp-ui-doc-show
lsp-ui-doc-glance)
:bind (:map lsp-mode-map
("C-c C-d" . 'lsp-ui-doc-glance))
:after (lsp-mode evil)
:config (setq lsp-ui-doc-enable t
evil-lookup-func #'lsp-ui-doc-glance ; Makes K in evil-mode toggle the doc for symbol at point
lsp-ui-doc-show-with-cursor nil ; Don't show doc when cursor is over symbol - too distracting
lsp-ui-doc-include-signature t ; Show signature
lsp-ui-doc-position 'at-point))
;;;; END lsp
(custom-set-variables
;; custom-set-variables was added by Custom.
;; If you edit it by hand, you could mess it up, so be careful.
;; Your init file should contain only one such instance.
;; If there is more than one, they won't work right.
'(custom-enabled-themes '(doom-gruvbox))
'(custom-safe-themes
'("38b43b865e2be4fe80a53d945218318d0075c5e01ddf102e9bec6e90d57e2134" "e4a702e262c3e3501dfe25091621fe12cd63c7845221687e36a79e17cf3a67e0" "b99ff6bfa13f0273ff8d0d0fd17cc44fab71dfdc293c7a8528280e690f084ef0" "3061706fa92759264751c64950df09b285e3a2d3a9db771e99bcbb2f9b470037" "e14289199861a5db890065fdc5f3d3c22c5bac607e0dbce7f35ce60e6b55fc52" "7c3d62a64bafb2cc95cd2de70f7e4446de85e40098ad314ba2291fc07501b70c" "1f292969fc19ba45fbc6542ed54e58ab5ad3dbe41b70d8cb2d1f85c22d07e518" "4d5d11bfef87416d85673947e3ca3d3d5d985ad57b02a7bb2e32beaf785a100e" "4594d6b9753691142f02e67b8eb0fda7d12f6cc9f1299a49b819312d6addad1d" "d97ac0baa0b67be4f7523795621ea5096939a47e8b46378f79e78846e0e4ad3d" "f64189544da6f16bab285747d04a92bd57c7e7813d8c24c30f382f087d460a33" "0c83e0b50946e39e237769ad368a08f2cd1c854ccbcd1a01d39fdce4d6f86478" "70c88c01b0b5fde9ecf3bb23d542acba45bb4c5ae0c1330b965def2b6ce6fac3" "13096a9a6e75c7330c1bc500f30a8f4407bd618431c94aeab55c9855731a95e1" "456697e914823ee45365b843c89fbc79191fdbaff471b29aad9dcbe0ee1d5641" "9b9d7a851a8e26f294e778e02c8df25c8a3b15170e6f9fd6965ac5f2544ef2a9" "dd4582661a1c6b865a33b89312c97a13a3885dc95992e2e5fc57456b4c545176" "c3c135e69890de6a85ebf791017d458d3deb3954f81dcb7ac8c430e1620bb0f1" "8c7e832be864674c220f9a9361c851917a93f921fedb7717b1b5ece47690c098" "8d3ef5ff6273f2a552152c7febc40eabca26bae05bd12bc85062e2dc224cde9a" "e8ceeba381ba723b59a9abc4961f41583112fc7dc0e886d9fc36fa1dc37b4079" "0d2c5679b6d087686dcfd4d7e57ed8e8aedcccc7f1a478cd69704c02e4ee36fe" "77fff78cc13a2ff41ad0a8ba2f09e8efd3c7e16be20725606c095f9a19c24d3d" "e8bd9bbf6506afca133125b0be48b1f033b1c8647c628652ab7a2fe065c10ef0" "93011fe35859772a6766df8a4be817add8bfe105246173206478a0706f88b33d" "9e5e0ff3a81344c9b1e6bfc9b3dcf9b96d5ec6a60d8de6d4c762ee9e2121dfb2" "f1e8339b04aef8f145dd4782d03499d9d716fdc0361319411ac2efc603249326" "02d422e5b99f54bd4516d4157060b874d14552fe613ea7047c4a5cfa1288cf4f" "aec7b55f2a13307a55517fdf08438863d694550565dee23181d2ebd973ebd6b8" "b5fd9c7429d52190235f2383e47d340d7ff769f141cd8f9e7a4629a81abc6b19" "720838034f1dd3b3da66f6bd4d053ee67c93a747b219d1c546c41c4e425daf93" default)))
(custom-set-faces
;; custom-set-faces was added by Custom.
;; If you edit it by hand, you could mess it up, so be careful.
;; Your init file should contain only one such instance.
;; If there is more than one, they won't work right.
)
;;; init.el ends here