Compare commits

..

No commits in common. "936e09ce31fcba7e87b0c942c5ee5a138a8e3add" and "a1dd786801320f43fea947d3c8cf51f033119b90" have entirely different histories.

10 changed files with 40 additions and 381 deletions

View file

@ -1 +0,0 @@
source "/home/green/.deno/env.fish"

View file

@ -1,6 +1,5 @@
# This file contains fish universal variable definitions. # This file contains fish universal variable definitions.
# VERSION: 3.0 # VERSION: 3.0
SETUVAR --export GOROOT:/usr/lib64/go1\x2e26\x2e5/go SETUVAR --export GOROOT:/usr/lib64/go1\x2e26\x2e5/go
SETUVAR --export SOPS_AGE_KEY_FILE:/home/green/\x2eage/key\x2etxt
SETUVAR __fish_initialized:4300 SETUVAR __fish_initialized:4300
SETUVAR fish_user_paths:/usr/lib64/go1\x2e26\x2e5/go/bin\x1e/home/green/\x2ecargo/bin\x1e/home/green/\x2elocal/bin\x1e/home/green/\x2elocal/share/npm/bin SETUVAR fish_user_paths:/usr/lib64/go1\x2e26\x2e5/go/bin\x1e/home/green/\x2ecargo/bin\x1e/home/green/\x2elocal/bin\x1e/home/green/\x2elocal/share/npm/bin

View file

@ -1,3 +0,0 @@
function k --wraps kubectl --description 'alias kubectl'
kubectl $argv
end

View file

@ -1,14 +0,0 @@
## Dotfiles management
Any changes to dotfiles (shell configs, app configs, scripts, etc. that live
under `~/.dotfiles`) must be made by editing the files inside the
`~/.dotfiles` repo itself, NOT by editing the symlinked target files in place.
- `~/.dotfiles` uses a symlink system (see `link.sh` / `link-root.sh`) to
link its contents into their expected locations (e.g. `~/.config/*`,
`~/.vimrc`, etc.).
- Always locate and edit the source file under `~/.dotfiles`, then verify
the symlink is in place (run `~/.dotfiles/link.sh` if a new file needs to
be linked).
- After making changes, consider committing them in the `~/.dotfiles` git
repo.

View file

@ -1,12 +0,0 @@
# picom configuration
#
# NOTE: This file exists but is NOT currently used. picom is launched directly
# from xinitrc with: picom --backend glx --vsync
#
# Kept here for reference. The xrender + sync-fence approach was tried to fix
# AMDGPU page flip failures when opening emacsclient -c frames, but caused
# worse compositing performance for all other programs.
#
# The underlying issue: emacsclient -c + picom (glx, vsync) causes AMDGPU
# page flip failures on AMD Phoenix hardware. No picom-side fix found yet.
# See: https://github.com/yshui/picom/issues (search "amdgpu page flip")

View file

@ -16,4 +16,3 @@ export PATH="/usr/local/bin:$PATH"
export PATH="$PATH:/home/green/.lmstudio/bin" export PATH="$PATH:/home/green/.lmstudio/bin"
# End of LM Studio CLI section # End of LM Studio CLI section
. "/home/green/.deno/env"

View file

