diff options
author | William Carroll <wpcarro@gmail.com> | 2020-02-08T15·57+0000 |
---|---|---|
committer | William Carroll <wpcarro@gmail.com> | 2020-02-10T10·06+0000 |
commit | 8584059e7cd72656b3e90785c25d2fbb5b350229 (patch) | |
tree | 4a017225a2a197220abdabe29bc81513f3b1ccee | |
parent | f145bc9eb6f1bc51fd70a3df02c978b3333fa012 (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.
-rw-r--r-- | emacs/.emacs.d/wpc/cycle.el | 50 |
1 files changed, 49 insertions, 1 deletions
diff --git a/emacs/.emacs.d/wpc/cycle.el b/emacs/.emacs.d/wpc/cycle.el index f876cf7054a4..9ec6ecd2fbc8 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 |