Skip to content
This repository was archived by the owner on Oct 21, 2022. It is now read-only.
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 18 additions & 3 deletions lein-light-nrepl/src/lighttable/nrepl/eval.clj
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,17 @@
(if (instance? clojure.lang.IObj thing)
(meta thing)))

(defn clean-serialize [res & [opts]]
(defn clean-serialize
"stringify the result 'res' into a form appropiate to its type. Defaults to
using 'pr-str' for most types.
Allowed options:
:print-length, restrict length of stringified results to it. Defaults to 1000
:allow-var?, whether to return a var itself or its stringified version.
Defaults to nil
:result, whether to return an atom itself or its content. Defaults to nil
:verbatim, whether to return an string itself or its 'pr-str' version"
[res & [opts]]
(binding [*print-length* (or (:print-length opts) *print-length* 1000)]
(cond
(fn? res) 'fn
Expand All @@ -70,7 +80,9 @@
(and (string? res) (:verbatim opts)) res
:else (pr-str res))))

(defn truncate [v]
(defn truncate

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can't find any references to this function. I think it's safe to remove, ignore for now, or just change the docstring to reflect that it's not used.

"useless function. Same as 'identity'"
[v]
v)

(defn ->result [opts f]
Expand Down Expand Up @@ -118,7 +130,10 @@
(str (reduce str "" (repeat (:start meta 0) "\n"))
code)))

(defn watch [v meta]
(defn watch
"stringify result-value 'v' with pretty-print, sends it back to Lighttable
and returns the value itself to continue the evaling call"
[v meta]
(let [ppv (with-out-str (pprint v))
data {:meta meta :result (subs ppv 0 (dec (count ppv)))}]
(core/safe-respond-to (:obj meta) :editor.eval.clj.watch data))
Expand Down
96 changes: 77 additions & 19 deletions src/lt/plugins/clojure.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -68,13 +68,15 @@
(run-local-server (clients/client! :nrepl.client))))))

(behavior ::on-eval.clj
:desc "Clojure: Eval editor content"
:triggers #{:eval}
:reaction (fn [editor]
(object/raise clj-lang :eval! {:origin editor
:info (assoc (@editor :info)
:print-length (object/raise-reduce editor :clojure.print-length+ nil)
:code (watches/watched-range editor nil nil nil))})))
(behavior ::on-eval.cljs
:desc "Clojurescript: Eval editor content"
:triggers #{:eval}
:reaction (fn [editor]
(object/raise clj-lang :eval! {:origin editor
Expand All @@ -87,6 +89,7 @@
"(set! js/COMPILED js/COMPILED-temp)"))})))

(behavior ::on-eval.one
:desc "Clojure(script): Eval a single form in editor"
:triggers #{:eval.one}
:reaction (fn [editor]
(let [code (watches/watched-range editor nil nil nil)
Expand All @@ -103,12 +106,17 @@
:info info}))))


