This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2022-10-11
Channels
- # announcements (2)
- # babashka (27)
- # beginners (99)
- # biff (16)
- # calva (15)
- # clj-kondo (6)
- # clj-on-windows (38)
- # clojure (54)
- # clojure-austin (1)
- # clojure-europe (30)
- # clojure-france (4)
- # clojure-nl (1)
- # clojure-norway (43)
- # clojure-spec (10)
- # conjure (28)
- # core-async (4)
- # cursive (7)
- # figwheel-main (1)
- # graphql (9)
- # gratitude (3)
- # honeysql (9)
- # introduce-yourself (1)
- # jobs (1)
- # joyride (128)
- # lambdaisland (2)
- # malli (8)
- # membrane (12)
- # nbb (5)
- # off-topic (1)
- # polylith (11)
- # re-frame (9)
- # reitit (1)
- # remote-jobs (5)
- # sci (15)
- # shadow-cljs (50)
- # tools-deps (2)
- # xtdb (12)
Hi, I'm just curious. Is it possible to edit text in the editor with joyride? What I want is to type English and to convert that text to a different language (On a keypress - like space/tab/enter, etc).
Yes, entirely possible to edit text. Check out https://github.com/BetterThanTomorrow/joyride/blob/master/examples/.joyride/scripts/ignore_form.cljs for some inspiration. It uses https://github.com/BetterThanTomorrow/joyride/blob/master/examples/.joyride/scripts/z_joylib/editor_utils.cljs which also should be regarded as inspiration. (I think I would use .change
on the edit builder rather than combining delete and insert.)
If you want to update the examples with something that changes text, please do! I think this is on of the most general usages of Joyride there is.
Also, if it is Clojure code you want to edit, consider using Calva's editor.replace
API: https://calva.io/api/#editorreplace Where it could be good to know that the editor.currentForm
API call gives the selection if there is one. (Calva treats any selection as the current form). https://calva.io/api/#rangescurrentform
@pez No, I do not want to edit Clojure code. All I want to do is transliterate English to Sinhala. It should work in the background replacing word by word without any key commands. Let me go through the samples. Looks promising. I was afraid I would have to write a VS extension. If I can get it done without that, I'd be happy.
@pez Is it possible to add other libs and use within the user script? I would like to use instaparse - otherwise I'd have to write the parser by hand.
I think our reach into the Clojure ecosystem is a bit limited. @U04V15CAJ knows more about this.
@pez, makes sense. Can I invoke a http request from a script then? That's the second option.
I think so. For workspace scripts, the joyride script should be able to load npm deps from the workspace.
We might first want to move to sci.async though since loading those deps happens asynchronously
so it seems we don't have to move to sci.async probably since es6 modules aren't supported in electron anyway
@pez What I do in nbb is use createRequire
which receives the path of the script and then I call .resolve
on that which returns the JS file of the library and then I load that using js/require
(well, I used to do that, now it's a bit more complicated, but this is how it should work in joyride / electron I think)
So in user space:
$ nbb
Welcome to nbb v1.0.136!
user=> (require '["module" :as m])
nil
user=> (require '["path" :as p])
nil
user=> (def req (m/createRequire (p/resolve "./script.cljs")))
#'user/req
user=> (.resolve req "squint-cljs")
"/Users/borkdude/dev/squint/index.js"
And then you can do (js/require resolved)
iff the resolved file is not an ES6 module ;)
how do I make a top level folder in vscode in that left pane... dang, it creates it in a subfolder
@pez I have one problem that you might be able to help with. joyride.core/*file*
isn't bound in the REPL, but it should. I've tried a bunch of things but I'm getting stackoverflows presumably due to debug logs in the nREPL or so
Sorry for being so irresponsive. Been in a meeting (in a #CBE668G4R meeting as it happens 😄 )
@pez Ended up using vscode.WorkspaceEdit
. It plays nicer than vscode.window.activeTextEditor
the latter creating selections after editing which makes it not good for on the fly replacement. I have a lot of bug fixing to do, but managed to call a REST endpoint upon space/tab/newline and replace previous word with the transliteration.
Loving calva btw. I can't use Clojure at my day job. But really enjoy the experience in VSCode. Thanks for all the effort you put in.
^ loading npm libraries in joyride. This needs a new release with the open PR which I'm sure @pez will merge somewhere this week ;)
@pez There have been some improvements to the promesa config in sci.configs. We could bump that + the promesa lib itself
This requires me first installing the relevant package with npm where the script resides is it?
We should document this. Packages can be installed either in ~/.config/joyride/
or in the workspace root.
Can you explain how such modules would be declared as dependencies for the installation process? (I've never used npm
and have avoided Node.js like the plague)
I'm allergic to JavaScript 😛
To use the example you need to have node. Then, in the workspace, you do:
$ npm init -y
$ npm install moment axios
BOOM.Ah, since it can require ["vscode" :as vscode]
I was wondering how/where it would find such other modules -- is "vscode"
treated specially?
npm init
creates a minimum package.json for you. npm install
create a node-modules
directory which is similar to the .m2
maven thing, but local.
And there's a "global" (user-level) option? Since my Joyride scripts are user-level, not workspace-level.
But it still tricked me into forgetting that we didn't support npm requires yet. Until I uttered that we should and @U04V15CAJ just made it work.
It seems to work to run those ^ commands in ~/.config/joyride
. Maybe @U04V15CAJ can explain why it works. 😃
OK, cool. So I can keep the rest of my system free of nodejs pollution then... Perhaps a note in the docs/readme about that?
My test might not have been sufficient. I just removed the dependency from my test workspace and ran the commands in the global folder. Then reloaded the vscode window and tried the examples in a user script. But you’ll find out, I guess.
> The node modules are resolved relative to the script in question
It seems, from my testing of createRequire
and .resolve
, that this should be read as that the first node_modules
found from the script and up through it's directory ancestors... Hmmm, that got very hard to read. Anyway, I wonder if something like this in Joyride docs would describe it correctly and well enough:
> npm packages that your scripts require should be npm
installed in a node_modules/
directory somewhere in the requiring script's path. E.g. if you have node_modules
in your system /
(this is not a recommendation), then all Joyride scripts will be able to require packages from there. If you have node_modules
side-by-side with a Joyride script, then only that script, sibling scripts and scripts in sub folders will be able to require from there. Some locations to consider are:
> • For Workspace scripts: The workspace root. The .joyride/
folder in the workspace.
> • For User scripts: ~/.config/joyride
(or any subfolder there, if that makes sense for how you organize your user scripts)
I think the suggestion should be that the node_modules should live as sibling of the script's directory or any of its parent directories.
Typically: the root of a project as dev dependencies (`npm install --save-dev`) (or one level higher, .joyride )
or indeed the joyride user directory for user script
And the example with the system root node_modules actually held true. I was making some mistakes testing it.
I'm giving a CLJS-related presentation soon and joyride will also be appearing in it. If you have some nice example of how you are using it, please link it in the thread. A screenshot of the script in action which I can fit in a slide will also do.
@U04V70XH6 Wanna share/screenshot your clojuredocs example?
I use this example quite a lot: https://github.com/BetterThanTomorrow/joyride/tree/master/examples#find-in-file-with-regexp-toggled-on Should be how VS Code works to begin with, but anyway. 😃
Another one. Pasting the contents of the current file in a new, untitled, file/buffer:
{
"key": "alt+ctrl+o p",
"command": "joyride.runCode",
"args": "(require '[promesa.core :as p]) (p/let [text (vscode/window.activeTextEditor.document.getText)\n doc (vscode/workspace.openTextDocument\n #js {:language \"clojure\", :content text})]\n (vscode/window.showTextDocument doc #js {:preview false, :preserveFocus false}))"
},
It's good when I want to modify a library function, since VS Code won't let me edit the buffer when its showing a file from a jar file.@U04V15CAJ Not sure what's to share -- it's this https://github.com/seancorfield/vscode-calva-setup/blob/develop/joyride/scripts/javadoc.cljs bound to a hot key 🙂
lol. ok. if you continue, we will have enough material for the London Clojurians meeting
Oh, that's the Java Docs version -- which is more complex. The ClojureDocs one just uses the current form as a selection to look up a URL on http://clojuredocs.org and open the Simple Browser. The Java Docs one requires you select a class name or expression (which will be eval'd) and then it gets the type/class of the result and gets the java docs URL and opens the Browser.
What do y'all use for doing screencasts/recordings? @U04V15CAJ @pez
Screencast: licecap or cmd-shift-5 (built into macOS which I know you're not using ;))
I tried OBS. It was horrible. Final Cut Pro is macOS @pez? I guess I could just use our Zoom account at work to create an ad hoc meeting, share my screen and record it 🙂 But editing afterward is still a pain (I have used YouTube's "studio" to post-edit videos after upload but... ugh! nasty!)
I just used OBS to record, but not edit and it worked for that. There are probably better (paid) solutions. I hate editing too. I found a program that let me cut out parts of the video. So I do everything in one take and when I make a mistake or want to do stuff over, I just cut out stuff from the 1 big take
I think I've also used Screenflow like almost a decode ago (on mac), a really polished product, but I think my license long expired
I keep meaning try StreamYard to see if it's any better than other streaming/recording options... I created an account ages ago and did a couple of test casts but never got around to doing anything publishable...
Oh, I think Martin (@U5H74UNSF)mentioned an online solution to me a while back. I'll ask him
It might be loom but I'm not sure: https://www.loom.com/share/72ee26ab1f2c4843aec9194ac7d8714e
Probably recording in Zoom works just as well but then you will have to upload the video to youtube (or similar) and edit in some other program (if you want to edit)
If on Linux, and you can put up with alpha-version bugs and glitches, I suggest trying Olive for editing.
Here's mine:
(ns hello-joyride-user-script
(:require
[joyride.core :as joyride]
["vscode" :as vscode]
["http" :as http]
[promesa.core :as p]
[clojure.string :as str]))
(defn current-line []
(-> vscode/window .-activeTextEditor .-selection .-active .-line))
(defn current-language []
(-> vscode/window .-activeTextEditor .-document .-languageId))
(defn get-current-line-text [line]
(let [activeEditor (.-activeTextEditor vscode/window)
selection-is-empty? (-> activeEditor .-selection .-isEmpty)]
(if selection-is-empty?
(.lineAt (.-document activeEditor)
line)
nil)))
(defn get-last-word-info [ch]
(let [line# (current-line)
line# (if (= \newline ch) (dec line#) line#)
line (.-_text (get-current-line-text line#))
last-word (last (str/split line #"\s+"))]
{:word last-word
:line line#
:length (count last-word)
:start (- (count line) (count last-word))}))
(defn transliterate [word completion-fn]
(let [data (atom "")]
(http/get (str "" word) #js {}
(fn [^js res]
(.on res "data" (fn [chunk]
(swap! data str (.toString chunk))))
(.on res "end" (fn [] (completion-fn @data)))))))
(comment
(vscode/workspace.onDidChangeTextDocument
(fn [^js change]
(when (and (= (current-language) "markdown")
(= (.-document change) (-> vscode/window .-activeTextEditor .-document)))
; I don't know, does tab come as tab or spaces?
(let [ch (#{\space \tab \newline " " " "} (-> change .-contentChanges (get 0) .-text))]
(when ch
(let [{:keys [word line start length]} (get-last-word-info ch)]
(transliterate word
(fn [data]
(let [edit (vscode/WorkspaceEdit.)]
(.replace edit
(-> change .-document .-uri)
(vscode/Range. line (dec start) line (+ start length -1))
data)
(.applyEdit vscode/workspace edit))))))))))
)
And this at work below:Awesome, @UC1DTFY1G! Is transliterating from one script representation (latin/english letters) to some other?
@pez Yes. The screencast above is transliteration from English to Sinhalese. Because it's a language only 16 million people use (and of a relatively poor people), there wasn't good support for Sinhalese for a long time so people used to just type whatever they wanted to say using the English alphabet although Sinhalese has it's own alphabet. The tools are getting better now, but the method of typing Sinhalese words using the English alphabet has remained. Hence, transliteration is a good choice for most people (myself included) when they don't want to memorize a new keyboard.
Thanks! What's the rationale behind the choice to transliterate word-for-word instead of character by character? I'm guessing it is not a 1->1 mapping?
@UC1DTFY1G: In Typist (a VS Code extension) there is a mode where it simulates writing by pasting it in character by character. I have commands for toggling this on and off. Thinking you could do the something similar toggling that transliteration on and off via keyboard shortcuts. In Typist, I use an atom https://github.com/PEZ/paste-replaced/blob/master/src/paste_replaced/replacer.cljs For your script the commands could just install and uninstall the onchange handler. (If this is a desirable feature, but it seems to me that it would be.)
@U04V15CAJ Typist is another example of how I use Joyride. I use it for prototyping when writing extensions. And for tweaking.
@pez You are right, it's not a 1 to 1 character mapping. A simple grammar I use with instaparse for transliteration now is below:
S=word (whitespace word)*;
word=(any|vowel|pureconsonant|consonant)+
vowel='e'|'E'|'a'|'U'|'O'|'i'|'u'|'A'|'I'|'o'|'aa'|'ii'|'ei'|'AA'|'ou'|'au'|'sru'|'srU';
pureconsonant='T'|'d'|'n'|'K'|'w'|'s'|'f'|'L'|'p'|'j'|'G'|'J'|'v'|'B'|'P'|'t'|'k'|'b'|'r'|'y'|'g'|'l'|'N'|'h'|'m'|'D'|'dh'|'ch'|'Dh'|'xd'|'xj'|'Sh'|'xb'|'sh'|'xg'|'Ch'|'Th'|'th'|'thh'|'xmb'|'chh'|'xdh'|'xgdh'|'xkdh';
consonant=pureconsonant,vowel;
any=#'.*';
whitespace=#'(\s|\n|\t)+'
But this doesn't capture all. For example a run of characters like wyaa
should ideally map to ව්යා
while the simple grammar above will map it to ව්යා
. While not incorrect, this is considered uncultured 😄@pez I haven't come to enabling/disabling the transliteration yet but yes. That's a must. So I will take a look at what you mentioned. Thanks. I was thinking I can just add and remove the listener to the text changed event on some key combo. Or is that impossible to do?
@pez As mentioned here: https://code.visualstudio.com/api/references/vscode-api#events All we'd need to do is have two key combinations referring to the same script and an atom to hold the callback for the event right? Or am I mistaken?
Yes, you can do it like that, similar to what we do in this example: https://github.com/BetterThanTomorrow/joyride/blob/master/examples/.joyride/scripts/workspace_activate.cljs Or you could have your handler check the status and be a noop if transcibation is not enabled.
(I realized I derailed my own thread here, but @U04V70XH6: this is what @U5H74UNSF uses, https://www.descript.com/, let's continue video editing tools in another thread from now on)
I might be presenting at a meetup next week. Preparing, I remember that I have made an extension (unpublished) that helps me step through Markdown Previews in VS Code. These are my slides, so that I can stay in VS Code as much as possible. Last time I presented anything there was no Joyride. Now that there is, I don't want to use a bloaty extension. 😃 So ported my extension to Joyride. The script:
(ns next-slide
(:require ["vscode" :as vscode]
[promesa.core :as p]
[clojure.edn :as edn]))
(def ^:private !state (atom {:active? false
:active-slide 0}))
(defn- ws-root []
(if (not= js/undefined
vscode/workspace.workspaceFolders)
(.-uri (first vscode.workspace.workspaceFolders))
(vscode/Uri.parse ".")))
(defn next!
([]
(next! true))
([forward?]
(p/let [config-uri (vscode/Uri.joinPath (ws-root) "slides.edn")
config-data (vscode/workspace.fs.readFile config-uri)
config-text (-> (js/Buffer.from config-data) (.toString "utf-8"))
config (edn/read-string config-text)
slides (:slides config)
next (if forward?
#(min (inc %) (dec (count slides)))
#(max (dec %) 0))]
(swap! !state update :active-slide next)
(vscode/commands.executeCommand "markdown.showPreview"
(vscode/Uri.joinPath (ws-root)
(nth slides (:active-slide @!state)))))))
(defn toggle-active! []
(swap! !state update :active? not)
(vscode/commands.executeCommand "setContext" "next-slide:active" (:active? @!state))
(vscode/window.showInformationMessage (str "next-slide:" (if (:active? @!state)
"activated"
"deactivated"))))
Keyboard shortcuts:
{
"key": "ctrl+alt+cmd+space n",
"command": "joyride.runCode",
"args": "(next-slide/toggle-active!)"
},
{
"key": "right",
"command": "joyride.runCode",
"args": "(next-slide/next! true)",
"when": "next-slide:active && !editorTextFocus"
},
{
"key": "left",
"command": "joyride.runCode",
"args": "(next-slide/next! false)",
"when": "next-slide:active && !editorTextFocus"
},
Then I stick a file like this in my workspace:
{:slides ["hello.md",
"vic-20.md",
"brooks.md",
"plotter.md",
"clojure.md",
"thanks.md"]}
This assumes those files are in the workspace root as well. Then when presenting, I:
1. Load the next_slide.cljs script (I have it as a User script).
2. ctrl+alt+cmd+space n
to activate next-slide.
3. Flick back and forth through the slides with right
and left
.