fix: pr-str/str of a var, and nREPL namespace switching
- core: pr-render/str-render now render a Jolt var as #'ns/name instead of
falling through to the generic table printer, which recursed into the var's
cyclic :meta/:ns refs and looped forever. Adds name-of/var-display helpers.
- jolt.nrepl: capture the post-eval namespace *after* running the form — jolt
evaluates map-literal values right-to-left, so {:val (eval form) :ns (the-ns)}
read the ns before in-ns ran, pinning every session to 'user'. Now in-ns/ns
switches persist across evals. render-value dropped: pr-str handles vars.
- specs: var printing (strings-spec) and nREPL in-ns/ns-persistence + explicit
:ns override (nrepl-test).
This commit is contained in:
parent
5b66cfaa97
commit
d00c3cc117
4 changed files with 38 additions and 7 deletions
|
|
@ -1532,6 +1532,25 @@
|
|||
(pr-render buf (in pair 1)))
|
||||
(buffer/push-string buf "}"))
|
||||
|
||||
(defn- name-of
|
||||
"Extract a plain name string from a string, symbol struct, or a namespace/var
|
||||
table (reading its :name) — never recurses into the cyclic ns structure."
|
||||
[x]
|
||||
(cond
|
||||
(nil? x) nil
|
||||
(string? x) x
|
||||
(and (struct? x) (= :symbol (get x :jolt/type))) (x :name)
|
||||
(or (struct? x) (table? x)) (name-of (get x :name))
|
||||
(string x)))
|
||||
|
||||
(defn- var-display
|
||||
"Render a Jolt var as #'ns/name. A var's :meta/:ns refs are cyclic, so this
|
||||
reads only its :name and :ns name — printing the var's pairs would loop."
|
||||
[v]
|
||||
(let [nm (name-of (v :name))
|
||||
ns (name-of (v :ns))]
|
||||
(if ns (string "#'" ns "/" nm) (string "#'" nm))))
|
||||
|
||||
(set pr-render
|
||||
(fn [buf v]
|
||||
(cond
|
||||
|
|
@ -1551,6 +1570,7 @@
|
|||
(number? v) (buffer/push-string buf (fmt-number v))
|
||||
(and (struct? v) (= :symbol (v :jolt/type)))
|
||||
(buffer/push-string buf (if (v :ns) (string (v :ns) "/" (v :name)) (v :name)))
|
||||
(and (table? v) (= :jolt/var (get v :jolt/type))) (buffer/push-string buf (var-display v))
|
||||
(core-sorted-map? v) (pr-render-pairs buf (sorted-map-entries v))
|
||||
(core-sorted-set? v) (pr-render-seq buf (v :items) "#{" "}")
|
||||
(lazy-seq? v) (pr-render-seq buf (realize-for-iteration v) "(" ")")
|
||||
|
|
@ -1580,6 +1600,7 @@
|
|||
(keyword? v) (string ":" (string v))
|
||||
(and (struct? v) (= :symbol (v :jolt/type)))
|
||||
(if (v :ns) (string (v :ns) "/" (v :name)) (v :name))
|
||||
(and (table? v) (= :jolt/var (get v :jolt/type))) (var-display v)
|
||||
(number? v) (fmt-number v)
|
||||
(= true v) "true"
|
||||
(= false v) "false"
|
||||
|
|
|
|||
|
|
@ -90,16 +90,13 @@
|
|||
; regardless of the ambient ns.
|
||||
(defn- eval-in-ns [ns-str form]
|
||||
(in-ns (symbol ns-str))
|
||||
(let [result (try {:val (eval form) :ns (:name (the-ns))}
|
||||
; Bind the value before reading the ns: jolt evaluates map-literal values
|
||||
; right-to-left, so the result ns must be captured *after* eval runs any in-ns.
|
||||
(let [result (try (let [v (eval form)] {:val v :ns (:name (the-ns))})
|
||||
(catch Throwable e {:err e :ns (:name (the-ns))}))]
|
||||
(in-ns 'jolt.nrepl)
|
||||
result))
|
||||
|
||||
; pr-str on a var loops forever on its cyclic ns refs, so render vars (def/defn
|
||||
; results) ourselves as #'ns/name rather than printing them.
|
||||
(defn- render-value [v ns-str]
|
||||
(if (var? v) (str "#'" ns-str "/" (get v :name)) (pr-str v)))
|
||||
|
||||
(defn- eval-handler [server msg send!]
|
||||
; current-ns is global ctx state shared by all fibers, so set the eval ns
|
||||
; explicitly each time: requested :ns, else the session's last ns, else user.
|
||||
|
|
@ -122,7 +119,7 @@
|
|||
(flush-out)
|
||||
(swap! server assoc :eval-ns ns)
|
||||
(when err (throw err))
|
||||
(respond {"ns" ns "value" (render-value val ns)})
|
||||
(respond {"ns" ns "value" (pr-str val)})
|
||||
(recur (next forms) ns))))
|
||||
(janet/setdyn :out old-out)
|
||||
(respond {"status" ["done"]}))
|
||||
|
|
|
|||
|
|
@ -64,6 +64,14 @@
|
|||
(check "ns field reported"
|
||||
"(some #(get % \"ns\") (jolt.nrepl/client-eval c \"(+ 1 1)\" s))" "user")
|
||||
|
||||
# in-ns switches the session ns, and it persists to the next eval
|
||||
(check "in-ns switches ns"
|
||||
"(some #(get % \"ns\") (jolt.nrepl/client-eval c \"(in-ns (quote foo.bar))\" s))" "foo.bar")
|
||||
(check "ns persists across evals"
|
||||
"(some #(get % \"ns\") (jolt.nrepl/client-eval c \"(+ 2 2)\" s))" "foo.bar")
|
||||
# explicit :ns on the message overrides
|
||||
(ev "(jolt.nrepl/request c {\"op\" \"eval\" \"code\" \"(+ 1 1)\" \"session\" s \"ns\" \"user\"})")
|
||||
|
||||
# eval error -> eval-error status, and the connection keeps working afterward
|
||||
(check "eval error status"
|
||||
"(boolean (some #(let [st (get % \"status\")] (and (sequential? st) (some (fn [x] (= \"eval-error\" x)) st))) (jolt.nrepl/client-eval c \"(/ 1 :z)\" s)))"
|
||||
|
|
|
|||
|
|
@ -13,6 +13,11 @@
|
|||
["string? true" "true" "(string? \"x\")"]
|
||||
["pr-str vector" "\"[1 2 3]\"" "(pr-str [1 2 3])"]
|
||||
["pr-str quotes str" "\"\\\"hi\\\"\"" "(pr-str \"hi\")"]
|
||||
# a var's :meta/:ns refs are cyclic — pr-str/str render it as #'ns/name
|
||||
# rather than recursing into (and looping on) the var's fields.
|
||||
["pr-str of a var" "\"#'user/vv\"" "(pr-str (def vv 1))"]
|
||||
["str of a var" "\"#'user/ww\"" "(str (def ww 2))"]
|
||||
["pr-str of a defn" "\"#'user/gg\"" "(pr-str (defn gg [x] x))"]
|
||||
["seq of string" "[\\a \\b]" "(seq \"ab\")"])
|
||||
|
||||
(defspec "clojure.string"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue