refactor(tazjin/emacs): refactor LRU workspace list to use ring.el

This built-in emacs library actually provides a data structure that
can work as an LRU list through the existing helper function to move
an element to the front of the ring if it already exists.

As a result, the code for workspace history moving becomes a lot less
brittle and complicated than it was before. No more carefully figuring
out when to modify state, just push it in the ring unless it's being
rotated already.

Change-Id: If354e0618fc5a6d7333776468eec077596cfe9df
Reviewed-on: https://cl.tvl.fyi/c/depot/+/9162
Reviewed-by: tazjin <tazjin@tvl.su>
Tested-by: BuildkiteCI
This commit is contained in:
Vincent Ambo 2023-08-28 23:25:59 +03:00 committed by tazjin
parent 0a7a9e96ab
commit d6bce3f83d

View file

@ -11,6 +11,7 @@
(require 'exwm-systemtray) (require 'exwm-systemtray)
(require 'exwm-xim ) (require 'exwm-xim )
(require 'f) (require 'f)
(require 'ring)
(require 's) (require 's)
(defcustom tazjin--screen-lock-command "tazjin-screen-lock" (defcustom tazjin--screen-lock-command "tazjin-screen-lock"
@ -136,47 +137,31 @@
;; Implement MRU functionality for EXWM workspaces, making it possible ;; Implement MRU functionality for EXWM workspaces, making it possible
;; to jump to the previous/next workspace very easily. ;; to jump to the previous/next workspace very easily.
(defvar *recent-workspaces* nil (defvar *recent-workspaces-ring* (make-ring 5)
"List of the most recently used EXWM workspaces.") "Ring of recently used EXWM workspaces.")
(defvar *workspace-jumping-to* nil (defvar *workspace-ring-is-rotating* nil
"What offset in the workspace history are we jumping to?") "Variable used to track whether the workspace ring is rotating,
and suppress insertions into the ring in that case.")
(defvar *workspace-history-position* 0
"Where in the workspace history are we right now?")
(defun update-recent-workspaces () (defun update-recent-workspaces ()
"Hook to run on every workspace switch which will prepend the new "Hook run on EXWM workspace switches, adding new workspaces to the
workspace to the MRU list, unless we are already on that ring."
workspace. Does not affect the MRU list if a jump is
in-progress."
(if *workspace-jumping-to* (unless *workspace-ring-is-rotating*
(setq *workspace-history-position* *workspace-jumping-to* (ring-remove+insert+extend *recent-workspaces-ring* exwm-workspace-current-index)))
*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) (add-to-list 'exwm-workspace-switch-hook #'update-recent-workspaces)
(defun switch-to-previous-workspace () (defun switch-to-previous-workspace ()
"Switch to the previous workspace in the MRU workspace list." "Switch to the previous workspace in the workspace ring."
(interactive) (interactive)
(let* (;; the previous workspace is one position further down in the (when-let ((*workspace-ring-is-rotating* t)
;; workspace history (previous (condition-case err (ring-next *recent-workspaces-ring*
(position (+ *workspace-history-position* 1)) exwm-workspace-current-index)
(target-idx (elt *recent-workspaces* position))) ('error (message "No previous workspace in history!") nil))))
(if (not target-idx) (exwm-workspace-switch previous)))
(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) (exwm-input-set-key (kbd "s-b") #'switch-to-previous-workspace)
@ -184,15 +169,11 @@ in-progress."
"Switch to the next workspace in the MRU workspace list." "Switch to the next workspace in the MRU workspace list."
(interactive) (interactive)
(if (= *workspace-history-position* 0) (when-let ((*workspace-ring-is-rotating* t)
(message "No next workspace in history!") (next (condition-case err (ring-previous *recent-workspaces-ring*
(let* (;; The next workspace is one position further up in the exwm-workspace-current-index)
;; history. This always exists unless someone messed with ('error (message "No next workspace in history!") nil))))
;; it. (exwm-workspace-switch next)))
(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) (exwm-input-set-key (kbd "s-f") #'switch-to-next-workspace)