modus-vivendi is built into Emacs 29+ so it loads reliably without a MELPA install — better for WSL where package errors were occurring. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
199 lines
5.3 KiB
EmacsLisp
199 lines
5.3 KiB
EmacsLisp
;;; init.el --- Emacs configuration -*- lexical-binding: t -*-
|
|
|
|
;;; Package management
|
|
|
|
(require 'package)
|
|
(add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/") t)
|
|
(package-initialize)
|
|
|
|
(unless package-archive-contents
|
|
(package-refresh-contents))
|
|
|
|
(require 'use-package)
|
|
(setq use-package-always-ensure t)
|
|
|
|
;;; Sane defaults
|
|
|
|
(setq-default
|
|
inhibit-startup-message t
|
|
visible-bell t
|
|
make-backup-files nil
|
|
auto-save-default nil
|
|
create-lockfiles nil
|
|
vc-follow-symlinks t
|
|
find-file-visit-truename t
|
|
fill-column 80
|
|
tab-width 4
|
|
indent-tabs-mode nil
|
|
truncate-lines t
|
|
sentence-end-double-space nil)
|
|
|
|
(menu-bar-mode -1)
|
|
(tool-bar-mode -1)
|
|
(scroll-bar-mode -1)
|
|
(tooltip-mode -1)
|
|
|
|
(setq display-line-numbers-type 'relative)
|
|
(global-display-line-numbers-mode 1)
|
|
(column-number-mode 1)
|
|
(global-hl-line-mode 1)
|
|
(show-paren-mode 1)
|
|
(electric-pair-mode 1)
|
|
(delete-selection-mode 1)
|
|
|
|
(setq global-auto-revert-non-file-buffers t)
|
|
(global-auto-revert-mode 1)
|
|
|
|
(setq scroll-margin 4
|
|
scroll-conservatively 101)
|
|
|
|
(setq uniquify-buffer-name-style 'forward)
|
|
|
|
;;; Font — matches ghostty / tmux setup
|
|
|
|
(set-face-attribute 'default nil
|
|
:family "Hack Nerd Font Mono"
|
|
:height 110)
|
|
|
|
;;; Theme
|
|
|
|
(use-package modus-themes
|
|
:ensure nil
|
|
:config
|
|
(load-theme 'modus-vivendi t))
|
|
|
|
;;; Discoverability
|
|
|
|
(use-package which-key
|
|
:config
|
|
(setq which-key-idle-delay 0.5)
|
|
(which-key-mode))
|
|
|
|
;;; Minibuffer — Vertico + Orderless + Marginalia + Consult
|
|
|
|
(use-package vertico
|
|
:config (vertico-mode))
|
|
|
|
(use-package orderless
|
|
:custom
|
|
(completion-styles '(orderless basic))
|
|
(completion-category-overrides '((file (styles basic partial-completion)))))
|
|
|
|
(use-package marginalia
|
|
:config (marginalia-mode))
|
|
|
|
(use-package consult
|
|
:bind (("C-x b" . consult-buffer)
|
|
("M-y" . consult-yank-pop)
|
|
("M-g M-g" . consult-goto-line)
|
|
("M-g i" . consult-imenu)
|
|
("M-s l" . consult-line)
|
|
("M-s r" . consult-ripgrep)))
|
|
|
|
;; Contextual actions on any minibuffer candidate or thing at point
|
|
(use-package embark
|
|
:bind (("C-." . embark-act)
|
|
("C-;" . embark-dwim))
|
|
:custom (embark-indicators '(embark-minimal-indicator)))
|
|
|
|
(use-package embark-consult
|
|
:hook (embark-collect-mode . consult-preview-at-point-mode))
|
|
|
|
;; Edit consult-ripgrep / grep results as a buffer; save to apply across files
|
|
(use-package wgrep
|
|
:custom (wgrep-auto-save-buffer t))
|
|
|
|
;;; In-buffer completion — Corfu + Cape
|
|
|
|
(use-package corfu
|
|
:custom
|
|
(corfu-auto t)
|
|
(corfu-auto-delay 0.2)
|
|
(corfu-auto-prefix 2)
|
|
(corfu-quit-no-match 'separator)
|
|
:config
|
|
(global-corfu-mode))
|
|
|
|
(use-package cape
|
|
:init
|
|
(add-to-list 'completion-at-point-functions #'cape-file)
|
|
(add-to-list 'completion-at-point-functions #'cape-dabbrev))
|
|
|
|
;;; Visual aids
|
|
|
|
(use-package rainbow-delimiters
|
|
:hook (prog-mode . rainbow-delimiters-mode))
|
|
|
|
;; nerd-icons supplies glyphs for doom-modeline; Hack Nerd Font Mono already
|
|
;; includes them, so M-x nerd-icons-install-fonts is only needed on first use
|
|
;; if you see boxes instead of icons.
|
|
(use-package nerd-icons)
|
|
|
|
(use-package doom-modeline
|
|
:hook (after-init . doom-modeline-mode)
|
|
:custom
|
|
(doom-modeline-height 28)
|
|
(doom-modeline-bar-width 4)
|
|
(doom-modeline-icon t)
|
|
(doom-modeline-major-mode-icon t)
|
|
(doom-modeline-buffer-file-name-style 'truncate-upto-project)
|
|
(doom-modeline-vcs-max-length 24))
|
|
|
|
;;; Tree-sitter — auto-switch to *-ts-mode when grammars are available
|
|
|
|
(use-package treesit-auto
|
|
:custom (treesit-auto-install 'prompt)
|
|
:config (global-treesit-auto-mode))
|
|
|
|
;;; LSP — Eglot (built-in since Emacs 29)
|
|
|
|
(use-package eglot
|
|
:ensure nil
|
|
:custom
|
|
(eglot-autoshutdown t)
|
|
(eglot-confirm-server-initiated-edits nil)
|
|
(eglot-events-buffer-size 0))
|
|
|
|
;;; Navigation
|
|
|
|
;; Jump to any visible character — type a few chars of the target, pick the label
|
|
(use-package avy
|
|
:bind (("M-j" . avy-goto-char-timer)
|
|
("C-c j" . avy-goto-line)))
|
|
|
|
;; Pin files to numbered slots per project; jump to them instantly
|
|
(use-package harpoon
|
|
:bind (("C-c h a" . harpoon-add-file)
|
|
("C-c h h" . harpoon-toggle-file)
|
|
("C-c h 1" . harpoon-go-to-1)
|
|
("C-c h 2" . harpoon-go-to-2)
|
|
("C-c h 3" . harpoon-go-to-3)
|
|
("C-c h 4" . harpoon-go-to-4)))
|
|
|
|
;; Expand selection by semantic units: word → symbol → string → block → …
|
|
(use-package expand-region
|
|
:bind ("C-=" . er/expand-region))
|
|
|
|
;;; Git
|
|
|
|
(use-package magit
|
|
:bind ("C-x g" . magit-status))
|
|
|
|
;;; Direnv — respect .envrc per buffer (extends your shell direnv hook into Emacs)
|
|
|
|
(use-package envrc
|
|
:hook (after-init . envrc-global-mode))
|
|
|
|
;;; Server — enables emacsclient ('e' alias) and AUCTeX inverse search
|
|
|
|
(use-package server
|
|
:ensure nil
|
|
:config (unless (server-running-p) (server-start)))
|
|
|
|
;;; Drop-in language configs (stow'd from laptop/ or work/)
|
|
|
|
(let ((lang-dir (expand-file-name "lisp/langs" user-emacs-directory)))
|
|
(when (file-directory-p lang-dir)
|
|
(dolist (f (directory-files lang-dir t "\\.el$"))
|
|
(load f nil t))))
|