DEV Community

bop
bop

Posted on

Making shadow-cljs REPL's More Interactive

So, if you ever tried to use some REPL you remember to be able to move your cursor not only sideways but also up and down to go trough some history.

On Clojure, this is very important and if you ever used Clojure's CLI you know that we end up with two executables on our machine: clj and clojure.

What is the difference between them?

So if you run $ clojure or $ clj, both will give you an interactive REPL to use. But they have some different behavior on them. Let's see:

Using clojure

clojure cli running

Using clj

clj cli running

As you can see when using clj instead clojure all the interactions you see happen with no problem.

But what's the difference?

Well, clj is using a tool to make it more interactive. This tool is called rwrap.

rwrap stands for "readline wrapper," and it is a utility primarily used to add readline functionality to command-line applications that lack built-in line editing capabilities.

It enhances the user experience by providing features like command history, line editing (such as editing and deleting characters in the input line), and command completion in terminal-based applications that do not inherently support these functionalities.

If we open the clj file we will see something like this:

#!/usr/bin/env bash

bin_dir=/usr/local/Cellar/clojure/1.11.1.1149/bin

if type -p rlwrap >/dev/null 2>&1; then
  exec rlwrap -r -q '\"' -b "(){}[],^%#@\";:'" "$bin_dir/clojure" "$@"
else
  echo "Please install rlwrap for command editing or use \"clojure\" instead."
  exit 1
fi
Enter fullscreen mode Exit fullscreen mode

Which, in other words, it's a script that wraps the clojure cli into rlwrap. Got it?

The thing is that shadow-cljs doesn't have that helper. So, when using any of the available terminal REPL's, like node-repl, it messes up everything and it's very hard to use.

Take a look

shadow-cljs

What's the solution for this?

Based on the clj script I added to my PATH the cljs script. That does the same thing but tries to find the installed shadow-cljs or fall back to the global one.

That's the final script I've been using:

#!/usr/bin/env bash

local_install=$(realpath ./node_modules/.bin/shadow-cljs)
global_install=/usr/local/bin/shadow-cljs
usable_install=$(if [ -f "$local_install" ]; then echo "$local_install"; else echo "$global_install"; fi)

if type -p rlwrap >/dev/null 2>&1; then
  exec rlwrap -r -q '\"' -b "(){}[],^%#@\";:'" "$usable_install" "$@"
else
  echo "Please install rlwrap for command editing."
  exit 1
fi
Enter fullscreen mode Exit fullscreen mode

I've saved it as cljs on my PATH. And now I can do this:

cljs shining

The end

In this article, we have learned how to improve the interactivity of Shadow CLJS REPLs by adding features like cursor navigation and command history. The solution discussed was to wrap Shadow CLJS in the rlwrap utility, similar to how the Clojure tool clj works. By using a simple script to launch Shadow CLJS through rlwrap, we can now fully enjoy the interactive REPL experience that is crucial for building and testing ClojureScript applications.

Thank you for reading!

Top comments (0)