         result (cond-> result insert (assoc :insert insert))]
     result))
 
-;; main parsers
-
-(def empty-result
-  {:lines []
-   :line-no -1
-   :track-indent? false
-   :insert {:line nil :col nil}
-   :stack []})
-
-(defn parse-line
-  ([line] (parse-line empty-result line))
+(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 push-char result (map-indexed vector (str line "\n")))]
+         result (reduce process-char result (map-indexed vector (str line "\n")))]
      result)))
 
-(defn parse-text
-  ([text] (parse-text empty-result text))
+(defn process-text
+  "Update the given result by processing the given text."
+  ([text] (process-text empty-result text))
   ([result text]
-   (let [result (reduce parse-line result (split-lines text))
+   (let [result (reduce process-line result (split-lines text))
          result (cond-> result (seq (:stack result)) close-delims)]
      result)))
 
-;; EVENTS
+;;------------------------------------------------------------------------
+;; 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]} (parse-text text)]
+    (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)))

        result (cond-> result should-close? (close-delims x-pos))

        ;; Update the delimiter stack with this character.
        result (update-in result [:stack] push-char* [x-pos ch])
        stack (:stack result)

        ;; Add potential insert point for closing delimiters if required.


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

;;------------------------------------------------------------------------
;; Simple clojure delimiter parsing
;;
;; It handles:
;;  - multi-line strings
;;  - comments
;;  - escaped characters
;;------------------------------------------------------------------------

(def matching-delim