(defn fill-placeholders [editor exp]
(defn fill-placeholders
"replace editor-selection-flags (placeholders) inside exp with the currently
selected code in the editor"
[editor exp]
(-> exp
(string/replace "__SELECTION*__" (pr-str (ed/selection editor)))
(string/replace "__SELECTION__" (ed/selection editor))))

(behavior ::on-eval.custom
:desc "Clojure(script): Eval a form that has been wrapped by a custom code,
thus changing the result. Ilustrative example: (eval (time form)) instead of (eval form)"
:triggers #{:eval.custom}
:reaction (fn [editor exp opts]
(let [code (fill-placeholders editor exp)
Expand Down Expand Up @@ -176,6 +184,8 @@
(= 'lighttable (second (reader/read-string (:content (files/open-sync project-file))))))))

(behavior ::eval!
:desc "Clojure(script): Send event information for evaluation to the appropiate nREPL
or LightTable-UI client"
:triggers #{:eval!}
:reaction (fn [this event]
(let [{:keys [info origin]} event
Expand Down Expand Up @@ -263,6 +273,8 @@
(notifos/done-working)))

(behavior ::cljs-result
:desc "Clojurescript: Receive a cljs result and dispatches it according
to its appropiate result type. Defaults to :inline"
:triggers #{:editor.eval.cljs.result}
:reaction (fn [obj res]
(notifos/done-working)
Expand All @@ -271,20 +283,24 @@
(object/raise obj ev res))))

(behavior ::cljs-result.replace
:desc "Clojurescript: replace current selection with the result of an evaluation"
:triggers #{:editor.eval.cljs.result.replace}
:reaction (fn [obj res]
(if-let [err (or (:stack res) (:ex res))]
(notifos/set-msg! err {:class "error"})
(ed/replace-selection obj (unescape-unicode (or (:result res) ""))))))

(behavior ::cljs-result.statusbar
:desc "Clojurescript: show the result of an evaluation on the statusbar"
:triggers #{:editor.eval.cljs.result.statusbar}
:reaction (fn [obj res]
(if-let [err (or (:stack res) (:ex res))]
(notifos/set-msg! err {:class "error"})
(notifos/set-msg! (unescape-unicode (or (:result res) "")) {:class "result"}))))

(behavior ::cljs-result.inline
:desc "Clojurescript: shows the result of an evaluation as an inline-widget. Dispatches it as
an exception or as an inline-result"
:triggers #{:editor.eval.cljs.result.inline}
:reaction (fn [obj res]
(let [meta (:meta res)
Expand All @@ -294,6 +310,7 @@
(object/raise obj :editor.eval.cljs.exception res :passed)
(object/raise obj :editor.result (unescape-unicode (or (:result res) "")) loc)))))

;; this is probably the same as ::cljs-result.inline but put the result widget somewhere else
(behavior ::cljs-result.inline-at-cursor
:triggers #{:editor.eval.cljs.result.inline-at-cursor}
:reaction (fn [obj res]
Expand All @@ -316,6 +333,8 @@
:meta meta})))))

(behavior ::clj-result
:desc "Clojure: Receive an eval! result and dispatches it according
to its appropiate result type. Defaults to :inline"
:triggers #{:editor.eval.clj.result}
:reaction (fn [obj res]
(notifos/done-working)
Expand All @@ -324,6 +343,7 @@
(object/raise obj ev res))))

(behavior ::clj-result.replace
:desc "Clojure: replace current selection with the result of an evaluation"
:triggers #{:editor.eval.clj.result.replace}
:reaction (fn [obj res]
(doseq [result (-> res :results)
Expand All @@ -335,6 +355,7 @@
(ed/replace-selection obj (:result result))))))

(behavior ::clj-result.statusbar
:desc "Clojure: show the result of an evaluation on the statusbar"
:triggers #{:editor.eval.clj.result.statusbar}
:reaction (fn [obj res]
(doseq [result (-> res :results)
Expand All @@ -346,6 +367,8 @@
(notifos/set-msg! (:result result) {:class "result"})))))

(behavior ::clj-result.inline
:desc "Clojure: displays the result of an eval! as an inline-widget.
Dispatches it as an exception or as an inline-result"
:triggers #{:editor.eval.clj.result.inline}
:reaction (fn [obj res]
(doseq [result (-> res :results)
Expand All @@ -354,9 +377,9 @@
:start-line (dec (:line meta))}]]
(if (:stack result)
(object/raise obj :editor.eval.clj.exception result :passed)
(do
(object/raise obj :editor.result (:result result) loc))))))
(object/raise obj :editor.result (:result result) loc)))))

;; this is probably the same as ::clj-result.inline but put the result widget somewhere else
(behavior ::clj-result.inline-at-cursor
:triggers #{:editor.eval.clj.result.inline-at-cursor}
:reaction (fn [obj res]
Expand All @@ -366,8 +389,7 @@
:start-line (-> res :meta :start)}]]
(if (:stack result)
(object/raise obj :editor.eval.clj.exception result :passed)
(do
(object/raise obj :editor.result (:result result) loc))))))
(object/raise obj :editor.result (:result result) loc)))))

