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.
|
# 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
|
||||||
|
|
|
||||||
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"
|
export PATH="$PATH:/home/green/.lmstudio/bin"
|
||||||
# End of LM Studio CLI section
|
# End of LM Studio CLI section
|
||||||
|
|
||||||
|
. "/home/green/.deno/env"
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,8 @@
|
||||||
(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)
|
||||||
|
|
||||||
|
|
@ -47,12 +49,20 @@
|
||||||
(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
|
||||||
(define-frame-preference "Default"
|
;; "Default" is the initial group name before grename runs at the bottom.
|
||||||
(0 t nil :class "Konqueror" :role "...konqueror-mainwindow")
|
;; These float rules must use "Default" — StumpWM evaluates frame preferences
|
||||||
(1 t nil :class "XTerm")
|
;; at window-open time against the group name, and the first group starts as
|
||||||
(:float t t :class "alsamixer-scratch")
|
;; "Default" until grename changes it at startup (but the rule is registered
|
||||||
(:float t t :class "ncmpcpp-scratch"))
|
;; 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"
|
(define-frame-preference "scratch-emacs-1"
|
||||||
(0 t t :title "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)))
|
(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 (focus-window win)))))
|
(t
|
||||||
|
(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."
|
||||||
|
|
@ -270,11 +312,124 @@ 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"))
|
(spawn-or-focus "ncmpcpp-scratch" "wezterm start --class ncmpcpp-scratch -- ncmpcpp" :persistent t))
|
||||||
;;; Config keymap
|
;;; 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))
|
(defvar *config-map* (make-sparse-keymap))
|
||||||
(define-key *config-map* (kbd "a") "alsamixer-float")
|
|
||||||
(defvar *brightness-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 "b") *brightness-map*)
|
||||||
|
|
||||||
|
;;; 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")
|
||||||
|
|
@ -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 "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*)
|
|
||||||
|
|
||||||
;;; Keymaps
|
;;; Gaps map bindings
|
||||||
|
|
||||||
(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")
|
||||||
|
|
||||||
(defvar *window-map* (make-sparse-keymap))
|
;;; Window map bindings
|
||||||
(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*)
|
||||||
|
|
||||||
(defvar *media-map* (make-sparse-keymap))
|
;;; Media map bindings
|
||||||
(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")
|
||||||
|
|
@ -308,10 +462,23 @@ 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")
|
||||||
(define-key *top-map* (kbd "s-h") "move-focus left")
|
(defun emacs-window-p (win)
|
||||||
(define-key *top-map* (kbd "s-j") "move-focus down")
|
(and win (string= (window-class win) "Emacs")))
|
||||||
(define-key *top-map* (kbd "s-k") "move-focus up")
|
|
||||||
(define-key *top-map* (kbd "s-l") "move-focus right")
|
(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-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")
|
||||||
|
|
@ -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-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")
|
||||||
|
|
@ -344,7 +507,15 @@ 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))
|
||||||
(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))
|
(find-if (lambda (w) (string= (window-class w) window-class))
|
||||||
(screen-windows screen)))
|
(screen-windows screen)))
|
||||||
(when window-title
|
(when window-title
|
||||||
|
|
|
||||||
|
|
@ -11,4 +11,7 @@ pipewire &
|
||||||
pipewire-pulse &
|
pipewire-pulse &
|
||||||
wireplumber &
|
wireplumber &
|
||||||
|
|
||||||
|
# Compositor - eliminates screen tearing
|
||||||
|
# picom --backend glx &
|
||||||
|
|
||||||
exec stumpwm
|
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")))
|
;; (setenv "PATH" (concat "/opt/homebrew/bin:" (getenv "PATH")))
|
||||||
#+end_src
|
#+end_src
|
||||||
** Straight
|
** 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
|
#+begin_src emacs-lisp
|
||||||
(defvar bootstrap-version)
|
(defvar bootstrap-version)
|
||||||
(let ((bootstrap-file
|
(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
|
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)
|
||||||
|
|
@ -311,6 +312,39 @@ 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
|
||||||
|
|
@ -428,6 +462,45 @@ 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
|
||||||
|
|
@ -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")
|
"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")
|
||||||
|
|
@ -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")
|
"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
|
||||||
|
|
||||||
|
|
@ -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"))
|
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
|
||||||
(setq gptl-default-mode 'org-mode)
|
: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
|
#+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)
|
||||||
|
|
@ -1455,6 +1581,14 @@ 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
|
||||||
|
|
|
||||||
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/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"
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue