about summary refs log tree commit diff
diff options
context:
space:
mode:
authorWilliam Carroll <wpcarro@gmail.com>2020-01-09T13·41+0000
committerWilliam Carroll <wpcarro@gmail.com>2020-01-17T10·56+0000
commitb52d210b9bc70e1f5e4a7bc8077db50e8bea4cd5 (patch)
treed18da1ef49efff0cf5016211fcef45a1024545da
parentef881e059bc5573ceceb40fe757940dd1fc83733 (diff)
Support cycle/previous-focus
Define a `cycle/previous-focus` function that returns the item that was
previously "focused" in the cycle. This is helpful for toggling back-and-forth
between buffers and EXWM workspaces for example without needing to define ad-hoc
variables to support it.

Also: Adds tests to cycle.el.

Also: Prefers `struct/set!` instead of `setf`. See the previous commit's message
for more information about that preference.
-rw-r--r--configs/shared/.emacs.d/wpc/cycle.el76
1 files changed, 56 insertions, 20 deletions
diff --git a/configs/shared/.emacs.d/wpc/cycle.el b/configs/shared/.emacs.d/wpc/cycle.el
index 894626383049..d469ee34c705 100644
--- a/configs/shared/.emacs.d/wpc/cycle.el
+++ b/configs/shared/.emacs.d/wpc/cycle.el
@@ -7,8 +7,13 @@
 
 ;;; Code:
 
-(require 'struct)
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Dependencies
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(require 'prelude)
 (require 'math)
+(require 'maybe)
 
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;; Wish list
@@ -24,16 +29,21 @@
 
 ;; `current-index' tracks the current index
 ;; `xs' is the original list
-(cl-defstruct cycle current-index xs)
+(cl-defstruct cycle current-index previous-index xs)
+
+(defconst cycle/enable-tests? t
+  "When t, run the tests defined herein.")
 
 (defun cycle/new (&rest xs)
   "Create an empty cycle."
   (make-cycle :current-index 0
+              :previous-index nil
               :xs xs))
 
 (defun cycle/from-list (xs)
   "Create a cycle from a list of `XS'."
   (make-cycle :current-index 0
+              :previous-index nil
               :xs xs))
 
 (defun cycle/to-list (xs)
@@ -58,19 +68,28 @@
       lo
     (+ 1 x)))
 
-(defun cycle/prev (cycle)
-  "Return the previous value in `CYCLE' and update `current-index'."
-  (let* ((current-index (cycle-current-index cycle))
-         (next-index (next-index<- 0 (cycle/count cycle) current-index)))
-    (setf (cycle-current-index cycle) next-index)
-    (nth next-index (cycle-xs cycle))))
-
-(defun cycle/next (cycle)
-  "Return the next value in `CYCLE' and update `current-index'."
-  (let* ((current-index (cycle-current-index cycle))
-         (next-index (next-index-> 0 (cycle/count cycle) current-index)))
-    (setf (cycle-current-index cycle) next-index)
-    (nth next-index (cycle-xs cycle))))
+(defun cycle/previous-focus (cycle)
+  "Return the previously focused entry in CYCLE."
+  (let ((i (cycle-previous-index cycle)))
+    (if (maybe/some? i)
+        (nth i (cycle-xs cycle))
+      nil)))
+
+(defun cycle/next (xs)
+  "Return the next value in `XS' and update `current-index'."
+  (let* ((current-index (cycle-current-index xs))
+         (next-index (next-index-> 0 (cycle/count xs) current-index)))
+    (struct/set! cycle previous-index current-index xs)
+    (struct/set! cycle current-index next-index xs)
+    (nth next-index (cycle-xs xs))))
+
+(defun cycle/prev (xs)
+  "Return the previous value in `XS' and update `current-index'."
+  (let* ((current-index (cycle-current-index xs))
+         (next-index (next-index<- 0 (cycle/count xs) current-index)))
+    (struct/set! cycle previous-index current-index xs)
+    (struct/set! cycle current-index next-index xs)
+    (nth next-index (cycle-xs xs))))
 
 (defun cycle/current (cycle)
   "Return the current value in `CYCLE'."
@@ -80,11 +99,13 @@
   "Return the length of `xs' in `CYCLE'."
   (length (cycle-xs cycle)))
 
-(defun cycle/jump (i cycle)
-  "Jump to the I index of CYCLE."
-  (setf (cycle-current-index cycle)
-        (math/mod i (cycle/count cycle)))
-  cycle)
+(defun cycle/jump (i xs)
+  "Jump to the I index of XS."
+  (let ((current-index (cycle-current-index xs))
+        (next-index (math/mod i (cycle/count xs))))
+    (struct/set! cycle previous-index current-index xs)
+    (struct/set! cycle current-index next-index xs))
+  xs)
 
 (defun cycle/focus (p cycle)
   "Focus the element in CYCLE for which predicate, P, is t."
@@ -101,5 +122,20 @@
        cycle-xs
        (list/contains? x)))
 
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Tests
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(when cycle/enable-tests?
+  (let ((xs (cycle/new 1 2 3)))
+    (prelude/assert (maybe/nil? (cycle/previous-focus xs)))
+    (prelude/assert (= 1 (cycle/current xs)))
+    (prelude/assert (= 2 (cycle/next xs)))
+    (prelude/assert (= 1 (cycle/previous-focus xs)))
+    (prelude/assert (= 1 (->> xs (cycle/jump 0) cycle/current)))
+    (prelude/assert (= 2 (->> xs (cycle/jump 1) cycle/current)))
+    (prelude/assert (= 3 (->> xs (cycle/jump 2) cycle/current)))
+    (prelude/assert (= 2 (cycle/previous-focus xs)))))
+
 (provide 'cycle)
 ;;; cycle.el ends here