Reveal 1.0: Read Eval Visualize Loop for Clojure

0

Demo

Repl is a large window accurate into a working program, nonetheless the textual nature of its output limits developer’s skill to glimpse the program: a text is just not an object, and we are facing objects in the VM.

Tag goals to resolve this narrate by organising an in-route of repl output pane that makes inspecting values as easy as deciding on an tantalizing datum. It acknowledges the cost of text as a typical interface, that’s why its output appears love a text: you’re going to be in a situation to amass it, copy it, attach it accurate into a file. Unlike text, point out output holds references to printed values, making inspecting chosen price a topic of opening a context menu.

Unlike datafy/nav primarily based instruments, Tag doesn’t attach in pressure a particular recordsdata illustration for any given object, making it an originate residing — that entails datafy/nav as one among the on hand alternatives. It doesn’t utilize datafy/nav by default on story of in the absence of inter-route of dialog to datafy is to lose.

Now not being restricted to text, Tag uses in level of fact excellent syntax highlighting to assist in differentiating varied objects: text java.lang.Integer appears in any other procedure searching on whether or not it changed into as soon as made from an emblem or a class.

The easiest solution to envision out it’s to speed a Tag repl:

clj 
-Sdeps '{:deps {vlaaad/point out {:mvn/model "1.0.126"}}}' 
-m vlaaad.point out repl

Executing this say will originate a repl and originate Tag output window that will think the evaluations in the shell.

faucet> make stronger

Clojure 1.10 added faucet> characteristic with the motive identical to printing the cost for debugging, nonetheless reasonably than characters you procure the thing. Tag repls present tapped values in their output windows — you won’t need println anymore!

Tap demo

Eval on need

You likely can evaluate code on any chosen price by the utilize of text input in the context menu. You likely can write either a single symbol of a characteristic to call or a bask in the place *v shall be changed with chosen price.

Eval on selection demo

Glimpse object fields and properties

Any object in the JVM has class and fields, making them without be troubled accessible for inspection is incredibly well-known. With java-bean contextual action you procure a debugger-love witness of objects in the VM. Rep admission to to this recordsdata vastly improves the visibility of the VM and permits to explore it. As an instance, for any class you’ve got gotten gotten on the classpath you’re going to be in a situation to procure the placement the place it’s coming from:

Java bean demo
I learned about it after imposing this characteristic 🙂

Discover and feel customization

Tag will also be configured with vlaaad.point out.prefs java property to make utilize of assorted font or theme:

Light theme

URL and file browser

You likely can originate URL-love issues and files: every internally in Tag and externally the utilize of assorted positive aspects for your OS e.g. file explorer, browser or text editor.

Browse demo

Doc and present

Tag can present you documentation and sources for diverse runtime values — namespaces, vars, symbols, positive aspects, keywords (if they elaborate a spec). Fancy cljdoc, it helps [[wikilink]] syntax in docstrings to talk over with assorted vars, making them accessible for extra exploration.

Doc and source demo

Ref watchers

Tag can see any object imposing clojure.lang.IRef (issues love atoms, agents, vars, refs) and masks it either automatically updated or as a log of successors.

Ref watchers demo

Charts

Tag can present recordsdata of particular shapes as charts which may perhaps likely be customarily explorable: even as you occur to search out an tantalizing recordsdata level on the chart, you’re going to be in a situation to then extra glimpse the recordsdata in that recordsdata level.

The most simple form is labeled numbers. Labeled methodology that those numbers exist in some series that has a assorted impress for every number. For maps, keys are labels, for sequential collections, indices are labels and for sets, numbers themselves are labels.

A pie chart reveals labeled numbers:

Pie chart demo

Other charts make stronger more versatile recordsdata shapes — every on story of they’ll present bigger than one recordsdata series, and on story of they’ll also be explored, the place it might likely very neatly be edifying to connect some metadata with the number. Since JVM numbers don’t allow metadata, you’re going to be in a situation to as an substitute utilize tuples the place potentially the well-known item is a host and second is the metadata. Bar charts can masks labeled numbers (single recordsdata series) or labeled numbers which may perhaps likely be themselves labeled (more than one recordsdata series):

Bar chart demo

Line charts are edifying to masks progressions, so Tag suggests them to masks sequential numbers (and labeled sequential numbers):

Line chart demo

In the end, Tag has scatter charts to masks coordinates on a 2D plane. A coordinate is represented as a tuple of two numbers and as with numbers, you’re going to be in a situation to utilize a tuple of coordinate and arbitrary price in the placement of coordinate. Tag will counsel scatter charts for collections of coordinates and labeled collections of coordinates.