@ -33,8 +33,6 @@
(setf *ignore-wm-inc-hints* t) (setf *ignore-wm-inc-hints* t)
(set-font "-b&h-luxi mono-medium-r-normal--20-*-*-*-m-0-iso10646-1") (set-font "-b&h-luxi mono-medium-r-normal--20-*-*-*-m-0-iso10646-1")
(setf *message-window-padding* 16) (setf *message-window-padding* 16)
(setf *message-window-margin* 20)
(setf *message-window-y-margin* 20)
(setf *message-window-gravity* :center) (setf *message-window-gravity* :center)
(setf *input-window-gravity* :center) (setf *input-window-gravity* :center)
@ -49,20 +47,12 @@
(setf *new-frame-action* :empty) (setf *new-frame-action* :empty)
(setf *suppress-frame-indicator* t) (setf *suppress-frame-indicator* t)
;;; Groups — must be set up before define-frame-preference so names match
(grename "1")
(run-commands "gnewbg 2" "gnewbg 3" "gnewbg 4")
;;; Window placement policy ;;; Window placement policy
;; "Default" is the initial group name before grename runs at the bottom. (define-frame-preference "Default"
;; These float rules must use "Default" — StumpWM evaluates frame preferences (0 t nil :class "Konqueror" :role "...konqueror-mainwindow")
;; at window-open time against the group name, and the first group starts as (1 t nil :class "XTerm")
;; "Default" until grename changes it at startup (but the rule is registered (:float t t :class "alsamixer-scratch")
;; at load time when the name is still being matched by content, not snapshot). (:float t t :class "ncmpcpp-scratch"))
;; In practice (:float t t) with target-group matching works correctly here.
(define-frame-preference nil
(:float t nil :class "alsamixer-scratch")
(:float t nil :class "ncmpcpp-scratch"))
(define-frame-preference "scratch-emacs-1" (define-frame-preference "scratch-emacs-1"
(0 t t :title "scratch-emacs-1")) (0 t t :title "scratch-emacs-1"))
@ -248,45 +238,13 @@ If PERSISTENT is t, smart-kill will hide the window instead of killing it."
(height (nth 5 rule))) (height (nth 5 rule)))
(stumpwm::float-window-move-resize win :x x :y y :width width :height height)))))) (stumpwm::float-window-move-resize win :x x :y y :width width :height height))))))
;; StumpWM keeps non-focused windows within the same frame mapped (stacked
;; behind the current one) rather than unmapping them like most tiling WMs.
;; This causes other windows to bleed through when transparency is used.
;; This hook hides all frame siblings when focus changes so only the
;; focused window and the wallpaper are visible through any transparency.
;; Named function (not lambda) so loadrc replaces it instead of accumulating copies.
(defun hide-unfocused-frame-siblings (new old)
(declare (ignore old))
(when (and new (typep new 'stumpwm::tile-window))
(let* ((group (window-group new))
(frame (window-frame new))
(siblings (remove new (frame-windows group frame))))
(mapc #'hide-window siblings)
(unhide-window new))))
(remove-hook *focus-window-hook* 'hide-unfocused-frame-siblings)
(add-hook *focus-window-hook* 'hide-unfocused-frame-siblings)
(defun float-window-to-current-group (win)
"Move a float window to the current group by directly manipulating group membership,
bypassing group-add-window (which would retrigger frame preferences and group switches)."
(let ((current (current-group))
(old (window-group win)))
(unless (eq old current)
(setf (group-windows old) (remove win (group-windows old)))
(setf (window-group win) current)
(push win (group-windows current)))))
(defun spawn-or-focus (class command) (defun spawn-or-focus (class command)
"Unhide or focus existing window with CLASS, or spawn COMMAND if none exists. "Unhide or focus existing window with CLASS, or spawn COMMAND if none exists."
Float windows are moved to the current group directly to avoid group switches."
(let ((win (find-if (lambda (w) (string= (window-class w) class)) (let ((win (find-if (lambda (w) (string= (window-class w) class))
(screen-windows (current-screen))))) (screen-windows (current-screen)))))
(cond ((null win) (run-shell-command command)) (cond ((null win) (run-shell-command command))
((eq win (current-window)) nil) ((eq win (current-window)) nil)
(t (t (focus-window win)))))
(when (typep win 'stumpwm::float-window)
(float-window-to-current-group win))
(focus-window win)))))
(defcommand smart-kill () () (defcommand smart-kill () ()
"Kill window normally, unless it's a persistent float — then hide it instead." "Kill window normally, unless it's a persistent float — then hide it instead."
@ -312,124 +270,11 @@ If PERSISTENT is t, smart-kill will hide the window instead of killing it."
(defcommand ncmpcpp-float () () (defcommand ncmpcpp-float () ()
"Open ncmpcpp in a persistent floating wezterm window." "Open ncmpcpp in a persistent floating wezterm window."
(spawn-or-focus "ncmpcpp-scratch" "wezterm start --class ncmpcpp-scratch -- ncmpcpp" :persistent t)) (spawn-or-focus "ncmpcpp-scratch" "wezterm start --class ncmpcpp-scratch -- ncmpcpp"))
;;; Keymaps ;;; Config keymap
;;
;; All named keymaps are defined here. Add a keymap to *hint-keymaps* to make
;; it auto-display its bindings in the top-left corner when its prefix key is
;; pressed, instead of requiring '?'. Remove from the list to disable hints.
(defvar *config-map* (make-sparse-keymap)) (defvar *config-map* (make-sparse-keymap))
(defvar *brightness-map* (make-sparse-keymap))
(defvar *gaps-map* (make-sparse-keymap))
(defvar *window-map* (make-sparse-keymap))
(defvar *media-map* (make-sparse-keymap))
(defvar *appearance-map* (make-sparse-keymap))
(defvar *appearance-all-map* (make-sparse-keymap))
;; Global opacity — stored so new windows can inherit it via *new-window-hook*
(defvar *global-opacity* nil)
;; Per-window opacity via picom-trans -c (current focused window)
(defmacro make-opacity-command (name opacity)
`(defcommand ,name () ()
,(format nil "Set current window opacity to ~a%." opacity)
(run-shell-command (format nil "picom-trans -c ~a" ,opacity))))
;; Global opacity — sets all existing windows and stores value for new ones
(defmacro make-global-opacity-command (name opacity)
`(defcommand ,name () ()
,(format nil "Set ALL windows opacity to ~a%." opacity)
(setf *global-opacity* ,opacity)
(dolist (w (screen-windows (current-screen)))
(run-shell-command
(format nil "picom-trans -w ~a ~a"
(xlib:window-id (window-xwin w)) ,opacity)))))
;; Apply global opacity to new windows as they appear
(add-hook *new-window-hook*
(lambda (win)
(when *global-opacity*
(run-shell-command
(format nil "picom-trans -w ~a ~a"
(xlib:window-id (window-xwin win)) *global-opacity*)))))
(make-opacity-command opacity-10 10)
(make-opacity-command opacity-20 20)
(make-opacity-command opacity-30 30)
(make-opacity-command opacity-40 40)
(make-opacity-command opacity-50 50)
(make-opacity-command opacity-60 60)
(make-opacity-command opacity-70 70)
(make-opacity-command opacity-80 80)
(make-opacity-command opacity-90 90)
(make-opacity-command opacity-100 100)
(make-global-opacity-command global-opacity-10 10)
(make-global-opacity-command global-opacity-20 20)
(make-global-opacity-command global-opacity-30 30)
(make-global-opacity-command global-opacity-40 40)
(make-global-opacity-command global-opacity-50 50)
(make-global-opacity-command global-opacity-60 60)
(make-global-opacity-command global-opacity-70 70)
(make-global-opacity-command global-opacity-80 80)
(make-global-opacity-command global-opacity-90 90)
(make-global-opacity-command global-opacity-100 100)
(define-key *appearance-map* (kbd "1") "opacity-10")
(define-key *appearance-map* (kbd "2") "opacity-20")
(define-key *appearance-map* (kbd "3") "opacity-30")
(define-key *appearance-map* (kbd "4") "opacity-40")
(define-key *appearance-map* (kbd "5") "opacity-50")
(define-key *appearance-map* (kbd "6") "opacity-60")
(define-key *appearance-map* (kbd "7") "opacity-70")
(define-key *appearance-map* (kbd "8") "opacity-80")
(define-key *appearance-map* (kbd "9") "opacity-90")
(define-key *appearance-map* (kbd "0") "opacity-100")
(define-key *appearance-all-map* (kbd "1") "global-opacity-10")
(define-key *appearance-all-map* (kbd "2") "global-opacity-20")
(define-key *appearance-all-map* (kbd "3") "global-opacity-30")
(define-key *appearance-all-map* (kbd "4") "global-opacity-40")
(define-key *appearance-all-map* (kbd "5") "global-opacity-50")
(define-key *appearance-all-map* (kbd "6") "global-opacity-60")
(define-key *appearance-all-map* (kbd "7") "global-opacity-70")
(define-key *appearance-all-map* (kbd "8") "global-opacity-80")
(define-key *appearance-all-map* (kbd "9") "global-opacity-90")
(define-key *appearance-all-map* (kbd "0") "global-opacity-100")
(defvar *brightness-map* (make-sparse-keymap))
(defvar *gaps-map* (make-sparse-keymap))
(defvar *window-map* (make-sparse-keymap))
(defvar *media-map* (make-sparse-keymap))
;; Keymaps that automatically show their bindings when activated.
;; Add or remove keymaps here to control which ones show hints.
(defvar *hint-keymaps*
(list *config-map*
*window-map*
*media-map*
*brightness-map*
*gaps-map*
*appearance-map*
*appearance-all-map*))
;; Show bindings in top-left for any keymap in *hint-keymaps*.
(add-hook *key-press-hook*
(lambda (key key-seq cmd)
(declare (ignore key cmd))
(let* ((oriented (reverse key-seq))
(maps (get-kmaps-at-key-seq (dereference-kmaps (top-maps)) oriented)))
(when-let ((hint-maps (remove-if-not
(lambda (m) (member m *hint-keymaps*))
maps)))
(let ((*message-window-gravity* :top-left))
(apply #'display-bindings-for-keymaps oriented hint-maps))))))
;;; Config map bindings
(define-key *config-map* (kbd "a") "alsamixer-float") (define-key *config-map* (kbd "a") "alsamixer-float")
(define-key *config-map* (kbd "b") *brightness-map*) (defvar *brightness-map* (make-sparse-keymap))
;;; Brightness map bindings
(define-key *brightness-map* (kbd "1") "brightness-10") (define-key *brightness-map* (kbd "1") "brightness-10")
(define-key *brightness-map* (kbd "2") "brightness-20") (define-key *brightness-map* (kbd "2") "brightness-20")
(define-key *brightness-map* (kbd "3") "brightness-30") (define-key *brightness-map* (kbd "3") "brightness-30")
@ -440,20 +285,21 @@ If PERSISTENT is t, smart-kill will hide the window instead of killing it."
(define-key *brightness-map* (kbd "8") "brightness-80") (define-key *brightness-map* (kbd "8") "brightness-80")
(define-key *brightness-map* (kbd "9") "brightness-90") (define-key *brightness-map* (kbd "9") "brightness-90")
(define-key *brightness-map* (kbd "0") "brightness-100") (define-key *brightness-map* (kbd "0") "brightness-100")
(define-key *config-map* (kbd "b") *brightness-map*)
;;; Gaps map bindings ;;; Keymaps
(defvar *gaps-map* (make-sparse-keymap))
(define-key *gaps-map* (kbd "0") "gaps-off") (define-key *gaps-map* (kbd "0") "gaps-off")
(define-key *gaps-map* (kbd "1") "gaps-small") (define-key *gaps-map* (kbd "1") "gaps-small")
(define-key *gaps-map* (kbd "2") "gaps-medium") (define-key *gaps-map* (kbd "2") "gaps-medium")
(define-key *gaps-map* (kbd "3") "gaps-large") (define-key *gaps-map* (kbd "3") "gaps-large")
;;; Window map bindings (defvar *window-map* (make-sparse-keymap))
(define-key *window-map* (kbd "r") "iresize") (define-key *window-map* (kbd "r") "iresize")
(define-key *window-map* (kbd "g") *gaps-map*) (define-key *window-map* (kbd "g") *gaps-map*)
(define-key *window-map* (kbd "t") *appearance-map*)
(define-key *window-map* (kbd "T") *appearance-all-map*)
;;; Media map bindings (defvar *media-map* (make-sparse-keymap))
(define-key *media-map* (kbd "v") "mpv-pick") (define-key *media-map* (kbd "v") "mpv-pick")
(define-key *media-map* (kbd "m") "mpv-url") (define-key *media-map* (kbd "m") "mpv-url")
(define-key *media-map* (kbd "d") "yt-download") (define-key *media-map* (kbd "d") "yt-download")
@ -462,23 +308,10 @@ If PERSISTENT is t, smart-kill will hide the window instead of killing it."
;;; Top-level bindings ;;; Top-level bindings
(define-key *top-map* (kbd "s-d") "rofi-run") (define-key *top-map* (kbd "s-d") "rofi-run")
(define-key *top-map* (kbd "s-w") "rofi-pull-window") (define-key *top-map* (kbd "s-w") "rofi-pull-window")
(defun emacs-window-p (win) (define-key *top-map* (kbd "s-h") "move-focus left")
(and win (string= (window-class win) "Emacs"))) (define-key *top-map* (kbd "s-j") "move-focus down")
(define-key *top-map* (kbd "s-k") "move-focus up")
(defcommand smart-move-focus (direction) ((:direction "Direction: ")) (define-key *top-map* (kbd "s-l") "move-focus right")
"If the focused window is Emacs and it has a window in DIRECTION, move
focus there via windmove. Otherwise move focus to the next StumpWM frame."
(if (and (emacs-window-p (current-window))
(search "t" (run-shell-command
(format nil "emacsclient -e '(if (ignore-errors (windmove-~(~a~) nil) t) t nil)'" direction)
t)))
nil
(move-focus direction)))
(define-key *top-map* (kbd "s-h") "smart-move-focus left")
(define-key *top-map* (kbd "s-j") "smart-move-focus down")
(define-key *top-map* (kbd "s-k") "smart-move-focus up")
(define-key *top-map* (kbd "s-l") "smart-move-focus right")
(define-key *top-map* (kbd "s-p") "next-in-frame") (define-key *top-map* (kbd "s-p") "next-in-frame")
(define-key *top-map* (kbd "s-n") "prev-in-frame") (define-key *top-map* (kbd "s-n") "prev-in-frame")
(define-key *top-map* (kbd "s-q") "smart-kill") (define-key *top-map* (kbd "s-q") "smart-kill")
@ -490,6 +323,10 @@ If PERSISTENT is t, smart-kill will hide the window instead of killing it."
(define-key *top-map* (kbd "s-W") *window-map*) (define-key *top-map* (kbd "s-W") *window-map*)
(define-key *top-map* (kbd "s-m") *media-map*) (define-key *top-map* (kbd "s-m") *media-map*)
;;; Groups
(grename "1")
(run-commands "gnewbg 2" "gnewbg 3" "gnewbg 4")
;;; Group switching ;;; Group switching
(define-key *top-map* (kbd "s-1") "gselect 1") (define-key *top-map* (kbd "s-1") "gselect 1")
(define-key *top-map* (kbd "s-2") "gselect 2") (define-key *top-map* (kbd "s-2") "gselect 2")
@ -507,15 +344,7 @@ If PERSISTENT is t, smart-kill will hide the window instead of killing it."
(let* ((screen (current-screen)) (let* ((screen (current-screen))
(current (current-group)) (current (current-group))
(target (find-group screen group-name)) (target (find-group screen group-name))
;; Once a scratchpad window has been created, it stays resident in (existing (or (when window-class
;; its own dedicated group even after we switch away from it. So the
;; most reliable "does it already exist" check is simply: does the
;; target group already have a window in it? This avoids relying on
;; window title, which for programs like Emacs changes constantly
;; based on the current buffer and would otherwise cause a fresh
;; instance to be spawned every time.
(existing (or (first (group-windows target))
(when window-class
(find-if (lambda (w) (string= (window-class w) window-class)) (find-if (lambda (w) (string= (window-class w) window-class))
(screen-windows screen))) (screen-windows screen)))
(when window-title (when window-title

View file

@ -11,7 +11,4 @@ pipewire &
pipewire-pulse & pipewire-pulse &
wireplumber & wireplumber &
# Compositor - eliminates screen tearing
# picom --backend glx &
exec stumpwm exec stumpwm

View file

@ -69,7 +69,7 @@ To get started, run =C-c C-v t=
;; (setenv "PATH" (concat "/opt/homebrew/bin:" (getenv "PATH"))) ;; (setenv "PATH" (concat "/opt/homebrew/bin:" (getenv "PATH")))
#+end_src #+end_src
** Straight ** Straight
I primarily use package.el/MELPA (via use-package :ensure) for most packages, and reserve straight.el for the exceptions: packages not available on MELPA, or where I want a specific git source/fork (e.g. beancount-mode, evil-markdown, the symex/countvajhula family, and select AI agent packages like claude-code.el, claude-code-ide.el, gptel-agent, and agent-shell). I don't use straight for much currently, but needed it in order to install beancount-mode and intend to migrate all my packages to it eventually.
#+begin_src emacs-lisp #+begin_src emacs-lisp
(defvar bootstrap-version) (defvar bootstrap-version)
(let ((bootstrap-file (let ((bootstrap-file
@ -246,7 +246,6 @@ Setting this in the :init of evil doesn't work for some reason. It has to be ear
eshell-mode-hook eshell-mode-hook
treemacs-mode-hook treemacs-mode-hook
vterm-mode-hook vterm-mode-hook
eat-mode-hook
nov-mode-hook)) nov-mode-hook))
(add-hook mode (lambda () (display-line-numbers-mode 0)))) (add-hook mode (lambda () (display-line-numbers-mode 0))))
(column-number-mode) (column-number-mode)
@ -312,39 +311,6 @@ buffer switching — splits should be intentional.
(tab-bar-echo-area-mode 1) (tab-bar-echo-area-mode 1)
(setq tab-bar-show nil)) (setq tab-bar-show nil))
#+end_src #+end_src
** Tabspaces
Buffers, and much of buffer-selection UI (=consult-buffer=, ibuffer, etc.),
are scoped per tab via =tabspaces=. Each tab gets its own isolated buffer
list, similar to workspaces in other editors — switching tabs only shows you
the buffers relevant to that tab.
#+begin_src emacs-lisp
(use-package tabspaces
:ensure t
:hook (after-init . tabspaces-mode)
:commands (tabspaces-switch-or-create-workspace
tabspaces-open-or-create-project-and-workspace)
:config
(setq tabspaces-use-filtered-buffers-as-default t)
(setq tabspaces-default-tab "Default")
(setq tabspaces-remove-to-default t)
(setq tabspaces-include-buffers '("*scratch*"))
;; Keep consult-buffer scoped to the current tab's buffer list.
;; tabspaces doesn't ship a consult source itself, so define one here
;; using its own buffer-list function, and put it ahead of consult's
;; default (unfiltered) buffer source.
(with-eval-after-load 'consult
(defvar consult--source-tabspaces
`(:name "Workspace Buffers"
:narrow ?w
:category buffer
:face consult-buffer
:history buffer-name-history
:state ,#'consult--buffer-state
:items ,(lambda () (mapcar #'buffer-name (tabspaces--buffer-list)))))
(consult-customize consult--source-buffer :hidden t :default nil)
(add-to-list 'consult-buffer-sources 'consult--source-tabspaces)))
#+end_src
* Evil * Evil
#+begin_src emacs-lisp #+begin_src emacs-lisp
(use-package evil (use-package evil
@ -462,45 +428,6 @@ at the tab level rather than with a dedicated workspace package.
(ace-window arg) (ace-window arg)
)) ))
#+end_src #+end_src
*** StumpWM-aware window navigation
=s-h/j/k/l= (mod+hjkl) move between Emacs windows using =windmove=. When
there's no further Emacs window in that direction (i.e. we're at the edge of
Emacs's frame), the command instead shells out to StumpWM via =stumpish= to
move focus to the next tiled frame in that direction — so navigation flows
seamlessly out of Emacs and into the rest of the WM using the same keys
StumpWM itself binds to =s-h/j/k/l=.
#+begin_src emacs-lisp
(defvar stumpwm-stumpish-path
(expand-file-name "~/.stumpwm.d/modules/util/stumpish/stumpish")
"Path to the stumpish binary used to talk to a running StumpWM.")
(defun stumpwm-move-focus (direction)
"Ask StumpWM to move focus to the frame in DIRECTION (\"left\" \"right\" \"up\" \"down\").
No-op on macOS (or anywhere StumpWM isn't running/available)."
(when (and (not IS-MACOS)
(file-executable-p stumpwm-stumpish-path))
(call-process stumpwm-stumpish-path nil nil nil
(concat "move-focus " direction))))
(defun stumpwm-windmove-or-escape (windmove-fn direction)
"Call WINDMOVE-FN; if it errors (no Emacs window in DIRECTION),
fall through to StumpWM and move focus to the next tiled frame there."
(condition-case nil
(funcall windmove-fn)
(error (stumpwm-move-focus direction))))
(defun stumpwm-windmove-left () (interactive) (stumpwm-windmove-or-escape #'windmove-left "left"))
(defun stumpwm-windmove-right () (interactive) (stumpwm-windmove-or-escape #'windmove-right "right"))
(defun stumpwm-windmove-up () (interactive) (stumpwm-windmove-or-escape #'windmove-up "up"))
(defun stumpwm-windmove-down () (interactive) (stumpwm-windmove-or-escape #'windmove-down "down"))
(global-set-key (kbd "s-h") #'stumpwm-windmove-left)
(global-set-key (kbd "s-j") #'stumpwm-windmove-down)
(global-set-key (kbd "s-k") #'stumpwm-windmove-up)
(global-set-key (kbd "s-l") #'stumpwm-windmove-right)
#+end_src
** Popper ** Popper
Transient/popup buffers — terminals, help, compilation, messages — are managed Transient/popup buffers — terminals, help, compilation, messages — are managed
by popper, which tracks them as a group and lets you cycle or dismiss them by popper, which tracks them as a group and lets you cycle or dismiss them
@ -911,8 +838,6 @@ I know these could be bound on a per-package basis, but since this is my primary
"sr" '(+eval/open-repl-other-window :which-key "Repl") "sr" '(+eval/open-repl-other-window :which-key "Repl")
"st" '(+vterm/toggle :which-key "Toggle vterm popup") "st" '(+vterm/toggle :which-key "Toggle vterm popup")
"sT" '(+vterm/here :which-key "Open vterm here") "sT" '(+vterm/here :which-key "Open vterm here")
"sa" '(eat :which-key "Eat (new/switch)")
"sA" '(eat-other-window :which-key "Eat (other window)")
;; Toggle ;; Toggle
"t" '(:ignore t :which-key "toggle") "t" '(:ignore t :which-key "toggle")
@ -928,6 +853,17 @@ I know these could be bound on a per-package basis, but since this is my primary
"v" '(:ignore t :which-key "visual/appearance") "v" '(:ignore t :which-key "visual/appearance")
"vt" '(load-theme :which-key "load theme") "vt" '(load-theme :which-key "load theme")
;; TODO: maybe make this mode-specific stuff, not using workspaces
;; Workspaces
;; "TAB TAB" '(+workspace/display :which-key "Display tab bar")
;; "TAB d" '(+workspace/delete :which-key "Delete this workspace")
;; "TAB l" '(+workspace/load :which-key "Load workspace from file")
;; "TAB n" '(+workspace/new :which-key "New workspace")
;; "TAB N" '(+workspace/new-named :which-key "New named workspace")
;; "TAB r" '(+workspace/rename :which-key "Rename workspace")
;; "TAB R" '(+workspace/restore-last-session :which-key "Restore last session")
;; "TAB s" '(+workspace/save :which-key "Save workspace")
;; "TAB x" '(+workspace/kill-session :which-key "Delete session")
)) ))
#+end_src #+end_src
@ -938,72 +874,10 @@ I know these could be bound on a per-package basis, but since this is my primary
deft-extensions '("org" "txt")) deft-extensions '("org" "txt"))
#+end_src #+end_src
* AI * AI
Multiple AI coding-agent integrations are configured here, all under the
=SPC c a= (mnemonic: "code agent") prefix. None of these packages are
loaded, started, or connected to anything at Emacs startup — they are
purely autoloaded via =:commands= and only spring into life when you
explicitly invoke one of the bindings below. This is deliberate: several
of these (claude-code family in particular) are tied to a specific
subscription/account, and accidentally having one auto-activate in the
wrong project (personal vs. work) would be a contract violation. So:
- No =:hook=, no =:init= that touches global state, no autostart.
- Each package is truly inert until you press its specific keybinding.
- You are always choosing, explicitly, which agent/account to invoke for
the current project.
#+begin_src emacs-lisp #+begin_src emacs-lisp
(use-package gptel (use-package gptel)
:commands (gptel gptel-send gptel-menu) (setq gptl-default-mode 'org-mode)
:config
(setq gptel-default-mode 'org-mode))
;; gptel-agent adds agentic/tool-use capabilities on top of gptel.
;; Deferred the same way — it does nothing until invoked.
(use-package gptel-agent
:straight (gptel-agent :host github :repo "skissue/gptel-agent")
:after gptel
:commands (gptel-agent))
;; claude-code.el: terminal/vterm-backed Claude Code session manager.
;; :commands ensures the package (and any of its process-launching code)
;; is not loaded until you explicitly call one of these.
(use-package claude-code
:straight (claude-code :host github :repo "stevemolitor/claude-code.el")
:commands (claude-code claude-code-toggle claude-code-send-region
claude-code-switch-to-buffer))
;; claude-code-ide.el: a separate, IDE-style (not terminal-based)
;; Claude Code integration. Kept fully independent from claude-code.el
;; above so you can compare the two without either auto-loading the
;; other.
(use-package claude-code-ide
:straight (claude-code-ide :host github :repo "manzaltu/claude-code-ide.el")
:commands (claude-code-ide claude-code-ide-menu))
;; agent-shell: general-purpose agent shell (not Claude-specific).
(use-package agent-shell
:straight (agent-shell :host github :repo "xenodium/agent-shell")
:commands (agent-shell))
#+end_src #+end_src
** Keybindings
All bindings live under =SPC c a=, alongside the rest of the =Code= prefix.
Nothing here is bound globally outside of =general-definition= below, and
none of it runs at startup — pressing one of these keys is the only thing
that ever loads/starts the corresponding package.
#+begin_src emacs-lisp
(with-eval-after-load 'general
(general-definition
"ca" '(:ignore t :which-key "Code agent")
"caa" '(gptel :which-key "gptel (chat)")
"cag" '(gptel-agent :which-key "gptel-agent")
"cac" '(claude-code :which-key "claude-code.el")
"caC" '(claude-code-ide :which-key "claude-code-ide.el")
"cas" '(agent-shell :which-key "agent-shell")))
#+end_src
* Org Mode * Org Mode
#+begin_src emacs-lisp #+begin_src emacs-lisp
(use-package org) (use-package org)
@ -1581,14 +1455,6 @@ This is mostly lifted from the doom emacs config. Beancount-mode by default has
;; kubernetes-tramp ;; kubernetes-tramp
#+end_src #+end_src
* Shells * Shells
** Eat
Eat (Emulate A Terminal) is a fast, full-featured terminal emulator for
Emacs, offered here as another shell option alongside eshell/vterm under
=SPC s=.
#+begin_src emacs-lisp
(use-package eat
:commands (eat eat-other-window))
#+end_src
** Enable fish completions ** Enable fish completions
Uses the external fish program to provide fish-style completions to eshell etc Uses the external fish program to provide fish-style completions to eshell etc
#+begin_src emacs-lisp #+begin_src emacs-lisp

View file

@ -34,7 +34,6 @@ backup_and_link "$DOTFILES/config/kanata" "$HOME/.config/kanata"
backup_and_link "$DOTFILES/config/nyxt" "$HOME/.config/nyxt" backup_and_link "$DOTFILES/config/nyxt" "$HOME/.config/nyxt"
backup_and_link "$DOTFILES/config/yazi" "$HOME/.config/yazi" backup_and_link "$DOTFILES/config/yazi" "$HOME/.config/yazi"
backup_and_link "$DOTFILES/config/mpd/mpd.conf" "$HOME/.config/mpd/mpd.conf" backup_and_link "$DOTFILES/config/mpd/mpd.conf" "$HOME/.config/mpd/mpd.conf"
backup_and_link "$DOTFILES/config/goose/.goosehints" "$HOME/.config/goose/.goosehints"
backup_and_link "$DOTFILES/config/rofi" "$HOME/.config/rofi" backup_and_link "$DOTFILES/config/rofi" "$HOME/.config/rofi"
backup_and_link "$DOTFILES/config/zathura" "$HOME/.config/zathura" backup_and_link "$DOTFILES/config/zathura" "$HOME/.config/zathura"