Hello. This is my Emacs configuration. It’s both documentation and code in one place, a paradigm referred to as Literate programming.
When Emacs starts it runs the code in init.el. Rather than storing the configuration here directly, we have this line:
(org-babel-load-file "~/.emacs.d/readme.org")That then loads this file, which will tangle and then evaluate every emacs-lisp
code block in here, unless it is explicitly marked with :tangle no, as is true
with the example above.
Note that evaluating this file with org-babel-load-file will result in some
variables being set unless we set the variable below. Instead of cluttering up
this file, we will write the generated code to a new file that can be easily
ignored:
(setq custom-file "~/.emacs.d/generated.el")(require 'package)
(add-to-list 'package-archives
'("MELPA" .
"http://melpa.org/packages/"))
(setq package-enable-at-startup nil)
(package-initialize)
(eval-when-compile
(require 'use-package))
(setq use-package-always-ensure t)
(setenv "COPYFILE_DISABLE" "1")
(setq quelpa-update-melpa-p nil)
(use-package quelpa)
(use-package quelpa-use-package)Start a local Unix-socket server in interactive sessions so emacsclient (and
agents) can open files / eval Lisp in the running Emacs. The macOS daemon path
still uses TCP with EMACS_SERVER_AUTH_KEY via launchctl.
(defun shanemcd/start-emacs-server ()
"Start Emacs server: TCP when daemonized, local socket otherwise."
(require 'server)
(unless (server-running-p)
(if (daemonp)
(progn
(setq server-use-tcp t
server-auth-key (getenv "EMACS_SERVER_AUTH_KEY")
server-port 52698)
(server-start)
;; Adjust "mac" if needed for your display configuration.
(make-frame '((display . "mac"))))
;; Interactive / Linux GUI: default local socket under
;; /run/user/$UID/emacs/server (or /tmp/emacs$UID/server).
(setq server-use-tcp nil)
(server-start))))
(add-hook 'after-init-hook #'shanemcd/start-emacs-server)
;; For agents / emacsclient --eval: open FILE in another window and leave
;; the selected window (e.g. agent-shell) alone.
(defun shanemcd/display-file-other-window (file)
"Visit FILE in another window without selecting it."
(let ((buffer (find-file-noselect (expand-file-name file))))
(display-buffer buffer
'((display-buffer-reuse-window
display-buffer-pop-up-window)
(inhibit-same-window . t)
(reusable-frames . nil)))
nil))My workflow is built around the assumption that the code I am working on may or may not be local to the machine I am working on.
For cases where I need to work remotely, I use tramp. This mostly works fine, but there are times where I am SSH’d into a remote machine where my code is hosted via a terminal, and I would like a way to open a file or directory in Emacs without having to switch contexts to copy / paste a path between the applications.
By starting the server below listening via TCP, we are able to open reverse emacsclient connections back to ourselves using this ZSH function:
#!/bin/env zsh
function re {
# Get the number of arguments
local num_args=$#
# If no arguments are provided, exit the function
if [ $num_args -eq 0 ]; then
echo "🤖 re (remote? reverse? emacsclient) 🤖"
echo "Usage: re [emacsclient options] <path>"
return 1
fi
# Extract the last argument as the path
local tramppath="$1"
# Check if a valid path was provided (should be the first arg)
if [ -z "$tramppath" ]; then
echo "Error: No path provided."
return 1
fi
# Run the emacsclient command with -cn option and --server-file and /sshx options
emacsclient -cn --server-file ~/server /sshx:$(hostname):$tramppath
}https://elpa.gnu.org/packages/delight.html
This package makes the mode line less noisy by allowing us to hide certain minor
modes. We’ll call this early so we can use as-needed, by using the delight
keyword when calling use-package.
(use-package delight)(setq python-shell-interpreter "/Users/shanemcd/.pyenv/shims/python"
flycheck-python-pycompile-executable "/Users/shanemcd/.pyenv/shims/python"
python-shell-exec-path "/Users/shanemcd/.pyenv/shims/python")(use-package markdown-mode
:config
(setq markdown-fontify-code-blocks-natively t))Uses go-grip for local offline GFM preview (no GitHub API rate limits). Toggle
with C-c C-c g in Markdown buffers; preview opens in the browser and refreshes
on save.
(use-package grip-mode
:after markdown-mode
:bind (:map markdown-mode-command-map
("g" . grip-mode))
:config
;; Ensure ~/.local/bin (go-grip) is visible even if Emacs was started
;; before the binary was installed.
(let ((local-bin (expand-file-name "~/.local/bin")))
(add-to-list 'exec-path local-bin)
(setenv "PATH" (concat local-bin path-separator (getenv "PATH"))))
(setopt grip-command 'go-grip
grip-preview-in-webkit nil
grip-real-time-refresh nil))(show-paren-mode)(use-package yaml-mode
:config
(setq yaml-indent-offset 2))
(defun my/yaml-outline-setup ()
"Configure outline-minor-mode for YAML to fold both keys and list items."
;; Match lines like:
;; topKey:
;; - listItem:
;; - listItem
(setq-local outline-regexp "^\\([[:space:]]*\\(-\\|\\w\\)\\)")
(outline-minor-mode 1))
(add-hook 'yaml-mode-hook #'my/yaml-outline-setup)(use-package groovy-mode
:config
(setq groovy-indent-offset 2))(use-package swift-mode)
(use-package ob-swift)(use-package go-mode
:config
(add-hook 'go-mode-hook
(lambda ()
(setq indent-tabs-mode 1)
(setq tab-width 8))))
(use-package ob-go)(use-package rust-mode
:mode "\\.rs\\'")(use-package dockerfile-mode)(use-package ob-mermaid)(use-package org
:mode ("\\.org\\'" . org-mode)
:bind (("C-c l" . org-store-link)
("C-c c" . org-capture)
("C-c C-w" . org-refile))
:config
(require 'org-tempo)
(setq org-directory "~/org")
(setq org-agenda-skip-unavailable-files t)
(setq org-agenda-files (directory-files-recursively "~/org/" "\\.org$"))
(setq org-use-speed-commands t)
(setq org-startup-with-inline-images t)
(setq org-capture-templates '(
("t" "TODO" entry (file+headline "~/org/incoming.org" "TODOs") "** TODO %?\n %i\n %a")
("e" "Log entry" entry (file+headline "~/org/log.org" "Log") "** %?\n %i\n %a")
("p" "Private note" entry (file+headline "~/org/journal.org" "Notes") "** %?\n %i\n %a")
))
(setq org-refile-targets '((org-agenda-files :maxlevel . 3)))
(setq org-imenu-depth 3)
(org-babel-do-load-languages
'org-babel-load-languages
'((shell . t)
(emacs-lisp . t)
(js . t)
(ruby . t)
(swift . t)
(mermaid . t)
(python . t)))
(setq org-babel-python-command "python3")
(setq org-startup-folded t)
(setq org-odt-preferred-output-format "docx")
(setq org-src-fontify-natively t
org-src-window-setup 'current-window
org-src-strip-leading-and-trailing-blank-lines t
org-src-preserve-indentation t
org-hide-emphasis-markers t
org-src-tab-acts-natively t))
(use-package org-appear
:after org
:hook (org-mode . org-appear-mode)
:config
(setq org-appear-autolinks t))
(defun my/org-roam-capture-finished ()
"Function to run after an Org-roam capture is finalized."
(setq org-agenda-files (directory-files-recursively "~/org/" "\\.org$")))
(use-package org-roam
:after org
:config
(setq org-roam-directory (file-truename "~/org/roam"))
(org-roam-db-autosync-mode)
(setq org-roam-node-display-template "${title:*} ${tags:20}")
(add-hook 'org-capture-after-finalize-hook 'my/org-roam-capture-finished)
:bind (("C-c r b" . org-roam-buffer-toggle)
("C-c r f" . org-roam-node-find)))
(use-package org-modern
:after org
:hook (org-mode . global-org-modern-mode))https://github.com/larstvei/ox-gfm
(use-package ox-gfm)(use-package vterm
;; :config
;; (setq vterm-tramp-shells '(("sshx" "/bin/zsh")))
)Terminal emulator from NonGNU/MELPA. The package ships Linux-compiled
terminfo databases; on macOS/BSD those make Backspace insert spaces
(and other keys misbehave). Recompile once per OS with
eat-compile-terminfo; Linux can keep the prebuilt files.
(use-package eat
:commands (eat eat-other-window)
:config
;; MELPA terminfo is Linux-built; Darwin/BSD need a local recompile.
;; Stamp is per-system-type so a shared emacs.d across machines is fine.
(when (memq system-type '(darwin berkeley-unix))
(let ((stamp (expand-file-name
(format ".terminfo-compiled-%s" system-type)
eat-term-terminfo-directory)))
(unless (file-exists-p stamp)
(eat-compile-terminfo)
(with-temp-file stamp (insert "ok\n"))))))(use-package ultra-scroll
;:vc (:url "https://github.com/jdtsmith/ultra-scroll") ; if desired (emacs>=v30)
:init
(setq scroll-conservatively 3 ; or whatever value you prefer, since v0.4
scroll-margin 0) ; important: scroll-margin>0 not yet supported
:config
(ultra-scroll-mode 1))(setq-default fill-column 80)(tool-bar-mode -1)
(menu-bar-mode -1)
(scroll-bar-mode -1)https://github.com/tonsky/FiraCode
;; Set Iosevka SS05 Expanded using XLFD names for each OS
(set-frame-font
(cond
((eq system-type 'darwin)
"-*-Iosevka SS05-medium-normal-expanded-*-16-*-*-*-m-0-iso10646-1")
((eq system-type 'gnu/linux)
"-UKWN-Iosevka SS05-medium-normal-expanded-*-16-*-*-*-d-0-iso10646-1"))
t t)(setq inhibit-splash-screen t)(setq column-number-mode t);; (global-display-line-numbers-mode)(use-package base16-theme)Automatically switch between light and dark themes based on system appearance.
(use-package auto-dark
:custom
(auto-dark-themes '((base16-tomorrow-night) (base16-one-light)))
(setq auto-dark-allow-osascript t)
:init
(auto-dark-mode))https://www.emacswiki.org/emacs/WindMove
(when (fboundp 'windmove-default-keybindings)
(windmove-default-keybindings))(defun my-toggle-emacs-bookmark (event)
"Toggle an Emacs bookmark at the line clicked."
(interactive "e")
(let* ((pos (posn-point (event-start event)))
(line (line-number-at-pos pos))
(bookmark-name (format "Line %d in %s" line (buffer-name))))
(save-excursion
(goto-char pos)
(if (bookmark-get-bookmark bookmark-name t)
(progn
(bookmark-delete bookmark-name)
(message "Deleted bookmark: %s" bookmark-name))
(bookmark-set bookmark-name)
(message "Set bookmark: %s" bookmark-name)))))
(global-set-key [left-fringe mouse-1] #'my-toggle-emacs-bookmark)(use-package spacious-padding
:config
(spacious-padding-mode))(toggle-frame-maximized)(use-package olivetti)(setq-default indent-tabs-mode nil tab-width 4)
(use-package sh-script
:mode "\\.sh\\'"
:config (setq sh-indentation 4 sh-basic-offset 4))(setq require-final-newline t)(use-package gptel
:bind ("C-c a" . gptel-send)
:init
(eval-when-compile
(require 'gptel nil t)
(require 'gptel-anthropic nil t))
:config
(require 'gptel-anthropic)
;; Define a custom Vertex AI backend that doesn't send model in request body
(cl-defstruct (gptel-vertex-anthropic (:constructor gptel--make-vertex-anthropic)
(:copier nil)
(:include gptel-anthropic)))
;; Override request building to exclude :model field
(cl-defmethod gptel--request-data ((backend gptel-vertex-anthropic) prompts)
(let ((data (cl-call-next-method)))
;; Remove :model from the plist since Vertex has it in the URL
(cl-remf data :model)
data))
;; Map Claude Code model aliases to Vertex AI model names
(let* ((model-alias (or (getenv "ANTHROPIC_MODEL") "claude-sonnet-4-5@20250929"))
(model-map '(("opusplan" . "claude-sonnet-4-5@20250929")
("opus" . "claude-opus-4-6@20250514")
("sonnet" . "claude-sonnet-4-5@20250929")
("haiku" . "claude-3-5-haiku@20241022")))
(model (or (cdr (assoc model-alias model-map)) model-alias))
(region (or (getenv "CLOUD_ML_REGION") "us-east5"))
(project (getenv "ANTHROPIC_VERTEX_PROJECT_ID")))
(setq-default gptel-backend
(gptel--make-vertex-anthropic
:curl-args nil
:name "Claude via Vertex"
:host (format "%s-aiplatform.googleapis.com" region)
:header (lambda (_)
`(("Authorization" . ,(concat "Bearer " (gptel--get-api-key)))))
:key (lambda ()
(with-temp-buffer
(call-process "gcloud" nil t nil "auth" "print-access-token")
(string-trim (buffer-string))))
:models (list (intern model))
:protocol "https"
:endpoint (format "/v1/projects/%s/locations/%s/publishers/anthropic/models/%s:streamRawPredict"
project region model)
:stream t
:request-params '(:anthropic_version "vertex-2023-10-16")
:url (format "https://%s-aiplatform.googleapis.com/v1/projects/%s/locations/%s/publishers/anthropic/models/%s:streamRawPredict"
region project region model)))
(setq-default gptel-model (intern model))));; (quelpa '(claudemacs :fetcher github :repo "cpoile/claudemacs"))Talks to a local OpenAI-compatible proxy on 127.0.0.1:32124 that shells out to
the Cursor agent CLI (same approach as
Nomadcxx/opencode-cursor).
Prerequisites:
agent login(Cursor Agent CLI)systemctl --user enable --now open-cursor-proxy(serves/v1/chat/completions)- Optional:
CURSOR_ACP_SESSION_RESUME=1for incremental multi-turn via--resume
(use-package gptel
:commands (gptel gptel-send gptel-menu)
:bind ("C-c RET" . gptel-send)
:config
(setq gptel-model 'composer-2.5-fast
gptel-backend
(gptel-make-openai "Cursor"
:host "127.0.0.1:32124"
:protocol "http"
:endpoint "/v1/chat/completions"
:stream t
:key "unused"
:models '(composer-2.5-fast
composer-2.5
claude-4.6-sonnet-medium
gpt-5.4-medium-fast
gemini-3-flash
cursor-grok-4.5-high-fast
cursor-grok-4.5-high
cursor-grok-4.5-medium-fast
claude-4.6-opus-high
auto))))Native Emacs shell for LLM agents over ACP.
Loaded from a local checkout for development
(xenodium/agent-shell); acp.el and shell-maker still come from
MELPA.
Providers:
- Cursor —
agent acp --approve-mcps(existingagent login) - Claude —
claude-agent-acpover Vertex AI (CLAUDE_CODE_USE_VERTEX+gcloudADC; project/region from ~/.zshrc via chezmoi) - Gemini —
gemini --acpover Vertex AI (GOOGLE_CLOUD_*/GEMINI_MODELfrom/.zshrc via chezmoi). Antigravity (~agy) has no ACP yet, so we keep Gemini CLI for agent-shell.
Prerequisites on PATH (via exec-path-from-shell): agent,
claude-agent-acp (npm i -g @agentclientprotocol/claude-agent-acp),
gemini (npm i -g @google/gemini-cli).
Past conversations live as Markdown under .agent-shell/transcripts/.
agent-recall indexes them so you can search, browse, and resume — no
desktop-save-mode / agent-shell-desktop required. Prefer
session/load so resumed buffers get prior messages back.
;; Dependencies still from MELPA (not vendored in the local checkout).
(use-package acp :ensure t)
(use-package shell-maker :ensure t)
(use-package agent-shell
:ensure nil
:load-path "~/github/xenodium/agent-shell"
:demand t
:bind (("C-c A" . agent-shell-cursor-start-agent)
("C-c C" . agent-shell-anthropic-start-claude-code)
("C-c G" . agent-shell-google-start-gemini))
:config
;; Cursor — `agent login` outside Emacs; no ACP authenticate request.
(setq agent-shell-cursor-authentication
(agent-shell-cursor-make-authentication :none t)
agent-shell-cursor-acp-command '("agent" "acp" "--approve-mcps"))
;; Claude — Vertex via env from ~/.zshrc (CLAUDE_CODE_USE_VERTEX, etc.).
(setq agent-shell-anthropic-authentication
(agent-shell-anthropic-make-authentication :login t))
;; Gemini — Vertex via env from ~/.zshrc (chezmoi); model via GEMINI_MODEL.
(setq agent-shell-google-authentication
(agent-shell-google-make-authentication :vertex-ai t)
agent-shell-google-gemini-acp-command '("gemini" "--acp"))
;; Environments are set after exec-path-from-shell (later in this file).
(setq agent-shell-preferred-agent-config '(preselect . cursor)
agent-shell-session-strategy 'prompt
;; Use session/load (not session/resume) so history is restored.
agent-shell-prefer-session-resume nil)
;; Typing anywhere in the transcript jumps to the prompt (like chat UIs).
;; Note: n/p/r stay navigation/quote when not at the prompt.
(defun shanemcd/agent-shell-self-insert (&optional n)
"Insert N characters at the prompt, moving point there if needed."
(interactive "p")
(unless (shell-maker-point-at-last-prompt-p)
(goto-char (point-max)))
(self-insert-command (or n 1)))
(define-key agent-shell-mode-map [remap self-insert-command]
#'shanemcd/agent-shell-self-insert))
;; Search / browse / resume agent-shell transcripts.
;; Local checkout of https://github.com/shanemcd/agent-recall
;; (branch fix/session-id-and-resume-loop) until upstream merges.
;; Keys: C-c B browse, C-c R resume, C-c / live search.
(use-package agent-recall
:ensure nil
:load-path "~/github/shanemcd/agent-recall"
:after agent-shell
:hook (agent-shell-mode . agent-recall-track-sessions)
:bind (("C-c B" . agent-recall-browse)
("C-c R" . agent-recall-resume)
("C-c /" . agent-recall-search-live))
:config
(setq agent-recall-search-paths '("~/github" "~/projects" "~/.emacs.d")
agent-recall-extra-transcript-dirs
'((:dir "~/.agent-shell/transcripts/"))
agent-recall-search-function 'consult-ripgrep
agent-recall-browse-sort 'modified-desc))
;; Persistent project-aware sidebar for agent-shell.
;; https://github.com/cmacrae/agent-shell-sidebar
;; Keys: C-c s toggle, C-c f focus (C-c a is already ai-code-menu).
(use-package agent-shell-sidebar
:ensure nil
:quelpa (agent-shell-sidebar :fetcher github
:repo "cmacrae/agent-shell-sidebar")
:after agent-shell
:bind (("C-c s" . agent-shell-sidebar-toggle)
("C-c f" . agent-shell-sidebar-toggle-focus))
:custom
(agent-shell-sidebar-width "30%")
(agent-shell-sidebar-minimum-width 80)
(agent-shell-sidebar-maximum-width "50%")
(agent-shell-sidebar-position 'right)
(agent-shell-sidebar-locked t)
:config
(setq agent-shell-sidebar-default-config
(agent-shell-cursor-make-agent-config)))ai-code-interface.el — transient menu for context-aware coding
actions. Uses agent-shell as the backend. Menu is C-c a; start
Cursor/Claude/Gemini shells with C-c A / C-c C / C-c G.
(use-package ai-code
:ensure t
:after agent-shell
:bind ("C-c a" . ai-code-menu)
:config
(ai-code-set-backend 'agent-shell)
(with-eval-after-load 'magit
(ai-code-magit-setup-transients)))(use-package browse-at-remote
:commands browse-at-remote
:bind ("C-c g g" . browse-at-remote))(use-package company
:delight
:config
(setq company-minimum-prefix-length 1)
(global-company-mode t)
(setq company-global-modes '(not org-mode)))- Set up key binding for
dired-jump.- If you enter a file from dired and press this shortcut, you will pop back into the dired buffer
- Only show filenames in dired by default, hiding the permissions and other
details. Press
(to show details.
(global-set-key (kbd "C-x C-j") 'dired-jump)
(add-hook 'dired-mode-hook 'dired-hide-details-mode)
;(use-package dired-single)
(require 'dired-x)
(add-hook 'dired-mode-hook 'dired-omit-mode)
(setq-default dired-omit-files-p t) ; Buffer-local variable
(setq dired-omit-files (concat dired-omit-files "\\|^\\..+$"))(use-package dired-subtree
:after dired
:config
(bind-key "<tab>" #'dired-subtree-toggle dired-mode-map)
(bind-key "<backtab>" #'dired-subtree-cycle dired-mode-map)
(setq dired-subtree-use-backgrounds nil))(use-package drag-stuff
:config
(drag-stuff-define-keys))(use-package dumb-jump
:config
;(setq dumb-jump-selector 'helm)
(add-hook 'xref-backend-functions #'dumb-jump-xref-activate))(use-package fill-column-indicator
:config
(setq-default fci-rule-column 80)
(setq fci-rule-color (face-attribute 'highlight :background)))(use-package flycheck
:delight
:config
;; Silence the once-per-mode "no syntax checker can run here" notice in
;; lisp-interaction-mode buffers. Their only checker (the emacs-lisp byte
;; compiler) is disabled there by Emacs 30+ trusted-content rules
;; (CVE-2024-53920), so Flycheck has nothing to do in those buffers.
(setq flycheck-global-modes '(not lisp-interaction-mode))
(global-flycheck-mode))I unbind flyspell-mode-map because I use C-. for embark-act.
(use-package flyspell
:delight
:config
(define-key flyspell-mode-map (kbd "C-.") nil)
(add-hook 'prog-mode-hook 'flyspell-prog-mode)
(add-hook 'text-mode-hook 'flyspell-mode)
(add-hook 'markdown-mode-hook 'flyspell-mode))(use-package htmlize
:commands (htmlize-buffer
htmlize-file
htmlize-many-files
htmlize-many-files-dired
htmlize-region))(use-package imenu-list
:bind
(("C-." . imenu-list-smart-toggle))
:config
(setq imenu-list-focus-after-activation t))(use-package tramp
:defer t
:config
(setopt tramp-remote-path '(tramp-own-remote-path))
(setq tramp-histfile-override nil))(use-package magit
:bind ("C-x g" . magit)
:commands magit-project-status)
(use-package project
:bind
(:map project-prefix-map
("m" . magit-project-status))
:config
(add-to-list 'project-switch-commands '(magit-project-status "Magit") t))“Move where I mean” - C-a takes you to the first character on the line.
(use-package mwim
:config
(global-set-key (kbd "C-a") 'mwim-beginning)
(global-set-key (kbd "C-e") 'mwim-end))(use-package nerd-icons)
(use-package nerd-icons-dired
:delight
:hook
(dired-mode . nerd-icons-dired-mode))(use-package rainbow-delimiters
:config
(add-hook 'prog-mode-hook #'rainbow-delimiters-mode))(use-package reveal-in-osx-finder)(use-package vundo
:commands (vundo)
:config
(setq vundo-compact-display t))(use-package ws-butler
:delight
:config
(ws-butler-global-mode t))(use-package wttrin
:config
(setq wttrin-default-cities '("New York NY" "Winchester VA" "Durham NC" "Kaohsiung City")))(use-package ztree)(use-package yasnippet
:commands yas-minor-mode
:hook (go-mode . yas-minor-mode))(use-package winum
:config
(winum-mode)
:bind
(("M-0" . 'winum-select-window-0-or-10)
("M-1" . 'winum-select-window-1)
("M-2" . 'winum-select-window-2)
("M-3" . 'winum-select-window-3)
("M-4" . 'winum-select-window-4)
("M-5" . 'winum-select-window-5)
("M-6" . 'winum-select-window-6)
("M-7" . 'winum-select-window-7)
("M-8" . 'winum-select-window-8))
)(use-package pandoc-mode
:config
(add-hook 'markdown-mode-hook 'pandoc-mode));; Use Emacs 30's built-in :vc support instead of quelpa
(use-package marp-mode
:vc (:url "https://github.com/shanemcd/marp-mode"
:branch "main")
:hook (markdown-mode . marp-mode))(use-package hide-mode-line)(setq backup-directory-alist `(("." . "~/.emacs.bak")))
(setenv "PINENTRY_USER_DATA" "USE_CURSES=0")(use-package exec-path-from-shell
:config
(setq exec-path-from-shell-arguments '("-li"))
(setenv "SHELL" "/bin/zsh")
(exec-path-from-shell-copy-envs '("GOPATH"
"PATH"
"LC_ALL"
"LANG"
"LC_TYPE"
"SSH_AGENT_PID"
"SSH_AUTH_SOCK"
"SHELL"
"CLAUDE_CODE_USE_VERTEX"
"CLOUD_ML_REGION"
"ANTHROPIC_VERTEX_PROJECT_ID"
"ANTHROPIC_MODEL"
"ANTHROPIC_DEFAULT_HAIKU_MODEL"
"GOOGLE_CLOUD_PROJECT"
"GOOGLE_CLOUD_LOCATION"
"GOOGLE_GENAI_USE_VERTEXAI"
"GEMINI_MODEL"
"GEMINI_SANDBOX"
"SANDBOX_FLAGS"
"CURSOR_ACP_SESSION_RESUME"))
;; agent-shell is loaded earlier; snapshot env now that PATH/Vertex vars exist.
(when (fboundp 'agent-shell-make-environment-variables)
(setq agent-shell-cursor-environment
(agent-shell-make-environment-variables :inherit-env t)
agent-shell-anthropic-claude-environment
(agent-shell-make-environment-variables :inherit-env t)
agent-shell-google-gemini-environment
(agent-shell-make-environment-variables :inherit-env t))))
Trying to piece together a more modern completion system
;; Enable rich annotations using the Marginalia package
(use-package marginalia
;; Bind `marginalia-cycle' locally in the minibuffer. To make the binding
;; available in the *Completions* buffer, add it to the
;; `completion-list-mode-map'.
:bind (:map minibuffer-local-map
("M-A" . marginalia-cycle))
;; The :init section is always executed.
:init
;; Marginalia must be activated in the :init section of use-package such that
;; the mode gets enabled right away. Note that this forces loading the
;; package.
(marginalia-mode))(use-package embark
:ensure t
:bind
(("C-." . embark-act) ;; pick some comfortable binding
("C-;" . embark-dwim) ;; good alternative: M-.
("C-h B" . embark-bindings)) ;; alternative for `describe-bindings'
:init
;; Optionally replace the key help with a completing-read interface
(setq prefix-help-command #'embark-prefix-help-command)
;; Show the Embark target at point via Eldoc. You may adjust the
;; Eldoc strategy, if you want to see the documentation from
;; multiple providers. Beware that using this can be a little
;; jarring since the message shown in the minibuffer can be more
;; than one line, causing the modeline to move up and down:
;; (add-hook 'eldoc-documentation-functions #'embark-eldoc-first-target)
;; (setq eldoc-documentation-strategy #'eldoc-documentation-compose-eagerly)
:config
;; Hide the mode line of the Embark live/completions buffers
(add-to-list 'display-buffer-alist
'("\\`\\*Embark Collect \\(Live\\|Completions\\)\\*"
nil
(window-parameters (mode-line-format . none)))));; Example configuration for Consult
(use-package consult
;; Replace bindings. Lazily loaded by `use-package'.
:bind (;; C-c bindings in `mode-specific-map'
("C-c M-x" . consult-mode-command)
("C-c h" . consult-history)
("C-c k" . consult-kmacro)
("C-c m" . consult-man)
("C-c i" . consult-info)
([remap Info-search] . consult-info)
;; C-x bindings in `ctl-x-map'
("C-x M-:" . consult-complex-command) ;; orig. repeat-complex-command
("C-x b" . consult-buffer) ;; orig. switch-to-buffer
("C-x 4 b" . consult-buffer-other-window) ;; orig. switch-to-buffer-other-window
("C-x 5 b" . consult-buffer-other-frame) ;; orig. switch-to-buffer-other-frame
("C-x t b" . consult-buffer-other-tab) ;; orig. switch-to-buffer-other-tab
("C-x r b" . consult-bookmark) ;; orig. bookmark-jump
("C-x p b" . consult-project-buffer) ;; orig. project-switch-to-buffer
;; Custom M-# bindings for fast register access
("M-#" . consult-register-load)
("M-'" . consult-register-store) ;; orig. abbrev-prefix-mark (unrelated)
("C-M-#" . consult-register)
;; Other custom bindings
("M-y" . consult-yank-pop) ;; orig. yank-pop
;; M-g bindings in `goto-map'
("M-g e" . consult-compile-error)
("M-g f" . consult-flymake) ;; Alternative: consult-flycheck
("M-g g" . consult-goto-line) ;; orig. goto-line
("M-g M-g" . consult-goto-line) ;; orig. goto-line
("M-g o" . consult-outline) ;; Alternative: consult-org-heading
("M-g m" . consult-mark)
("M-g k" . consult-global-mark)
("M-g i" . consult-imenu)
("M-g I" . consult-imenu-multi)
;; M-s bindings in `search-map'
("M-s d" . consult-find) ;; Alternative: consult-fd
("M-s c" . consult-locate)
("M-s g" . consult-grep)
("M-s G" . consult-git-grep)
("M-s r" . consult-ripgrep)
("M-s l" . consult-line)
("M-s L" . consult-line-multi)
("M-s k" . consult-keep-lines)
("M-s u" . consult-focus-lines)
;; Isearch integration
("M-s e" . consult-isearch-history)
:map isearch-mode-map
("M-e" . consult-isearch-history) ;; orig. isearch-edit-string
("M-s e" . consult-isearch-history) ;; orig. isearch-edit-string
("M-s l" . consult-line) ;; needed by consult-line to detect isearch
("M-s L" . consult-line-multi) ;; needed by consult-line to detect isearch
;; Minibuffer history
:map minibuffer-local-map
("M-s" . consult-history) ;; orig. next-matching-history-element
("M-r" . consult-history)) ;; orig. previous-matching-history-element
;; Enable automatic preview at point in the *Completions* buffer. This is
;; relevant when you use the default completion UI.
:hook (completion-list-mode . consult-preview-at-point-mode)
;; The :init configuration is always executed (Not lazy)
:init
;; Tweak the register preview for `consult-register-load',
;; `consult-register-store' and the built-in commands. This improves the
;; register formatting, adds thin separator lines, register sorting and hides
;; the window mode line.
(advice-add #'register-preview :override #'consult-register-window)
(setq register-preview-delay 0.5)
;; Use Consult to select xref locations with preview
(setq xref-show-xrefs-function #'consult-xref
xref-show-definitions-function #'consult-xref)
;; Configure other variables and modes in the :config section,
;; after lazily loading the package.
:config
;; Optionally configure preview. The default value
;; is 'any, such that any key triggers the preview.
;; (setq consult-preview-key 'any)
;; (setq consult-preview-key "M-.")
;; (setq consult-preview-key '("S-<down>" "S-<up>"))
;; For some commands and buffer sources it is useful to configure the
;; :preview-key on a per-command basis using the `consult-customize' macro.
(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 "M-."
:preview-key '(:debounce 0.4 any))
;; Optionally configure the narrowing key.
;; Both < and C-+ work reasonably well.
(setq consult-narrow-key "<") ;; "C-+"
;; Optionally make narrowing help available in the minibuffer.
;; You may want to use `embark-prefix-help-command' or which-key instead.
;; (keymap-set consult-narrow-map (concat consult-narrow-key " ?") #'consult-narrow-help)
)
(use-package consult-eglot
:after eglot);; Pulls in embark as a dependency
(use-package embark-consult
:ensure t ; only need to install it, embark loads it after consult if found
:hook
(embark-collect-mode . consult-preview-at-point-mode))(use-package vertico
:custom
(vertico-resize t) ;; Grow and shrink the Vertico minibuffer
(vertico-cycle t) ;; Enable cycling for `vertico-next/previous'
:init
(vertico-mode))
(use-package vertico-directory
:ensure f
:bind (:map vertico-map
("C-l" . vertico-directory-up)
("RET" . vertico-directory-enter)
("DEL" . vertico-directory-delete-char)));; Persist history over Emacs restarts. Vertico sorts by history position.
(use-package savehist
:init
(savehist-mode));; A few more useful configurations...
(use-package emacs
:custom
;; Hide commands in M-x which do not work in the current mode. Vertico
;; commands are hidden in normal buffers. This setting is useful beyond
;; Vertico.
(read-extended-command-predicate #'command-completion-default-include-p)
:init
;; Add prompt indicator to `completing-read-multiple'.
;; We display [CRM<separator>], e.g., [CRM,] if the separator is a comma.
(defun crm-indicator (args)
(cons (format "[CRM%s] %s"
(replace-regexp-in-string
"\\`\\[.*?]\\*\\|\\[.*?]\\*\\'" ""
crm-separator)
(car args))
(cdr args)))
(advice-add #'completing-read-multiple :filter-args #'crm-indicator));; Optionally use the `orderless' completion style.
(use-package orderless
:custom
;; Configure a custom style dispatcher (see the Consult wiki)
;; (orderless-style-dispatchers '(+orderless-consult-dispatch orderless-affix-dispatch))
;; (orderless-component-separator #'orderless-escapable-split-on-space)
(completion-styles '(orderless ))
(completion-category-defaults nil)
(completion-category-overrides '((file (styles partial-completion)))))(use-package wgrep)(use-package eglot)
(use-package dape
:after eglot
:config
;; Turn on global bindings for setting breakpoints with mouse
(dape-breakpoint-global-mode)
(setq dape-inlay-hints t))(use-package smart-mode-line
:init
(sml/setup))(use-package sudo-edit)This makes it consistent with Linux.
(when (eq system-type 'darwin)
(setq mac-command-modifier 'meta)
(setq mac-option-modifier 'super)
(setq mac-control-modifier 'control))Pulled from https://www.emacswiki.org/emacs/KillingBuffers#h5o-2
(defun kill-other-buffers ()
"Kill all other buffers."
(interactive)
(mapc 'kill-buffer (delq (current-buffer) (buffer-list))))(setq doc-view-resolution 300)(defun preview-font ()
"Interactively preview available fonts."
(interactive)
(let ((font (completing-read "Preview font: " (font-family-list))))
(set-frame-font font t t)))
(defun preview-font-full ()
"Preview full font faces including variants."
(interactive)
(let* ((fonts (delete-dups (sort (x-list-fonts "*" nil) #'string<)))
(font (completing-read "Preview font face: " fonts)))
(set-frame-font font t t)))
(defun print-current-font ()
"Print the current frame font in the minibuffer and echo area."
(interactive)
(message "Current font: %s" (frame-parameter nil 'font)))On Fedora Kinoite and other Atomic Desktops, /home is symlinked to
/var/home. This causes issues with breakpoints not working in certain debuggers.
(when-let ((real-home (file-truename (getenv "HOME"))))
(when (not (string= (getenv "HOME") real-home))
(setenv "HOME" real-home)))