Compare commits
No commits in common. "936e09ce31fcba7e87b0c942c5ee5a138a8e3add" and "a1dd786801320f43fea947d3c8cf51f033119b90" have entirely different histories.
936e09ce31
...
a1dd786801
10 changed files with 40 additions and 381 deletions
|
|
@ -1 +0,0 @@
|
||||||
source "/home/green/.deno/env.fish"
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
function k --wraps kubectl --description 'alias kubectl'
|
|
||||||
kubectl $argv
|
|
||||||
end
|
|
||||||
|
|
@ -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.
|
|
||||||
|
|
@ -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")
|
|
||||||
|
|
@ -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"
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
;;
|
(defvar *config-map* (make-sparse-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 *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
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,4 @@ 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 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
|
||||||
|
|
|
||||||
1
link.sh
1
link.sh
|
|
@ -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"
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue