This is a literate Emacs configuration file written in Org mode. The primary goal is to create a setup that is well-documented, modular, and easy to maintain. All configuration is tangled into `init.el` upon saving this file.
This section contains critical setup that must run at the very beginning of the Emacs startup process, before any packages are loaded.
These settings disable distracting UI elements and set up fundamental frame behavior to ensure a clean and predictable launch.
;; Set frame behavior early
(setq frame-resize-pixelwise t
frame-inhibit-implied-resize t)
;; Disable UI elements for a minimal appearance
(scroll-bar-mode -1)
(tool-bar-mode -1)
(tooltip-mode -1)
(menu-bar-mode -1)
(set-fringe-mode 10) ; A little breathing room
;; Inhibit startup screens and messages for a faster, quieter launch
(setq inhibit-splash-screen t
inhibit-startup-screen t
inhibit-x-resources t
inhibit-startup-echo-area-message user-login-name
inhibit-startup-buffer-menu t
inhibit-startup-message t)
;; Set up the visible bell instead of an audible one
(setq visible-bell t)
;; Use short 'y/n' answers instead of 'yes/no'
(defalias 'yes-or-no-p 'y-or-n-p)
;; Reduce native compilation noise
(when (featurep 'native-compile)
(setq native-comp-async-report-warnings-errors nil))
;; Ensure Emacs uses the proper PATH from bash shell
(defun update-path-from-bash ()
"Update PATH and exec-path from bash shell environment."
(let ((path-from-bash (shell-command-to-string "bash -i -c 'echo $PATH'")))
(setenv "PATH" (string-trim path-from-bash))
(setq exec-path (split-string (getenv "PATH") path-separator))))
(update-path-from-bash)I use `straight.el` for package management, which works directly with Git repositories. It is paired with `use-package` for declarative configuration. This block bootstraps `straight.el` if it’s not already installed.
(setq straight-use-package-by-default t)
;; Ensure we can get packages from nongnu.org
(custom-set-variables
'(straight-recipe-overrides '((nil
(nongnu-elpa :type git
:repo "https://github.com/emacsmirror/nongnu_elpa"
:depth (full single-branch)
:local-repo "nongnu-elpa"
:build nil)))))
(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)
(setq use-package-always-ensure t)
;; Diminish hides or shortens minor mode names in the mode line
(straight-use-package 'diminish)
;; GCMH - Garbage Collector Magic Hack for better performance
(use-package gcmh
:config
(gcmh-mode 1))This configures Org mode basics, especially the function to automatically tangle this configuration file (`Emacs.org` -> `init.el`) every time it is saved.
(setq org-support-shift-select t)
;; Automatically tangle our Emacs.org config file when we save it
(defun efs/org-babel-tangle-config ()
"Auto-tangle config file on save."
(condition-case err
(when (and (buffer-file-name)
(string-equal (file-name-directory (buffer-file-name))
(expand-file-name user-emacs-directory)))
;; Dynamic scoping to the rescue
(let ((org-confirm-babel-evaluate nil))
(org-babel-tangle)))
(error
(message "Error tangling config: %s" (error-message-string err)))))
(add-hook 'org-mode-hook
(lambda ()
(add-hook 'after-save-hook #'efs/org-babel-tangle-config nil 'local)))
(with-eval-after-load 'org
(require 'org-tempo) ;; Needed as of Org 9.2 for structure templates
(add-to-list 'org-structure-template-alist '("sh" . "src shell"))
(add-to-list 'org-structure-template-alist '("el" . "src emacs-lisp"))
(add-to-list 'org-structure-template-alist '("py" . "src python")))This section configures the fundamental, non-UI behavior of Emacs, from user information to editing enhancements and file handling.
Consolidated configuration for user settings, file handling, editing behavior, and built-in features.
(use-package emacs
:ensure nil
:bind (("M-o" . other-window)
("M-j" . duplicate-dwim)
("RET" . newline-and-indent)
;; Unbind some keys to use for other purposes
("C-z" . nil)
("C-x C-z" . nil)
("C-x C-k RET" . nil))
:custom
;; User information
(user-full-name "Sean Mooney")
(user-mail-address "sean@seanmooney.info")
;; Use UTF-8 everywhere
(coding-system-for-read 'utf-8)
(coding-system-for-write 'utf-8)
(ad-redefinition-action 'accept)
;; Don't create lockfiles
(create-lockfiles nil)
;; Disable backup files
(make-backup-files nil)
(backup-inhibited t)
;; Disable auto-save files (#filename#)
(auto-save-default nil)
(auto-save-mode nil)
;; Editing behavior
(completion-ignore-case t)
(completions-detailed t)
;; Highlight the current line in programming, text, and org modes.
(global-hl-line-mode t)
;; When pasting, overwrite the currently selected region.
(delete-selection-mode 1)
(help-window-select t)
;; Don't store duplicate entries in the kill ring
(kill-do-not-save-duplicates t)
;; Default width for text wrapping
(fill-column 80)
(column-number-mode 1)
;; Completion settings
(completions-max-height 15)
(tab-always-indent 'complete)
:config
;; Font lock (syntax highlighting)
(global-font-lock-mode 1)
(setq font-lock-maximum-decoration t))Additional packages that enhance the text editing experience beyond built-in functionality.
;; Enable line numbers for modes where it's most useful.
(dolist (mode '(text-mode-hook
prog-mode-hook
conf-mode-hook))
(add-hook mode #'display-line-numbers-mode))
;; But disable them for modes where they are distracting.
(dolist (mode '(org-mode-hook
term-mode-hook
shell-mode-hook
treemacs-mode-hook
eshell-mode-hook))
(add-hook mode (lambda () (display-line-numbers-mode -1))))
;; Automatically pair delimiters like parentheses and quotes.
(use-package elec-pair
:ensure nil
:hook (after-init . electric-pair-mode)
:config
;; A handy command for deleting a pair of surrounding delimiters.
(global-set-key (kbd "C-c d") #'delete-pair)
(setq delete-pair-blink-delay 0.0))
;; Visually highlight matching parentheses.
(use-package paren
:ensure nil
:hook (after-init . show-paren-mode)
:custom
(show-paren-style 'mixed)
(show-paren-context-when-offscreen t))
;; Allows repeating commands with C-x z.
(use-package repeat
:config
(repeat-mode 1))
;; Color-code matching delimiters for better code readability
(use-package rainbow-delimiters
:hook (prog-mode . rainbow-delimiters-mode))
;; Move text (lines or regions) up and down
(use-package move-text
:bind (("M-<up>" . move-text-up)
("M-<down>" . move-text-down))
:config
(move-text-default-bindings))
;; Multiple cursors for simultaneous editing
(use-package multiple-cursors
:bind (("C-S-c C-S-c" . mc/edit-lines) ; Add cursor to each line in region
("C->" . mc/mark-next-like-this) ; Mark next occurrence
("C-<" . mc/mark-previous-like-this) ; Mark previous occurrence
("C-c C-<" . mc/mark-all-like-this) ; Mark all occurrences
("C-S-<mouse-1>" . mc/add-cursor-on-click)) ; Add cursor with mouse
:config
;; Don't warn about commands that haven't been used with multiple cursors
(setq mc/always-run-for-all t))
This configures how Emacs handles files, symlinks, and saving state.
(use-package files
:ensure nil
:straight (:type built-in)
:custom
;; Prefer newer versions of files when loading Lisp code.
(load-prefer-newer t)
;; Don't warn me about large files. I know what I'm doing.
(large-file-warning-threshold nil)
;; When visiting a file, resolve symlinks to the true path.
(find-file-visit-truename t))
;; Remember the cursor position in files between sessions.
(use-package saveplace
:ensure nil
:hook (after-init . save-place-mode))
;; Remember minibuffer history between sessions.
(use-package savehist
:ensure nil
:hook (after-init . savehist-mode)
:custom (history-length 300))
;; Remember recently opened files.
(use-package recentf
:ensure nil
:hook (after-init . recentf-mode)
:custom
(recentf-max-saved-items 100)
(recentf-exclude '("/tmp/" "/ssh:" "/sudo:" "\\.git/")))
;; Automatically revert file buffers when they change on disk.
(use-package autorevert
:ensure nil
:custom
(auto-revert-interval 1) ; Check every second
(auto-revert-check-vc-info t) ; Also check version control info
(auto-revert-verbose t) ; Show messages when reverting
(global-auto-revert-non-file-buffers t) ; Also revert non-file buffers like Dired
(auto-revert-avoid-polling nil) ; Use file notifications when available
:config
(global-auto-revert-mode 1))This setup enables undo-tree-mode, a more powerful way of handling undo/redo that visualizes the history as a tree. More importantly, it configures Emacs to save the undo history of files to a dedicated directory (~/.config/emacs/undo/), so you can undo changes even after closing and reopening a file.
(use-package undo-tree
:hook (after-init . global-undo-tree-mode)
:bind (("C-z" . undo-tree-undo)
("C-S-z" . undo-tree-redo))
:custom
;; Save undo history across sessions
(undo-tree-auto-save-history t)
;; Create the undo directory if it doesn't exist
(undo-tree-history-directory-alist
`(("." . ,(expand-file-name "undo/" user-emacs-directory))))
;; Increase the amount of history stored
(undo-tree-buffer-size-limit (* 1024 1024 8)) ; 8MB
(undo-tree-max-history-size 1000)
:config
;; Unbind C-/ from undo-tree to allow our comment binding
(define-key undo-tree-map (kbd "C-/") nil))Settings for Emacs’s built-in version control integration.
(use-package vc
:ensure nil
:custom
;; VC should follow symbolic links.
(vc-follow-symlinks t))settings for magit for more powerful git integration
(use-package magit
:bind (("C-x g" . magit-status)
("C-x M-g" . magit-dispatch))
:custom
(magit-display-buffer-function #'magit-display-buffer-same-window-except-diff-v1))
;; Show git diff indicators in the fringe
(use-package diff-hl
:hook ((prog-mode . diff-hl-mode)
(dired-mode . diff-hl-dired-mode))
:config
;; Integration with magit - refresh diff-hl when magit updates
(with-eval-after-load 'magit
(add-hook 'magit-pre-refresh-hook #'diff-hl-magit-pre-refresh)
(add-hook 'magit-post-refresh-hook #'diff-hl-magit-post-refresh)))This section covers all visual aspects of Emacs, from fonts and colors to window layouts and completion UIs.
I use the `fontaine` package to easily switch between predefined font configurations. My default is `Source Code Pro` for code and `FiraGO` for proportional text.
(use-package fontaine
:demand t
:init
(setq fontaine-latest-state-file
(locate-user-emacs-file "fontaine-latest-state.eld"))
(setq fontaine-presets
'((small
:default-height 90)
(regular
:default-height 120)
(medium
:default-weight semilight
:default-height 140)
(large
:default-weight semilight
:default-height 180
:bold-weight extrabold)
(dyslexia-friendly
:default-family "OpenDyslexic"
:variable-pitch-family "OpenDyslexic"
:default-height 130
:variable-pitch-height 1.1)
(t ; our shared fallback properties
:default-family "Source Code Pro"
:default-weight semilight
:default-height 100
:variable-pitch-family "FiraGO"
:variable-pitch-weight normal
:variable-pitch-height 1.05
:bold-weight bold
:italic-slant italic)))
:bind ("C-c f" . fontaine-set-preset))
;; Improve line spacing for better readability
(setq-default line-spacing 0.2)
;; Pulsar briefly highlights the current line after certain commands
;; Excellent accessibility feature for tracking cursor movement
(use-package pulsar
:config
(pulsar-global-mode 1)
:custom
;; Highlight line after these commands for better cursor tracking
(pulsar-pulse-functions '(isearch-repeat-forward
isearch-repeat-backward
recenter-top-bottom
move-to-window-line-top-bottom
reposition-window
bookmark-jump
other-window
delete-window
delete-other-windows
forward-page
backward-page
scroll-up-command
scroll-down-command
windmove-right
windmove-left
windmove-up
windmove-down)))I use the `ef-themes` collection by Protesilaos Stavrou for its excellent contrast and beautiful color palettes. I define a dark (`ef-cherie`) and light (`ef-summer`) theme to toggle between.
(use-package ef-themes
:config
;; Define the pair of themes to toggle between.
(setq ef-themes-to-toggle '(ef-cherie ef-summer))
;; Disable all other themes to avoid awkward blending.
(mapc #'disable-theme custom-enabled-themes)
;; Load the default dark theme.
(load-theme 'ef-cherie :no-confirm))These settings control the appearance of the Emacs frame, windows, and how they are split.
;; Enable smooth, pixel-based scrolling.
(setq pixel-scroll-precision-mode t)
(setq pixel-scroll-precision-use-momentum nil)
;; Add a hint of transparency and maximize the frame on startup.
(set-frame-parameter (selected-frame) 'alpha-background 93)
(add-to-list 'default-frame-alist '(alpha-background . 93))
(set-frame-parameter (selected-frame) 'fullscreen 'maximized)
(add-to-list 'default-frame-alist '(fullscreen . maximized))
;; Improve display characters in terminal mode.
(set-display-table-slot standard-display-table 'vertical-border ?\u2502)
(set-display-table-slot standard-display-table 'truncation ?\u2192)
;; Custom function to toggle a 2-window split between vertical and horizontal.
(defun toggle-window-split ()
"Switch between horizontal and vertical split window layout."
(interactive)
(if (= (count-windows) 2)
(let* ((other-win (next-window))
;; Is the split vertical? (i.e. do windows share a left edge)
(is-vertical-split (= (nth 0 (window-edges))
(nth 0 (window-edges other-win)))))
;; Delete the other window, which collapses the split
(delete-other-windows)
;; And re-split in the other direction
(if is-vertical-split
(split-window-horizontally)
(split-window-vertically)))
(message "This command only works when there are exactly two windows.")))
(global-set-key (kbd "C-c j") #'toggle-window-split)I use a modern completion system composed of several packages that work together.
verticoprovides the core vertical minibuffer UI.marginaliaadds rich annotations (file permissions, command docs) to completions.orderlessenables powerful out-of-order matching.consultenhances built-in commands like `find-file` and `switch-to-buffer` with previews.corfuprovides an in-buffer completion popup.
(use-package vertico
:init (vertico-mode)
:custom
(vertico-cycle t)
(vertico-resize nil))
(use-package marginalia
:after vertico
:init (marginalia-mode))
(use-package orderless
:custom
(completion-styles '(orderless flex basic))
(completion-category-overrides '((file (styles basic partial-completion)))))
(use-package corfu
:hook (prog-mode . corfu-mode)
:custom
(corfu-auto nil)
(corfu-auto-delay 0.1)
(corfu-quit-no-match 'separator)
;; Disable corfu in modes where it's disruptive
(corfu-mode-modes '(not eshell-mode shell-mode term-mode))
:init
(global-corfu-mode))
;; Adds more completion sources (backends) for Corfu
(use-package cape
:init
(add-to-list 'completion-at-point-functions #'cape-file))
(use-package consult
:bind (("C-x f" . consult-find)
("M-s M-o" . consult-outline)
("C-f" . consult-line)
("C-x b" . consult-buffer) ; a powerful switch-to-buffer
("C-j" . consult-imenu)
("C-x p b" . consult-project-buffer)
("M-y" . consult-yank-pop)
("M-g g" . consult-goto-line)
("C-c m" . consult-man)
("C-c i" . consult-info)
("C-c h" . consult-history)
("M-s c" . consult-locate)
("M-s g" . consult-grep)
("M-s G" . consult-git-grep)
("M-s r" . consult-ripgrep)
;; Isearch integration
("M-s e" . consult-isearch-history)
:map isearch-mode-map
("M-e" . consult-isearch-history)
("M-s e" . consult-isearch-history)
("M-s l" . consult-line)
("M-s L" . consult-line-multi))
:init
;; Add consult bindings to org-mode and org-agenda
(with-eval-after-load "org"
(keymap-set org-mode-map "C-j" #'consult-org-heading))
(with-eval-after-load "org-agenda"
(keymap-set org-agenda-mode-map "C-j" #'consult-org-agenda))
:config
(setq consult-line-start-from-top nil)
;; Integrate with xref for "find definitions/references"
(with-eval-after-load "xref"
(require 'consult-xref)
(setq xref-show-xrefs-function #'consult-xref)
(setq xref-show-definitions-function #'consult-xref)))
Configuration for Dired, Emacs’s built-in file manager.
(use-package dired
:straight (:type built-in)
:ensure nil
:hook ((dired-mode . hl-line-mode)
(dired-mode . dired-hide-details-mode))
:custom
(dired-listing-switches "-alFh") ; ls-like output
(dired-dwim-target t) ; Smart target for copying/renaming
(dired-recursive-copies 'always)
(dired-recursive-deletes 'always))
;; dired-x provides extra functionality for dired
(use-package dired-x
:ensure nil
:straight (:type built-in)
:after dired
:bind (("C-x C-j" . dired-jump)) ; Jump to dired of current file
:custom
;; Only omit system/backup files, not regular dot files
(dired-omit-files "^\\.\\.$\\|\\.DS_Store$\\|\\.localized$\\|~$\\|#.*#$")
(dired-guess-shell-gnutar "tar"))
;; Ranger-style file browser with three-pane layout and previews
(use-package ranger
:bind (("C-x r d" . ranger)
("C-x r j" . deer)) ; Minimal ranger mode
:custom
(ranger-cleanup-eagerly t) ; Clean up ranger buffers
(ranger-cleanup-on-disable t)
(ranger-show-dotfiles t)
(ranger-preview-file t) ; Show file previews
(ranger-max-preview-size 10) ; Limit preview to 10MB files
:config
;; Don't show hidden files by default (toggle with zh)
(setq ranger-show-hidden nil))
;; Modern icons for dired
(use-package nerd-icons-dired
:after (dired nerd-icons)
:hook (dired-mode . nerd-icons-dired-mode))I use Ibuffer to manage open buffers, with custom groups to keep things organized.
(use-package ibuffer
:ensure nil
:bind ("C-x C-b" . ibuffer)
:custom
(ibuffer-show-empty-filter-groups nil)
(ibuffer-saved-filter-groups
'(("default"
("org" (or (mode . org-mode) (name . "^\\*Org Src")))
("emacs" (or (name . "^\\*scratch\\*$") (name . "^\\*Messages\\*$")))
("dired" (mode . dired-mode))
("terminal" (or (mode . term-mode) (mode . shell-mode)))
("help" (or (name . "^\\*Help\\*$") (name . "^\\*helpful"))))))
:config
(add-hook 'ibuffer-mode-hook
(lambda () (ibuffer-switch-to-saved-filter-groups "default"))))Additional UI packages that help with discoverability and navigation.
;; `which-key` displays available keybindings in a popup.
(use-package which-key
:config
(which-key-mode))
;; Enhanced help system with more detailed information and better formatting
(use-package helpful
:bind (("C-h f" . helpful-callable) ; Enhanced function help
("C-h v" . helpful-variable) ; Enhanced variable help
("C-h k" . helpful-key) ; Enhanced key help
("C-h x" . helpful-command)) ; Enhanced command help
:custom
;; Show source code for elisp functions
(helpful-switch-buffer-function #'helpful-switch-to-buffer))
;; Transient menu framework (required for claude-code)
(use-package transient
:straight t)
;; Clean up mode line by hiding/shortening minor mode names
(use-package diminish
:ensure nil ; Already installed above
:config
;; Hide these minor modes from the mode line
(diminish 'which-key-mode)
(diminish 'eldoc-mode)
(diminish 'auto-revert-mode)
(diminish 'visual-line-mode)
(diminish 'subword-mode)
(diminish 'rainbow-delimiters-mode)
(diminish 'flyspell-mode)
(diminish 'writegood-mode))
;; `treemacs` provides a file tree sidebar.
(use-package treemacs
:defer t
:bind (("C-x t w" . treemacs-select-window)
("C-x t 1" . treemacs-delete-other-windows)
("C-x t t" . treemacs)
("C-x t d" . treemacs-select-directory))
:config
(setq treemacs-collapse-dirs (if treemacs-python-executable 3 0)
treemacs-display-in-side-window t
treemacs-follow-after-init t
treemacs-expand-after-init t
treemacs-git-command-pipe ""
treemacs-hide-dot-git-directory t
treemacs-indentation 2
treemacs-litter-directories '("/node_modules" "/.venv" "/.cask")
treemacs-position 'left
treemacs-show-hidden-files t
treemacs-width 35)
(treemacs-follow-mode t)
(treemacs-filewatch-mode t)
(treemacs-fringe-indicator-mode 'always)
;; Enable automatic project following
(treemacs-project-follow-mode t))
;; Custom integration with project.el for single-project display
(defun my/treemacs-display-current-project-exclusively ()
"Display only the current project in treemacs, removing all others."
(when-let* ((project (project-current))
(project-root (project-root project)))
(treemacs-block-refresh
;; Remove all projects from workspace
(treemacs-remove-project-from-workspace
(treemacs-workspace->projects (treemacs-current-workspace)))
;; Add and display only the current project
(treemacs-add-and-display-current-project-exclusively))))
;; Advice to automatically update treemacs when switching projects
(defun my/treemacs-project-switch-advice (&rest _args)
"Advice function to update treemacs when switching projects."
(when (and (featurep 'treemacs)
(treemacs-current-workspace))
(run-with-idle-timer 0.1 nil #'my/treemacs-display-current-project-exclusively)))
;; Add advice to project-switch-project
(with-eval-after-load 'project
(advice-add 'project-switch-project :after #'my/treemacs-project-switch-advice))
;; Git integration for treemacs
(use-package treemacs-magit
:after (treemacs magit)
:defer t)
;; Modern icon support for better readability
(use-package nerd-icons
:config
;; Run M-x nerd-icons-install-fonts after first install
(unless (find-font (font-spec :name "Symbols Nerd Font Mono"))
(when (y-or-n-p "Nerd fonts not found. Install them? ")
(nerd-icons-install-fonts))))
(use-package treemacs-nerd-icons
:after (treemacs nerd-icons)
:config
(treemacs-load-theme "nerd-icons"))Configuration for packages that enhance reading comprehension and writing quality, particularly beneficial for dyslexic users.
Creates a focused writing environment with comfortable margins and reduced visual clutter.
(use-package olivetti
:bind ("C-c o" . olivetti-mode)
:custom
(olivetti-body-width 80)
(olivetti-minimum-body-width 60)
(olivetti-recall-visual-line-mode-entry-state t))Helps improve writing clarity and catch common errors beyond spell-checking.
(use-package writegood-mode
:hook (text-mode . writegood-mode)
:custom
(writegood-weasel-words-length 5))
Codespell catches common spelling errors in code, comments, and documentation. Particularly useful for catching typos in variable names and comments.
;; Codespell integration for catching spelling errors in code
(defun my-codespell-buffer ()
"Run codespell on the current buffer."
(interactive)
(if (executable-find "codespell")
(let ((temp-file (make-temp-file "codespell-")))
(write-region (point-min) (point-max) temp-file)
(with-temp-buffer
(call-process "codespell" nil t nil temp-file)
(if (> (buffer-size) 0)
(progn
(display-buffer (current-buffer))
(message "Codespell found issues - see *codespell* buffer"))
(message "No spelling errors found by codespell")))
(delete-file temp-file))
(message "Codespell not found. Install with: pip install codespell")))
(defun my-codespell-region (start end)
"Run codespell on the selected region."
(interactive "r")
(if (executable-find "codespell")
(let ((temp-file (make-temp-file "codespell-region-")))
(write-region start end temp-file)
(with-temp-buffer
(call-process "codespell" nil t nil temp-file)
(if (> (buffer-size) 0)
(progn
(display-buffer (current-buffer))
(message "Codespell found issues in region"))
(message "No spelling errors found in region")))
(delete-file temp-file))
(message "Codespell not found. Install with: pip install codespell")))
(defun my-codespell-project ()
"Run codespell on the current project."
(interactive)
(if (executable-find "codespell")
(if-let ((project-root (project-root (project-current))))
(let ((default-directory project-root))
(compile "codespell --skip=.git,*.lock,*.json"))
(message "Not in a project"))
(message "Codespell not found. Install with: pip install codespell")))This section configures Emacs for software development, including linters, language servers, and language-specific setups.
These are language-agnostic tools that form the foundation of the IDE experience.
;; `flymake` is the built-in alternative.
;; I bind keys for navigating its diagnostics.
(use-package flymake
:ensure nil
:bind (:map flymake-mode-map
("C-c n" . flymake-goto-next-error)
("C-c p" . flymake-goto-prev-error)))
;; `eglot` is a minimal, built-in LSP client.
(use-package eglot
:hook ((python-mode . eglot-ensure)
(python-ts-mode . eglot-ensure)
(js-mode . eglot-ensure)
(typescript-mode . eglot-ensure)
(zig-mode . eglot-ensure))
:bind (("C-c l c" . eglot-reconnect)
("C-c l d" . flymake-show-buffer-diagnostics)
("C-c l f f" . eglot-format)
("C-c l f b" . eglot-format-buffer)
("C-c l l" . eglot)
("C-c l r n" . eglot-rename)
("C-c l s" . eglot-shutdown)
("C-c l i" . eglot-inlay-hints-mode))
:custom
;; Shutdown LSP server when the last managed buffer is killed.
(eglot-autoshutdown t))
;; Configuration for Emacs's compilation interface.
(use-package compile
:ensure nil
:bind (("C-c b" . compile)
("C-c B" . recompile)) ; Removed C-c t conflict
:custom
(compilation-scroll-output 'first-error)
(compilation-skip-threshold 2)) ; Skip warningsTraditional spell checker that’s reliable and doesn’t interfere with syntax highlighting.
;; Flyspell for spell checking
(use-package flyspell
:ensure nil
:hook ((text-mode . flyspell-mode)
(org-mode . flyspell-mode)
(markdown-mode . flyspell-mode)
(prog-mode . flyspell-prog-mode)) ; Only check comments/strings in code
:bind (("M-$" . flyspell-correct-word-before-point)
("C-M-$" . ispell-change-dictionary))
:custom
(flyspell-issue-message-flag nil) ; Don't show messages for every word
(flyspell-issue-welcome-flag nil) ; Don't show welcome message
:config
;; Better visual feedback
(set-face-attribute 'flyspell-incorrect nil :underline '(:color "red" :style wave))
(set-face-attribute 'flyspell-duplicate nil :underline '(:color "orange" :style wave)))Tree-sitter provides faster and more accurate syntax parsing, which improves highlighting and code analysis. `treesit-auto` manages the installation of parsers.
(use-package treesit-auto
:custom
(treesit-auto-install 'prompt)
:config
;; Only add tree-sitter modes for languages that benefit from it
(treesit-auto-add-to-auto-mode-alist '(python bash javascript typescript json yaml zig))
(global-treesit-auto-mode))This section configures the Python development environment, including virtual environment management with `pyvenv` and linting with `ruff`.
(add-to-list 'vc-directory-exclusion-list ".venv")
(use-package pyvenv
:config
(pyvenv-mode 1)
;; Set correct Python interpreter when a virtual env is activated/deactivated.
(setq pyvenv-post-activate-hooks
(list (lambda ()
(setq python-shell-interpreter (concat pyvenv-virtual-env "bin/python3")))))
(setq pyvenv-post-deactivate-hooks
(list (lambda ()
(setq python-shell-interpreter "python3")))))
(use-package python
:ensure nil
:hook (python-mode . (lambda ()
(setq-local tab-width 4)
(setq-local python-indent-offset 4)))
:custom
;; Use the fast and powerful `ruff` linter for checking Python code.
(python-check-command "ruff check --ignore-noqa")
;; Ensure syntax highlighting works properly
(python-font-lock-keywords-level 2))This section configures the Markdown syntax highlighting.
(use-package markdown-mode
:ensure t
:mode ("README\\.md\\'" . gfm-mode)
:init (setq markdown-command "multimarkdown")
:bind (:map markdown-mode-map
("C-c C-e" . markdown-do)))This section configures Zig development support with syntax highlighting, LSP integration, and Tree-sitter parsing.
(use-package zig-mode
:hook (zig-mode . (lambda ()
(setq-local tab-width 4)
(setq-local indent-tabs-mode nil))))`direnv` is a tool that loads and unloads environment variables depending on the current directory. This package integrates it with Emacs.
(use-package direnv
:config
(direnv-mode))EditorConfig helps maintain consistent coding styles across different editors and IDEs.
(use-package editorconfig
:config
(editorconfig-mode 1))Enhanced project.el integration with useful keybindings for project-based workflows. Custom helper functions provide integrated workflows leveraging treemacs, eat, magit, and consult.
;; Custom project helper functions
(defun my/project-workspace-setup ()
"Setup 2-pane workspace: dired on left, eat terminal on right (50:50 split)."
(interactive)
(let ((project-root (project-root (project-current))))
;; Close treemacs if it's loaded and has a workspace
(when (and (featurep 'treemacs)
(fboundp 'treemacs-current-workspace)
(treemacs-current-workspace))
(treemacs-kill-buffer))
;; Start with a clean slate
(delete-other-windows)
;; Open dired in project root
(dired project-root)
;; Split window vertically (50:50)
(split-window-right)
;; Move to right pane and open terminal
(other-window 1)
(eat-project)
;; Terminal should be the active buffer (already is from other-window)
))
(defun my/project-dev-setup ()
"Open terminal + magit for development workflow."
(interactive)
(let ((project-root (project-root (project-current))))
(eat-project)
(magit-status project-root)))
(defun my/project-smart-compile ()
"Compile using project-appropriate command based on detected project type."
(interactive)
(let* ((project-root (project-root (project-current)))
(compile-cmd (cond
((file-exists-p (expand-file-name "Makefile" project-root)) "make")
((file-exists-p (expand-file-name "package.json" project-root)) "npm run build")
((file-exists-p (expand-file-name "Cargo.toml" project-root)) "cargo build")
((file-exists-p (expand-file-name "pyproject.toml" project-root)) "python -m build")
((file-exists-p (expand-file-name "CMakeLists.txt" project-root)) "cmake --build build")
(t "make"))))
(compile compile-cmd)))
(defun my/consult-project-ripgrep ()
"Ripgrep in current project with better defaults."
(interactive)
(consult-ripgrep (project-root (project-current))))
(defun my/project-show-treemacs ()
"Show treemacs for current project."
(interactive)
(if (treemacs-current-workspace)
(treemacs-select-window)
(treemacs)))
(defun my/project-ranger ()
"Open ranger in current project root."
(interactive)
(let ((project-root (project-root (project-current))))
(ranger project-root)))
(defun my/project-recent-files ()
"Show recent files in current project using consult."
(interactive)
(unless (bound-and-true-p recentf-mode)
(recentf-mode 1))
(let* ((project-root (project-root (project-current)))
(project-files (when (and project-root
(bound-and-true-p recentf-list))
(seq-filter
(lambda (file)
(string-prefix-p project-root file))
recentf-list))))
(if project-files
(find-file (completing-read "Recent project files: " project-files))
(message "No recent files found in this project"))))
(use-package project
:ensure nil
:bind (("C-x p p" . project-switch-project)
("C-x p f" . project-find-file)
("C-x p g" . project-find-regexp)
("C-x p d" . project-find-dir)
("C-x p t" . eat-project) ; Modern terminal for project
("C-x p a" . ansi-term)) ; Alternative terminal option
:custom
;; Enhanced project switching menu with streamlined, logically grouped actions
(project-switch-commands
'(;; Core File Operations (most frequent)
(project-find-file "Find file" ?f)
(consult-find "Find externally" ?F)
(my/project-recent-files "Recent files" ?r)
(consult-project-buffer "Project buffers" ?b)
;; Navigation & Browsing
(my/project-ranger "Browse (ranger)" ?d)
(my/consult-project-ripgrep "Search project" ?s)
;; Development Workflow
(eat-project "Terminal" ?t)
(magit-status "Git status" ?g)
(my/project-smart-compile "Compile" ?c)
;; Layout & Cleanup
(my/project-workspace-setup "Workspace setup" ?w)
(my/project-show-treemacs "Treemacs" ?T)
(project-kill-buffers "Kill buffers" ?k))))Configuration for various terminal emulators inside Emacs. I use `eat`, a modern term-mode replacement. Terminal commands are bound under the `C-c t` prefix to avoid conflicts with spell-checking commands.
(straight-use-package
'(eat :type git
:host codeberg
:repo "akib/emacs-eat"
:files ("*.el" ("term" "term/*.el") "*.texi"
"*.ti" ("terminfo/e" "terminfo/e/*")
("terminfo/65" "terminfo/65/*")
("integration" "integration/*")
(:exclude ".dir-locals.el" "*-tests.el"))))
(use-package eat
:ensure nil ; It's installed by `straight-use-package` above
:bind (("C-c t t" . eat)
("C-c t a" . ansi-term) ; Fallback terminal
("C-c t p" . eat-project)) ; Project-specific terminal
:hook (eat-mode . (lambda () (setq-local global-hl-line-mode nil))))Configuration for `gptel`, a client for interacting with Large Language Models.
(use-package gptel
:custom
(gptel-default-mode 'org-mode)
:config
;; Configure to use a local Ollama instance with configurable host
(let ((ollama-host (or (getenv "OLLAMA_HOST") "192.168.16.172:11434")))
(setq gptel-backend (gptel-make-ollama "Ollama"
:host ollama-host
:stream t
:models '(
"hf.co/unsloth/gemma-3-4b-it-qat-GGUF:UD-Q8_K_XL"
"hf.co/unsloth/DeepSeek-R1-0528-Qwen3-8B-GGUF:UD-Q4_K_XL"
"hf.co/unsloth/Magistral-Small-2506-GGUF:Q3_K_XL"
"omaciel/ticketeer-granite3.3"
"hf.co/unsloth/GLM-Z1-9B-0414-GGUF:Q5_K_XL"))))
;; Add error handling for unavailable backends
:init
(defun my/gptel-check-backend ()
"Check if gptel backend is available and provide feedback."
(condition-case err
(gptel--model-capable-p 'stream)
(error
(message "GPTel backend unavailable: %s" (error-message-string err))
nil)))
(add-hook 'gptel-pre-request-hook #'my/gptel-check-backend))
(require 'gptel-integrations)This configures Emacs as a client for the Model Context Protocol (MCP), allowing gptel to automatically pull in context from external sources like the project’s file system (a simple RAG setup). This provides the language model with relevant information about the project you’re working on.
(use-package mcp
:straight (mcp :type git :host github :repo "lizqwerscott/mcp.el")
:after gptel
:custom
(mcp-hub-servers
`(;; 1. A Filesystem Server (with error checking)
;; This server exposes the root directory of your current project to the LLM.
;; Only enabled if npx is available.
,@(when (executable-find "npx")
`(("filesystem" . (:command "npx"
:args ("-y" "@modelcontextprotocol/server-filesystem"
,(or (ignore-errors (project-root (project-current)))
default-directory))))))
;; 2. A Fetch Server (with error checking)
;; This server can fetch content from URLs.
;; Only enabled if uvx is available.
,@(when (executable-find "uvx")
`(("fetch" . (:command "uvx" :args ("mcp-server-fetch")))))))
:config
;; Load the hub functionality and tell gptel to use MCP as a context provider.
(require 'mcp-hub)
:hook (after-init . (lambda ()
(when mcp-hub-servers
(condition-case err
(mcp-hub-start-all-server)
(error
(message "MCP servers failed to start: %s" (error-message-string err))))))))(use-package claude-code
:straight (:type git :host github :repo "stevemolitor/claude-code.el" :branch "main"
:files ("*.el" (:exclude "demo.gif")))
:bind-keymap
("C-c a" . claude-code-command-map) ; Choose your preferred prefix
:custom
;; Configure to use claude installation from PATH
(claude-code-program (or (executable-find "claude")
(executable-find "claude-code")
"claude"))
:config
(claude-code-mode)
;; Configure for your wide screen setup
(add-to-list 'display-buffer-alist
'("^\\*claude"
(display-buffer-in-side-window)
(side . right)
(window-width . 0.33))))This section is for custom functions and global keybindings that don’t belong to a specific package.
;; AI-enhanced development commands
(defun my/explain-code-with-ai ()
"Explain selected code using AI."
(interactive)
(condition-case err
(if (region-active-p)
(gptel-send (concat "Explain this code:\n\n"
(buffer-substring-no-properties
(region-beginning) (region-end))))
(message "Please select code to explain"))
(error
(message "Error with AI explain: %s" (error-message-string err)))))
(defun my/review-code-with-ai ()
"Review selected code for improvements."
(interactive)
(condition-case err
(if (region-active-p)
(gptel-send (concat "Review this code for best practices and suggest improvements:\n\n"
(buffer-substring-no-properties
(region-beginning) (region-end))))
(message "Please select code to review"))
(error
(message "Error with AI review: %s" (error-message-string err)))))
(defun my/document-code-with-ai ()
"Generate documentation for selected code using AI."
(interactive)
(condition-case err
(if (region-active-p)
(gptel-send (concat "Generate documentation for this code:\n\n"
(buffer-substring-no-properties
(region-beginning) (region-end))))
(message "Please select code to document"))
(error
(message "Error with AI documentation: %s" (error-message-string err)))))
;; AI-enhanced writing assistance functions
(defun my/improve-writing-with-ai ()
"Improve selected text for clarity, grammar, and style using AI."
(interactive)
(condition-case err
(if (region-active-p)
(gptel-send (concat "Improve this text for clarity, grammar, and style. "
"Keep the meaning and intent intact:\n\n"
(buffer-substring-no-properties
(region-beginning) (region-end))))
(message "Please select text to improve"))
(error
(message "Error with AI writing improvement: %s" (error-message-string err)))))
(defun my/adjust-tone-with-ai (tone)
"Adjust the tone of selected text (professional, casual, academic, friendly)."
(interactive "sTone (professional/casual/academic/friendly): ")
(condition-case err
(if (region-active-p)
(gptel-send (concat (format "Rewrite this text in a %s tone while keeping the core message:\n\n" tone)
(buffer-substring-no-properties
(region-beginning) (region-end))))
(message "Please select text to adjust tone"))
(error
(message "Error with AI tone adjustment: %s" (error-message-string err)))))
(defun my/summarize-text-with-ai ()
"Summarize selected text using AI."
(interactive)
(condition-case err
(if (region-active-p)
(gptel-send (concat "Provide a clear, concise summary of this text:\n\n"
(buffer-substring-no-properties
(region-beginning) (region-end))))
(message "Please select text to summarize"))
(error
(message "Error with AI summarization: %s" (error-message-string err)))))
(defun my/expand-text-with-ai ()
"Expand selected text with more detail using AI."
(interactive)
(condition-case err
(if (region-active-p)
(gptel-send (concat "Expand this text with more detail and examples while maintaining clarity:\n\n"
(buffer-substring-no-properties
(region-beginning) (region-end))))
(message "Please select text to expand"))
(error
(message "Error with AI text expansion: %s" (error-message-string err)))))
(defun my/proofread-with-ai ()
"Proofread selected text for grammar, spelling, and style issues using AI."
(interactive)
(condition-case err
(if (region-active-p)
(gptel-send (concat "Proofread this text for grammar, spelling, punctuation, and style issues. "
"Provide specific corrections and explanations:\n\n"
(buffer-substring-no-properties
(region-beginning) (region-end))))
(message "Please select text to proofread"))
(error
(message "Error with AI proofreading: %s" (error-message-string err)))))
;; Bury the current buffer instead of killing it.
(global-set-key (kbd "C-c k") #'bury-buffer)
;; A convenient key for replacing text via regexp.
(global-set-key (kbd "C-c r") #'replace-regexp)
;; Toggles whitespace visibility.
(global-set-key (kbd "C-c w") #'whitespace-mode)
;; Custom function to comment/uncomment line or region without moving cursor
(defun my/comment-dwim-line-or-region ()
"Comment or uncomment current line or region without moving cursor."
(interactive)
(condition-case err
(if (region-active-p)
;; If region is selected, comment/uncomment the region
(comment-or-uncomment-region (region-beginning) (region-end))
;; If no region, comment/uncomment current line without moving cursor
(save-excursion
(comment-line 1)))
(error
(message "Error commenting: %s" (error-message-string err)))))
;; Toggle comment/uncomment for region or line
;; Clear any existing binding for C-/ first
(global-unset-key (kbd "C-/"))
(global-set-key (kbd "C-/") #'my/comment-dwim-line-or-region)
;; Keybinding for the restart command.
(global-set-key (kbd "C-c x r") #'restart-emacs)
;; AI-enhanced development keybindings (C-c g prefix for all AI functions)
(global-set-key (kbd "C-c g e") #'my/explain-code-with-ai)
(global-set-key (kbd "C-c g r") #'my/review-code-with-ai)
(global-set-key (kbd "C-c g d") #'my/document-code-with-ai)
;; AI-enhanced writing keybindings (C-c g prefix)
(global-set-key (kbd "C-c g i") #'my/improve-writing-with-ai) ; Improve text
(global-set-key (kbd "C-c g t") #'my/adjust-tone-with-ai) ; Adjust tone
(global-set-key (kbd "C-c g s") #'my/summarize-text-with-ai) ; Summarize
(global-set-key (kbd "C-c g x") #'my/expand-text-with-ai) ; Expand text
(global-set-key (kbd "C-c g p") #'my/proofread-with-ai) ; Proofread
;; Writing assistance and accessibility keybindings
(global-set-key (kbd "C-c o") #'olivetti-mode) ; Focus mode
(global-set-key (kbd "C-c W") #'writegood-mode) ; Toggle writing analysis
;; Spell checking keybindings (C-c s prefix)
(global-set-key (kbd "C-c s c") #'flyspell-correct-word-before-point) ; Quick spell correction
(global-set-key (kbd "C-c s n") #'flyspell-goto-next-error) ; Next spelling error
(global-set-key (kbd "C-c s l") #'ispell-change-dictionary) ; Change dictionary
;; Codespell keybindings (C-c s prefix)
(global-set-key (kbd "C-c s b") #'my-codespell-buffer) ; Check buffer
(global-set-key (kbd "C-c s r") #'my-codespell-region) ; Check region
(global-set-key (kbd "C-c s p") #'my-codespell-project) ; Check projectThis section contains advanced package management functions for straight.el, including health checking, version control integration, and a transient menu interface.
Functions for basic package management operations like freezing versions and updating packages.
;; Core package management functions
(defun my/straight-freeze-versions ()
"Freeze current package versions to lock file."
(interactive)
(condition-case err
(progn
(message "Freezing package versions...")
(straight-freeze-versions)
(message "Package versions frozen to straight/versions/default.el"))
(error
(message "Error freezing packages: %s" (error-message-string err)))))
(defun my/straight-update-all ()
"Update and rebuild all straight packages."
(interactive)
(condition-case err
(progn
(message "Pulling all packages...")
(straight-pull-all)
(message "Rebuilding all packages...")
(straight-rebuild-all)
(message "All packages updated and rebuilt successfully"))
(error
(message "Error updating packages: %s" (error-message-string err)))))Functions for checking package health, cleaning up build artifacts, and maintaining package repositories.
;; Package health and maintenance functions
(defun my/straight-check-all ()
"Check for broken or problematic packages."
(interactive)
(condition-case err
(progn
(message "Checking package health...")
(let ((issues '()))
;; Check for missing repositories
(dolist (package (hash-table-keys straight--recipe-cache))
(let ((repo-dir (straight--repos-dir (symbol-name package))))
(unless (file-directory-p repo-dir)
(push (format "Missing repository: %s" package) issues))))
;; Check for build issues
(dolist (package (hash-table-keys straight--recipe-cache))
(let ((build-dir (straight--build-dir (symbol-name package))))
(when (and (file-directory-p build-dir)
(= 0 (length (directory-files build-dir nil "\\.el\\'"))))
(push (format "Empty build directory: %s" package) issues))))
(if issues
(with-current-buffer (get-buffer-create "*Package Health*")
(erase-buffer)
(insert "Package Health Issues:\n\n")
(dolist (issue issues)
(insert "• " issue "\n"))
(display-buffer (current-buffer))
(message "Found %d package issues - see *Package Health* buffer" (length issues)))
(message "All packages appear healthy"))))
(error
(message "Error checking package health: %s" (error-message-string err)))))
(defun my/straight-prune-build ()
"Clean up unused build artifacts."
(interactive)
(condition-case err
(progn
(message "Pruning build artifacts...")
(let ((pruned 0))
(dolist (build-dir (directory-files (straight--build-dir) t))
(when (and (file-directory-p build-dir)
(not (member (file-name-nondirectory build-dir) '("." "..")))
(not (gethash (intern (file-name-nondirectory build-dir))
straight--recipe-cache)))
(delete-directory build-dir t)
(setq pruned (1+ pruned))))
(message "Pruned %d unused build directories" pruned)))
(error
(message "Error pruning build artifacts: %s" (error-message-string err)))))
(defun my/straight-normalize-all ()
"Fix repository states by normalizing all packages."
(interactive)
(condition-case err
(when (yes-or-no-p "This will reset all package repositories. Continue? ")
(message "Normalizing all package repositories...")
(straight-normalize-all)
(message "All packages normalized successfully"))
(error
(message "Error normalizing packages: %s" (error-message-string err)))))
(defun my/straight-rebuild-package ()
"Rebuild a specific package interactively."
(interactive)
(condition-case err
(let* ((packages (hash-table-keys straight--recipe-cache))
(package (intern (completing-read "Rebuild package: "
(mapcar #'symbol-name packages)))))
(message "Rebuilding package: %s" package)
(straight-rebuild-package package)
(message "Package %s rebuilt successfully" package))
(error
(message "Error rebuilding package: %s" (error-message-string err)))))Functions for managing lockfile versions, including backup, restore, commit, and diff operations.
;; Version control integration functions
(defun my/straight-backup-lockfile ()
"Create a timestamped backup of the current lockfile."
(interactive)
(condition-case err
(let* ((lockfile (straight--versions-lockfile))
(backup-dir (expand-file-name "versions/backups" (straight--dir)))
(timestamp (format-time-string "%Y%m%d-%H%M%S"))
(backup-file (expand-file-name (format "lockfile-%s.el" timestamp) backup-dir)))
(unless (file-directory-p backup-dir)
(make-directory backup-dir t))
(if (file-exists-p lockfile)
(progn
(copy-file lockfile backup-file)
(message "Lockfile backed up to: %s" backup-file))
(message "No lockfile found to backup")))
(error
(message "Error backing up lockfile: %s" (error-message-string err)))))
(defun my/straight-restore-lockfile ()
"Restore from a previous lockfile backup."
(interactive)
(condition-case err
(let* ((backup-dir (expand-file-name "versions/backups" (straight--dir)))
(lockfile (straight--versions-lockfile)))
(if (file-directory-p backup-dir)
(let* ((backups (directory-files backup-dir nil "lockfile-.*\\.el$"))
(backup (when backups
(completing-read "Restore from backup: " backups))))
(when backup
(let ((backup-path (expand-file-name backup backup-dir)))
(when (yes-or-no-p (format "Restore lockfile from %s? This will overwrite current lockfile." backup))
(copy-file backup-path lockfile t)
(message "Lockfile restored from: %s" backup)))))
(message "No backup directory found")))
(error
(message "Error restoring lockfile: %s" (error-message-string err)))))
(defun my/straight-commit-lockfile ()
"Commit lockfile changes with a descriptive message."
(interactive)
(condition-case err
(let* ((lockfile (straight--versions-lockfile))
(default-directory user-emacs-directory))
(if (and (file-exists-p lockfile)
(vc-backend lockfile))
(let ((commit-msg (format "Pin package versions (%s)"
(format-time-string "%Y-%m-%d %H:%M"))))
(vc-checkin (list lockfile) nil commit-msg)
(message "Lockfile committed: %s" commit-msg))
(message "Lockfile not under version control or doesn't exist")))
(error
(message "Error committing lockfile: %s" (error-message-string err)))))
(defun my/straight-diff-lockfile ()
"View changes in the lockfile compared to the last commit."
(interactive)
(condition-case err
(let* ((lockfile (straight--versions-lockfile))
(default-directory user-emacs-directory))
(if (and (file-exists-p lockfile)
(vc-backend lockfile))
(vc-diff nil t (list lockfile))
(message "Lockfile not under version control or doesn't exist")))
(error
(message "Error viewing lockfile diff: %s" (error-message-string err)))))A magit-style transient menu that provides organized access to all package management functions.
;; Transient menu for package management
(defun my/straight-transient ()
"Open the package management transient menu."
(interactive)
(transient-setup 'my/straight-transient))
(transient-define-prefix my/straight-transient ()
"Package management with straight.el"
:info-manual "(straight) Top"
[["Actions"
("f" "Freeze versions" my/straight-freeze-versions)
("u" "Update all packages" my/straight-update-all)
("r" "Rebuild package" my/straight-rebuild-package)]
["Maintenance"
("c" "Check package health" my/straight-check-all)
("p" "Prune build artifacts" my/straight-prune-build)
("n" "Normalize repositories" my/straight-normalize-all)]
["Version Control"
("b" "Backup lockfile" my/straight-backup-lockfile)
("B" "Restore lockfile" my/straight-restore-lockfile)
("C" "Commit lockfile" my/straight-commit-lockfile)
("d" "Diff lockfile" my/straight-diff-lockfile)]
["Quit"
("q" "Quit" transient-quit-one)]])All package management functions are bound under the `C-c p` prefix for easy access.
;; Package management keybindings (C-c p prefix)
(global-set-key (kbd "C-c p m") #'my/straight-transient) ; Main transient menu
(global-set-key (kbd "C-c p f") #'my/straight-freeze-versions) ; Freeze versions
(global-set-key (kbd "C-c p u") #'my/straight-update-all) ; Update all packages
(global-set-key (kbd "C-c p c") #'my/straight-check-all) ; Check package health
(global-set-key (kbd "C-c p p") #'my/straight-prune-build) ; Prune build artifacts
(global-set-key (kbd "C-c p r") #'my/straight-rebuild-package) ; Rebuild package
(global-set-key (kbd "C-c p b") #'my/straight-backup-lockfile) ; Backup lockfile
(global-set-key (kbd "C-c p R") #'my/straight-restore-lockfile) ; Restore lockfile
(global-set-key (kbd "C-c p C") #'my/straight-commit-lockfile) ; Commit lockfile
(global-set-key (kbd "C-c p d") #'my/straight-diff-lockfile) ; Diff lockfile