├── .gitignore ├── license.txt ├── project.clj ├── readme.md ├── resources └── public │ ├── demo.html │ ├── index.html │ ├── inline_breakpoints.html │ ├── issue_53.html │ ├── issue_7.html │ ├── playground.html │ ├── styles │ └── default.css │ └── tests.html ├── scripts ├── dev-server.sh ├── reveal.cljs ├── reveal.sh ├── run-demo-node-source-maps-server.sh └── run-node-demo.sh └── src ├── demo-node └── dirac_sample │ └── demo.cljs ├── demo └── dirac_sample │ └── demo.cljs ├── shared └── dirac_sample │ └── logging.clj └── tests └── dirac_sample ├── inline_breakpoints.cljs ├── issue_53.cljs ├── issue_7.cljs ├── main.cljs └── playground.cljs /.gitignore: -------------------------------------------------------------------------------- 1 | /.cljs_rhino_repl 2 | /.lein-env 3 | pom.xml 4 | *jar 5 | /lib/ 6 | /classes/ 7 | /out/ 8 | /target/ 9 | .lein-deps-sum 10 | .lein-repl-history 11 | .lein-plugins/ 12 | .repl* 13 | /checkouts* 14 | /resources/public/.compiled 15 | /resources/demo-node/.compiled 16 | .idea 17 | *.iml 18 | .nrepl-port 19 | .test-dirac-chrome-profile 20 | .figwheel* 21 | .tmp 22 | figwheel_server.log 23 | -------------------------------------------------------------------------------- /license.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) BinaryAge Limited and contributors: 2 | https://github.com/binaryage/dirac-sample/graphs/contributors 3 | 4 | MIT License 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining 7 | a copy of this software and associated documentation files (the 8 | "Software"), to deal in the Software without restriction, including 9 | without limitation the rights to use, copy, modify, merge, publish, 10 | distribute, sublicense, and/or sell copies of the Software, and to 11 | permit persons to whom the Software is furnished to do so, subject to 12 | the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be 15 | included in all copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 18 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 20 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 21 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 22 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 23 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 | -------------------------------------------------------------------------------- /project.clj: -------------------------------------------------------------------------------- 1 | (def devtools-version "0.9.10") 2 | (def dirac-version "1.3.11") 3 | (def figwheel-version "0.5.19") 4 | (defproject binaryage/dirac-sample "0.1.0-SNAPSHOT" 5 | :description "An example integration of Dirac DevTools" 6 | :url "https://github.com/binaryage/dirac-sample" 7 | 8 | :dependencies [[org.clojure/clojure "1.10.1"] 9 | [org.clojure/clojurescript "1.10.520"] 10 | [nrepl/nrepl "0.6.0"] 11 | [clojure-complete "0.2.5" :exclusions [org.clojure/clojure]] 12 | [binaryage/devtools ~devtools-version] 13 | [binaryage/dirac ~dirac-version] 14 | [figwheel ~figwheel-version]] 15 | 16 | :plugins [[lein-cljsbuild "1.1.7"] 17 | [lein-shell "0.5.0"] 18 | [lein-cooper "1.2.2"] 19 | [lein-figwheel ~figwheel-version]] 20 | 21 | ; ========================================================================================================================= 22 | 23 | :source-paths ["src/shared" 24 | "scripts" ; just for IntelliJ 25 | "src/demo" 26 | "src/demo-node" 27 | "src/tests"] 28 | 29 | :clean-targets ^{:protect false} ["target" 30 | "resources/public/.compiled" 31 | "resources/demo-node/.compiled"] 32 | 33 | ; this effectively disables checkouts and gives us a chance to re-enable them on per-profile basis, see :checkouts profile 34 | ; http://jakemccrary.com/blog/2015/03/24/advanced-leiningen-checkouts-configuring-what-ends-up-on-your-classpath/ 35 | :checkout-deps-shares ^:replace [] 36 | 37 | ; ========================================================================================================================= 38 | 39 | :cljsbuild {:builds {}} ; prevent https://github.com/emezeske/lein-cljsbuild/issues/413 40 | 41 | :profiles {; -------------------------------------------------------------------------------------------------------------- 42 | :clojure17 43 | {:dependencies ^:replace [[org.clojure/clojure "1.7.0" :upgrade false] 44 | [org.clojure/clojurescript "1.7.228" :upgrade false] 45 | [binaryage/devtools ~devtools-version] 46 | [binaryage/dirac ~dirac-version]]} 47 | 48 | :clojure18 49 | {:dependencies ^:replace [[org.clojure/clojure "1.8.0" :upgrade false] 50 | [org.clojure/clojurescript "1.9.908" :upgrade false] 51 | [binaryage/devtools ~devtools-version] 52 | [binaryage/dirac ~dirac-version]]} 53 | 54 | :clojure19 55 | {:dependencies ^:replace [[org.clojure/clojure "1.9.0" :upgrade false] 56 | [org.clojure/clojurescript "1.10.339" :upgrade false] 57 | [binaryage/devtools ~devtools-version] 58 | [binaryage/dirac ~dirac-version]]} 59 | 60 | :clojure110 61 | {:dependencies []} 62 | 63 | :clojure-current 64 | [:clojure110] 65 | 66 | ; -------------------------------------------------------------------------------------------------------------- 67 | :demo 68 | {:cljsbuild {:builds {:demo 69 | {:source-paths ["src/shared" 70 | "src/demo"] 71 | :compiler {:output-to "resources/public/.compiled/demo/demo.js" 72 | :output-dir "resources/public/.compiled/demo" 73 | :asset-path ".compiled/demo" 74 | :preloads [devtools.preload dirac.runtime.preload] 75 | :main dirac-sample.demo 76 | :external-config {:dirac.runtime/config {:nrepl-config {:reveal-url-script-path "scripts/reveal.sh" 77 | ;:reveal-url-request-handler (fn [config url line column] 78 | ; (str "ERR REPLY>" url)) 79 | }}} 80 | :optimizations :none 81 | :source-map true}}}}} 82 | 83 | ; -------------------------------------------------------------------------------------------------------------- 84 | :demo-advanced 85 | {:cljsbuild {:builds {:demo-advanced 86 | {:source-paths ["src/shared" 87 | "src/demo"] 88 | :compiler {:output-to "resources/public/.compiled/demo_advanced/dirac_sample.js" 89 | :output-dir "resources/public/.compiled/demo_advanced" 90 | :asset-path ".compiled/demo_advanced" 91 | :pseudo-names true 92 | :preloads [dirac.runtime.preload] 93 | :main dirac-sample.demo 94 | :optimizations :advanced}}}}} 95 | 96 | ; -------------------------------------------------------------------------------------------------------------- 97 | :demo-node 98 | {:cljsbuild {:builds {:demo 99 | {:source-paths ["src/shared" 100 | "src/demo-node"] 101 | :compiler {:output-to "resources/demo-node/.compiled/demo.js" 102 | :output-dir "resources/demo-node/.compiled" 103 | :asset-path ".compiled" 104 | :source-map-asset-path "http://localhost:9988/.compiled" ; see run-demo-node-source-maps-server.sh, CLJS-1075 105 | :preloads [devtools.preload dirac.runtime.preload] 106 | :main dirac-sample.demo 107 | :target :nodejs 108 | :optimizations :none}}}}} 109 | 110 | ; -------------------------------------------------------------------------------------------------------------- 111 | :demo-node-inline-sm 112 | {:cljsbuild {:builds {:demo {:compiler {:inline-source-maps true}}}}} 113 | 114 | ; -------------------------------------------------------------------------------------------------------------- 115 | :tests 116 | {:cljsbuild {:builds {:tests 117 | {:source-paths ["src/shared" 118 | "src/tests"] 119 | :compiler {:output-to "resources/public/.compiled/tests/tests.js" 120 | :output-dir "resources/public/.compiled/tests" 121 | :asset-path ".compiled/tests" 122 | :preloads [devtools.preload dirac.runtime.preload] 123 | :main dirac-sample.main 124 | :optimizations :none 125 | :source-map true}}}}} 126 | 127 | ; -------------------------------------------------------------------------------------------------------------- 128 | :cider 129 | {:dependencies [[cider/cider-nrepl "0.15.1"]] 130 | :repl-options {:nrepl-middleware [cider.nrepl.middleware.apropos/wrap-apropos 131 | cider.nrepl.middleware.classpath/wrap-classpath 132 | cider.nrepl.middleware.complete/wrap-complete 133 | cider.nrepl.middleware.debug/wrap-debug 134 | cider.nrepl.middleware.format/wrap-format 135 | cider.nrepl.middleware.info/wrap-info 136 | cider.nrepl.middleware.inspect/wrap-inspect 137 | cider.nrepl.middleware.macroexpand/wrap-macroexpand 138 | cider.nrepl.middleware.ns/wrap-ns 139 | cider.nrepl.middleware.pprint/wrap-pprint 140 | cider.nrepl.middleware.pprint/wrap-pprint-fn 141 | cider.nrepl.middleware.refresh/wrap-refresh 142 | cider.nrepl.middleware.resource/wrap-resource 143 | cider.nrepl.middleware.stacktrace/wrap-stacktrace 144 | cider.nrepl.middleware.test/wrap-test 145 | cider.nrepl.middleware.trace/wrap-trace 146 | cider.nrepl.middleware.out/wrap-out 147 | cider.nrepl.middleware.undef/wrap-undef 148 | cider.nrepl.middleware.version/wrap-version]} 149 | } 150 | 151 | :dirac-logging 152 | {:dependencies [[clj-logging-config "1.9.12"]] 153 | :repl-options {:init ^:replace (do 154 | (require 'dirac.agent) 155 | (require 'dirac.logging) 156 | (dirac.logging/setup! {:log-out :console 157 | :log-level "TRACE"}) 158 | (dirac.agent/boot!))}} 159 | 160 | ; -------------------------------------------------------------------------------------------------------------- 161 | :repl 162 | {:repl-options {:port 8230 163 | :nrepl-middleware [dirac.nrepl/middleware] 164 | :init (do 165 | (require 'dirac.agent) 166 | (dirac.agent/boot!))}} 167 | 168 | ; -------------------------------------------------------------------------------------------------------------- 169 | :figwheel-config 170 | {:figwheel {:server-port 7111 171 | :server-logfile ".figwheel/demo.log" 172 | :repl false} 173 | :cljsbuild {:builds 174 | {:demo 175 | {:figwheel true}}}} 176 | 177 | :figwheel-repl 178 | {:figwheel {:repl true}} 179 | 180 | :figwheel-nrepl 181 | [:figwheel-config 182 | ; following https://github.com/bhauman/lein-figwheel/wiki/Using-the-Figwheel-REPL-within-NRepl 183 | {:dependencies [[figwheel-sidecar ~figwheel-version]] 184 | :repl-options {:init ^:replace (do 185 | (require 'dirac.agent) 186 | (use 'figwheel-sidecar.repl-api) 187 | (start-figwheel! 188 | {:figwheel-options {:server-port 7111} ;; <-- figwheel server config goes here 189 | :build-ids ["demo"] ;; <-- a vector of build ids to start autobuilding 190 | :all-builds ;; <-- supply your build configs here 191 | [{:id "demo" 192 | :figwheel true 193 | :source-paths ["src/shared" 194 | "src/demo"] 195 | :compiler {:output-to "resources/public/.compiled/demo/demo.js" 196 | :output-dir "resources/public/.compiled/demo" 197 | :asset-path ".compiled/demo" 198 | :preloads ['devtools.preload 'dirac.runtime.preload] 199 | :main 'dirac-sample.demo 200 | :optimizations :none 201 | :source-map true}}]}) 202 | (dirac.agent/boot!) 203 | #_(cljs-repl)) 204 | 205 | } 206 | }] 207 | 208 | ; -------------------------------------------------------------------------------------------------------------- 209 | :checkouts 210 | {:checkout-deps-shares ^:replace [:source-paths 211 | :test-paths 212 | :resource-paths 213 | :compile-path 214 | #=(eval leiningen.core.classpath/checkout-deps-paths)] 215 | :cljsbuild {:builds 216 | {:demo 217 | {:source-paths ["checkouts/cljs-devtools/src/lib" 218 | "checkouts/dirac/src/runtime"]} 219 | :tests 220 | {:source-paths ["checkouts/cljs-devtools/src/lib" 221 | "checkouts/dirac/src/runtime"]}}}} 222 | 223 | ; -------------------------------------------------------------------------------------------------------------- 224 | :debugger-5005 225 | {:jvm-opts ["-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005"]} 226 | 227 | :suspended-debugger-5005 228 | {:jvm-opts ["-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=5005"]} 229 | 230 | :debugger-5006 231 | {:jvm-opts ["-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5006"]} 232 | 233 | :suspended-debugger-5006 234 | {:jvm-opts ["-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=5006"]} 235 | 236 | :debugger-5007 237 | {:jvm-opts ["-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5007"]} 238 | 239 | :suspended-debugger-5007 240 | {:jvm-opts ["-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=5007"]} 241 | 242 | ; -------------------------------------------------------------------------------------------------------------- 243 | :cooper-config 244 | {:cooper {"figwheel" ["lein" "dev-fig"] 245 | "server" ["lein" "dev-server"]}}} 246 | 247 | ; ========================================================================================================================= 248 | 249 | :aliases {"demo" "demo110" 250 | 251 | "demo110" ["with-profile" "+demo,+clojure110" "do" 252 | ["clean"] 253 | ["cljsbuild" "once"] 254 | ["shell" "scripts/dev-server.sh"]] 255 | "demo19" ["with-profile" "+demo,+clojure19" "do" 256 | ["clean"] 257 | ["cljsbuild" "once"] 258 | ["shell" "scripts/dev-server.sh"]] 259 | "demo18" ["with-profile" "+demo,+clojure18" "do" 260 | ["clean"] 261 | ["cljsbuild" "once"] 262 | ["shell" "scripts/dev-server.sh"]] 263 | "demo17" ["with-profile" "+demo,+clojure17" "do" 264 | ["clean"] 265 | ["cljsbuild" "once"] 266 | ["shell" "scripts/dev-server.sh"]] 267 | "demo-advanced" ["with-profile" "+demo-advanced" "do" 268 | ["cljsbuild" "once"] 269 | ["shell" "scripts/dev-server.sh"]] 270 | 271 | "demo-node" "demo-node110" 272 | "demo-node110" ["with-profile" "+demo-node,+clojure110" "do" 273 | ["clean"] 274 | ["cljsbuild" "once"] 275 | ["shell" "scripts/run-node-demo.sh"]] 276 | "demo-node19" ["with-profile" "+demo-node,+clojure19" "do" 277 | ["clean"] 278 | ["cljsbuild" "once"] 279 | ["shell" "scripts/run-node-demo.sh"]] 280 | "demo-node18" ["with-profile" "+demo-node,+clojure18" "do" 281 | ["clean"] 282 | ["cljsbuild" "once"] 283 | ["shell" "scripts/run-node-demo.sh"]] 284 | "demo-node17" ["with-profile" "+demo-node,+clojure17" "do" 285 | ["clean"] 286 | ["cljsbuild" "once"] 287 | ["shell" "scripts/run-node-demo.sh"]] 288 | "demo-node-dev" ["with-profile" "+demo-node,+clojure-current,+checkouts" "do" 289 | ["cljsbuild" "once" "demo"] 290 | ["shell" "scripts/run-node-demo.sh"]] 291 | "demo-node-dev-inlined-sm" ["with-profile" "+demo-node,+demo-node-inline-sm,+clojure-current,+checkouts" "do" 292 | ["cljsbuild" "once" "demo"] 293 | ["shell" "scripts/run-node-demo.sh" "1"]] 294 | 295 | "repl17" ["with-profile" "+repl,+clojure17" "repl"] 296 | "repl18" ["with-profile" "+repl,+clojure18" "repl"] 297 | "repl19" ["with-profile" "+repl,+clojure19" "repl"] 298 | "repl110" ["with-profile" "+repl,+clojure110" "repl"] 299 | "repl-dev" ["with-profile" "+repl,+clojure-current,+checkouts,+dirac-logging,+debugger-5005" "repl"] 300 | "repl-cider" ["with-profile" "+repl,+clojure-current,+cider" "repl"] 301 | "repl-figwheel" ["with-profile" "+repl,+clojure-current,+checkouts,+figwheel-nrepl" "repl"] 302 | 303 | "fig-repl" ["with-profile" "+repl,+clojure-current,+figwheel-config,+figwheel-repl" "figwheel"] 304 | "auto-compile-tests" ["with-profile" "+tests,+checkouts" "cljsbuild" "auto"] 305 | "auto-compile-demo" ["with-profile" "+demo,+checkouts" "cljsbuild" "auto"] 306 | "dev-fig" ["with-profile" "+demo,+tests,+checkouts,+figwheel-config" "figwheel" "demo" "tests"] 307 | "dev-server" ["shell" "scripts/dev-server.sh"] 308 | "dev" ["with-profile" "+cooper-config" "do" 309 | ["clean"] 310 | ["cooper"]]}) 311 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # This project is deprecated since Dirac v1.4.0 2 | 3 | Please use Dirac integration examples in 4 | 5 | [https://github.com/binaryage/dirac/tree/master/examples](https://github.com/binaryage/dirac/tree/master/examples) 6 | 7 | --- 8 | --- 9 | --- 10 | 11 | # dirac-sample [![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg)](license.txt) 12 | 13 | This project is an example of integration of [**Dirac DevTools**](https://github.com/binaryage/dirac) into a 14 | Leiningen-based ClojureScript project. 15 | 16 | ![](https://box.binaryage.com/dirac-main-01.png) 17 | 18 | ## Local setup 19 | 20 | git clone https://github.com/binaryage/dirac-sample.git 21 | cd dirac-sample 22 | 23 | ## Demo time! 24 | 25 | ### Installation 26 | 27 | Launch latest [Chrome Canary](https://www.google.com/chrome/browser/canary.html) from command-line. 28 | I recommend to run it with a dedicated user profile, because you will install there a helper [Chrome Extension](https://chrome.google.com/webstore/detail/dirac-devtools/kbkdngfljkchidcjpnfcgcokkbhlkogi). 29 | Also you have to run it with [remote debugging](https://developer.chrome.com/devtools/docs/debugger-protocol) enabled on port 9222 (better make an alias of this command): 30 | 31 | /Applications/Google\ Chrome\ Canary.app/Contents/MacOS/Google\ Chrome\ Canary \ 32 | --remote-debugging-port=9222 \ 33 | --no-first-run \ 34 | --user-data-dir=.test-dirac-chrome-profile 35 | 36 | Now you can install the [Dirac DevTools Chrome extension](https://chrome.google.com/webstore/detail/dirac-devtools/kbkdngfljkchidcjpnfcgcokkbhlkogi). 37 | 38 | After installation, should see a new extension icon next to your address bar . 39 | 40 | Now you can launch the demo project from terminal: 41 | 42 | lein demo 43 | 44 | At this point you should have a demo website running at [http://localhost:9977](http://localhost:9977). 45 | 46 | Please navigate there, do not open internal DevTools and click Dirac icon while on the `http://localhost:9977/demo.html` page. 47 | It should open you a new window with Dirac DevTools app. 48 | It will look almost the same as internal DevTools, but you can tell the difference at first glance: active tab highlight 49 | will be green instead of blue (see the screenshots above). 50 | 51 | Ok, now you can switch to Javascript Console in Dirac DevTools. Focus prompt field and press `CTRL+,` or `CTRL+.`. 52 | This will cycle between Javascript to ClojureScript REPL prompts. 53 | 54 | You should see a red message on a green background: `Dirac Agent is not listening at ws://localhost:8231 (need help?).` 55 | 56 | That's correct. Dirac REPL uses nREPL protocol so we have to provide it with some nREPL server. 57 | Luckily enough leiningen offers nREPL server by simply running (in a new terminal session): 58 | 59 | lein repl 60 | 61 | The terminal should print something similar to this: 62 | 63 | Compiling ClojureScript... 64 | nREPL server started on port 8230 on host 127.0.0.1 - nrepl://127.0.0.1:8230 65 | REPL-y 0.3.7, nREPL 0.2.12 66 | Clojure 1.8.0 67 | Java HotSpot(TM) 64-Bit Server VM 1.8.0_60-b27 68 | Docs: (doc function-name-here) 69 | (find-doc "part-of-name-here") 70 | Source: (source function-name-here) 71 | Javadoc: (javadoc java-object-or-class-here) 72 | Exit: Control+D or (exit) or (quit) 73 | Results: Stored in vars *1, *2, *3, an exception in *e 74 | 75 | user=> 76 | Dirac Agent v0.5.0 77 | Connected to nREPL server at nrepl://localhost:8230. 78 | Agent is accepting connections at ws://localhost:8231. 79 | 80 | Last three lines ensure you that Dirac Agent was launched alongside your nREPL server. It connected to it and is accepting 81 | DevTools connections on the websocket port 8231. 82 | 83 | After your Dirac Agent is up your Dirac DevTools should eventually reconnect. 84 | 85 | Connected? The red message should go away and you should see `cljs.user` indicating your 86 | current namespace. REPL is ready for your input at this point. You can try: 87 | 88 | (+ 1 2) 89 | js/window 90 | (doc filter) 91 | (filter odd? (range 42)) 92 | 93 | If you see something very similar to the first screenshot at the top, you have Dirac running properly. 94 | 95 | **Congratulations!** 96 | 97 | ### Hello, World! 98 | 99 | Let's try to call `hello!` function from our namespace `dirac-sample.demo`. 100 | 101 | (dirac-sample.demo/hello! "World") 102 | 103 | It worked `"Hello, World!"` was logged into the console (white background means that the logging output originated in Javascript land). 104 | 105 | As you probably know you should first require (or eval) namespace in the REPL context to make it aware of namespace content. 106 | 107 | (require 'dirac-sample.demo) 108 | 109 | But still you have to type fully qualified name because currently you are in `cljs.user` namespace. To switch you can use `in-ns` special function. 110 | 111 | Let's try it: 112 | 113 | (in-ns) 114 | 115 | You get an error `java.lang.IllegalArgumentException: Argument to in-ns must be a symbol.`. This is a Java exception from nREPL side. 116 | Execute `(doc in-ns)` to see the documentation for this special REPL function. It expects namespace name as the first argument. 117 | 118 | (in-ns 'dirac-sample.demo) 119 | (hello! "Dirac") 120 | 121 | Should log `Hello, Dirac!` into the console without warnings. 122 | 123 | ### Breakpoints 124 | 125 | You can also test evaluation of ClojureScript in the context of selected stack frame when paused on a breakpoint: 126 | 127 | 1. click the "demo a breakpoint" button on the page 128 | 2. debugger should pause on the `(js-debugger)` line in the breakpoint-demo function 129 | 130 | Custom formatters should be presented as inlined values in the source code. 131 | Also property names in the scope panel are sorted and displayed in a more friendly way. 132 | 133 | Now hit ESC to bring up console drawer. Make sure you are switched to Dirac REPL and then enter: 134 | 135 | numbers 136 | 137 | You should see actual value `(0 1 2)` of the `numbers` variable from local scope (formatted by custom formatters from cljs-devtools). 138 | Same way as you would expect when evaluating a Javascript command in a breakpoint context. Actually you can try it. 139 | Hit `CTRL+.` to switch to Javascript console prompt (white background) and enter: 140 | 141 | numbers 142 | 143 | This should return the same output. 144 | 145 | And now return back to Dirac REPL by pressing `CTRL+.` again and enter: 146 | 147 | (str (map inc numbers)) 148 | 149 | You should get back a string `"(1 2 3)"`. 150 | 151 | This is a proof that Dirac REPL can execute arbitrary ClojureScript code in the context of a selected stack frame. 152 | -------------------------------------------------------------------------------- /resources/public/demo.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Dirac DevTools Demo 5 | 6 | 7 | 8 | 9 | 10 |

