Skip to content

Latest commit

 

History

History
168 lines (112 loc) · 7.85 KB

guide.adoc

File metadata and controls

168 lines (112 loc) · 7.85 KB

Morse

Why Morse?

One of the prime value propositions in using a Lisp language is that you should be able to interact with your live program. The typical access mechanism for Clojure programs is the REPL, but its print-oriented streaming nature limits interactive and graphical data exploration.

Morse, like REBL before it, is a library that provides a graphical browser for Clojure data that allows active traversal into and back out of nested structures. REBL was intended to sit in the middle of your editor<→process REPL streams and automatically render and cache all REPL results. This made it difficult to integrate in dev environments that used other than raw streaming REPLs. In Morse the emphasis is now on inspecting on demand via the inspect API, and REPL interception is strictly optional. This should make Morse easy to integrate with all dev setups.

An overview of the Morse UI

It’s not always feasible to execute a graphical browser process inside of the program process, e.g. when the inspected program is running remotely. Morse can be configured to connect to and inspect a remote program, a facility built on the new Replicant* libraries. Morse uses Replicant to efficiently and incrementally traverse remote data, extending its power to a variety of new use cases.

Clojure, Morse and the Lisp Value Proposition

Clojure lets programmers solve problems by staying connected to their running programs and live data, incrementally building up both the program and their understanding of the problem they are trying to solve. Morse, Replicant, and the new add-libs features of Clojure version 1.12.0-alpha3 all work together to amplify the power of the programmer during interactive development.

This software is considered an alpha release and subject to change.

More about Morse

Usage

Morse has two inspection modes: in-process and remote. In this section we’ll outline some common use cases and describe how to use Morse in each case.

Using Morse to develop and inspect your application state

Having Morse available as a nimble data inspector in your development process provides a powerful lever for understanding application state and data collections. Morse can run inside of your application process and access its full power and runtime state. Typically, you’ll want to run Morse during development time to gain insight into an evolving application.

This document assumes the use of deps.clj and the Clojure CLI, please read the Leiningen guide for lein use.

To add Morse as a :dev dependency, simply add the following to your deps.edn file:

:aliases
{:dev
  {:extra-deps {io.github.nubank/morse {:git/tag "v2023.04.30.01" :git/sha "d99b09c"}}}
}

With this dependency in place you can run your Clojure REPL with the :dev alias active to make Morse available on the classpath:

clj -A:dev

You then require the Morse namespace:

(require '[dev.nu.morse :as morse])

You then launch the Morse UI:

(morse/launch-in-proc)

The Morse API provides an inspect function taking an object and displaying it in the Morse UI.

(morse/inspect {:a 1 :b 2})

You should see the map {:a 1 :b 2} in the data Morse data browser.

Using Morse to inspect the application state of a remote process

Sometimes you’ll have an application that cannot take Morse as a dependency or perhaps cannot run a GUI. In this circumstance Morse can remotely connect to a process and inspect its state. Morse Remote inspection requires two parts to operate. First, a server component replicant-server runs in the process you wish to inspect (often your REPL). Second, Morse itself acts as a client to that active Replicant server.

In the deps.edn file for the process that you would like to inspect, add the following:

{:dev
  {:extra-deps
    {io.github.clojure/data.alpha.replicant-server {:git/tag "v2023.05.02.01" :git/sha "947d8a8"}}}}
}

After starting the process, will require the Replicant namespace:

(require '[clojure.data.alpha.replicant.server.prepl :as replicant])

You then launch a Replicant server, giving it a :host string mapping and an optional :port number mapping:

(replicant/start :host "hostname" :port num)

Finally, in a terminal start Morse as a CLI tool via:

clj -Tmorse morse :host '"hostname"' :port num

Instructions for installing Morse as a Clojure CLI tool are in the README.

Once connected, the REPL pane in Morse is a remote client of the server (via a socket) of an active Replicant server. Expressions you type into Morse are evaluated in the context of the process hosting the Replicant server. This is just like any remote socket-based REPL. Therefore, in order to view values in Morse is to bind them to vars in the user namespace and evaluate those names in the Morse editor buffer.

Bootstrapping Morse for remote inspection

Sometimes you have an application running that you would like to use Morse inspection to investigate but there is no way to do so because the application doesn’t have replicant-server available. If you’re able to launch a socket REPL in the process that you would like to inspect then there is a way to interactively load Replicant into the running process to enable Morse inspection. Starting with version 1.12.0-alpha3, Clojure provides a capability to add dependencies at run-time using the add-lib function available in the REPL. If your application process is running in a REPL then you can leverage Morse as needed by executing the following steps. This capability relies on Clojure CLI 1.11.1.1267 or later to function. Assuming that your remote process runs in an environment with these versions present then you can use the following steps to connect Morse interactively.

First, in your running process you can add the replicant-server library at run-time using the add-lib function to load the latest version:

(add-lib 'io.github.clojure/data.alpha.replicant-server)

This should load the replicant-server dependency into the running process which will allow you to require the Replicant namespace:

(require '[clojure.data.alpha.replicant.server.prepl :as replicant])

You then launch a Replicant server, giving it a :host string mapping and an optional :port number mapping:

(replicant/start :host "hostname" :port num)

Finally, in a terminal start Morse as a CLI tool via:

clj -Tmorse morse :host '"hostname"' :port num

Instructions for installing Morse as a Clojure CLI tool are in the README.

Once connected, the REPL pane in Morse is a remote client of the server (via a socket) of an active Replicant server. Expressions you type into Morse are evaluated in the context of the process hosting the Replicant server. This is just like any remote socket-based REPL. Therefore, in order to view values in Morse is to bind them to vars in the user namespace and evaluate those names in the Morse editor buffer.

Requirements

  • Clojure, 1.10.0 or higher

  • Java 11 or higher