BetterThanTomorrow / calva

Clojure & ClojureScript Interactive Programming for VS Code
https://marketplace.visualstudio.com/items?itemName=betterthantomorrow.calva
Other
1.61k stars 213 forks source link

Add custom commands from libraries #1442

Open Cyrik opened 2 years ago

Cyrik commented 2 years ago

Add custom snippets through code or a special file in a lib, similar to the new clj-kondo auto-include config. This would make it easier for tooling libraries to provide commands for ease of use. Currently to use something like debux, scope capture, omni-trace or even zprint I have to require it during every repl session, in every namespace. If the tools could provide custom snippets this would make them a lot easier to use, especially for beginners.

Using omni-trace as an example you could have the following snippet to trace code in the repl:

((requiring-resolve 'cyrik.omni-trace/run-traced) '$current-form)

By combing this with #1441 you could now also use libraries like debux or scope-capture to wrap existing code during a debug session.

I'm not set on a way to register those snippets. The most general solution would probably be a way to call a calva registration function through the running repl, probably by using a custom nrepl middleware function, but that's also a hard dependency on nrepl and makes it harder for library authors to do. A more user-friendly way would be a file, let's say calva-commands.edn that has to exist in the jar. I'm not sure if calva is aware of all loaded jars or if they can be scanned, so this might be impossible. The easiest solution would probably be a .calva/ folder in the project root where any library can create it's own .edn file or subfolder and those would be read automatically, like clj-kondo is doing now: https://github.com/clj-kondo/clj-kondo/issues/1483

PEZ commented 2 years ago

Let me see if I understand the use case. A library can add snippets making it convenient for Calva users to use the library?

Cyrik commented 2 years ago

Yes. It's mostly helpful for dev-time libraries, though. I don't want to over-promote my own stuff, but it's the reason I thought of this so here goes. When I want to debug something I'm working on I have omni-trace in my deps, so then to use it I have to do:

(require '[cyrik.omni-trace :as o])

(o/run-traced 'cyrik.omni-trace.testing-ns/run-machine)

(tap> (o/rooted-flamegraph 'cyrik.omni-trace.testing-ns/run-machine))

I have that in my personal snippets so it's easy to just hit a key and it runs, but all users would have to create that snippet themselves. The same thing applies to the something like

((requiring-resolve 'clojure.tools.deps.alpha.repl/add-libs) '$current-form)

This would also make it possible to bundle useful snippets into a library that can be pulled in, so you get multiple new snippets that might not fit into calva itself but also don't belong to any specific library.

Combining this with #1441 would also give lib authors a nice way to provide "live code patterns", for example in re-frame you often write something like this:

(rf/reg-event-fx ;; register an event handler
  :buy           ;; for events with this name
  (fn [cofx [_ item-id]] ;; get the co-effects and destructure the event
    {:http-xhrio {:uri (str "http://url.com/product/" item-id "/purchase")
                  :method :post
                  :timeout 10000
                  :response-format (ajax/json-response-format {:keywords? true})
                  :on-success [:added-cart]
                  :on-failure [:notified-error]}
     :db (update-in (:db cofx) [:cart :items] conj {:item item-id})}))

Which could be provided as a "live code" command by the library itself or by a calva snippet utility library.

PEZ commented 2 years ago

Isn't the live code pattern very similar to what VS Code code snippets do?

Cyrik commented 2 years ago

Yes, and they would be even better if we could hook into that system as well, I didn't know that existed since it doesn't seem to work with clojure? What would make it more powerful than the vscode version is the eval part of "eval and replace" since this would let you transform the substitution in kind of like a macro. Although I find the replacement part less interesting than the "libraries can provide their own" part. It's just that the combination makes both even better. If we could now also hook into the vscode snippet api it would be even better, but might also be a lot harder to implement. My inspiration came from emacs .el files, but with the added benefit of users not having to copy around files by hand and then having outdated snippets at some point.

PEZ commented 2 years ago

We can probably create something similar to code snippets, but more powerful. I somehow doubt there are enough extension points on code snippets themselves, but i haven't actually looked in to it, so I could be entirely wrong.

There is a Clojure code snippets extension that provides a lot of snippets. You might want to check it out. To get some inspiration, if nothing else.

Cyrik commented 2 years ago

@PEZ I've thought about this some more and I think I might have come at the "reasons for the feature" explanation wrong. The basic thing that I want is a way to extend calva in a very user-friendly way, usually bundled with a library that provides some tooling. One of the best-known usage examples of those features is something like Sayid, where my own stuff is a rewrite that works with cljs and doesn't rely on emacs or nrepl. To make projects like that easily usable you kind of need editor integration, but having a plugin for each editor makes it harder for the end-user to get working. So my solution is to try to integrate into the already existing plugins, starting with calva and then emacs and cursive.