Dirac DevTools Demo Project

11 |

12 | Dirac DevTools provides a custom DevTools frontend packaged in a Chrome Extension.
13 | To use REPL from Dirac you also need to start an nREPL server and a Dirac Agent server.
14 | Please follow the setup steps on the homepage to exercise it. 15 |

16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /resources/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Dirac DevTools Index 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /resources/public/inline_breakpoints.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /resources/public/issue_53.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /resources/public/issue_7.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /resources/public/playground.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |

Playground

10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /resources/public/styles/default.css: -------------------------------------------------------------------------------- 1 | html { font-family: arial } 2 | -------------------------------------------------------------------------------- /resources/public/tests.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Dirac DevTools Tests 5 | 6 | 7 | 8 | 9 |

Dirac DevTools ad-hoc manual tests

10 |

note: you have run `lein dev` instead of `lein demo` to have these tests compiled:

11 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /scripts/dev-server.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | 5 | cd "$(dirname "${BASH_SOURCE[0]}")"; cd .. 6 | 7 | ROOT=`pwd` 8 | DEVSERVER_ROOT="$ROOT/resources/public" 9 | DEVSERVER_PORT=9977 10 | 11 | cd "$DEVSERVER_ROOT" 12 | 13 | set +e 14 | PYTHON_PATH=`which python` 15 | set -e 16 | if [ -z "$PYTHON_PATH" ]; then 17 | echo "Error: python does not seem to be installed on your PATH. We use python to start a simple HTTP server." 18 | exit 3 19 | else 20 | echo "Starting HTTP server on port $DEVSERVER_PORT => http://localhost:$DEVSERVER_PORT" 21 | fi 22 | 23 | # taken from https://stackoverflow.com/a/52967771/84283 24 | VERSION=$(python -V 2>&1 | cut -d\ -f 2) # python 2 prints version to stderr 25 | VERSION=(${VERSION//./ }) # make an version parts array 26 | if [[ ${VERSION[0]} -lt 3 ]]; then 27 | LAUNCH_SERVER_CMD="python -m SimpleHTTPServer" 28 | else 29 | LAUNCH_SERVER_CMD="python -m http.server" 30 | fi 31 | 32 | ${LAUNCH_SERVER_CMD} "$DEVSERVER_PORT" 2> /dev/null \ 33 | || echo "Error: failed to start '${LAUNCH_SERVER_CMD} ...', do you have python properly installed? isn't the port $DEVSERVER_PORT already used?" 34 | -------------------------------------------------------------------------------- /scripts/reveal.cljs: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env lumo 2 | 3 | ; this is an example fuzzy matcher to open devtools urls via nREPL 4 | 5 | (ns fuzzy.finder 6 | (:require [lumo.core :refer [*command-line-args*]] 7 | [clojure.string :as string])) 8 | 9 | ; -- node requires ---------------------------------------------------------------------------------------------------------- 10 | 11 | (def url-api (js/require "url")) 12 | (def fs-api (js/require "fs")) 13 | (def child-process-api (js/require "child_process")) 14 | 15 | ; -- config ----------------------------------------------------------------------------------------------------------------- 16 | 17 | ; TODO: make this configurable externally? 18 | (def search-dirs ["src" "resources/public"]) ; folders will be searched in this order 19 | 20 | ; -- utils ------------------------------------------------------------------------------------------------------------------ 21 | 22 | (defn coerce-buffer-to-string [buffer & [encoding]] 23 | (if (js/Buffer.isBuffer buffer) 24 | (.toString buffer (or encoding "utf-8")) 25 | (.toString buffer))) 26 | 27 | (defn print-err [& args] 28 | (binding [*print-fn* *print-err-fn*] 29 | (apply println args))) 30 | 31 | (defn list-dir [dir] 32 | (let [items (map #(str dir "/" %) (.readdirSync fs-api dir)) 33 | * (fn [item] 34 | (let [stat (.lstatSync fs-api item)] 35 | (if (.isDirectory stat) 36 | (list-dir item) 37 | [item])))] 38 | (mapcat * items))) 39 | 40 | (defn path-segments [path] 41 | (filter (complement empty?) (string/split path "/"))) 42 | 43 | (defn strip-extra-nil-args [args] 44 | (reverse (drop-while nil? (reverse args)))) 45 | 46 | (defn call-spawn-api! [& args] 47 | (let [sanitized-args (strip-extra-nil-args args)] ; node API is strict about extra nil args 48 | (.apply (.-spawnSync child-process-api) child-process-api (into-array sanitized-args)))) 49 | 50 | (defn spawn! [cmd & [args opts]] 51 | (let [result (call-spawn-api! cmd (into-array args) opts) 52 | stdout (.-stdout result) 53 | stderr (.-stderr result) 54 | status (.-status result)] 55 | (if stdout 56 | (println (coerce-buffer-to-string stdout))) 57 | (if stderr 58 | (print-err (coerce-buffer-to-string stderr))) 59 | status)) 60 | 61 | ; -- fuzzy search for best match -------------------------------------------------------------------------------------------- 62 | 63 | (defn filter-files-by-filename [files filename] 64 | (let [postfix (str "/" filename)] 65 | (filter #(string/ends-with? % postfix) files))) 66 | 67 | (defn compute-score [reversed-candidate reversed-ideal] 68 | (count (take-while true? (map = reversed-candidate reversed-ideal)))) 69 | 70 | (defn compute-file-score [reversed-ideal file] 71 | (let [score (compute-score (reverse (path-segments file)) reversed-ideal)] 72 | [file score])) 73 | 74 | (defn compare-files-scores [file-score1 file-score2] 75 | (compare (second file-score1) (second file-score2))) 76 | 77 | (defn compute-score-table [files ideal] 78 | (let [reversed-ideal (reverse ideal) 79 | table (map (partial compute-file-score reversed-ideal) files)] 80 | (reverse (sort compare-files-scores table)))) 81 | 82 | (defn find-best-candidate [file-path dir] 83 | (let [file-segments (path-segments file-path) 84 | filename (last file-segments) 85 | all-files (list-dir dir) 86 | candidate-files (filter-files-by-filename all-files filename) 87 | score-table (compute-score-table candidate-files file-segments) 88 | best-candidate (first score-table)] 89 | best-candidate)) 90 | 91 | (defn strong-candidate? [file-score] 92 | (> (second file-score) 1)) 93 | 94 | (defn select-matching-file-for-url [file-url] 95 | (let [parsed-url (.parse url-api file-url) 96 | file-path (.-pathname parsed-url) 97 | best-candidates (keep (partial find-best-candidate file-path) search-dirs) ; for each search-dir find the best candidate 98 | strong-candidates (filter strong-candidate? best-candidates) ; take only candidates with score > 1 (thanks to clojure's convention assume we have at least 2-segment namespaces) 99 | winner (first (first strong-candidates))] 100 | winner)) 101 | 102 | ; -- opening files ---------------------------------------------------------------------------------------------------------- 103 | 104 | (defmulti open-file! (fn [tool & _args] (keyword tool))) 105 | 106 | (defmethod open-file! :idea [_ path line _column] 107 | (let [file+line (str path ":" line)] 108 | (spawn! "idea" [file+line]))) 109 | 110 | ; -- main work -------------------------------------------------------------------------------------------------------------- 111 | 112 | (defn work! [& [file-url line column]] 113 | (if-let [matching-file (select-matching-file-for-url file-url)] 114 | (do 115 | (println (str "Requested url: " file-url "\n" 116 | "Matching file: '" matching-file "'")) 117 | (open-file! :idea matching-file line column)) 118 | (do 119 | (print-err (str "No matching file found for url: " file-url)) 120 | 1))) 121 | 122 | (defn main! [args] 123 | (try 124 | (apply work! args) 125 | (catch :default e 126 | (print-err (str "Exception: " (.-message e) "\n" (.-stack e))) 127 | 101))) 128 | 129 | ; -- entry point ------------------------------------------------------------------------------------------------------------ 130 | 131 | (js/process.exit (main! *command-line-args*)) 132 | -------------------------------------------------------------------------------- /scripts/reveal.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | 5 | # set working directory as project's root now 6 | cd "$(dirname "${BASH_SOURCE[0]}")"; cd .. 7 | 8 | ./scripts/reveal.cljs $@ 9 | -------------------------------------------------------------------------------- /scripts/run-demo-node-source-maps-server.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | 5 | cd "$(dirname "${BASH_SOURCE[0]}")"; cd .. 6 | 7 | ROOT=`pwd` 8 | SERVER_ROOT="$ROOT/resources/demo-node" 9 | SERVER_PORT=9988 10 | 11 | pushd "$SERVER_ROOT" > /dev/null 12 | 13 | set +e 14 | PYTHON_PATH=`which python` 15 | set -e 16 | if [ -z "$PYTHON_PATH" ]; then 17 | echo "Error: python does not seem to be installed on your PATH. We use python to start a simple HTTP server." 18 | exit 3 19 | else 20 | echo "Starting HTTP server on port $SERVER_PORT => http://localhost:$SERVER_PORT" 21 | fi 22 | 23 | python -m SimpleHTTPServer "$SERVER_PORT" 2> /dev/null \ 24 | || echo "Error: failed to start 'python -m SimpleHTTPServer ...', do you have python properly installed? isn't the port $SERVER_PORT already used?" 25 | 26 | popd 27 | -------------------------------------------------------------------------------- /scripts/run-node-demo.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | 5 | # http://stackoverflow.com/a/22644006/84283 6 | trap "exit" INT TERM 7 | trap "kill 0" EXIT 8 | 9 | cd "$(dirname "${BASH_SOURCE[0]}")"; cd .. 10 | 11 | ROOT=`pwd` 12 | NODE_TARGET_ROOT="$ROOT/resources/demo-node" 13 | 14 | if [ -z "$1" ]; then 15 | echo "launching source-maps server..." 16 | scripts/run-demo-node-source-maps-server.sh & 17 | fi 18 | 19 | pushd "$NODE_TARGET_ROOT" > /dev/null 20 | 21 | node --inspect .compiled/demo.js 22 | 23 | popd 24 | -------------------------------------------------------------------------------- /src/demo-node/dirac_sample/demo.cljs: -------------------------------------------------------------------------------- 1 | (ns dirac-sample.demo 2 | (:require-macros [dirac-sample.logging :refer [log]]) 3 | (:require [dirac.runtime :as dirac] 4 | [cljs.nodejs :as nodejs])) 5 | 6 | ; -- hello demo ------------------------------------------------------------------------------------------------------------- 7 | 8 | (defn hello! [greetings] 9 | (log (str "Hello, " (or greetings "there") "!"))) 10 | 11 | ; -- breakpoint demo -------------------------------------------------------------------------------------------------------- 12 | 13 | (defn breakpoint-demo [count] 14 | (let [numbers (range count)] 15 | (doseq [number numbers] 16 | (let [is-odd? (odd? number) 17 | line (str "number " number " is " (if is-odd? "odd" "even"))] 18 | (println line) 19 | (println "should stop on a breakpoint (if debugger attached)...") 20 | (js-debugger))))) 21 | 22 | (defn call-breakpoint-demo! [] 23 | (log "calling breakpoint-demo:") 24 | (breakpoint-demo 3)) 25 | 26 | ; -- debugger exercise ------------------------------------------------------------------------------------------------------ 27 | 28 | (defn on-user-input [_text] 29 | (call-breakpoint-demo!) 30 | (println "Press ENTER to repeat or CTRL+C to exit")) 31 | 32 | ; http://st-on-it.blogspot.cz/2011/05/how-to-read-user-input-with-nodejs.html 33 | (defn start-input-loop! [callback] 34 | (let [stdin js/process.stdin] 35 | (.setEncoding stdin "utf8") 36 | (.resume stdin) 37 | (.on stdin "data" callback))) 38 | 39 | (defn run-debugger-exercise! [] 40 | (println "attach a debugger and hit ENTER to call-breakpoint-demo!") 41 | (start-input-loop! on-user-input)) 42 | 43 | ; -- main ------------------------------------------------------------------------------------------------------------------- 44 | 45 | (defn -main [& args] 46 | (hello! "Dirac") 47 | (println "tag:" (dirac/get-tag)) 48 | (run-debugger-exercise!)) 49 | 50 | (nodejs/enable-util-print!) 51 | (set! *main-cli-fn* -main) 52 | -------------------------------------------------------------------------------- /src/demo/dirac_sample/demo.cljs: -------------------------------------------------------------------------------- 1 | (ns dirac-sample.demo 2 | (:require-macros [dirac-sample.logging :refer [log]]) 3 | (:require [dirac.runtime :as dirac])) 4 | 5 | ; -- installation ----------------------------------------------------------------------------------------------------------- 6 | 7 | (enable-console-print!) 8 | 9 | (println "tag:" (dirac/get-tag)) 10 | 11 | ; -- hello demo ------------------------------------------------------------------------------------------------------------- 12 | 13 | (defn hello! [greetings] 14 | (log (str "Hello, " (or greetings "there") "!"))) 15 | 16 | ; -- breakpoint demo -------------------------------------------------------------------------------------------------------- 17 | 18 | (defn breakpoint-demo [count] 19 | (let [numbers (range count)] 20 | (doseq [number numbers] 21 | (let [is-odd? (odd? number) 22 | line (str "number " number " is " (if is-odd? "odd" "even"))] 23 | (js-debugger) 24 | (println line))))) 25 | 26 | (defn ^:export breakpoint-demo-handler [] 27 | (log "calling breakpoint-demo:") 28 | (breakpoint-demo 3)) 29 | 30 | (comment 31 | ; 32 | ; some things to test in "joined" Cursive REPL 33 | ; 34 | ; 0. make sure nREPL server is up and running and your Dirac DevTools REPL is connected 35 | ; 1. connect Cursive to remote REPL on port 8230 36 | ; 2. run (dirac! :join) 37 | ; 3. switch to this file, 38 | ; 4 use Cursive's Tools -> REPL -> 'Switch REPL NS to current file' 39 | ; 5. use Cursive's Tools -> REPL -> 'Load File in REPL' 40 | ; 6. move cursor at closing brace of following form and use Cursive's Tools -> REPL -> 'Send ... to REPL' 41 | ; 42 | (hello! "from Cursive REPL")) 43 | 44 | (log "demo loaded") 45 | -------------------------------------------------------------------------------- /src/shared/dirac_sample/logging.clj: -------------------------------------------------------------------------------- 1 | (ns dirac-sample.logging) 2 | 3 | (defmacro log [& args] 4 | `(do (.log js/console ~@args) nil)) -------------------------------------------------------------------------------- /src/tests/dirac_sample/inline_breakpoints.cljs: -------------------------------------------------------------------------------- 1 | (ns dirac-sample.inline-breakpoints 2 | (:require-macros [dirac-sample.logging :refer [log]]) 3 | (:require [clojure.string :as string])) 4 | 5 | (defn ^:export trigger [] 6 | (map (fn [x] (str x)) (range 10)) 7 | (-> "abc_efg" 8 | (string/upper-case) 9 | (string/replace #"ABC" "XYZ"))) 10 | -------------------------------------------------------------------------------- /src/tests/dirac_sample/issue_53.cljs: -------------------------------------------------------------------------------- 1 | (ns dirac-sample.issue-53 2 | (:require-macros [dirac-sample.logging :refer [log]])) 3 | 4 | ; https://github.com/binaryage/dirac/issues/53 5 | 6 | (defn repro [count] 7 | (let [x 1 8 | y 2 9 | x 3 10 | z #(println x)] 11 | (js-debugger))) 12 | 13 | (defn ^:export trigger [] 14 | (repro 3)) 15 | -------------------------------------------------------------------------------- /src/tests/dirac_sample/issue_7.cljs: -------------------------------------------------------------------------------- 1 | (ns dirac-sample.issue-7 2 | (:require-macros [dirac-sample.logging :refer [log]])) 3 | 4 | ; https://github.com/binaryage/dirac/issues/7 5 | 6 | (def circular1 (atom nil)) 7 | (reset! circular1 circular1) 8 | 9 | (defn ^:export trigger [] 10 | (let [circular circular1] 11 | ; at this point we should be able to play with infinitely expanding structure "circular" in Scope Panel to expose issue #7 12 | (js-debugger))) 13 | 14 | (new x) 15 | -------------------------------------------------------------------------------- /src/tests/dirac_sample/main.cljs: -------------------------------------------------------------------------------- 1 | (ns dirac-sample.main) 2 | 3 | ; intentionally left empty 4 | ; we need :main for :preloads to work properly 5 | -------------------------------------------------------------------------------- /src/tests/dirac_sample/playground.cljs: -------------------------------------------------------------------------------- 1 | (ns dirac-sample.playground 2 | (:require-macros [dirac-sample.logging :refer [log]]) 3 | (:require [goog.i18n.uChar :as u] 4 | [clojure.string :as s])) 5 | 6 | ; https://github.com/binaryage/dirac/issues/58 7 | (log "u/toCharCode" u/toCharCode (u/toCharCode "a")) 8 | 9 | (log "s/reverse" s/reverse (s/reverse "abc")) 10 | --------------------------------------------------------------------------------