Browse code

Merge pull request #48 from jbweston/feat/cmdline-history-select

Cycle command-line history

Closes #43.

Joseph Weston authored on 11/12/2021 20:50:56 • GitHub committed on 11/12/2021 20:50:56
Showing 3 changed files
... ...
@@ -43,6 +43,7 @@
43 43
 (def default-db
44 44
   {:name "DMR"
45 45
    :cmdline {:current ""
46
+             :selected-history nil
46 47
              :history []}
47 48
    :spells spells
48 49
    :equipment equipment
... ...
@@ -40,6 +40,44 @@
40 40
  (fn [_ [_ x]]
41 41
      {:window/scroll-to x}))
42 42
 
43
+(defn- cycle-history [cs direction]
44
+  (let [history (-> cs :history)
45
+        current (-> cs :current)
46
+        orig (some-> cs :selected-history :orig)
47
+        idx (some-> cs :selected-history :index)
48
+        history-end (- (count history) 1)
49
+        historical-input #(-> history (get %) :input)
50
+        next (case direction :backward dec :forward inc)
51
+        at-first? (= idx history-end)
52
+        at-last?  (= idx 0)
53
+        going-forward? (= direction :forward)
54
+        going-backward? (= direction :backward)
55
+        not-cycling? (-> cs :selected-history nil?)]
56
+    (cond
57
+      (empty? history)                   {:current current :selected-history nil}
58
+      (and at-first? going-forward?)     {:current orig :selected-history nil}
59
+      (and at-last? going-backward?)     {} ; do nothing
60
+      (and not-cycling? going-forward?)  {} ; do nothing
61
+      (and not-cycling? going-backward?) {:current (historical-input history-end)
62
+                                          :selected-history {:orig current
63
+                                                             :index history-end}}
64
+      :else                              {:current (historical-input (next idx))
65
+                                          :selected-history {:orig orig
66
+                                                             :index (next idx)}})))
67
+
68
+(re-frame/reg-event-db
69
+ ::prompt-keypress
70
+ (re-frame/path :cmdline)
71
+ (fn [cmd [_ event]]
72
+   (let [direction (case (.-key event)
73
+                     "ArrowUp"   :backward
74
+                     "ArrowDown" :forward
75
+                     nil)]
76
+     (if direction
77
+       (do (.preventDefault event)
78
+           (merge cmd (cycle-history cmd direction)))
79
+       cmd))))
80
+
43 81
 (re-frame/reg-event-fx
44 82
  ::submit-cmd
45 83
  (fn [cofx [_ prompt]]
... ...
@@ -51,9 +89,12 @@
51 89
      ; don't always have to prefix with a conditional
52 90
      (cond-> db
53 91
       true (update-in [:cmdline :current] (constantly nil))
92
+      true (update-in [:cmdline :selected-history] (constantly nil))
54 93
       (not-empty? cmdline)
55 94
       (as-> db
56 95
         (let [output (execute db cmdline)]
57 96
             (update-in db [:cmdline :history] conj
58 97
                 {:input cmdline :output output}))))
59
-     :fx [[:dispatch [::scroll-to prompt]]]})))
98
+     ; dispatch-later to ensure that the DOM has already been updated,
99
+     ; so that scrollMaxY has been changed appropriately.
100
+     :fx [[:dispatch-later {:ms 10 :dispatch [::scroll-to prompt]}]]})))
... ...
@@ -12,12 +12,14 @@
12 12
   (let [cmdline (re-frame/subscribe [::subs/cmdline])
13 13
         update-cmdline #(re-frame/dispatch-sync
14 14
                          [::events/update-cmdline (-> % .-target .-value)])
15
+        key-pressed #(re-frame/dispatch-sync [::events/prompt-keypress %])
15 16
         submit-cmd #(do (.preventDefault %)
16 17
                         (re-frame/dispatch [::events/submit-cmd (-> % .-target)]))]
17 18
     [:form {:class (styles/prompt-style)
18 19
             :on-submit submit-cmd}
19 20
      [:input {:value @cmdline
20 21
               :on-change update-cmdline
22
+              :on-keyDown key-pressed
21 23
               :type "text"}]]))
22 24
 
23 25
 (defn title []