 (defn recognize? [letters]
   (let [last-word (str/join (reverse (take-while #(not= " " %) letters)))]
     (contains? valid-words last-word)))
+
+(defonce valid-commands #{"clear"})
+
+(defmulti dispatch-enter
+  (fn [cursor]
+    (let [letters (get-in cursor [:active :letters])
+          command (str/join (take-while #(not= " " %) (reverse letters)))]
+      (if (contains? valid-commands command)
+        command
+        :default))))
+
+(defmethod dispatch-enter :default
+  [cursor]
+  (as-> cursor c
+    (assoc c :history (cons (:active c) (:history c)))
+    (assoc c :active {:state [:empty] :letters []})))
+
+(defmethod dispatch-enter "clear"
+  [cursor]
+  (as-> cursor c
+    (assoc c :history [])
+    (assoc c :active {:state [:empty] :letters []})))49
 
 (defn handle-keydown [owner e]
   (let [key (.-key e)]

        (apply dom/div #js {:style #js {:fontSize "30px"
                                        :lineHeight "40px"
                                        :padding "15px 15px 0 15px"}}
               (if (:focus state)
                 (concat rendered-words (if space [(dom/span nil " ") cur] [cur]))
                 rendered-words))))))

(defn app-view [cursor owner]
  (reify

    om/IRenderState
    (render-state [_ state]
      (let [words (str/split (str/join (reverse (:letters cursor))) " ")
            spacing (contains? #{:typing-space :mashing-space} (first (:state cursor)))
            commanding (contains? valid-commands (first words))
            cursor-char (dom/span #js {:style #js {:color "#900"}} "\u2588")
            rendered-words (interpose
                            (dom/span nil " ")
                            (map #(if (contains? valid-words %)
