I'm using Vscode/Calva with the portal extension, and connecting remotely to a project where I cannot add portal as a dependency (also on clojure 1.11 so no add-lib). Is there any way to use portal? Something like a calva middleware maybe?
If the project is using lein, you can add the dependency to your lein profile
I think the problem here is that the remote app is already running, exposing an nrepl server?
Yep, it's deployed in a server exposing nrepl
I would try to convince whoever runs it to include portal middleware. Itβs safer than many alternative ways to inspect the running process, as I see it.
If it works at all, I imagine it would have to be by sending serialized strings (losing metadata etc), but better than nothing
I can probably add portal to the project, it just might take a few weeks for the deployed version to be updated
I think you can use portal client side. And itβs probably the same as what you are talking about with serialized data.
I find this standalone portal which may be the option for this: https://cljdoc.org/d/djblue/portal/0.58.3/doc/guides/portal-standalone
The question is more how to send the data to portal (in a not too annoying way, I could copy paste the output of the eval). Maybe a joyride script that captures the output of calva eval commands, and sends it to portal?
Yeah. Calva has commands for copying the latest result to the clipboard. And a simple #joyride script should be able to post to the standalone portal with the data encoded correctly.
Thanks, I wanted to see if there was already something done, but writing that joyride script shouldn't be difficult
There may be already something done. Ask in #joyride about it. But also, probably fun to solve. π
I would use the runCommand command to string the copying and sending to portal as a sequence. VS Code has API for accessing the clipboard data. https://code.visualstudio.com/api/references/vscode-api#Clipboard
I wrote a little something about runCommands here: https://blog.agical.se/en/posts/vs-code-runcommands-for-multi-commands-keyboard-shortcuts/ It includes some tips about finding command ids and such.
TL;DR: π The Calva load current file reimplemented (well, actshhuallyyyy) using runCommands:
{
"command": "runCommands",
"key": "ctrl+alt+c ctrl+alt+enter",
"args": {
"commands": [
"editor.action.selectAll",
"calva.evaluateSelection",
"cursorUndo"
]
}
},nice π
Hereβs a bit of a crazy way to fire of a joyride script without hosting a script:
{
"command": "joyride.runCode",
"comment": "Replaces current selection with a markdown link",
"args": "(require '[\"vscode\" :as vscode]\n '[promesa.core :as p]\n '[joyride.core :as joy])\n\n(defn current-selection []\n (let [editor vscode/window.activeTextEditor\n selection (.-selection editor)]\n selection))\n\n(defn current-document []\n (let [editor vscode/window.activeTextEditor\n document (.-document editor)]\n document))\n\n(defn current-selection-text []\n (.getText (current-document) (current-selection)))\n\n(defn insert-text!+ \n ([text]\n (insert-text!+ text vscode/window.activeTextEditor (.-active (current-selection))))\n ([text editor position]\n (-> (.edit editor\n (fn [builder]\n (.insert builder position text))\n #js {:undoStopBefore true :undoStopAfter false})\n (p/catch (fn [e]\n (js/console.error e))))))\n\n(defn replace-range!+\n ([text]\n (replace-range!+ text vscode/window.activeTextEditor (current-selection)))\n ([text editor range]\n (-> (.edit editor\n (fn [builder]\n (.replace builder range text))\n #js {:undoStopBefore true :undoStopAfter false})\n (p/catch (fn [e]\n (js/console.error e))))))\n\n(defn delete-range!\n [editor range]\n (-> (p/do (.edit editor\n (fn [builder]\n (.delete builder range))\n #js {:undoStopBefore true :undoStopAfter false}))\n (p/catch (fn [e]\n (js/console.error e)))))\n\n(defn markdown-link! []\n (p/do (replace-range!+ (str \"[\" (current-selection-text) \"]()\"))\n (let [pos (.translate (.-end (current-selection)) 0, -1)]\n (aset vscode/window.activeTextEditor \"selection\" (vscode/Selection. pos pos)))))\n\n(markdown-link!)",
"key": "ctrl+alt+j ctrl+cmd+m"
},(Without recommending to doing it that way π )
So because Portal can be hosted by joyride, you can actually do something like π which gives you the identical experience of https://github.com/djblue/portal/blob/master/src/portal/nrepl.clj#L60-L96 but entirely remotely:
(ns portal.eval
(:require [portal.api :as p]
["vscode" :as vscode]
["$v0" :as calva]))
(defn eval-str []
(when-not (seq (p/sessions))
(p/open {:launcher :vs-code})
(add-tap #'p/submit))
(let [editor (.-activeTextEditor vscode/window)
ns (second (read-string (.. editor -document getText)))
code (second (.currentEnclosingForm calva/ranges))
file (.. editor -document -fileName)
line (inc (.. editor -selection -active -line))
column (inc (.. editor -selection -active -character))
time (js/Date.)
start (.now js/Date)]
(-> (.evaluateCode calva/repl "clj" code {} #js {:ns (name ns)})
(.then (fn [result]
(update
(merge
{:level :info}
(js->clj result :keywordize-keys true))
:result
(fn [result]
(try
(read-string result)
(catch :default _
result))))))
(.catch (fn [ex]
(merge
{:level :error
:result ex})))
(.then (fn [result]
(tap> (with-meta
(merge result
{:ns (symbol ns)
:code code
:file file
:line line
:column column
:time time
:ms (- (.now js/Date) start)
:runtime :clj})
{:portal.viewer/for
{:code :portal.viewer/code
:time :portal.viewer/relative-time
:ms :portal.viewer/duration-ms}
:portal.viewer/code {:language :clojure}}))))))) It has the additional advantage of opening up portal on eval if portal isn't already open π