Skip to content
This repository was archived by the owner on Oct 21, 2022. It is now read-only.

Commit 9834dbe

Browse files
committed
Merge pull request #52 from LightTable/modernize-eval
Modernize eval
2 parents 2bf826c + b41f113 commit 9834dbe

11 files changed

Lines changed: 178 additions & 78 deletions

File tree

.travis.yml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
language: clojure
2+
script:
3+
- cd runner && lein test
4+
jdk:
5+
- oraclejdk8
6+
notifications:
7+
irc: "chat.freenode.net#lighttable"
8+
email:
9+
- gabriel.horner@gmail.com
10+
- mrundberget@hotmail.com
11+
- kenny.evitt@gmail.com

README.md

Lines changed: 42 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,36 @@
22

33
The official Clojure language plugin for Light Table.
44

5+
## Supported Clojure versions
6+
7+
This plugin requires projects Clojure 1.5.1 and higher. Starting with 0.2.0 this plugin will only be maintained for projects with Clojure 1.7.0 and higher.
8+
9+
## Supported ClojureScript versions
10+
11+
This plugin works for projects on recent versions of ClojureScript e.g. 1.7.X. For projects with ClojureScript versions 0.0-2341 and higher, Clojure 1.7.0 is required.
12+
513
## First ClojureScript Repl
614