(behavior ::clj-result.return
:triggers #{:editor.eval.clj.result.return}
Expand All @@ -382,6 +404,8 @@
:meta meta})))))

(behavior ::clj-exception
:desc "Clojure: displays an inline widget with stacktrace information and
a summary in the statusbar"
:triggers #{:editor.eval.clj.exception}
:reaction (fn [obj res passed?]
(when-not passed?
Expand All @@ -390,10 +414,12 @@
loc {:line (dec (:end-line meta)) :ch (:end-column meta 0)
:start-line (dec (:line meta 1))}]
(notifos/set-msg! (:result res) {:class "error"})
(object/raise obj :editor.exception (:stack res) loc))
))
(object/raise obj :editor.exception (:stack res) loc))))

(behavior ::cljs-exception
:desc "Clojurescript: Takes the result of evaling a cljs form which resulted in an
exception. Displays a message in the status bar and an exception widget with
the stacktrace"
:triggers #{:editor.eval.cljs.exception}
:reaction (fn [obj res passed?]
(when-not passed?
Expand All @@ -413,9 +439,10 @@
msg
"Unknown error")]
(notifos/set-msg! msg {:class "error"})
(object/raise obj :editor.exception stack loc))
))
(object/raise obj :editor.exception stack loc))))

;; this is probably to avoid returning (print expr) as an inline result, instead sends it
;; to the console
(behavior ::eval-print
:triggers #{:editor.eval.clj.print}
:reaction (fn [this str]
Expand All @@ -424,9 +451,10 @@
:line (when (object/has-tag? this :nrepl.client)
"stdout")
:id (:id str)
:content (:out str)}
))))
:content (:out str)}))))