Scatter chart demo

Table witness

There are cases the place it’s higher to make sense of the cost when it’s represented by a table: collections of homogeneous objects the place columns support you to evaluate corresponding aspects of those objects, and wide deeply nested recordsdata constructions the place it’s more uncomplicated to stumble on at them layer by layer.

Table view demo

…and more

Tag changed into as soon as designed to be performant: it might perhaps likely movement syntax-highlighted output very rapidly. As neatly as to that, there are varied helpers for recordsdata inspection:

  • text search that is attributable to / or Ctrl F;
  • out of the box lambdaisland’s deep-diff output highlighting: all you’ve got gotten gotten to achieve is occupy it on the classpath;
  • varied contextual actions:
    • deref derefable issues;
    • procure meta if a chosen price has some meta;
    • convert java array to vector;
    • witness the coloration of a aspect that describes a coloration (love "#fff" or :purple);

UI ideas and navigation

Concepts

Tag UI is made from 3 parts:

  • output panel that contains recordsdata submitted to repeat window (e.g. repl output);
  • a context menu that can invoke actions on chosen values;
  • outcomes panel that has 1 or more tabs with action outcomes made from the context menu.

Navigation:

  • Consume Condominium, Enter or suited mouse button to originate a context menu on need;
  • Consume Tab to replace focal level between output and outcomes panel;
  • In outcomes panel:
    • Consume Ctrl ← and Ctrl → to replace tabs in outcomes panel;
    • Consume Esc to finish the tab
  • In a context menu:
    • Consume and to lope focal level between on hand actions and input text field;
    • Consume Enter to achieve chosen action or bask in written in the text field;
    • Consume Esc to finish the context menu.

Customization

Tag will also be custom-made the utilize of vlaaad.point out.prefs java property that contains an edn blueprint of UI preferences. Supported keys (all non-compulsory):

  • :theme — coloration theme, :gentle or :darkish;
  • :font-family — arrangement font title (love "Consolas") or URL (love "file:/route/to/font.ttf" or "https://ff.static.1001fonts.catch/u/b/ubuntu.mono.ttf") — point out handiest helps monospaced fonts;
  • :font-size — font size, number.

Example:

$ clj -A:point out 
-J-Dvlaaad.point out.prefs='{:font-family "Consolas" :font-size 15}' 
-m vlaaad.point out repl

User API

The well-known entry present Tag is vlaaad.point out ns that has varied repls and lower-level efficiency for recordsdata inspection.

repl

It’s a repl wraps clojure.well-known/repl with extra make stronger for :repl/quit and faucet>. It’s miles as easy as it will get. I put it to use the total time. Example:

$ clj -A:point out -m vlaaad.point out repl
# Tag window appears
Clojure 1.10.1
user=>

io-prepl

This prepl works love clojure.core.server/io-prepl. Its motive is to be speed in a route of for your machine that you just may perhaps likely likely very neatly be trying to connect to the utilize of any other prepl-mindful tool. Example:

$ clj -A:point out 
-J-Dclojure.server.point out='{:port 5555 :accept vlaaad.point out/io-prepl}'

Now you’re going to be in a situation to connect to this route of the utilize of any socket repl and this can present a Tag window for every connection:

$ nc localhost 5555
# point out window appears
(+ 1 2 3) # input
{:price :ret, :val "6", :ns "user", :ms 1, :bask in "(+ 1 2 3)"} # output

distant-prepl

Tag is one of the well-known edifying when it runs in the heart of the place the map happens. This prepl, unlike the previous two, is just not love that: it connects to route of and reveals a window for values that arrived from the network. It will’t occupy the earnings of easy accessibility to printed references on story of those references are pointing to values deserialized from bytes, not values in the purpose VM. It’s soundless effective and performant repl, and it’s edifying even as you occur to may perhaps likely very neatly be trying to make utilize of Instruct to talk to any other route of that doesn’t occupy Tag on the classpath (e.g. manufacturing or ClojureScript prepl).

Example:

  1. Open a prepl without Tag on the classpath:
    $  clj 
    -Sdeps '{:deps {org.clojure/clojurescript {:mvn/model "1.10.764"}}}' 
    -J-Dclojure.server.cljs-prepl='{:port 50505 :accept cljs.server.browser/prepl}'
    
  2. Connect with that prepl the utilize of Tag:
    $ clj -A:point out -m vlaaad.point out distant-prepl :port 50505
    # at this level, 2 issues occur:
    # 1. Browser window with cljs prepl appears
    # 2. Tag window opens
    
    # input
    js/window
    
    # output
    {:price :ret, 
     :val #object [Window [object Window]], 
     :ns "cljs.user", 
     :ms 25, 
     :bask in "js/window"}
    

