From 764e9a6978f5219ddb7284b0d12cdfdc46a9a190 Mon Sep 17 00:00:00 2001 From: Martin Blais Date: Wed, 23 Mar 2011 17:51:09 -0400 Subject: [PATCH 1/5] Fixed stdout going to the minibuffer on converting a LazySeq result. --- src/swank/commands/basic.clj | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/swank/commands/basic.clj b/src/swank/commands/basic.clj index a397280..16f7b59 100644 --- a/src/swank/commands/basic.clj +++ b/src/swank/commands/basic.clj @@ -63,7 +63,14 @@ (defslimefn interactive-eval [string] (with-emacs-package - (pr-str (first (eval-region string))))) + (pr-str + (let [value (first (eval-region string))] + ;; If the result is a seq, consume it here instead of getting evaluated + ;; from pr-str to allow side-effects to go to the repl. + (if (instance? clojure.lang.LazySeq value) + (doall value) + value) + )))) (defslimefn listener-eval [form] (with-emacs-package From d8e58e6dff7d595587ead989e26ae664e122c062 Mon Sep 17 00:00:00 2001 From: Martin Blais Date: Fri, 18 May 2012 19:55:23 -0400 Subject: [PATCH 2/5] Initial prototype for support for clojurescript evaluation. --- src/swank/commands/cljs.clj | 59 +++++++++++++++++++++++++++++++++++++ src/swank/swank.clj | 2 +- 2 files changed, 60 insertions(+), 1 deletion(-) create mode 100644 src/swank/commands/cljs.clj diff --git a/src/swank/commands/cljs.clj b/src/swank/commands/cljs.clj new file mode 100644 index 0000000..a88b773 --- /dev/null +++ b/src/swank/commands/cljs.clj @@ -0,0 +1,59 @@ +(ns ^{:doc "Support for sending evaluation of forms into a ClojureScript repl."} + swank.cljsrepl + (:use [swank.core :only (with-emacs-package)] + [swank.commands :onlny (defslimefn)]) + (:require [cljs.repl :as repl] + [cljs.repl.browser :as browser] + [cljs.compiler :as comp]) + ) + +(def cljs-env "Global cljs environment for a repl." (atom nil)) + +;; FIXME: this sucks, I wish I didn't need a thread. Need to expose better +;; access to cljs repl over there. +(defn- make-env + "Create a new ClojureScript browser repl and run it in a background thread." + [] + (let [env (browser/repl-env), ;; FIXME: we should allow customization + thread (Thread. (fn [] (repl/repl env)))] + (.start thread) + env)) + +(defn eval-in-cljs [form-string] + ;; Create a repl as global on demand, if not already started. + ;; FIXME: not sure if we want to do this automatically in the future. + (when-not @cljs-env (swap! cljs-env (fn [_] (make-env)))) + + (let [form (read-string form-string), + ;; Note: the following is lifted from cljs.repl.browser; FIXME: we + ;; should add support there to do this without a repl thread. + context {:context :statement + :locals {} + :ns (@comp/namespaces comp/*cljs-ns*)}] + + #_(.println System/out form) + + ;; FIXME: we need to report error when no browser is connected, send to + ;; thread, etc. + (repl/evaluate-form @cljs-env context "" form) + )) + +(defslimefn ^{:doc"Evaluate a Clojure form in a global ClojureScript environment."} + interactive-eval-with-target [target form-string] + (condp = target + :cljs-repl (eval-in-cljs form-string) + ;; Note: eventually add support for other repls. + (:abort (throw (Exception. (format "Emacs eval abort - Invalid eval target '%s'" target))))) + ) + + +;;------------------------------------------------------------------------------ +;; Required emacs configuration: +;; +;; You will have to insert this advice in your .emacs in order to instruct +;; slime to use an alternative target for evaluation. +;; +;; (defadvice slime-interactive-eval (around slime-current-eval-target activate) +;; (if (string-match "\\.cljs$" (buffer-file-name)) +;; (slime-eval-with-transcript `(swank:interactive-eval-with-target :cljs-repl ,string)) +;; ad-do-it)) diff --git a/src/swank/swank.clj b/src/swank/swank.clj index abfc0f6..73f1f01 100644 --- a/src/swank/swank.clj +++ b/src/swank/swank.clj @@ -7,7 +7,7 @@ [clojure.main :only [repl]]) (:require [swank.commands] [swank.commands basic indent completion - contrib inspector]) + contrib inspector cljs]) ;; FIXME: I'll remove this and make it more explicit later (:import [java.lang System Thread] [java.io File]) (:gen-class)) From 03b463998058fa257ad66eb17f2c708af38ae1a6 Mon Sep 17 00:00:00 2001 From: Martin Blais Date: Sun, 20 May 2012 14:57:08 -0400 Subject: [PATCH 3/5] Added support for registration of environments for ClojureScript evaluation. --- src/swank/commands/cljs.clj | 56 +++++++++++++------------------------ src/swank/swank.clj | 2 +- 2 files changed, 21 insertions(+), 37 deletions(-) diff --git a/src/swank/commands/cljs.clj b/src/swank/commands/cljs.clj index a88b773..41b5ba0 100644 --- a/src/swank/commands/cljs.clj +++ b/src/swank/commands/cljs.clj @@ -1,5 +1,5 @@ (ns ^{:doc "Support for sending evaluation of forms into a ClojureScript repl."} - swank.cljsrepl + swank.commands.cljs (:use [swank.core :only (with-emacs-package)] [swank.commands :onlny (defslimefn)]) (:require [cljs.repl :as repl] @@ -7,23 +7,17 @@ [cljs.compiler :as comp]) ) -(def cljs-env "Global cljs environment for a repl." (atom nil)) +(def cljs-targets "A mapping of registered repl environments which can be used as targets." (atom {})) -;; FIXME: this sucks, I wish I didn't need a thread. Need to expose better -;; access to cljs repl over there. -(defn- make-env - "Create a new ClojureScript browser repl and run it in a background thread." - [] - (let [env (browser/repl-env), ;; FIXME: we should allow customization - thread (Thread. (fn [] (repl/repl env)))] - (.start thread) - env)) +(defn register-repl + "Register a new REPL environment for interactive-eval-with-target to dispatch to." + [key env] + (swap! cljs-targets assoc key env)) -(defn eval-in-cljs [form-string] - ;; Create a repl as global on demand, if not already started. - ;; FIXME: not sure if we want to do this automatically in the future. - (when-not @cljs-env (swap! cljs-env (fn [_] (make-env)))) +(defn eval-in-cljs + "Evaluate the given string in the provided ClojureScript repl environment." + [env form-string] (let [form (read-string form-string), ;; Note: the following is lifted from cljs.repl.browser; FIXME: we ;; should add support there to do this without a repl thread. @@ -31,29 +25,19 @@ :locals {} :ns (@comp/namespaces comp/*cljs-ns*)}] - #_(.println System/out form) - - ;; FIXME: we need to report error when no browser is connected, send to - ;; thread, etc. - (repl/evaluate-form @cljs-env context "" form) + (repl/evaluate-form env context "" form) )) -(defslimefn ^{:doc"Evaluate a Clojure form in a global ClojureScript environment."} +(defslimefn ^{:doc "Evaluate a Clojure form in a ClojureScript environment."} interactive-eval-with-target [target form-string] - (condp = target - :cljs-repl (eval-in-cljs form-string) - ;; Note: eventually add support for other repls. - (:abort (throw (Exception. (format "Emacs eval abort - Invalid eval target '%s'" target))))) - ) + (let [env (get @cljs-targets target)] + (if env + (eval-in-cljs env form-string) + (throw (Exception. + (format "Emacs eval abort; eval target '%s' not found" target))) + ))) -;;------------------------------------------------------------------------------ -;; Required emacs configuration: -;; -;; You will have to insert this advice in your .emacs in order to instruct -;; slime to use an alternative target for evaluation. -;; -;; (defadvice slime-interactive-eval (around slime-current-eval-target activate) -;; (if (string-match "\\.cljs$" (buffer-file-name)) -;; (slime-eval-with-transcript `(swank:interactive-eval-with-target :cljs-repl ,string)) -;; ad-do-it)) +;; Note: you will need an Emacs customization that overrides +;; slime-interactive-eval tocall (swank:interactive-eval-with-target) instead of +;; (swank:interactive-eval), such as is provided in clojure-mode.el. diff --git a/src/swank/swank.clj b/src/swank/swank.clj index 73f1f01..abfc0f6 100644 --- a/src/swank/swank.clj +++ b/src/swank/swank.clj @@ -7,7 +7,7 @@ [clojure.main :only [repl]]) (:require [swank.commands] [swank.commands basic indent completion - contrib inspector cljs]) ;; FIXME: I'll remove this and make it more explicit later + contrib inspector]) (:import [java.lang System Thread] [java.io File]) (:gen-class)) From c31adc8cba522dd6b0b49f77634aae2c993bd563 Mon Sep 17 00:00:00 2001 From: Martin Blais Date: Sun, 20 May 2012 15:08:46 -0400 Subject: [PATCH 4/5] Cleaned up comments. --- src/swank/commands/cljs.clj | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/swank/commands/cljs.clj b/src/swank/commands/cljs.clj index 41b5ba0..98df91d 100644 --- a/src/swank/commands/cljs.clj +++ b/src/swank/commands/cljs.clj @@ -3,7 +3,6 @@ (:use [swank.core :only (with-emacs-package)] [swank.commands :onlny (defslimefn)]) (:require [cljs.repl :as repl] - [cljs.repl.browser :as browser] [cljs.compiler :as comp]) ) @@ -14,7 +13,6 @@ [key env] (swap! cljs-targets assoc key env)) - (defn eval-in-cljs "Evaluate the given string in the provided ClojureScript repl environment." [env form-string] @@ -38,6 +36,11 @@ ))) -;; Note: you will need an Emacs customization that overrides +;; Notes: +;; +;; You will need an Emacs customization that overrides ;; slime-interactive-eval tocall (swank:interactive-eval-with-target) instead of ;; (swank:interactive-eval), such as is provided in clojure-mode.el. +;; +;; Also, before you can eval to a target, you will need your VM to have a repl +;; instance registered via 'register-repl' (e.g. browser repl). From 41f39e56a30ab53af28ea2ac72e838bebabb18a7 Mon Sep 17 00:00:00 2001 From: Martin Blais Date: Sun, 20 May 2012 15:48:37 -0400 Subject: [PATCH 5/5] Bug fix: installed *cljs-ns* as a binding when evaluating. --- src/swank/commands/cljs.clj | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/swank/commands/cljs.clj b/src/swank/commands/cljs.clj index 98df91d..cb2c5b8 100644 --- a/src/swank/commands/cljs.clj +++ b/src/swank/commands/cljs.clj @@ -16,15 +16,16 @@ (defn eval-in-cljs "Evaluate the given string in the provided ClojureScript repl environment." [env form-string] - (let [form (read-string form-string), - ;; Note: the following is lifted from cljs.repl.browser; FIXME: we - ;; should add support there to do this without a repl thread. - context {:context :statement - :locals {} - :ns (@comp/namespaces comp/*cljs-ns*)}] + (binding [comp/*cljs-ns* comp/*cljs-ns*] + (let [form (read-string form-string), + ;; Note: the following is lifted from cljs.repl.browser; FIXME: we + ;; should add support there to do this without a repl thread. + context {:context :statement + :locals {} + :ns (@comp/namespaces comp/*cljs-ns*)}] - (repl/evaluate-form env context "" form) - )) + (repl/evaluate-form env context "" form) + ))) (defslimefn ^{:doc "Evaluate a Clojure form in a ClojureScript environment."} interactive-eval-with-target [target form-string]