                          (throw (str "no matching open delimiter for " ch))))
     :else stack))
 
-(defmethod push-char* ";"
-  [stack [x-pos ch]]
-  (cond
-    (in-escape? stack) (pop stack)
+(defmethod push-char ";"
+  [stack [x-pos ch]]
+  (cond
+    (escaping? stack) (pop stack)
     (in-code? stack) (conj stack [x-pos ch])
     :else stack))
 
-(defmethod push-char* "\n"
-  [stack [x-pos ch]]
-  (let [s0 (cond-> stack (in-escape? stack) pop)
+(defmethod push-char "\n"
+  [stack [x-pos ch]]
+  (let [s0 (cond-> stack (escaping? stack) pop)
         s1 (cond-> s0 (in-comment? s0) pop)]
     s1))
 
-(defmethod push-char* "\\"
-  [stack [x-pos ch]]
-  (cond
-    (in-escape? stack) (pop stack)
+(defmethod push-char "\\"
+  [stack [x-pos ch]]
+  (cond
+    (escaping? stack) (pop stack)
     :else (conj stack [x-pos ch])))
 
-(defmethod push-char* "\""
-  [stack [x-pos ch]]
-  (cond
-    (in-escape? stack) (pop stack)
+(defmethod push-char "\""
+  [stack [x-pos ch]]
+  (cond
+    (escaping? stack) (pop stack)
     (in-str? stack) (pop stack)
     :else (conj stack [x-pos ch])))
 
-(defmethod push-char* :default
-  [stack [x-pos ch]]
-  (cond
-    (in-escape? stack) (pop stack)
-    :else stack))
+(defmethod push-char :default
+  [stack [x-pos ch]]
+  (cond
+    (escaping? stack) (pop stack)
+    :else stack))
+
+;;------------------------------------------------------------------------
+;; Closing Delimiter inferencing
+;;------------------------------------------------------------------------
+
+;; Utilities
 
 (defn whitespace? [ch]
   (re-find #"[\s,]" ch))


(defonce app-state (atom {:text ""}))

(defn remove-trailing-closers
  [line]
  (string/replace line #"[\]})]+\s*$" ""))

;;------------------------------------------------------------------------
;; Simple clojure delimiter parsing
;;------------------------------------------------------------------------

(def matching-delim

        result (cond-> result insert (assoc :insert insert))]
    result))

(defn process-line
  "Update the given result by processing the given line of text."
  ([line] (process-line empty-result line))
  ([{:keys [stack lines line-no] :as result} line]
   (let [result (assoc result
                  :track-indent? (and (seq stack) (not (in-str? stack)))
                  :lines (conj lines line)
                  :line-no (inc line-no))
         result (reduce process-char result (map-indexed vector (str line "\n")))]
     result)))

(defn process-text
  "Update the given result by processing the given text."
  ([text] (process-text empty-result text))
  ([result text]
   (let [result (reduce process-line result (split-lines text))
         result (cond-> result (seq (:stack result)) close-delims)]
     result)))

;;------------------------------------------------------------------------
;; Editor
;;------------------------------------------------------------------------

;; EVENTS: TODO:
;; when editing current line, prevent invalid closers
;; when leaving current line, remove trailing closers
;; when edited, updated paren overlay

(defn remove-trailing-closers
  [line]
  (string/replace line #"[\]})]+\s*$" ""))

;; VIEW

(defn update-text!
  [cursor-index text]
  (try
    (let [{:keys [stack lines]} (process-text text)]
      (swap! app-state assoc :stack stack)
      (swap! app-state assoc :text text)
      (swap! app-state assoc :full-text (join "\n" lines)))