ui

Calling this characteristic will make and present a Tag window. It returns a characteristic that you just’re going to be in a situation to put up values to — they’ll seem in the output panel. All constructed-in visible repls are thin wrappers of assorted repls that put up values to a window created by this generic characteristic. You likely can put it to use to make custom-made Tag-flavored repls, or, reasonably than the utilize of it as a repl, you’re going to be in a situation to configure Instruct to handiest present tapped values.

Example:

(require '[vlaaad.reveal :as reveal])

;; originate a window that will present tapped values: 
(add-faucet (point out/ui))

 ;; put up price to the window: 
(faucet> {:will-i-see-this-in-point out-window? correct})

With user API you ought so that you just can configure your editor to make utilize of Tag, nonetheless there are soundless some parts righteous of dialogue.

Cursive

For Cursive, you may perhaps likely likely honest soundless make a “native repl” speed configuration with “clojure.well-known” repl form. For prefs, utilize “JVM Args” input, nonetheless notify that it splits args on areas, so you may perhaps likely likely honest soundless utilize commas, e.g. -Dvlaaad.point out.prefs={:theme,:gentle}. Right here is one of the well-known easy setup that permits IDEA to originate your software and fix a repl connection for sending forms.

In most cases this setup is just not preferrred: you may perhaps likely likely honest are trying to originate an software the utilize of some assorted methodology and then connect to it the utilize of IDEA. In that case, you may perhaps likely likely honest soundless not utilize “distant repl” speed configuration, since this can rewrite your forms and outcomes to one thing unreadable. As an substitute, you may perhaps likely likely honest soundless soundless utilize the “native repl” speed configuration that uses repl client that connects to your route of. Example:

  1. Manufacture your purpose route of some extent out server:

    clj -A:point out -J-Dclojure.server.repl='{:port 5555 :accept vlaaad.point out/repl}'
    
  2. Add a dependency on distant-repl to your deps.edn:

    {:aliases 
     {:distant-repl {:extra-deps {vlaaad/distant-repl {:mvn/model "1.1"}}}}}
    
  3. Build a “native repl” speed configuration with “clojure.well-known” repl form, make it “Bustle with Deps” with distant-repl alias, and in Parameters specify -m vlaaad.distant-repl :port 5555.

Nrepl-primarily based editors

For pattern workflows that require nrepl Tag has a middleware that will present review outcomes produced by nrepl: vlaaad.point out.nrepl/middleware, you will prefer so as to add it to your middleware list. The minimum required model of nrepl is 0.6.0.

Example of the utilize of this middleware with say line nrepl entry level:

$ clj -A:point out -m nrepl.cmdline --middleware '[vlaaad.reveal.nrepl/middleware]'

Alternatively, you’re going to be in a situation to make .nrepl.edn file for your project checklist that shall be picked up by nrepl. Example .nrepl.edn file:

{:middleware [vlaaad.reveal.nrepl/middleware]}

Residence windows

It’s potentially a factual thought so as to add -Dfile.encoding=UTF-8 to JVM alternatives.

There are 3 ways to expand Instruct to your wants: custom-made formatters, actions, and views. All three are on hand in vlaaad.point out.ext namespace (aliased as rx in following examples).

One characteristic that they all piece is annotations — non-intrusive metadata that exists alongside your objects in the Tag dispute. Unlike datafy/nav primarily based tooling, it doesn’t obstruct your objects, leaving Clojure’s metadata precisely as it’s for your program, and, since the annotation is alongside the thing, Tag permits any object to be annotated — not accurate IMetas.

Formatters

Formatters elaborate how values are confirmed in the output panel. Formatter dispatch is a multimethod that appears at :vlaaad.point out.movement/form meta key or, if it’s absent, at object’s class. The advisable solution to expand this multi-procedure is the utilize of (defstream dispatch-val [x ann?] sf) macro that automatically marks the formatted role with the cost that is being formatted. There is a little residing of positive aspects that impact the streaming of the formatting in an efficient procedure known as streaming positive aspects (sfs for short).

Low-level text emitting sfs

These are customarily aged in the defstream body to configure how one thing appears as text. Such sfs don’t mark the text they emit with values that shall be on hand for inspection, as an substitute they depend on their context (e.g. defstream) to mark what they emit. There is handiest 5 of them:

  • (raw-string x style?) and (escaped-string x style? damage out-fn damage out-style?) emit syntax-highlighted text. Both accept style blueprint that make stronger following keys:
    • :possess – text possess coloration, either a string love "#ff0000", web coloration keyword love :purple, or one among particular values that elaborate theme-dependent coloration:
      • :util for tool-connected text, not values (e.g. => for denoting output);
      • :symbol for symbol coloration, here is moreover a default coloration for text;
      • :keyword for keyword coloration;
      • :string for denoting string values;
      • :object for denoting composite objects that customarily print some assorted values as a aspect of their text illustration;
      • :scalar for values customarily considered as indivisible, similar to numbers, booleans and enums;
      • :success to indicate success (e.g. handed checks message);
      • :failure to indicate failure (e.g. exception);
    • :selectable – whether or not the emitted text will also be chosen (defaults to correct).
  • (horizontal sf*) and (vertical sf*) wrap a variable series of sfs and align them, e.g. you’re going to be in a situation to take into accout streaming a blueprint as horizontal {, entries and }, the place in entries every entry is aligned vertically;
  • separator visually separates emitted forms, in horizontal blocks it’s a non-selectable situation, in vertical blocks it’s an empty line;

Delegating sfs

These sfs will let you movement assorted values the utilize of their default streaming. Right here is moreover a location to annotate the streamed values.

  • (movement x ann?) emits a formatting for handed price — here is the coronary heart of a formatting route of;
  • (horizontally xs ann?) and (vertically xs ann?) work on collections. The distinction with their low-level sf counterparts is that they don’t realize the total series sooner than streaming. You likely can without be troubled attain (vertically (differ)), and this cannot block the route of of streaming;
  • (objects xs ann?) guesses the formatting: searching on the input, may perhaps likely behave either as horizontally or as vertically. Would possibly perhaps likely realize the total series sooner than streaming;
  • (entries m ann?) is a variation of vertically optimized for blueprint entries.

Annotations are handiest edifying if they are aged, and they also’re aged from actions. There is an instance that configures formatting with annotations and uses these annotations for vital recordsdata inspections here.

Overriding sfs

These sfs allow modifying some aspect of a streaming:

  • (as x ann? sf) permits the utilize of non-default streaming characteristic for some price x, while making present:price action on hand to witness the cost’s default formatting. An instance the place this is in a position to likely very neatly be edifying is showing identification hash code that customarily has a assorted illustration of an int to signify its which methodology:
     (defn identification-hash-code-sf [x]
       (let [hash (System/identityHashCode x)]
         (rx/as hash
           (rx/raw-string (format "0x%x" hash) {:possess :scalar}))))
    
  • (movement-as-is sf) makes sf price streamable as itself. Streaming positive aspects are recurring positive aspects that utilize demunged class title as a formatted illustration, and when sf is submitted to Tag, this can utilize this default formatting too. There a scenarios the place you may perhaps likely likely honest are trying to accurate movement some formatted forms to Tag (e.g. outcomes of custom-made actions), and here is attain it.
  • (override-style sf f args*) transforms the text form of any other sf, edifying in cases the place you may perhaps likely likely honest are trying to mark total objects and their constituents in any other procedure (e.g. styling semantically “not eminent” objects as gray).

Actions

If chosen text in Tag UI has connected price, soliciting for a context menu on this can present a popup that checks all registered actions and counsel appropriate ones. Consume (defaction identity [x ann?] body*) macro to register new actions.

Action body may perhaps likely honest soundless return a 0-arg characteristic to present that this action is on hand: this characteristic shall be done when the action is chosen in the context menu popup. Any assorted outcomes, alongside side thrown exceptions will not be eminent. The action body may perhaps likely honest soundless be reasonobly rapidly (e.g. not performing disk IO) since all actions are continuously checked when the user asks for a popup. Returned characteristic, on the assorted hand, may perhaps likely honest block for as prolonged as wanted: Tag will present a loading indicator while it’s done.

Minimal action instance that reveals reveals how strings stumble on unescaped (e.g. masks "good daynworld" as good day and world on separate lines):

(rx/defaction ::unescape [x]
  (when (string? x)
    #(rx/movement-as-is 
       (rx/as x (rx/raw-string x {:possess style/string-coloration})))))

