about summary refs log tree commit diff
path: root/emacs/.emacs.d/wpc/cycle.el
diff options
context:
space:
mode:
authorWilliam Carroll <wpcarro@gmail.com>2020-02-08T15·57+0000
committerWilliam Carroll <wpcarro@gmail.com>2020-02-10T10·06+0000
commit8584059e7cd72656b3e90785c25d2fbb5b350229 (patch)
tree4a017225a2a197220abdabe29bc81513f3b1ccee /emacs/.emacs.d/wpc/cycle.el
parentf145bc9eb6f1bc51fd70a3df02c978b3333fa012 (diff)
Support cycle/{append,remove}
Supporting these functions was a little tricky. For example, how should we
handle calling cycle/remove on the item that is currently focused? After
attempting to be clever, I decided to just set the value to nil and let the
consumer decide what is best for them. I can always support a more opinionated
version that fallsback to previous-index if previous-index is set. But until I
have a better idea of how I'm going to consume this, I think nil is the best
option.
Diffstat (limited to 'emacs/.emacs.d/wpc/cycle.el')
-rw-r--r--emacs/.emacs.d/wpc/cycle.el50
1 files changed, 49 insertions, 1 deletions
diff --git a/emacs/.emacs.d/wpc/cycle.el b/emacs/.emacs.d/wpc/cycle.el
index f876cf7054..9ec6ecd2fb 100644
--- a/emacs/.emacs.d/wpc/cycle.el
+++ b/emacs/.emacs.d/wpc/cycle.el
@@ -150,6 +150,46 @@ ITEM is the first item in XS that t for `equal'."
   "Return t if cycle XS has a non-nil value for current-index."
   (maybe/some? (cycle-current-index xs)))
 
+(defun cycle/append (x xs)
+  "Add X to the left of the focused element in XS.
+If there is no currently focused item, add X to the beginning of XS."
+  (if (cycle/empty? xs)
+      (progn
+        (struct/set! cycle xs (list x) xs)
+        (struct/set! cycle current-index 0 xs)
+        (struct/set! cycle previous-index nil xs))
+    (let ((curr-i (cycle-current-index xs))
+          (prev-i (cycle-previous-index xs)))
+      (if curr-i
+          (progn
+            (struct/set! cycle xs (-insert-at curr-i x (cycle-xs xs)) xs)
+            (when (>= prev-i curr-i) (struct/set! cycle previous-index (1+ prev-i) xs))
+            (when curr-i (struct/set! cycle current-index (1+ curr-i) xs)))
+        (progn
+          (struct/set! cycle xs (cons x (cycle-xs xs)) xs)
+          (when prev-i (struct/set! cycle previous-index (1+ prev-i) xs))))
+      xs)))
+
+(defun cycle/remove (x xs)
+  "Attempt to remove X from XS.
+
+X is found using `equal'.
+
+If X is the currently focused value, after it's deleted, current-index will be
+  nil.  If X is the previously value, after it's deleted, previous-index will be
+  nil."
+  (let ((curr-i (cycle-current-index xs))
+        (prev-i (cycle-previous-index xs))
+        (rm-i (-elem-index x (cycle-xs xs))))
+    (struct/set! cycle xs (-remove-at rm-i (cycle-xs xs)) xs)
+    (when prev-i
+      (when (> prev-i rm-i) (struct/set! cycle previous-index (1- prev-i) xs))
+      (when (= prev-i rm-i) (struct/set! cycle previous-index nil xs)))
+    (when curr-i
+      (when (> curr-i rm-i) (struct/set! cycle current-index (1- curr-i) xs))
+      (when (= curr-i rm-i) (struct/set! cycle current-index nil xs)))
+    xs))
+
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;; Tests
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@@ -164,7 +204,15 @@ ITEM is the first item in XS that t for `equal'."
     (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)))
-    (prelude/assert (= 2 (cycle/focus-previous! xs)))))
+    (prelude/assert (= 2 (cycle/focus-previous! xs)))
+    (prelude/assert (equal '(1 4 2 3) (cycle-xs (cycle/append 4 xs))))
+    (prelude/assert (equal '(1 2 3) (cycle-xs (cycle/remove 4 xs))))
+    (progn
+      (cycle/focus-item 3 xs)
+      (cycle/focus-item 2 xs)
+      (cycle/remove 1 xs)
+      (prelude/assert (= 2 (cycle/current xs)))
+      (prelude/assert (= 3 (cycle/previous-focus xs))))))
 
 (provide 'cycle)
 ;;; cycle.el ends here