aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorscgilardi <scgilardi@gmail.com>2008-12-27 23:45:10 +0000
committerscgilardi <scgilardi@gmail.com>2008-12-27 23:45:10 +0000
commit250b45c739235f30b134c5f613f8d705b7214a0e (patch)
tree552272ae4a2d29beae63edf9f10fe3a8a2a0ea89
parentb58849f2a1e2de5114bc46f0e42695f6605cb4c9 (diff)
revert accidental checkin of repl_ln.clj
-rw-r--r--src/clojure/contrib/repl_ln.clj109
1 files changed, 87 insertions, 22 deletions
diff --git a/src/clojure/contrib/repl_ln.clj b/src/clojure/contrib/repl_ln.clj
index 372eb3ff..7e72a836 100644
--- a/src/clojure/contrib/repl_ln.clj
+++ b/src/clojure/contrib/repl_ln.clj
@@ -54,6 +54,14 @@
:depth 0)
"Default/root values for repl info")
+(defvar- +special-character+
+ { (int \return) :eol
+ (int \newline) :eol
+ (int \,) :ws
+ (int \;) :cte
+ -1 :eos }
+ "Maps interesting character codes to keywords representing their type")
+
(defonce- *serial-number* (atom 0)
"Serial number counter")
@@ -76,11 +84,65 @@
{:keys [serial thread depth]} *info*]
(format name-fmt serial thread depth)))
-(defn- prompt-hook
- []
- (let [prompt (*private* :prompt)]
- (var-set Compiler/LINE (.getLineNumber *in*))
- (prompt)))
+(defn- next-char
+ "Reads the next character in s and either returns it or one of the
+ following keywords if the character is of the corresponding type:
+ :ws whitespace
+ :eol end-of-line
+ :eos end-of-stream
+ :cte comment-to-end character"
+ [s]
+ (let [c (.read s)]
+ (cond-let [type]
+ (+special-character+ c) type
+ (Character/isWhitespace c) :ws
+ :else c)))
+
+(defn- skip-to-end
+ "Skips characters on stream s until an end of stream or end of line"
+ [s]
+ (loop [c (next-char s)]
+ (if (#{:eol :eos} c)
+ c
+ (recur (next-char s)))))
+
+(defn- find-readable-this-line
+ "Skips characters on stream s until end of stream, end of line, or a
+ character of interest to the Reader. Returns :eos on end of stream, :eol
+ on end of line, :eol or :eos after skipping to end of line or end of
+ stream on semicolon, or :readable otherwise. Before returning :readable,
+ the readable character is pushed back onto the stream."
+ [s]
+ (loop [c (next-char s)]
+ (case c
+ :eol c
+ :eos c
+ :cte (skip-to-end s)
+ :ws (recur (next-char s))
+ (do
+ (.unread s c)
+ :readable))))
+
+(defn- read-hook
+ "Read hook for clojure.main/repl that keeps the compiler's line number in
+ sync with that of our input stream, prompts only when there is nothing
+ interesting remaining to read on the previous input line, and calls the
+ Reader only when there's something interesting to read on the current
+ line."
+ [eof]
+ (let [{:keys [prompt flush read]} *private*]
+ (loop [c (find-readable-this-line *in*)]
+ (case c
+ :eos eof
+ :eol
+ (do
+ (prompt)
+ (flush)
+ (recur (find-readable-this-line *in*)))
+ :readable
+ (do
+ (var-set Compiler/LINE (.getLineNumber *in*))
+ (read eof))))))
(defn- process-inits
"Processes initial pairs of args of the form:
@@ -206,20 +268,19 @@
- :prompt-fmt, Prompt format string
default: the prompt-fmt of the parent repl, or \"%S:%L %N=> \""
[& options]
- (let [{:keys [init need-prompt prompt flush read eval print caught in out err
+ (let [{:keys [init prompt flush read eval print caught in out err
encoding name-fmt prompt-fmt]
- :or {init #()
- prompt #(clojure.core/print (repl-prompt))
- need-prompt #(.atLineStart *in*)
- flush flush
- read read
- eval eval
- print prn
- caught #(.println *err* (clojure.main/repl-exception %))
- in System/in
- out System/out
- err System/err
- encoding RT/UTF8}}
+ :or {init #()
+ prompt #(clojure.core/print (repl-prompt))
+ flush flush
+ read #(read *in* false %)
+ eval eval
+ print prn
+ caught #(.println *err* (clojure.main/repl-exception %))
+ in System/in
+ out System/out
+ err System/err
+ encoding RT/UTF8}}
(apply hash-map options)]
(try
(Var/pushThreadBindings
@@ -237,14 +298,18 @@
:thread (.getId (Thread/currentThread))
:depth (inc (:depth *info*)))
(assoc! *private*
- :prompt prompt)
+ :prompt prompt
+ :flush flush
+ :read read)
(set-repl-name (or name-fmt (:name-fmt *info*)))
(set-repl-prompt (or prompt-fmt (:prompt-fmt *info*)))
+ ;; unread newline to enable first prompt
+ (.unread *in* (int \newline))
(clojure.main/repl
:init init
- :prompt prompt-hook
- :flush flush
- :read read
+ :prompt #()
+ :flush #()
+ :read read-hook
:eval eval
:print print
:caught caught)