Compare commits
10 commits
a1dd786801
...
936e09ce31
| Author | SHA1 | Date | |
|---|---|---|---|
| 936e09ce31 | |||
| cc54f69933 | |||
| 0f471e2c6e | |||
| 415f33880c | |||
| a64efec920 | |||
| 20bcc0d97f | |||
| e6ff121cc7 | |||
| 5b4686f3b9 | |||
| 030a4fb510 | |||
| f70c35af6d |
10 changed files with 381 additions and 40 deletions
1
config/fish/conf.d/deno.fish
Normal file
1
config/fish/conf.d/deno.fish
Normal file
|
|
@ -0,0 +1 @@
|
|||
source "/home/green/.deno/env.fish"
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
# This file contains fish universal variable definitions.
|
||||
# VERSION: 3.0
|
||||
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_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
|
||||
|
|
|
|||
3
config/fish/functions/k.fish
Normal file
3
config/fish/functions/k.fish
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
function k --wraps kubectl --description 'alias kubectl'
|
||||
kubectl $argv
|
||||
end
|
||||
14
config/goose/.goosehints
Normal file
14
config/goose/.goosehints
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
## 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.
|
||||
12
config/picom/picom.conf
Normal file
12
config/picom/picom.conf
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
# 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")
|
||||
|
|
@ -16,3 +16,4 @@ export PATH="/usr/local/bin:$PATH"
|
|||
export PATH="$PATH:/home/green/.lmstudio/bin"
|
||||
# End of LM Studio CLI section
|
||||
|
||||
. "/home/green/.deno/env"
|
||||
|
|
|
|||
|
|
@ -33,6 +33,8 @@
|
|||
(setf *ignore-wm-inc-hints* t)
|
||||
(set-font "-b&h-luxi mono-medium-r-normal--20-*-*-*-m-0-iso10646-1")
|
||||
(setf *message-window-padding* 16)
|
||||
(setf *message-window-margin* 20)
|
||||
(setf *message-window-y-margin* 20)
|
||||
(setf *message-window-gravity* :center)
|
||||
(setf *input-window-gravity* :center)
|
||||
|
||||
|
|
@ -47,12 +49,20 @@
|
|||
(setf *new-frame-action* :empty)
|
||||
(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
|
||||
(define-frame-preference "Default"
|
||||
(0 t nil :class "Konqueror" :role "...konqueror-mainwindow")
|
||||
(1 t nil :class "XTerm")
|
||||
(:float t t :class "alsamixer-scratch")
|
||||
(:float t t :class "ncmpcpp-scratch"))
|
||||
;; "Default" is the initial group name before grename runs at the bottom.
|
||||
;; These float rules must use "Default" — StumpWM evaluates frame preferences
|
||||
;; at window-open time against the group name, and the first group starts as
|
||||
;; "Default" until grename changes it at startup (but the rule is registered
|
||||
;; at load time when the name is still being matched by content, not snapshot).
|
||||
;; 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"
|
||||
(0 t t :title "scratch-emacs-1"))
|
||||
|
|
@ -238,13 +248,45 @@ If PERSISTENT is t, smart-kill will hide the window instead of killing it."
|
|||
(height (nth 5 rule)))
|
||||
(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)
|
||||
"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))
|
||||
(screen-windows (current-screen)))))
|
||||
(cond ((null win) (run-shell-command command))
|
||||
((eq win (current-window)) nil)
|
||||
(t (focus-window win)))))
|
||||
(t
|
||||
(when (typep win 'stumpwm::float-window)
|
||||
(float-window-to-current-group win))
|
||||
(focus-window win)))))
|
||||
|
||||
(defcommand smart-kill () ()
|
||||
"Kill window normally, unless it's a persistent float — then hide it instead."
|
||||
|
|
@ -270,11 +312,124 @@ If PERSISTENT is t, smart-kill will hide the window instead of killing it."
|
|||
|
||||
(defcommand ncmpcpp-float () ()
|
||||
"Open ncmpcpp in a persistent floating wezterm window."
|
||||
(spawn-or-focus "ncmpcpp-scratch" "wezterm start --class ncmpcpp-scratch -- ncmpcpp"))
|
||||
;;; Config keymap
|
||||
(spawn-or-focus "ncmpcpp-scratch" "wezterm start --class ncmpcpp-scratch -- ncmpcpp" :persistent t))
|
||||
;;; Keymaps
|
||||
;;
|
||||
;; 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))
|
||||
(define-key *config-map* (kbd "a") "alsamixer-float")
|
||||
(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 "b") *brightness-map*)
|
||||
|
||||
;;; Brightness map bindings
|
||||
(define-key *brightness-map* (kbd "1") "brightness-10")
|
||||
(define-key *brightness-map* (kbd "2") "brightness-20")
|
||||
(define-key *brightness-map* (kbd "3") "brightness-30")
|
||||
|
|
@ -285,21 +440,20 @@ 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 "9") "brightness-90")
|
||||
(define-key *brightness-map* (kbd "0") "brightness-100")
|
||||
(define-key *config-map* (kbd "b") *brightness-map*)
|
||||
|
||||
;;; Keymaps
|
||||
|
||||
(defvar *gaps-map* (make-sparse-keymap))
|
||||
;;; Gaps map bindings
|
||||
(define-key *gaps-map* (kbd "0") "gaps-off")
|
||||
(define-key *gaps-map* (kbd "1") "gaps-small")
|
||||
(define-key *gaps-map* (kbd "2") "gaps-medium")
|
||||
(define-key *gaps-map* (kbd "3") "gaps-large")
|
||||
|
||||
(defvar *window-map* (make-sparse-keymap))
|
||||
;;; Window map bindings
|
||||
(define-key *window-map* (kbd "r") "iresize")
|
||||
(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*)
|
||||
|
||||
(defvar *media-map* (make-sparse-keymap))
|
||||
;;; Media map bindings
|
||||
(define-key *media-map* (kbd "v") "mpv-pick")
|
||||
(define-key *media-map* (kbd "m") "mpv-url")
|
||||
(define-key *media-map* (kbd "d") "yt-download")
|
||||
|
|
@ -308,10 +462,23 @@ If PERSISTENT is t, smart-kill will hide the window instead of killing it."
|
|||
;;; Top-level bindings
|
||||
(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-h") "move-focus left")
|
||||
(define-key *top-map* (kbd "s-j") "move-focus down")
|
||||
(define-key *top-map* (kbd "s-k") "move-focus up")
|
||||
(define-key *top-map* (kbd "s-l") "move-focus right")
|
||||
(defun emacs-window-p (win)
|
||||
(and win (string= (window-class win) "Emacs")))
|
||||
|
||||
(defcommand smart-move-focus (direction) ((:direction "Direction: "))
|
||||
"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-n") "prev-in-frame")
|
||||
(define-key *top-map* (kbd "s-q") "smart-kill")
|
||||
|
|
@ -323,10 +490,6 @@ 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-m") *media-map*)
|
||||
|
||||
;;; Groups
|
||||
(grename "1")
|
||||
(run-commands "gnewbg 2" "gnewbg 3" "gnewbg 4")
|
||||
|
||||
;;; Group switching
|
||||
(define-key *top-map* (kbd "s-1") "gselect 1")
|
||||
(define-key *top-map* (kbd "s-2") "gselect 2")
|
||||
|
|
@ -344,7 +507,15 @@ If PERSISTENT is t, smart-kill will hide the window instead of killing it."
|
|||
(let* ((screen (current-screen))
|
||||
(current (current-group))
|
||||
(target (find-group screen group-name))
|
||||
(existing (or (when window-class
|
||||
;; Once a scratchpad window has been created, it stays resident in
|
||||
;; 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))
|
||||
(screen-windows screen)))
|
||||
(when window-title
|
||||
|
|
|
|||
|
|
@ -11,4 +11,7 @@ pipewire &
|
|||
pipewire-pulse &
|
||||
wireplumber &
|
||||
|
||||
# Compositor - eliminates screen tearing
|
||||
# picom --backend glx &
|
||||
|
||||
exec stumpwm
|
||||
|
|
|
|||
162
emacs-config.org
162
emacs-config.org
|
|
@ -69,7 +69,7 @@ To get started, run =C-c C-v t=
|
|||
;; (setenv "PATH" (concat "/opt/homebrew/bin:" (getenv "PATH")))
|
||||
#+end_src
|
||||
** Straight
|
||||
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.
|
||||
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).
|
||||
#+begin_src emacs-lisp
|
||||
(defvar bootstrap-version)
|
||||
(let ((bootstrap-file
|
||||
|
|
@ -246,6 +246,7 @@ Setting this in the :init of evil doesn't work for some reason. It has to be ear
|
|||
eshell-mode-hook
|
||||
treemacs-mode-hook
|
||||
vterm-mode-hook
|
||||
eat-mode-hook
|
||||
nov-mode-hook))
|
||||
(add-hook mode (lambda () (display-line-numbers-mode 0))))
|
||||
(column-number-mode)
|
||||
|
|
@ -311,6 +312,39 @@ buffer switching — splits should be intentional.
|
|||
(tab-bar-echo-area-mode 1)
|
||||
(setq tab-bar-show nil))
|
||||
#+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
|
||||
#+begin_src emacs-lisp
|
||||
(use-package evil
|
||||
|
|
@ -428,6 +462,45 @@ at the tab level rather than with a dedicated workspace package.
|
|||
(ace-window arg)
|
||||
))
|
||||
#+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
|
||||
Transient/popup buffers — terminals, help, compilation, messages — are managed
|
||||
by popper, which tracks them as a group and lets you cycle or dismiss them
|
||||
|
|
@ -838,6 +911,8 @@ 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")
|
||||
"st" '(+vterm/toggle :which-key "Toggle vterm popup")
|
||||
"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
|
||||
"t" '(:ignore t :which-key "toggle")
|
||||
|
|
@ -853,17 +928,6 @@ I know these could be bound on a per-package basis, but since this is my primary
|
|||
"v" '(:ignore t :which-key "visual/appearance")
|
||||
"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
|
||||
|
||||
|
|
@ -874,10 +938,72 @@ I know these could be bound on a per-package basis, but since this is my primary
|
|||
deft-extensions '("org" "txt"))
|
||||
#+end_src
|
||||
* 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
|
||||
(use-package gptel)
|
||||
(setq gptl-default-mode 'org-mode)
|
||||
(use-package gptel
|
||||
:commands (gptel gptel-send gptel-menu)
|
||||
: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
|
||||
|
||||
** 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
|
||||
#+begin_src emacs-lisp
|
||||
(use-package org)
|
||||
|
|
@ -1455,6 +1581,14 @@ This is mostly lifted from the doom emacs config. Beancount-mode by default has
|
|||
;; kubernetes-tramp
|
||||
#+end_src
|
||||
* 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
|
||||
Uses the external fish program to provide fish-style completions to eshell etc
|
||||
#+begin_src emacs-lisp
|
||||
|
|
|
|||
1
link.sh
1
link.sh
|
|
@ -34,6 +34,7 @@ backup_and_link "$DOTFILES/config/kanata" "$HOME/.config/kanata"
|
|||
backup_and_link "$DOTFILES/config/nyxt" "$HOME/.config/nyxt"
|
||||
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/goose/.goosehints" "$HOME/.config/goose/.goosehints"
|
||||
|
||||
backup_and_link "$DOTFILES/config/rofi" "$HOME/.config/rofi"
|
||||
backup_and_link "$DOTFILES/config/zathura" "$HOME/.config/zathura"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue