                (project-short project))})
 
 (defn get-project [project-name]
-  (-> @projects
-      (get project-name)
-      :project))
+  (-> (get @projects project-name)
+      (dissoc ::run-state)))
 
 (defn add-project [project-root]
   (load-project! project-root))


(defn pprint-str [o]
  (let [w (java.io.StringWriter.)]
    (pprint o w)
    (.toString w)))



  (swap! projects dissoc name))

(defn reload-project! [name]
  (let [root (-> @projects (get name) :root)]
    (unload-project! name)
    (load-project! root)))

(defn get-project* [name]
  (if-let [project (@projects name)]
    project
    (throw (ex-info "Project doesn't exist" {:name name}))))

;; adapated from leiningen.core.eval
(defn- overridden-env
  "Returns an overridden version of the current environment as an Array of
  Strings of the form name=val, suitable for passing to Runtime#exec."
  [env]
  (->> env
       (filter val)
       (map #(str (name (key %)) "=" (val %)))
       (into-array String)))

;; adapated from leiningen.core.eval
(defn sh
  "A version of clojure.java.shell/sh that streams in/out/err."
  [cmd & {:keys [dir]}]
  (let [env (overridden-env (System/getenv))
        proc (.exec (Runtime/getRuntime) (into-array cmd) env
                    (io/file dir))]
    (.addShutdownHook (Runtime/getRuntime)
                      (Thread. (fn [] (.destroy proc))))
    ;; TODO: wrap setup in try/finally and close streams
    (let [out (io/reader (.getInputStream proc))
          err (io/reader (.getErrorStream proc))
          out-writer (java.io.StringWriter.)
          err-writer (java.io.StringWriter.)
          pump-out (doto (Pipe. out out-writer) .start)
          pump-err (doto (Pipe. err err-writer) .start)]
      {:process proc
       :pump-out pump-out
       :pump-err pump-err
       :out-writer out-writer
       :err-writer err-writer})))

;;; Objective
;; Launch a process & observe its output in a webui.

;; Technique
;;  - .exec, redirect out & err to StringWriters
;;  - shove Process to another thread and waitFor it to end
;;  - associate process, outSW, and errSW to project's ::run-state





(defn start-repl! [name]
  (let [project (get-project* name)]
    (when (-> project ::run-state deref :repl)
      (throw (ex-info "Project already running a repl!" {:name name})))

    (let [env (overridden-env (System/getenv))
          repl-process (sh ["lein"
                            "repl"
                            ":headless"] :dir ".")]
      (swap! (::run-state project) assoc :repl repl-process))))


;;; Util
