Interactive development with Ruby and Clojure for the Pulsar editor!
Lazuli the evolution of
Chlorine, for the both Clojure
and Ruby languages (and possibly more in the future!). It aims to bring the
features of Chlorine to any supported language - basically, semantic
autocomplete and go to var definition using runtime information (that is, a code
that is running) instead of relying on static analysis that might miss most
cases, like dynamic definition of methods using has_many
, belongs_to
, or
even by defining routes in Rails
Lazuli connects to a nREPL server like nrepl-lazuli for Ruby, or nREPL for Clojure. For ClojureScript, it also allows you to connect directly to Shadow-CLJS.
It will use runtime information to evaluate code inside the editor, and also add
some semantic information like where some function/method was defined. In Ruby,
for example, it'll try to avoid going to the first definition (which usually is
just a Gem or other library) and match the actual user's code (as it's possible
to see in the example below, where Go To Var Definition goes to has_many
and
to the actual routes.rb
). It also adds semantic autocomplete, meaning that it
uses runtime info to actually run code to complete stuff (that might be
dangerous if one of the code is trying to remove a file, for example, so use it
with caution).
Lazuli connects to a Clojure REPL. Different from other plug-ins, Lazuli tries
to understand the EDN that's being returned, and then display in a meaningful
way (collections are rendered like trees, tagged literals can be expanded, big
strings can be printed as string format like "some\nthing"
or can be
"expanded" so that newlines become real newlines and it's possible to see the
full string, etc).
For ClojureScript, there are some enhancements to the overall experience: Lazuli can show compilation errors, and it will also show if the compilation failed:
Also, for stacktraces, Lazuli will try to use a source map and map your stacktraces to CLJS files. This can also be disabled, if you want to check exactly what was the Javascript code that the compiler generated
Lazuli traces your code to check where a method was called, and then keeps a
binding of it. You can check these traces in the "Trace" section of the "Lazuli
REPL" tab, and filter by typing parts of a filename (like controller
for
example). The traces are shown in the order they were executed - so if you
visted a "Users List" page in Rails, it'll probably have a trace like
users_controller.rb
> user.rb
> index.html.erb
.
Traces also automatically generate "Watch Points" for you
Watch points can be added manually (more on that on future versions, for now it's a little buggy) or automatically by Lazuli. One way they are generated automatically are by tracing the code, which Lazuli does by default (it'll be configurable in the future, it might be a performance hit in some edge cases) or by running the command "Load File and Inspect" which will instrument the current file and, as soon as you hit that code, it'll make the watch point for you.
Watch points are basically "saved context" (or, to use Ruby's correct terms,
binding
s) so that you can evaluate code inside an instance or method. This
also adds semantic autocomplete and goto var definition (it does that by running
your code and checking results, trying to comple the last portion of your call.
So, for example, my.object.cal
<- if you put the cursor at the end of this
word, Lazuli will evaluate my.object
, get the result of it and call .methods
on it to check which methods are available for autocomplete).
Watch points are not bullet-proof - Lazuli will try to use the closest watch point it finds related to the current row/column the current editor is pointing to. For example, suppose we have the code:
def something(a, b)
"#{a.upcase} - #{b.downcase}"
end
def other_thing(a, b)
a / b
end
If we have a watch point in the first method - that is, something
- and we
try to evaluate something inside the second method - the other_thing
- it
will happily use the first method's watch point and we will have an unreliable
result - that is, a
and b
being strings instead of numbers. To fix this,
just run some code that touches other_thing
.
Install nrepl-lazuli and configure your app to run the nREPL server (more info on the nREPL Lazuli repo). Connect the editor to that REPL, and interact with the code you want to evaluate, to generate traces and watch points. Then, have fun!
By default, the package register keybindings for evaluating code. CTRL+Enter will evaluate a "top-block" and SHIFT+Enter will evaluate a "block". See docs/blocks.md to check what are these things.
If you have something selected, you can hit "CTRL+Enter" to evaluate only the selected text. With Ruby, this will also use the "watch points" so you can evaluate a local variable if you have a watch point with that binding saved.
Lazuli will also define ctrl-alt-shift-down
to "goto definition", ctrl-shit-c
to clear-console, and ctrl-shit-r
to clear the inline results. These will be bound only if you don't use the VIM-Mode Plus package.
If you do, while in Normal Mode, these keybindings will be bound to g f
(go to definition), space l
to clear console, and space space
to clear the inline results. You can change these bindings on your keymaps file, and you can add more keybindings at any time.
This project, and others exist thanks to all the people who contribute, both from this repo or from the old Chlorine one.
Please notice that the contributions mention Chlorine. Both Lazuli and Chlorine share more than 80% of the code, so contributing to one will contribute to both.
Become a financial contributor and help us sustain our community. Contribute:
Support this project with your organization. Your logo will show up here with a link to your website. [Contribute]