As talked about earlier, there may perhaps be an even bigger instance that reveals how actions and formatting can fabricate on every assorted to assist with recordsdata exploration:

Actions demo

Views

A well-known distinction between Output panel and Outcomes panel is that the latter can present any graphical node allowed by Tag’s UI framework (JavaFX). Tag is constructed on cljfx — declarative, functional and extensible wrapper of JavaFX inspired by react. Tag converts all action outcomes to cljfx aspect descriptions with vlaaad.point out.witness/Viewable protocol that reveals them with output panel witness by default. You likely can reify an occasion of the protocol with (witness-as-is desc) characteristic.

Short cljfx intro

To be taught cljfx/JavaFX, you may perhaps likely likely honest soundless battle thru cljfx readme and examples to procure familiar with semantics and explore JavaFX javadoc to search out on hand views. This might likely very neatly be an infinite job, so that you just can procure a feel for it here is this short introduction.

To list a node, cljfx uses maps with a assorted key — :fx/form — that defines a form of node, while assorted keys elaborate properties of that node. Price on :fx/form key shall be a keyword (kebab-cased JavaFX class title) or a characteristic (that receives a blueprint of props and returns any other description).
Some examples of most normally aged descriptions:

;; showing a text
{:fx/form :impress
 :text (str (differ 10))}

