feat: add cycling for all buffers

This commit is contained in:
Pavel Korytov 2023-02-18 16:46:47 +03:00
parent 7d5f0922a3
commit 7b0a70b449

View file

@ -36,6 +36,8 @@
;; Other useful functions are: ;; Other useful functions are:
;; - `perspective-exwm-cycle-exwm-buffers-backward' and ;; - `perspective-exwm-cycle-exwm-buffers-backward' and
;; `perspective-exwm-cycle-exwm-buffers-backward' ;; `perspective-exwm-cycle-exwm-buffers-backward'
;; - `perspective-exwm-cycle-all-buffers-backward' and
;; `perspective-exwm-cycle-all-buffers-forward'
;; - `perspective-exwm-switch-perspective' ;; - `perspective-exwm-switch-perspective'
;; - `perspective-exwm-copy-to-workspace' and ;; - `perspective-exwm-copy-to-workspace' and
;; `perspective-exwm-move-to-workspace' ;; `perspective-exwm-move-to-workspace'
@ -62,8 +64,8 @@
"A function to return the current EXWM window title." "A function to return the current EXWM window title."
exwm-title) exwm-title)
(defcustom perspective-exwm-get-exwm-buffer-name #'perspective-exwm--get-class (defcustom perspective-exwm-get-buffer-name #'perspective-exwm--get-class
"A function to get the EXWM buffer title. "Retrieve buffer name for the cycle commands.
Meant to be ran in the context of the target buffer, e.g. with Meant to be ran in the context of the target buffer, e.g. with
`with-current-buffer'. `with-current-buffer'.
@ -75,6 +77,12 @@ The two default options are:
:type 'function :type 'function
:options '(perspective-exwm--get-class perspective-exwm--get-title)) :options '(perspective-exwm--get-class perspective-exwm--get-title))
(defcustom perspective-exwm-cycle-max-message-length
(- (frame-width) 10)
"Maximum length of the message displayed by the cycle commands."
:group 'perspective-exwm
:type 'integer)
(defcustom perspective-exwm-override-initial-name nil (defcustom perspective-exwm-override-initial-name nil
"Set initial perspective name for a particular EXWM workspace." "Set initial perspective name for a particular EXWM workspace."
:group 'perspective-exwm :group 'perspective-exwm
@ -105,13 +113,84 @@ Used in `perspective-exwm-switch-perspective'."
Used in `perspective-exwm-switch-perspective'." Used in `perspective-exwm-switch-perspective'."
:group 'perspective-exwm) :group 'perspective-exwm)
(defun perspective-exwm--cycle-exwm-buffers (dir) (defun perspective-exwm--cycle-get-message (all-buffers cycle-buffers)
"Cycle EXWM buffers in the current perspective. "Return the display message for the buffer cycling commands.
ALL-BUFFERS is the list of all buffers in the current perspective.
CYCLE-BUFFERS are the buffers to cycle through."
;; Iterate over all buffers
(cl-loop with seen-current = nil
for buf in all-buffers
for name = (with-current-buffer buf
(or (funcall perspective-exwm-get-buffer-name)
(buffer-name)))
for is-current = (eq (current-buffer) buf)
for is-skip = (not (member buf cycle-buffers))
if is-current do (setq seen-current t)
if is-current
collect (concat "[" (propertize name 'face 'perspective-exwm-cycle-current-face) "] ") into current-list
else if is-skip
collect (concat "[" (propertize name 'face 'perspective-exwm-cycle-skip-face) "] ") into skip-list
else if seen-current
collect (format " %s " name) into after-list
else
collect (format " %s " name) into before-list
;; 4 list:
;; - current-list - current buffers
;; - skip-list - buffers displayed in other windows
;; - before-list - buffers before current
;; - after-list - buffers after current
;; We want to display them in the following order:
;; skip-list before-list current-list after-list
;; And trim before-list and after-list to fit the message
;; length; that means trimming the end of before-list and
;; the beginning of after-list.
finally return
(let* ((skip-msg (mapconcat #'identity skip-list ""))
(current-msg (mapconcat #'identity current-list ""))
(len (+ (length skip-msg) (length current-msg) 8))
(before-stack (reverse before-list))
(after-stack after-list))
;; Length of nil is 0 :'(
(cl-loop for before-elem-len = (if before-stack (length (car before-stack)) 10000)
for after-elem-len = (if after-stack (length (car after-stack)) 10000)
while (and (or before-stack after-stack)
(< (+ len (min before-elem-len after-elem-len)) perspective-exwm-cycle-max-message-length))
for before = (when (and before-stack
(< (+ len before-elem-len) perspective-exwm-cycle-max-message-length))
(pop before-stack))
if before collect before into before-msg-list
if before do (setq len (+ len before-elem-len))
for after = (when (and after-stack
(< (+ len after-elem-len) perspective-exwm-cycle-max-message-length))
(pop after-stack))
if after concat after into after-msg
if after do (setq len (+ len after-elem-len))
finally return
(concat
skip-msg
(when before-stack
(format " (%s) "
(propertize (number-to-string (length before-stack))
'face 'perspective-exwm-cycle-skip-face)))
(mapconcat #'identity (reverse before-msg-list) "")
current-msg
after-msg
(when after-stack
(format " (%s) "
(propertize (number-to-string (length after-stack))
'face 'perspective-exwm-cycle-skip-face))))))))
(defun perspective-exwm--cycle-exwm-buffers (dir &optional all)
"Cycle buffers in the current perspective.
DIR is either 'forward or 'backward. A buffer is skipped if it is DIR is either 'forward or 'backward. A buffer is skipped if it is
already displayed in some other window of the current already displayed in some other window of the current
perspective. The buffer name comes from perspective. The buffer name comes from
`perspective-exwm-get-exwm-buffer-name'. `perspective-exwm-get-buffer-name'.
If ALL is nil, then cycle only EXWM buffers. Otherwise, cycle
all.
The function prints out the state to the messages. The current The function prints out the state to the messages. The current
buffer after the switch is highlighted with `warning', skipped buffer after the switch is highlighted with `warning', skipped
@ -122,7 +201,7 @@ buffer is highlighted with `persp-selected-face'"
(cl-loop for buf in (persp-current-buffers) (cl-loop for buf in (persp-current-buffers)
for is-another = (and (get-buffer-window buf) (not (eq current buf))) for is-another = (and (get-buffer-window buf) (not (eq current buf)))
if (and (buffer-live-p buf) if (and (buffer-live-p buf)
(eq 'exwm-mode (buffer-local-value 'major-mode buf)) (or all (eq 'exwm-mode (buffer-local-value 'major-mode buf)))
(not (string-match-p ignore-rx (buffer-name buf)))) (not (string-match-p ignore-rx (buffer-name buf))))
collect buf into all-buffers collect buf into all-buffers
and if (not is-another) collect buf into cycle-buffers and if (not is-another) collect buf into cycle-buffers
@ -137,19 +216,8 @@ buffer is highlighted with `persp-selected-face'"
(length cycle-buffers))) (length cycle-buffers)))
(next-buffer (nth next-pos cycle-buffers))) (next-buffer (nth next-pos cycle-buffers)))
(switch-to-buffer next-buffer) (switch-to-buffer next-buffer)
(message (let ((msg (perspective-exwm--cycle-get-message all-buffers cycle-buffers)))
"%s" (message msg))))))
(cl-loop for buf in all-buffers
for name = (with-current-buffer buf (funcall perspective-exwm-get-exwm-buffer-name))
for is-current = (eq (current-buffer) buf)
for is-skip = (not (member buf cycle-buffers))
if is-current
concat (concat "[" (propertize name 'face 'perspective-exwm-cycle-current-face) "] ") into res
else if is-skip
concat (concat "[" (propertize name 'face 'perspective-exwm-cycle-skip-face) "] ") into res
else
concat (format " %s " name) into res
finally return res))))))
;;;###autoload ;;;###autoload
(defun perspective-exwm-cycle-exwm-buffers-forward () (defun perspective-exwm-cycle-exwm-buffers-forward ()
@ -169,6 +237,18 @@ detail."
(interactive) (interactive)
(perspective-exwm--cycle-exwm-buffers 'backward)) (perspective-exwm--cycle-exwm-buffers 'backward))
;;;###autoload
(defun perspective-exwm-cycle-all-buffers-forward ()
"Cycle all buffers in the current perspective forward."
(interactive)
(perspective-exwm--cycle-exwm-buffers 'forward t))
;;;###autoload
(defun perspective-exwm-cycle-all-buffers-backward ()
"Cycle all buffers in the current perspective backward."
(interactive)
(perspective-exwm--cycle-exwm-buffers 'backward t))
;;;###autoload ;;;###autoload
(defun perspective-exwm-switch-perspective () (defun perspective-exwm-switch-perspective ()
"Switch to a perspective on any workspace." "Switch to a perspective on any workspace."