feat(tazjin/emacs): implement MRU navigation for exwm workspaces

this makes it possible to move forwards/backwards in workspace history
in the order in which I used them, while tracking the offset (e.g. it
is possible to go 3 steps back, do something, then move 2 steps
forward again).

this should make it possible to learn ad-hoc relative layouts for
whatever task i'm working on and reduce the number of times where i
frantically flip through all workspaces and try to figure out where
anything is.

note that this key binding is not very ergonomic, but i've remapped it
on my kinesis to the prior/next buttons. i never use those. using
<prior>/<next> directly doesn't work because too many modes override
them.

Change-Id: I257723b9e14a68b53be68539dd752db3445546e7
Reviewed-on: https://cl.tvl.fyi/c/depot/+/5243
Tested-by: BuildkiteCI
Reviewed-by: tazjin <tazjin@tvl.su>
This commit is contained in:
Vincent Ambo 2022-02-07 21:27:50 +03:00 committed by tazjin
parent 50d959175d
commit e00dd88b66

View file

@ -140,6 +140,68 @@
(interactive) (interactive)
(exwm-workspace-switch-create ,i)))) (exwm-workspace-switch-create ,i))))
;; Implement MRU functionality for EXWM workspaces, making it possible
;; to jump to the previous/next workspace very easily.
(defvar *recent-workspaces* nil
"List of the most recently used EXWM workspaces.")
(defvar *workspace-jumping-to* nil
"What offset in the workspace history are we jumping to?")
(defvar *workspace-history-position* 0
"Where in the workspace history are we right now?")
(defun update-recent-workspaces ()
"Hook to run on every workspace switch which will prepend the new
workspace to the MRU list, unless we are already on that
workspace. Does not affect the MRU list if a jump is
in-progress."
(if *workspace-jumping-to*
(setq *workspace-history-position* *workspace-jumping-to*
*workspace-jumping-to* nil)
;; reset the history position to the front on a normal jump
(setq *workspace-history-position* 0)
(unless (eq exwm-workspace-current-index (car *recent-workspaces*))
(setq *recent-workspaces* (cons exwm-workspace-current-index
(-take 9 *recent-workspaces*))))))
(add-to-list 'exwm-workspace-switch-hook #'update-recent-workspaces)
(defun switch-to-previous-workspace ()
"Switch to the previous workspace in the MRU workspace list."
(interactive)
(let* (;; the previous workspace is one position further down in the
;; workspace history
(position (+ *workspace-history-position* 1))
(target-idx (elt *recent-workspaces* position)))
(if (not target-idx)
(message "No previous workspace in history!")
(setq *workspace-jumping-to* position)
(exwm-workspace-switch target-idx))))
(exwm-input-set-key (kbd "s-b") #'switch-to-previous-workspace)
(defun switch-to-next-workspace ()
"Switch to the next workspace in the MRU workspace list."
(interactive)
(if (<= *workspace-history-position* 1)
(message "No next workspace in history!")
(let* (;; The next workspace is one position further up in the
;; history. This always exists unless someone messed with
;; it.
(position (- *workspace-history-position* 1))
(target-idx (elt *recent-workspaces* position)))
(setq *workspace-jumping-to* position)
(exwm-workspace-switch target-idx))))
(exwm-input-set-key (kbd "s-f") #'switch-to-next-workspace)
;; Launch applications / any command with completion (dmenu style!) ;; Launch applications / any command with completion (dmenu style!)
(exwm-input-set-key (kbd "s-d") #'counsel-linux-app) (exwm-input-set-key (kbd "s-d") #'counsel-linux-app)
(exwm-input-set-key (kbd "s-x") #'run-external-command) (exwm-input-set-key (kbd "s-x") #'run-external-command)