;; showing a button with a callback: 
{:fx/form :button
 :text "Deploy"
 :on-action (fn [event] (deploy-to-manufacturing!))}

;; combining views collectively
{:fx/form :v-box ;; vertically
 :young folk [{:fx/type rx/value-view ;; built-in component
             :value msft-stock}
            {:fx/type :h-box ;; horizontally
             :children [{:fx/type :button
                         :text "Sell"
                         :on-action (fn [_] (sell! :msft))}
                        {:fx/form :button
                         :text "Carry"
                         :on-action (fn [_] (put off! :msft))}]}]}

While cljfx helps the utilize of maps to elaborate callbacks, you may perhaps likely likely honest soundless handiest utilize positive aspects — habits of blueprint match handling is an implementation aspect that is topic to alter.

Constructed-in parts

Tag provides an entry to varied constructed-in parts:

  • price-witness is a default witness aged in Output panel that present values the utilize of streaming formatting, as an example:
    {:fx/form rx/price-witness
     :price (all-ns)}
    
  • see:all and see:most up-to-date actions are powered by ref-see-all-witness and ref-see-most up-to-date-witness. Furthermore, there may perhaps be (observable ref fn) utility characteristic that permits seeing a ref thru a become — it’s supposed to be aged with these views, as an example:
    {:fx/form rx/ref-see-most up-to-date-witness
     :ref (rx/observable my-int-atom (juxt dec identification inc))}
    
  • observable-witness permits deriving the total cljfx aspect from IRef dispute, and showing it updated live every time the ref is mutated. There is an instance showing how it’ll also be aged for organising live notice and controls for integrant-managed app dispute.
  • derefable-witness asynchronously derefs a blocking off derefable (e.g. future or promise);
  • table-witness reveals a table. Unlike witness:table action, it doesn’t wager the columns, as an substitute you’ve got gotten gotten to produce them your self, as an example:
     {:fx/form rx/table-witness
      :objects [:foo :foo/bar :foo/bar/baz :+]
      :columns [{:fn namespace} 
                {:fn name} 
                {:fn #(resolve (symbol %)) 
                 :header 'resolve}]}
    
  • chart views: pie-chart-witness, bar-chart-witness, line-chart-witness and scatter-chart-witness. They attain not strive to wager the form of recordsdata in the same procedure that their corresponding actions attain, e.g. line chart recordsdata sequence continuously must be labeled even when there may perhaps be handiest one recordsdata series:
    {:fx/form line-chart-witness
     :recordsdata #{(blueprint #(* % %) (differ 100))}}
    

Fancy visualizations don’t have to be leaf nodes that you just’re going to be in a situation to handiest stumble on at — wouldn’t or not or not it’s effective to amass a recordsdata level on a plot and explore it as a price? Tag helps this endured recordsdata exploration for constructed-in views love charts and tables out of the box. As neatly as to that it provides a system to install the action popup on any JavaFX node with a assorted aspect — popup-witness:

{:fx/form rx/popup-witness
 :price (the-ns 'clojure.core)
 :desc {:fx/form :impress
        :text "The Clojure language library"}}

This description reveals impress that you just’re going to be in a situation to search recordsdata from a context menu on, and its popup will counsel acions on clojure.core ns. There is an even bigger instance showing make a custom-made witness for a chess server that shows filled with life games as chess boards and permits inspecting any piece:

Custom views demo

If repl is a window to a working program, then Tag is an originate door — and which it’s possible you’ll very neatly be welcome to come in. I procure reasonably just a few leverage from the skill to glimpse any object I see, and I’m hoping you’re going to obtain Tag edifying too.

Read More

Leave A Reply

Your email address will not be published.