   (let [{:keys [repl console]} system
         {:keys [error etype result]} (eval-in-repl repl line)]
     (if error
-      (do (println-console console "ETYPE:" etype)
-          (println-console console "ERROR:" error))
-      (println-console console result))))
+      (do (cprintln console "ETYPE:" etype)
+          (cprintln console "ERROR:" error))
+      (cprintln console result))))
+
+(defn newline? [c] (= c 13))
+(defn escape?  [c] (= c 27))
+(defn percent? [c] (= c 37))
+
+(defn min-dec [x minimum]
+  (max (dec x) minimum))
+
+(defn max-inc [x maximum]
+  (min (inc x) maximum))
+
+(defn insert [vec pos item]
+  (print-err "vec" vec)
+  (print-err "pos" pos)
+  (print-err "item" item)
+  (apply conj (subvec vec 0 pos) item (subvec vec pos)))
+
+(defn insert-char [buffer [x y] c]
+  (update-in buffer [y] insert x (char c)))
+
+(defn inc-x [cursor] (update-in cursor [0] inc))
+(defn dec-x [cursor] (update-in cursor [0] min-dec 0))
+(defn inc-y [cursor] (update-in cursor [1] inc))
+(defn dec-y [cursor] (update-in cursor [1] min-dec 0))
+
+(defn set-x [cursor n] (assoc cursor 0 n))
+(defn set-y [cursor n] (assoc cursor 1 n))
+
+(defn start-buffer [console]
+  (let [reader (:reader console)]
+    (loop [buffer [[]]
+           cursor [0 0]
+           c (.readCharacter reader)]
+      (print-err "buffer" buffer)
+      (print-err "cursor" cursor)
+      (cprint console (char c))
+      (cond
+        (escape? c) (let [escape-seq [(.readCharacter reader) (.readCharacter reader)]]
+                      (cprint console (char (nth escape-seq 0)))
+                      (cprint console (char (nth escape-seq 1)))
+                      (condp = escape-seq
+                        [91 65] (recur buffer
+                                       (dec-y cursor)
+                                       (.readCharacter reader))
+                        [91 66] (recur buffer
+                                       (inc-y cursor)
+                                       (.readCharacter reader))
+                        [91 67] (recur buffer
+                                       (inc-x cursor)
+                                       (.readCharacter reader))
+                        [91 68] (recur buffer
+                                       (dec-x cursor)
+                                       (.readCharacter reader))))
+        (newline? c) (do (cprint console (char 27))
+                         (cprint console (char 91))
+                         (cprint console (char 83))
+                         (recur (conj buffer [])
+                            (-> cursor inc-y (set-x 0))
+                            (.readCharacter reader)))
+        (percent? c) (let [c (.readCharacter reader)]
+                       (if (= c 114)
+                         (clojure.string/join "\n" (map #(apply str %) buffer))
+                         (recur buffer cursor c)))
+        :else (recur (insert-char buffer cursor c)
+                     (update-in cursor [0] inc)
+                     (.readCharacter reader))))))
 
 (defmulti run-line (fn [system line] line))
 
 (defmethod run-line "%b" [system line]
-  (let [console (:console system)]
-    (loop [buffer [line]]
-      (print-err "buffer" buffer)
-      (if (= (last buffer) "%r")
-        (let [command (->> buffer
-                           drop-first-and-last
-                           (clojure.string/join "\n"))]
-          (remove-n-from-history console (count buffer))
-          (add-to-history console command)
-          (eval-and-print system command))
-        (recur (->> (read-console-line console)
-                    (conj buffer)))))))
+  (let [console (:console system)
+        buffer (start-buffer console)]
+    (eval-and-print system buffer)))
 
 (defmethod run-line "exit" [system _]
   (component/stop system)

          .readLine
          clojure.string/trim-newline))

(defn println-console [console & args]
  (binding [*out* (:out console)]
    (apply println args)))


(defn new-repl [command]
  (map->Repl {:command command}))

(defn format-response [response]
  (clojure.set/rename-keys response {"result" :result
                                     "error" :error
