;;; 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 "-ic") (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 2) (add-hook 'cperl-mode-hook (lambda () (add-hook 'before-save-hook #'perltidy-buffer nil t))) (let ((local-perl-path (expand-file-name "~/perl5/lib/perl5"))) (setenv "PERL5LIB" local-perl-path) (setenv "PERL_LOCAL_LIB_ROOT" (expand-file-name "~/perl5")) (setenv "PERL_MB_OPT" "--install_base ~/perl5") (setenv "PERL_MM_OPT" "INSTALL_BASE=~/perl5") ;; Update Emacs' executable paths so it finds local binaries (like cpanm) (setenv "PATH" (concat (expand-file-name "~/perl5/bin:") (getenv "PATH"))) (add-to-list 'exec-path (expand-file-name "~/perl5/bin"))) (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))) (make-local-variable 'flycheck-perl-include-path) (add-to-list 'flycheck-perl-include-path "~/perl5/lib/perl5/") (when (file-directory-p local-lib) (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 '(modus-vivendi)) '(custom-safe-themes '("4990532659bb6a285fee01ede3dfa1b1bdf302c5c3c8de9fad9b6bc63a9252f7" "7771c8496c10162220af0ca7b7e61459cb42d18c35ce272a63461c0fc1336015" "a9eeab09d61fef94084a95f82557e147d9630fbbb82a837f971f83e66e21e5ad" "e1df746a4fa8ab920aafb96c39cd0ab0f1bac558eff34532f453bd32c687b9d6" "7ec8fd456c0c117c99e3a3b16aaf09ed3fb91879f6601b1ea0eeaee9c6def5d9" "df6dfd55673f40364b1970440f0b0cb8ba7149282cf415b81aaad2d98b0f0290" "4b88b7ca61eb48bb22e2a4b589be66ba31ba805860db9ed51b4c484f3ef612a7" "dfb1c8b5bfa040b042b4ef660d0aab48ef2e89ee719a1f24a4629a0c5ed769e8" "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