715
Welcome first time ClojureScript users! Please see [David Nolen's tutorial](https://github.com/swannodette/lt-cljs-tutorial) to get familiar with ClojureScript and comfortable with LightTable's repl. Note while doing that tutorial you were in a namespace. A namespace is necessary for a LightTable repl. Once you have finished the tutorial, create your own ClojureScript project with `lein new mies my-project` and eval there. If you want to add dependencies to your project, read the [below section](#clojurescript-eval) as that requires a different type of LightTable connection.
816

17+
## Cljc eval
18+
19+
By default, \*.cljc files are identified as Clojure files. Thus when you eval, it will eval as a
20+
Clojure file. If you'd like to eval as a ClojureScript file, run the command `Editor: Set current
21+
editor syntax`, select `ClojureScript` and then eval.
22+
923
## ClojureScript Eval
1024

11-
There are 3 ways to eval ClojureScript, 2 of which use your ClojureScript javascript. To add one of these connections, run the command `Connect: Add Connection`. The 3 connections to choose from:
25+
There are 3 options to eval ClojureScript, 2 of which use your ClojureScript javascript. To add one of these connections, run the command `Connect: Add Connection`. The 3 connections to choose from:
1226

1327
1. `Light Table UI` - Connect to the LightTable js process. Great for a headless mode, writing plugins and to try out ClojureScript features. Note, you use the ClojureScript version that comes with LightTable.
1428

1529
2. `Browser` - Connect to a web page that has the compiled ClojureScript sourced e.g. `file:///path/to/index.html`. You must navigate the internal browser to that web page. Recommended for ease of use.
1630

1731
3. `Browser (External)` - Connect to a web page that has the compiled ClojureScript sourced e.g. `file:///path/to/index.html`. In addition to navigating the external browser, you must copy the script tag into that web page. Requires more setup than the internal browser but gives you the freedom to use any browser.
1832

33+
Note that for Browser options, compiled ClojureScript cannot be compiled with `:advanced` `:optimizations` mode.
34+
1935
## ClojureScript Workflows
2036

2137
For ClojureScript projects:
@@ -33,14 +49,37 @@ For LightTable plugins:
3349
Your project is connected to `LightTable UI`. When you save any plugin cljs file, compiled js is generated and saved. Any change
3450
can be eval-ed.
3551

52+
## Connect to remote nREPL
53+
54+
When you eval a Clojure project, Light Table automatically starts an nREPL server and connects to it. If you'd prefer to start an nREPL server,
55+
open the `Connections` panel, press `Add Connection` button and select the `Clojure (remote nREPL)` client. Make sure your project.clj
56+
has the following `:dependencies` and `:repl-options`:
57+
58+
```clojure
59+
(defproject lttest "0.1.0-SNAPSHOT"
60+
:description "FIXME: write description"
61+
:dependencies [[org.clojure/clojure "1.6.0"]
62+
[lein-light-nrepl "X.X.X"]]
63+
:repl-options {:nrepl-middleware [lighttable.nrepl.handler/lighttable-ops]})
64+
```
65+
66+
For projects using Clojure >= 1.5.1 and < 1.7.0, `X.X.X` refers to `0.1.3`, an older unmaintained version.
67+
For projects using Clojure >= 1.7.0, `X.X.X` refers to the latest version of `lein-light-nrepl`:
68+
69+
[![Clojars Project](http://clojars.org/lein-light-nrepl/latest-version.svg)](http://clojars.org/lein-light-nrepl)
70+
3671
## License
3772

3873
Distributed under the MIT License, see license.md for the full text.
3974

40-
## For Commiters
75+
## For Committers
4176

77+
* Project layout
78+
* runner/: Contains uberjar to inject our nREPL middleware into a project and then start a repl
79+
* lein-light-nrepl/: Contains nREPL middleware that needs to be deployed to Clojars when changed
80+
* src/ and everything else: Normal LightTable plugin
4281
* When releasing a new plugin version and lein-light-nrepl has changed:
4382
* Bump lein-light-nrepl and lein-light in runner/.
44-
* Update the uberjar with `lein uberjar` in `runner/target/lein-light-standalone.jar`.
83+
* Update the uberjar with `lein uberjar` in `runner` to produce `runner/target/lein-light-standalone.jar`.
4584
* Release the new version of lein-light-nrepl to [clojars](https://clojars.org/lein-light-nrepl)
4685
* No process for upgrading `clojure-mode.js` until [this issue](https://github.com/LightTable/Clojure/issues/26) is addressed.

build.sh

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
#!/bin/sh
2-
find . -name '*.DS_Store' -type f -delete
32
cd runner
43
lein uberjar
5-
lein install
64
cd ../lein-light-nrepl
75
lein install
86
echo " --- Done!"

lein-light-nrepl/project.clj

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
1-
(defproject lein-light-nrepl "0.1.3"
1+
(defproject lein-light-nrepl "0.2.0"
22
:description "nrepl client for Light Table clj and cljs eval."
33
:url "https://github.com/LightTable/Clojure/tree/master/lein-light-nrepl"
44
:license {:name "Eclipse Public License"
55
:url "http://www.eclipse.org/legal/epl-v10.html"}
6-
:dependencies [[org.clojure/clojure "1.5.1"]
7-
[org.clojure/tools.nrepl "0.2.3"]
6+
:dependencies [[org.clojure/clojure "1.7.0"]
7+
[org.clojure/tools.nrepl "0.2.10"]
88
[commons-io/commons-io "2.4"]
9-
[org.clojure/tools.reader "0.8.16"]
10-
[clj-stacktrace "0.2.7"]
11-
[org.clojure/clojurescript "0.0-2202"
9+
[org.clojure/tools.reader "0.9.2"]
10+
[clj-stacktrace "0.2.8"]
11+
[org.clojure/clojurescript "0.0-3308"
1212
:exclusions [org.apache.ant/ant]]
13-
[clojure-complete "0.2.3"]]
13+
[clojure-complete "0.2.4"]]
1414
:jvm-opts ["-Xmx1g"])

lein-light-nrepl/src/lighttable/nrepl/cljs.clj

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
[lighttable.nrepl.exception :as exception]
99
[cljs.compiler :as comp]
1010
[cljs.analyzer :as cljs]
11+
[cljs.closure :as cljsc]
1112
[cljs.source-map :as sm]
1213
[cljs.env :as cljs-env :refer [with-compiler-env]]
1314
[clojure.test :as test]
@@ -72,8 +73,12 @@
7273
g' (reduce #(update-in % [n] without %2) g m)]
7374
(recur g' (conj l n) (union s' (intersection (no-incoming g') m)))))))
7475

76+
(let [ups-deps (cljsc/get-upstream-deps)
77+
opts {:ups-libs (:libs ups-deps)
78+
:ups-foreign-libs (:foreign-libs ups-deps)}]
79+
(def compiler-env
80+
(cljs-env/default-compiler-env opts)))
7581

76-
(def compiler-env (cljs-env/default-compiler-env))
7782
(def build-env (atom {}))
7883

7984
(defn ns->cljs-file [s]
@@ -130,7 +135,8 @@
130135
(with-bindings bindings#
131136
(with-compiler-env compiler-env
132137
(cljs.compiler/with-core-cljs
133-
~@body)))))
138+
nil
139+
(fn [] ~@body))))))
134140

135141
(defn with-forms [{:keys [file] :as cur}]
136142
(let [file (file|resource->file file)]
@@ -140,7 +146,7 @@
140146
(with-cljs-env cur
141147
(assoc cur
142148
:file file-loc
143-
:forms (eval/lined-read (slurp file))
149+
:forms (eval/lined-read (slurp file) :cljs)
144150
:mtime mtime))))))
145151

146152
(defn analyze [env form]
@@ -437,9 +443,10 @@
437443
(with-compiler-env compiler-env
438444
(binding [cljs/*cljs-ns* 'cljs.user]
439445
(comp/with-core-cljs
440-
(cljs/analyze {:context :expr :ns {} :locals {}} (list 'ns ns))
441-
(when (and path (fs/exists? path))
442-
(cljs/analyze-file (str "file://" path))))))))
446+
nil
447+
(fn [] (cljs/analyze {:context :expr :ns {} :locals {}} (list 'ns ns))
448+
(when (and path (fs/exists? path))
449+
(cljs/analyze-file (str "file://" path)))))))))
443450

444451
(defmethod core/handle "editor.eval.cljs" [{:keys [ns path code pos meta transport session] :as msg}]
445452
(let [ns (str ns)
@@ -456,7 +463,7 @@
456463
(try
457464
(with-bindings bindings
458465
(let [code (eval/prep-code msg)
459-
forms (eval/lined-read code)
466+
forms (eval/lined-read code :cljs)
460467
env {:context :expr :file path :locals {}}
461468
forms (if-not pos
462469
forms
@@ -465,12 +472,14 @@
465472
(core/respond msg :editor.eval.cljs.location (clojure.core/meta (first forms))))
466473
(with-compiler-env compiler-env
467474
(comp/with-core-cljs
468-
(if-not (first forms)
469-
(core/respond msg :editor.eval.cljs.no-op {})
470-
(core/respond msg :editor.eval.cljs.code {:results (doall (for [f forms]
471-
(eval-cljs env f)))
472-
:ns cljs/*cljs-ns*
473-
:meta (or meta {})}))))))
475+
nil
476+
(fn []
477+
(if-not (first forms)
478+
(core/respond msg :editor.eval.cljs.no-op {})
479+
(core/respond msg :editor.eval.cljs.code {:results (doall (for [f forms]
480+
(eval-cljs env f)))
481+
:ns cljs/*cljs-ns*
482+
:meta (or meta {})})))))))
474483
(catch Exception e
475484
(let [ex (ex-data e)]
476485
(core/respond msg :editor.eval.cljs.exception {:stack (exception/clean-trace e)

lein-light-nrepl/src/lighttable/nrepl/eval.clj

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,16 @@
1212
[clojure.tools.reader.reader-types :as rt])
1313
(:import java.io.Writer))
1414

15-
(defn try-read [rdr]
15+
(defn- try-read [rdr feature]
16+
{:pre [(#{:clj :cljs} feature)]}
1617
(when rdr
17-
(reader/read rdr false ::EOF)))
18+
(reader/read {:read-cond :allow :features #{feature} :eof ::EOF} rdr)))
1819

19-
(defn lined-read [string]
20-
(let [rdr (rt/indexing-push-back-reader string)]
21-
(take-while #(not= ::EOF %) (repeatedly #(try-read rdr)))))
20+
(defn lined-read
21+
([string] (lined-read string :clj))
22+
([string feature]
23+
(let [rdr (rt/indexing-push-back-reader string)]
24+
(take-while #(not= ::EOF %) (repeatedly #(try-read rdr feature))))))
2225

2326
(defn find-form [forms pos]
2427
(let [cur-line (inc (:line pos))

lein-light-nrepl/src/lighttable/nrepl/sonar.clj

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
[lighttable.nrepl.exception :as exception]
66
[clojure.test :as test]
77
[clojure.walk :as walk]
8-
[cljs.compiler :as compiler]
98
[cljs.env :as cljs-env]
109
[cljs.analyzer :as cljs]
1110
[clojure.set :as set]))

runner/project.clj

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,12 @@
11
(defproject lein-light "0.1.3"
2-
:description "FIXME: write description"
3-
:url "http://github.com/kodowa/lein-light"
2+
:description "Provide uberjar to start headless repl with LT middleware"
43
:license {:name "Eclipse Public License"
54
:url "http://www.eclipse.org/legal/epl-v10.html"}
6-
:dependencies [[org.clojure/clojure "1.5.1"]
7-
[leiningen "2.3.4"
8-
:exclusions [stencil]]
5+
:dependencies [[org.clojure/clojure "1.7.0"]
6+
[leiningen "2.5.2" :exclusions [stencil]]
97
[fs "1.3.3"]]
108
:uberjar-name "lein-light-standalone.jar"
11-
:aot :all
9+
:profiles {:uberjar {:aot :all}}
1210
:source-paths ["src/"]
1311
:jvm-opts ["-Xmx1g"]
1412
:main leiningen.light-nrepl)

runner/src/leiningen/light_nrepl.clj

Lines changed: 57 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -3,68 +3,84 @@
33
(:require [leiningen.core.project :as lp]
44
[leiningen.repl :as repl]
55
[clojure.string :as string]
6-
[fs.core :as fs])
7-
(:use [leiningen.core.eval :only [eval-in-project]]))
6+
[fs.core :as fs]))
87

98
(defn parse-version [ver]
10-
(when ver
11-
(let [[major minor patch] (string/split ver #"\.")
12-
[patch extra] (string/split patch #"-")]
13-
{:major (Integer. major)
14-
:minor (Integer. minor)
15-
:patch (Integer. patch)})))
9+
(assert (and ver (re-find #"^\d+\.\d+\.\d+" ver))
10+
(str "Invalid version number: " (pr-str ver) ". Must be in format X.X.X"))
11+
(let [[major minor patch] (string/split ver #"\.")
12+
[patch extra] (string/split patch #"-")]
13+
{:major (Integer. major)
14+
:minor (Integer. minor)
15+
:patch (Integer. patch)}))
1616

17-
(defn valid-clojure? [ver]
17+
(defn at-least-version? [ver min-version]
18+
(let [{:keys [major minor patch]} (parse-version ver)]
19+
(or (> major (:major min-version))
20+
(and (= major (:major min-version)) (> minor (:minor min-version)))
21+
(and (= major (:major min-version)) (= minor (:minor min-version)) (>= patch (:patch min-version))))))
22+
23+
(defn maintained-clojure-version?
24+
"Determine if Clojure version is supported for latest middleware.
25+
Return true for nil since there is no version and thus we are providing one"
26+
[ver]
1827
(if-not ver
1928
true
20-
(let [{:keys [major minor patch]} (parse-version ver)]
21-
;;do this by negation. It's an invalid version if any of the
22-
;;following are true
23-
(not
24-
(or (< major 1)
25-
(and (= major 1) (< minor 5))
26-
(and (= major 1) (= minor 5) (< patch 1)))))))
27-
28-
(defn proj->name [proj]
29-
(str (:name proj) " " (:version proj)))
29+
;; 1.7.0 candidates conflict with 1.7.0
30+
(and (not (.startsWith ver "1.7.0-"))
31+
(at-least-version? ver {:major 1 :minor 7 :patch 0}))))
3032

31-
(defn prep [project name]
33+
(defn prep
34+
"Build a project map for the repl with LT middleware injected"
35+
[project name clj-version]
3236
(let [init `(swap! lighttable.nrepl.core/my-settings merge {:name ~(or name (str (:name project) " " (:version project))) :project (quote ~project)})
3337
init (if-let [cur-init (-> project :repl-options :init)]
3438
(list 'do cur-init init)
3539
init)
36-
profile {:dependencies '[[lein-light-nrepl/lein-light-nrepl "0.1.3"]
37-
[org.clojure/tools.reader "0.8.3"]]
40+
lein-light-version (if (maintained-clojure-version? clj-version)
41+
;; Maintained lein-light-nrepl
42+
"0.2.0"
43+
;; Deprecated/unmaintained lein-light-nrepl
44+
"0.1.3")
45+
profile {:dependencies [['lein-light-nrepl/lein-light-nrepl lein-light-version]]
3846
:repl-options {:nrepl-middleware ['lighttable.nrepl.handler/lighttable-ops]
39-
:init (with-meta init {:replace true})}}
47+
:init (with-meta init {:replace true})}}
4048
project (lp/merge-profiles project [profile])]
4149
(println "final project: " project)
42-
project))
43-
44-
(defn find-clojure-version [proj]
45-
(let [deps (:dependencies proj)]
46-
(second (first (filter #(= (first %) 'org.clojure/clojure) deps)))))
50+
project))
4751

48-
(defn light
49-
"Start a Light Table client for this project"
50-
[project & [name]]
51-
(when-not (valid-clojure? (find-clojure-version project))
52+
(defn abort-unsupported-versions [clj-version cljs-version]
53+
(when (and clj-version (not (at-least-version? clj-version {:major 1 :minor 5 :patch 1})))
5254
(binding [*out* *err*]
5355
(println "Light Table requires Clojure Version 1.5.1 or higher")
5456
(System/exit 0)))
55-
(try
56-
(repl/repl (prep project name) ":headless")
57-
(catch Exception e
58-
(.printStackTrace e)
59-
(System/exit 1))))
57+
(when (and cljs-version (at-least-version? cljs-version {:major 0 :minor 0 :patch 2341})
58+
(not (maintained-clojure-version? clj-version)))
59+
(binding [*out* *err*]
60+
(println "Light Table requires Clojure Version >= 1.7.0 for ClojureScript versions >= 0.0-2341")
61+
(System/exit 0))))
62+
63+
(defn find-dependency-version [proj dep]
64+
(let [deps (:dependencies proj)]
65+
(second (first (filter #(= (first %) dep) deps)))))
6066

61-
(defn check-project [path]
62-
(when (fs/exists? path)
63-
path))
67+
(defn light
68+
"Start a Light Table client for this project"
69+
[project name]
70+
(let [clj-version (find-dependency-version project 'org.clojure/clojure)
71+
cljs-version (some-> (find-dependency-version project 'org.clojure/clojurescript)
72+
;; Make 0.0- conform to standard patch versions
73+
(string/replace "0.0-" "0.0."))]
74+
(abort-unsupported-versions clj-version cljs-version)
75+
(try
76+
(repl/repl (prep project name clj-version) ":headless")
77+
(catch Exception e
78+
(.printStackTrace e)
79+
(System/exit 1)))))
6480

6581
(defn -main [& [name]]
6682
(let [path (str (fs/absolute-path fs/*cwd*) "/project.clj")]
67-
(if (check-project path)
83+
(if (fs/exists? path)
6884
(light (lp/init-project (lp/read path)) name)
6985
(binding [*out* *err*]
7086
(println "Could not find project.clj file at: " path)))))
1.07 MB
Binary file not shown.

0 commit comments

Comments
 (0)