;; this is probably to avoid returning (print expr) as an inline result, instead sends it
;; to the console but as an error element (red css color and so)
(behavior ::eval-print-err
:triggers #{:editor.eval.clj.print.err}
:reaction (fn [this str]
Expand Down Expand Up @@ -517,18 +545,33 @@
;; watches
;;****************************************************

;; For more information on watches check
;; Original anouncement: https://groups.google.com/forum/#!msg/light-table-discussion/lyFzPGI2XMs/ec8T1OUPvMsJ
;; blog posts: http://scattered-thoughts.net/blog/2014/01/27/were-not-even-trying/?utm_source=dlvr.it&utm_medium=twitter
;; https://medium.com/@zindlerb/guide-to-light-table-watches-fad560f698d3#.oqwq991sx
;; fancy Rolex watches plugin: https://groups.google.com/forum/#!topic/light-table-discussion/NQWGC0vVHMY

(behavior ::cljs-watch-src
:desc "Clojurescript: wraps the watched source code with a call to 'js/lttools.watch' to catch
its result and send it back to LightTable while continuing normal evaluation of an expression.
(Check the wrapping function for more information)"
:triggers #{:watch.src+}
:reaction (fn [editor cur meta src]
(let [meta (assoc meta :ev :editor.eval.cljs.watch)]
(str "(js/lttools.watch " src " (clj->js " (pr-str meta) "))"))))

(behavior ::clj-watch-src
:desc "Clojure: wraps the watched source code with a call to 'lighttable.nrepl.eval/watch' to catch
its result and send it back to LightTable while continuing normal evaluation of an expression.
(Check the wrapping function for more information)"
:triggers #{:watch.src+}
:reaction (fn [editor cur meta src]
(str "(lighttable.nrepl.eval/watch " src " " (pr-str meta) ")")))

(defn fill-watch-placeholders [exp src meta watch]
(defn fill-watch-placeholders
"replace editor-selection-flags (placeholders) for custom watches inside exp
with the src-code to be watched"
[exp src meta watch]
(-> exp
(string/replace "\n" " ")
(string/replace "__SELECTION*__" (pr-str src))
Expand All @@ -537,12 +580,18 @@
(string/replace #"__\|(.*)\|__" watch)))

(behavior ::cljs-watch-custom-src
:desc "Clojurescript: prepare exp for watching by filling its placeholders and wrapping
its watcher-code with custom call to :editor.eval.cljs.watch"
:triggers #{:watch.custom.src+}
:reaction (fn [editor cur meta opts src]
(let [watch (str "(js/lttools.raise " (:obj meta) " :editor.eval.cljs.watch {:meta " (pr-str (merge (dissoc opts :exp) meta)) " :result $1})")]
(let [watch (str "(js/lttools.raise " (:obj meta)
" :editor.eval.cljs.watch {:meta " (pr-str (merge (dissoc opts :exp) meta))
" :result $1})")]
(fill-watch-placeholders (:exp opts) src meta watch))))

(behavior ::clj-watch-custom-src
:desc "Clojure: prepare exp for watching by filling its placeholders and wrapping
its watcher-code with custom call to :editor.eval.cljs.watch"
:triggers #{:watch.custom.src+}
:reaction (fn [editor cur meta opts src]
(let [wrapped (if (:verbatim opts)
Expand All @@ -551,6 +600,7 @@
watch (str "(lighttable.nrepl.core/safe-respond-to " (:obj meta) " :editor.eval.clj.watch {:meta " (pr-str (merge (dissoc opts :exp) meta)) " :result " wrapped "})")]
(fill-watch-placeholders (:exp opts) src meta watch))))

;; this is probably to update the value of watches during evaluation of a form
(behavior ::cljs-watch-result
:triggers #{:editor.eval.cljs.watch}
:reaction (fn [editor res]
Expand All @@ -564,6 +614,7 @@
str-result (util/escape str-result)]
(object/raise (:inline-result watch) :update! str-result)))))

;; this is probably to update the value of watches during evaluation of a form
(behavior ::clj-watch-result
:triggers #{:editor.eval.clj.watch}
:reaction (fn [editor res]
Expand All @@ -578,6 +629,8 @@
;;****************************************************

(behavior ::clj-doc
:desc "Clojure: gets the symbol at the cursor position and request its
docstring from the nREPL"
:triggers #{:editor.doc}
:reaction (fn [editor]
(let [token (find-symbol-at-cursor editor)
Expand All @@ -593,8 +646,7 @@
:info info
:origin editor
:create try-connect})
command info :only editor)))
))
command info :only editor)))))

(behavior ::print-clj-doc
:triggers #{:editor.clj.doc}
Expand All @@ -617,6 +669,8 @@
(assoc token-left :loc loc)))))

(behavior ::cljs-doc
:desc "Clojurescript: gets the symbol at the cursor position and request its
docstring from the nREPL"
:triggers #{:editor.doc}
:reaction (fn [editor]
(let [token (find-symbol-at-cursor editor)
Expand All @@ -643,16 +697,20 @@
(object/raise editor :editor.doc.show! result)))))

(behavior ::clj-doc-search
:desc "Clojure: Links the 'Search language docs' input-text on the sidebar
with a trigger to :docs.clj.search to retrieve all the documentation
on a user-input"
:triggers #{:types+}
:reaction (fn [this cur]
(conj cur {:label "clj" :trigger :docs.clj.search :file-types #{"Clojure"}})
))
(conj cur {:label "clj" :trigger :docs.clj.search :file-types #{"Clojure"}})))

(behavior ::cljs-doc-search
:desc "Clojurescript: Links the 'Search language docs' input-text on the sidebar
with a trigger to :docs.clj.search to retrieve all the documentation
on a user-input"
:triggers #{:types+}
:reaction (fn [this cur]
(conj cur {:label "cljs" :trigger :docs.cljs.search :file-types #{"ClojureScript"}})
))
(conj cur {:label "cljs" :trigger :docs.cljs.search :file-types #{"ClojureScript"}})))

;;****************************************************
;; autocomplete
Expand Down