Last active
February 12, 2026 10:38
-
-
Save reflechant/c900eb968fc75a16a676428f29ed2138 to your computer and use it in GitHub Desktop.
new Emacs config
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| ;;; init.el --- Personal Emacs config -*- lexical-binding: t; -*- | |
| ;;;;;;;;;;;;;;;;;;;;;;;;;;; | |
| ;; Package Management ;; | |
| ;;;;;;;;;;;;;;;;;;;;;;;;;;; | |
| (require 'package) | |
| (add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/") t) | |
| ;; use-package is built-in in Emacs 30 but :ensure needs this module | |
| (require 'use-package-ensure) | |
| (setq use-package-always-ensure t) | |
| ;; Keep Custom's auto-generated stuff out of init.el | |
| (setq custom-file (expand-file-name "custom.el" user-emacs-directory)) | |
| ;;;;;;;;;;;;;;;;;;;;;;;;;;; | |
| ;; Sane Defaults ;; | |
| ;;;;;;;;;;;;;;;;;;;;;;;;;;; | |
| (setopt use-short-answers t) ; y/n instead of yes/no | |
| (setq inhibit-startup-message t) ; skip splash screen | |
| (setq column-number-mode t) ; show column in modeline | |
| ;; Fill column indicator at 80 chars | |
| (setopt display-fill-column-indicator-column 80) | |
| (global-display-fill-column-indicator-mode t) | |
| ;; Line numbers in code | |
| (add-hook 'prog-mode-hook #'display-line-numbers-mode) | |
| ;; Remember cursor position in files | |
| (save-place-mode 1) | |
| ;; Remember recent files | |
| (recentf-mode 1) | |
| (setq recentf-max-saved-items 50) | |
| ;; Remember minibuffer history (Vertico sorts by this) | |
| (savehist-mode 1) | |
| ;; Auto-pair brackets (disabled in paredit buffers below) | |
| (electric-pair-mode t) | |
| ;; Smooth pixel scrolling | |
| (pixel-scroll-precision-mode t) | |
| ;; Store backups in a dedicated directory | |
| (setq backup-directory-alist | |
| `(("." . ,(expand-file-name "backups" user-emacs-directory)))) | |
| ;; Hide commands in M-x that don't apply to current mode | |
| (setq read-extended-command-predicate #'command-completion-default-include-p) | |
| ;;;;;;;;;;;;;;;;;;;;;;;;;;; | |
| ;; Evil Mode + Leader ;; | |
| ;;;;;;;;;;;;;;;;;;;;;;;;;;; | |
| ;; Vim emulation — C-z toggles back to Emacs keybindings anytime | |
| (use-package evil | |
| :init | |
| (setq evil-want-integration t) | |
| (setq evil-want-keybinding nil) ; let evil-collection handle non-core modes | |
| (setq evil-want-C-u-scroll t) ; C-u scrolls up like vim (use universal-argument via SPC u) | |
| (setq evil-undo-system 'undo-redo) ; Emacs 28+ built-in undo-redo | |
| :config | |
| (evil-mode 1)) | |
| ;; Evil bindings for 150+ Emacs packages (magit, dired, org, etc.) | |
| (use-package evil-collection | |
| :after evil | |
| :config | |
| (evil-collection-init)) | |
| ;; gc to comment/uncomment (works on lines and selections) | |
| (use-package evil-nerd-commenter | |
| :after evil | |
| :bind ("M-;" . evilnc-comment-or-uncomment-lines)) | |
| ;; Leader key system — press SPC in normal mode to see all commands | |
| (use-package general | |
| :after evil | |
| :config | |
| (general-create-definer my-leader-def | |
| :keymaps '(normal visual emacs) | |
| :prefix "SPC" | |
| :global-prefix "C-SPC") ; C-SPC works in insert/emacs state too | |
| (my-leader-def | |
| "" '(nil :which-key "leader") | |
| "SPC" '(execute-extended-command :which-key "M-x") | |
| "u" '(universal-argument :which-key "universal arg") | |
| "TAB" '(evil-switch-to-windows-last-buffer :which-key "last buffer") | |
| "!" '(shell-command :which-key "shell command") | |
| "/" '(consult-ripgrep :which-key "ripgrep") | |
| ";" '(eval-expression :which-key "eval expression") | |
| "'" '(eshell :which-key "eshell") | |
| ;; Files | |
| "f" '(:ignore t :which-key "file") | |
| "f f" '(find-file :which-key "find file") | |
| "f r" '(consult-recent-file :which-key "recent files") | |
| "f s" '(save-buffer :which-key "save") | |
| "f S" '(write-file :which-key "save as") | |
| "f R" '(rename-visited-file :which-key "rename current file") | |
| ;; Buffers | |
| "b" '(:ignore t :which-key "buffer") | |
| "b b" '(consult-buffer :which-key "switch buffer") | |
| "b d" '(kill-current-buffer :which-key "kill buffer") | |
| "b l" '(ibuffer :which-key "list buffers") | |
| "b n" '(next-buffer :which-key "next buffer") | |
| "b p" '(previous-buffer :which-key "previous buffer") | |
| "b r" '(revert-buffer-quick :which-key "revert buffer") | |
| "b s" '(scratch-buffer :which-key "scratch buffer") | |
| "b m" '(bookmark-set :which-key "set bookmark") | |
| "b M" '(consult-bookmark :which-key "jump to bookmark") | |
| ;; Project (built-in project.el) | |
| "p" '(:ignore t :which-key "project") | |
| "p f" '(project-find-file :which-key "find file in project") | |
| "p p" '(project-switch-project :which-key "switch project") | |
| "p s" '(project-find-regexp :which-key "grep in project") | |
| "p b" '(consult-project-buffer :which-key "project buffers") | |
| "p c" '(project-compile :which-key "compile") | |
| "p e" '(project-eshell :which-key "eshell in project root") | |
| "p d" '(project-dired :which-key "dired in project root") | |
| "p k" '(project-kill-buffers :which-key "kill project buffers") | |
| "p r" '(project-query-replace-regexp :which-key "replace in project") | |
| ;; Search | |
| "s" '(:ignore t :which-key "search") | |
| "s s" '(consult-line :which-key "search in buffer") | |
| "s S" '(isearch-forward :which-key "isearch forward") | |
| "s r" '(consult-ripgrep :which-key "ripgrep from here") | |
| "s f" '(consult-find :which-key "find file by name") | |
| "s i" '(consult-imenu :which-key "imenu symbols") | |
| "s I" '(consult-imenu-multi :which-key "imenu all buffers") | |
| "s l" '(consult-line-multi :which-key "search all open buffers") | |
| "s o" '(consult-outline :which-key "outline headings") | |
| "s R" '(query-replace :which-key "search & replace in buffer") | |
| ;; Code / LSP | |
| "c" '(:ignore t :which-key "code") | |
| "c a" '(eglot-code-actions :which-key "code actions") | |
| "c r" '(eglot-rename :which-key "rename symbol") | |
| "c f" '(apheleia-format-buffer :which-key "format buffer") | |
| "c d" '(xref-find-definitions :which-key "go to definition") | |
| "c D" '(xref-find-references :which-key "find references") | |
| "c e" '(consult-flymake :which-key "list diagnostics") | |
| "c j" '(flymake-goto-next-error :which-key "next error") | |
| "c k" '(flymake-goto-prev-error :which-key "prev error") | |
| "c o" '(eglot-code-action-organize-imports :which-key "organize imports") | |
| "c x" '(eglot-code-action-quickfix :which-key "quickfix") | |
| "c h" '(eldoc :which-key "docs at point") | |
| ;; Git | |
| "g" '(:ignore t :which-key "git") | |
| "g g" '(magit-status :which-key "status") | |
| "g b" '(magit-blame :which-key "blame") | |
| "g l" '(magit-log-current :which-key "log current branch") | |
| "g L" '(magit-log-all :which-key "log all branches") | |
| "g d" '(diff-hl-show-hunk :which-key "show hunk diff") | |
| "g r" '(diff-hl-revert-hunk :which-key "revert hunk") | |
| "g n" '(diff-hl-next-hunk :which-key "next changed hunk") | |
| "g p" '(diff-hl-previous-hunk :which-key "prev changed hunk") | |
| "g f" '(magit-file-dispatch :which-key "file actions") | |
| "g s" '(magit-stage-file :which-key "stage current file") | |
| ;; Window management | |
| "w" '(:ignore t :which-key "window") | |
| "w v" '(split-window-right :which-key "split vertical") | |
| "w s" '(split-window-below :which-key "split horizontal") | |
| "w d" '(delete-window :which-key "close window") | |
| "w w" '(other-window :which-key "other window") | |
| "w m" '(delete-other-windows :which-key "maximize") | |
| "w =" '(balance-windows :which-key "balance windows") | |
| "w r" '(evil-window-rotate-downwards :which-key "rotate windows") | |
| "w h" '(evil-window-left :which-key "go left") | |
| "w j" '(evil-window-down :which-key "go down") | |
| "w k" '(evil-window-up :which-key "go up") | |
| "w l" '(evil-window-right :which-key "go right") | |
| ;; Toggles | |
| "t" '(:ignore t :which-key "toggle") | |
| "t t" '(treemacs :which-key "file tree") | |
| "t d" '(my/load-dark-theme :which-key "dark theme") | |
| "t l" '(my/load-light-theme :which-key "light theme") | |
| "t T" '(consult-theme :which-key "browse themes") | |
| "t n" '(display-line-numbers-mode :which-key "line numbers") | |
| "t w" '(whitespace-mode :which-key "whitespace") | |
| "t f" '(display-fill-column-indicator-mode :which-key "fill column") | |
| "t v" '(visual-line-mode :which-key "word wrap") | |
| ;; Help | |
| "h" '(:ignore t :which-key "help") | |
| "h k" '(describe-key :which-key "describe key") | |
| "h f" '(describe-function :which-key "describe function") | |
| "h v" '(describe-variable :which-key "describe variable") | |
| "h m" '(describe-mode :which-key "describe mode") | |
| "h p" '(describe-package :which-key "describe package") | |
| "h i" '(info :which-key "info manual") | |
| "h a" '(apropos :which-key "search all help") | |
| "h b" '(embark-bindings :which-key "all keybindings") | |
| ;; Org | |
| "o" '(:ignore t :which-key "org") | |
| "o a" '(org-agenda :which-key "agenda") | |
| "o c" '(org-capture :which-key "capture") | |
| "o l" '(org-store-link :which-key "store link") | |
| "o t" '(org-todo-list :which-key "global todo list") | |
| ;; Evaluate elisp | |
| "e" '(:ignore t :which-key "eval") | |
| "e b" '(eval-buffer :which-key "eval buffer") | |
| "e r" '(eval-region :which-key "eval region") | |
| "e e" '(eval-last-sexp :which-key "eval last sexp") | |
| ;; Quit | |
| "q" '(:ignore t :which-key "quit") | |
| "q q" '(save-buffers-kill-terminal :which-key "quit emacs") | |
| "q r" '(restart-emacs :which-key "restart emacs") | |
| ;; Packages | |
| "P" '(:ignore t :which-key "packages") | |
| "P r" '(package-refresh-contents :which-key "refresh archives") | |
| "P u" '(package-upgrade-all :which-key "upgrade all") | |
| "P l" '(package-list-packages :which-key "list packages"))) | |
| ;; Show available keys after pressing a prefix | |
| (use-package which-key | |
| :diminish | |
| :config | |
| (which-key-mode)) | |
| (use-package diminish) | |
| ;;;;;;;;;;;;;;;;;;;;;;;;;;; | |
| ;; Appearance ;; | |
| ;;;;;;;;;;;;;;;;;;;;;;;;;;; | |
| ;; Font | |
| (set-face-attribute 'default nil :family "Fira Code" :height 120) | |
| ;; Dark theme (Spacemacs-like) | |
| (use-package doom-themes | |
| :config | |
| (load-theme 'doom-one t) | |
| (doom-themes-visual-bell-config) | |
| (doom-themes-treemacs-config) | |
| (doom-themes-org-config)) | |
| ;; Light themes for daytime | |
| (use-package ef-themes | |
| :defer t) | |
| ;; Quick theme switching | |
| (defun my/load-dark-theme () | |
| "Switch to dark theme." | |
| (interactive) | |
| (mapc #'disable-theme custom-enabled-themes) | |
| (load-theme 'doom-one t)) | |
| (defun my/load-light-theme () | |
| "Switch to light theme." | |
| (interactive) | |
| (mapc #'disable-theme custom-enabled-themes) | |
| (load-theme 'ef-light t)) | |
| ;; Icons (run M-x nerd-icons-install-fonts on first launch) | |
| (use-package nerd-icons) | |
| ;; Modeline | |
| (use-package doom-modeline | |
| :init (doom-modeline-mode 1) | |
| :custom | |
| (doom-modeline-height 35)) | |
| ;; Font ligatures (Fira Code) | |
| (use-package ligature | |
| :config | |
| (ligature-set-ligatures | |
| 'prog-mode | |
| '("www" "**" "***" "**/" "*>" "*/" "\\\\" "\\\\\\" | |
| "{-" "::" ":::" ":=" "!!" "!=" "!==" "-}" "----" "-->" "->" "->>" | |
| "-<" "-<<" "-~" "#{" "#[" "##" "###" "####" "#(" "#?" "#_" "#_(" | |
| ".-" ".=" ".." "..<" "..." "?=" "??" ";;" "/*" "/**" | |
| "/=" "/==" "/>" "//" "///" "&&" "||" "||=" "|=" "|>" "^=" "$>" | |
| "++" "+++" "+>" "=:=" "==" "===" "==>" "=>" "=>>" "<=" | |
| "=<<" "=/=" ">-" ">=" ">=>" ">>" ">>-" ">>=" ">>>" "<*" | |
| "<*>" "<|" "<|>" "<$" "<$>" "<!--" "<-" "<--" "<->" "<+" | |
| "<+>" "<=" "<==" "<=>" "<=<" "<>" "<<" "<<-" "<<=" "<<<" | |
| "<~" "<~~" "</" "</>" "~@" "~-" "~>" "~~" "~~>" "%%")) | |
| (global-ligature-mode t)) | |
| ;; Colorful parentheses | |
| (use-package rainbow-delimiters | |
| :hook (prog-mode . rainbow-delimiters-mode)) | |
| ;;;;;;;;;;;;;;;;;;;;;;;;;;; | |
| ;; Completion Framework ;; | |
| ;;;;;;;;;;;;;;;;;;;;;;;;;;; | |
| ;; Vertical completion UI | |
| (use-package vertico | |
| :custom | |
| (vertico-count 20) | |
| (vertico-resize t) | |
| :config | |
| (vertico-mode)) | |
| ;; Fuzzy/orderless matching | |
| (use-package orderless | |
| :custom | |
| (completion-styles '(orderless basic)) | |
| (completion-category-overrides '((file (styles basic partial-completion))))) | |
| ;; Enhanced commands (search, buffer switch, etc.) | |
| (use-package consult | |
| :bind (("C-x b" . consult-buffer) | |
| ("M-y" . consult-yank-pop) | |
| ("M-g g" . consult-goto-line) | |
| ("M-g M-g" . consult-goto-line) | |
| ("M-g i" . consult-imenu)) | |
| :hook (completion-list-mode . consult-preview-at-point-mode) | |
| :init | |
| (setq xref-show-xrefs-function #'consult-xref | |
| xref-show-definitions-function #'consult-xref) | |
| :config | |
| (consult-customize | |
| consult-theme :preview-key '(:debounce 0.2 any) | |
| consult-ripgrep consult-git-grep consult-grep consult-bookmark | |
| consult-recent-file consult-xref | |
| consult--source-bookmark consult--source-file-register | |
| consult--source-recent-file consult--source-project-recent-file | |
| :preview-key '(:debounce 0.4 any)) | |
| (setq consult-narrow-key "<")) | |
| ;; Annotations in minibuffer completions | |
| (use-package marginalia | |
| :init (marginalia-mode)) | |
| ;; Context-dependent actions on targets | |
| (use-package embark | |
| :bind (("C-." . embark-act) | |
| ("C-h B" . embark-bindings)) | |
| :init | |
| (setq prefix-help-command #'embark-prefix-help-command) | |
| :config | |
| (add-to-list 'display-buffer-alist | |
| '("\\`\\*Embark Collect \\(Live\\|Completions\\)\\*" | |
| nil | |
| (window-parameters (mode-line-format . none))))) | |
| (use-package embark-consult | |
| :after (embark consult) | |
| :hook (embark-collect-mode . consult-preview-at-point-mode)) | |
| ;; Inline completion popup (replaces company-mode) | |
| (use-package corfu | |
| :custom | |
| (corfu-auto t) ; show completions automatically | |
| (corfu-auto-delay 0.1) | |
| (corfu-cycle t) ; cycle through candidates | |
| :init | |
| (global-corfu-mode)) | |
| ;; Extra completion sources for corfu | |
| (use-package cape | |
| :init | |
| (add-hook 'completion-at-point-functions #'cape-dabbrev) | |
| (add-hook 'completion-at-point-functions #'cape-file)) | |
| ;;;;;;;;;;;;;;;;;;;;;;;;;;; | |
| ;; Development Tools ;; | |
| ;;;;;;;;;;;;;;;;;;;;;;;;;;; | |
| ;; Tree-sitter grammar management | |
| (use-package treesit-auto | |
| :custom | |
| (treesit-auto-install 'prompt) | |
| :config | |
| (treesit-auto-add-to-auto-mode-alist 'all) | |
| (global-treesit-auto-mode)) | |
| ;; LSP via built-in eglot | |
| (use-package eglot | |
| :hook ((go-ts-mode rust-mode rust-ts-mode python-ts-mode python-mode | |
| js-ts-mode typescript-ts-mode zig-mode) . eglot-ensure) | |
| :config | |
| (setq eglot-autoshutdown t)) ; shut down server when last buffer is closed | |
| ;; Format on save with external formatters | |
| (use-package apheleia | |
| :diminish | |
| :config | |
| (apheleia-global-mode t)) | |
| ;; Git porcelain | |
| (use-package magit | |
| :defer t) | |
| ;; Git gutter indicators | |
| (use-package diff-hl | |
| :config | |
| (global-diff-hl-mode) | |
| (add-hook 'magit-pre-refresh-hook 'diff-hl-magit-pre-refresh) | |
| (add-hook 'magit-post-refresh-hook 'diff-hl-magit-post-refresh)) | |
| ;;;;;;;;;;;;;;;;;;;;;;;;;;; | |
| ;; Clojure + CIDER ;; | |
| ;;;;;;;;;;;;;;;;;;;;;;;;;;; | |
| (use-package clojure-mode | |
| :mode (("\\.clj\\'" . clojure-mode) | |
| ("\\.edn\\'" . clojure-mode) | |
| ("\\.cljs\\'" . clojurescript-mode) | |
| ("\\.cljc\\'" . clojurec-mode))) | |
| (use-package cider | |
| :defer t | |
| :diminish subword-mode | |
| :custom | |
| (cider-repl-pop-to-buffer-on-connect t) | |
| (cider-show-error-buffer t) | |
| (cider-auto-select-error-buffer t)) | |
| (use-package clj-deps-new | |
| :defer t) | |
| ;; Structural editing for Lisps — paredit handles parens, so disable electric-pair | |
| (use-package paredit | |
| :hook ((clojure-mode . paredit-mode) | |
| (clojurescript-mode . paredit-mode) | |
| (clojurec-mode . paredit-mode) | |
| (cider-repl-mode . paredit-mode) | |
| (emacs-lisp-mode . paredit-mode) | |
| (lisp-interaction-mode . paredit-mode)) | |
| :config | |
| (add-hook 'paredit-mode-hook | |
| (lambda () (electric-pair-local-mode -1)))) | |
| ;;;;;;;;;;;;;;;;;;;;;;;;;;; | |
| ;; Languages ;; | |
| ;;;;;;;;;;;;;;;;;;;;;;;;;;; | |
| ;; Rust | |
| (use-package rust-mode | |
| :defer t) | |
| ;; Zig | |
| (use-package zig-mode | |
| :defer t) | |
| ;; Racket | |
| (use-package racket-mode | |
| :defer t) | |
| (use-package geiser-racket | |
| :defer t) | |
| ;; Web (HTML, JSX, TSX) | |
| (use-package web-mode | |
| :mode ("\\.html\\'" "\\.jsx\\'" "\\.tsx\\'")) | |
| ;; YAML | |
| (use-package yaml-mode | |
| :defer t) | |
| ;; Markdown | |
| (use-package markdown-mode | |
| :mode ("\\.md\\'" ("README\\.md\\'" . gfm-mode)) | |
| :custom | |
| (markdown-command "multimarkdown")) | |
| ;;;;;;;;;;;;;;;;;;;;;;;;;;; | |
| ;; Org Mode ;; | |
| ;;;;;;;;;;;;;;;;;;;;;;;;;;; | |
| (use-package org | |
| :ensure nil ; built-in | |
| :custom | |
| (org-directory "~/org") | |
| (org-agenda-files '("~/org")) | |
| (org-startup-indented t) | |
| (org-hide-emphasis-markers t) | |
| (org-return-follows-link t) | |
| :config | |
| (setq org-capture-templates | |
| '(("t" "Todo" entry (file+headline "~/org/inbox.org" "Tasks") | |
| "* TODO %?\n %i\n %a") | |
| ("n" "Note" entry (file+headline "~/org/inbox.org" "Notes") | |
| "* %?\n %i\n %a")))) | |
| ;; Pretty org headers, bullets, tables | |
| (use-package org-modern | |
| :hook (org-mode . org-modern-mode)) | |
| ;;;;;;;;;;;;;;;;;;;;;;;;;;; | |
| ;; File Tree ;; | |
| ;;;;;;;;;;;;;;;;;;;;;;;;;;; | |
| (use-package treemacs | |
| :defer t | |
| :config | |
| (treemacs-follow-mode t) | |
| (treemacs-filewatch-mode t)) | |
| (use-package treemacs-magit | |
| :after (treemacs magit)) | |
| (use-package treemacs-nerd-icons | |
| :after treemacs | |
| :config | |
| (treemacs-load-theme "nerd-icons")) | |
| ;;;;;;;;;;;;;;;;;;;;;;;;;;; | |
| ;; Load custom.el ;; | |
| ;;;;;;;;;;;;;;;;;;;;;;;;;;; | |
| (when (file-exists-p custom-file) | |
| (load custom-file)) | |
| ;;; init.el ends here |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment