Browse files

Move exit & quit to the read side

The primary goal here is to make the client actually exit when
the nREPL server is in a separate process, which was broken.
This is also significantly safer, especially for scenarios
where you have a remote nREPL server that you *don't* actually
want to kill when you're just trying to bail out of your REPL
session. It seems counter-intuitive to have (exit) on the
client kill the server. We also now allow paren-less exit and
quit - perhaps a bit magical, but this will be nice for noobs.

The tradeoff is that this makes exit & quit pretty static.
Redefining them is still possible, but calling (exit) or
(quit) will quit, regardless of any new definitions on the
execution side.  That's less than ideal, but I prefer that
to the existing behavior.
  • Loading branch information...
1 parent c8ab98e commit cd4dcc196d1e93f489db2163a43c6d9550814eb1 @trptcolin committed Mar 29, 2012
@@ -4,6 +4,7 @@
[ :as nrepl.misc]
[ :as nrepl.server]
[ :as nrepl.transport]
+ [reply.exit]
[reply.reader.jline :as reader.jline]
[reply.signals :as signals]))
@@ -51,13 +52,13 @@
(prompt ns)
- (let [done (Object.)
+ (let [eof (Object.)
read-result (try (read)
(catch Exception e
(if (= (.getMessage e) "EOF while reading")
- done
+ eof
(prn e))))]
- (if (= done read-result)
+ (if (reply.exit/done? eof read-result)
(recur (execute-with-client
@@ -1,14 +1,18 @@
(ns reply.eval-modes.standalone
(:require [reply.eval-modes.standalone.concurrency :as concurrency]
[reply.eval-state :as eval-state]
+ [reply.exit :as exit]
[reply.initialization :as initialization]
[reply.reader.jline :as reader.jline]
[reply.signals :as signals]))
(def reply-read
(fn [prompt exit]
- (reader.jline/read prompt exit)))
+ (let [read-result (reader.jline/read prompt exit)]
+ (if (exit/done? exit read-result)
+ exit
+ read-result))))
(def reply-eval
@@ -0,0 +1,15 @@
+(ns reply.exit)
+(defn done-commands [eof]
+ #{eof 'quit 'exit '(quit) '(exit)})
+(defn done? [eof expression]
+ ((done-commands eof) expression))
+(defn exit
+ "Exits the REPL. This is fairly brutal, does (System/exit 0)."
+ []
+ (shutdown-agents)
+ (println "Bye for now!")
+ (System/exit 0))
@@ -61,13 +61,13 @@
(use '[clojure.pprint :only ~'[pp pprint]])
~(export-definition 'reply.initialization/help)
- ~(export-definition 'reply.main/exit)
- (def ~'quit ~'exit)
+ ;~(export-definition 'reply.exit/exit)
+ ;(def ~'quit ~'exit)
(ns reply.exports)
~(export-definition 'reply.initialization/intern-with-meta)
- (~'intern-with-meta '~'user '~'quit #'user/exit)
+ ;(~'intern-with-meta '~'user '~'quit #'user/exit)
(binding [*err* (]
~(export-definition 'reply.initialization/repl-defn)
@@ -1,20 +1,14 @@
(ns reply.main
(:require [reply.eval-modes.nrepl :as eval-modes.nrepl]
[reply.eval-modes.standalone :as eval-modes.standalone]
+ [reply.exit :as exit]
[reply.hacks.printing :as hacks.printing]
[reply.reader.jline :as reader.jline]
[reply.signals :as signals]
-(defn exit
- "Exits the REPL. This is fairly brutal, does (System/exit 0)."
- []
- (shutdown-agents)
- (println "Bye for now!")
- (System/exit 0))
(defn parse-args [args]
(loop [[option arg & more :as args] args
arg-map {:custom-init '()}]
@@ -52,7 +46,7 @@
clojure.repl/pst clj-stacktrace.repl/pst]
(catch Exception e# (clojure.repl/pst e#))
- (finally (exit))))
+ (finally (exit/exit))))
(defn set-prompt [options]
(when-let [prompt-form (:custom-prompt options)]
@@ -81,7 +75,7 @@ varargs list of arguments.
Available options: [:help :custom-init :skip-default-init :standalone :attach :port :color]
See -main for descriptions."
- (cond (:help options) (do (println (clojure.repl/doc -main)) (exit))
+ (cond (:help options) (do (println (clojure.repl/doc -main)) (exit/exit))
(:standalone options) (launch-standalone options)
:else (launch-nrepl options)))

0 comments on commit cd4dcc1

Please sign in to comment.