 
 (defn process-char
   "Update the given result by processing the given character and its position."
-  [{:keys [stack line-no track-indent?] :as result} [x-pos ch]]
+  [{:keys [stack line-no track-indent? cursor-x cursor-line] :as result} [x-pos ch]]
 
   (let [result (process-delim-trail result [x-pos ch])
         backup (:backup result)

      (html
        [:div
         [:textarea
          {:on-change (fn [evt]
                        (let [target (.-target evt)]
                          (update-text! (.-selectionStart target) (.-value target))))}]
         [:pre.computed (:full-text data)]]))))

;; hack to initialize the state on first load (not when reloading)

(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 cursor-line] :as result} line]
   (let [line-no (inc line-no)
         result (assoc result
                  :backup []
                  :delim-trail {:start nil :end nil}
                  :track-indent? (and (seq stack) (not (in-str? stack)))
                  :lines (conj lines "")
                  :line-no line-no)
         result (reduce pre-process-char result (str line "\n"))
         result (cond-> result
                  (not= line-no cursor-line) remove-delim-trail)
         ]
     result)))

(defn process-text
  "Update the given result by processing the given text."
  [result text & {:keys [cursor-line cursor-x]}]
  (let [result (assoc result
                      :cursor-line cursor-line
                      :cursor-x cursor-x)
        result (reduce process-line result (split-lines text))
        result (cond-> result (seq (:stack result)) close-delims)]
    result))

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

(defn update-text!
  [cursor-index text]
  (let [lines (split-lines (subs text 0 cursor-index))
        cursor-x (count (last lines))
        cursor-line (dec (count lines))
        {:keys [stack lines]} (process-text empty-result text
                                :cursor-line cursor-line
                                :cursor-x cursor-x)]
    (swap! app-state assoc :stack stack)
    (swap! app-state assoc :text text)
    (swap! app-state assoc :full-text (join "\n" lines))))

(defn trigger-change!
  "should be called when text or cursor position changes."
  [evt]
  (let [target (.-target evt)]
    (update-text! (.-selectionStart target) (.-value target))))

(defn root-comp
  [data owner]
