Fork me on GitHub
#calva
<
2022-10-01
>
skylize13:10:30

Am I correct that Calva alters the user's editor.wordSeparators for Clojure files? I think : should be removed from this list.

pez14:10:25

Calva sets the defaults. Users can have whatever they fancy. See https://calva.io/customizing/#clojure-defaults

skylize15:10:52

> Calva sets the defaults 👌 So yeah. What I'm saying is the default that Calva sets should not include : as a word separator, because in Clojure : is definitively not a word separator. It is either a totally valid arbitrary (except as a prefix) character in a symbol or a meaningful part of the name of a keyword. It never separates two discrete lexemes.

skylize15:10:24

(Already changed this for myself, no problem. 😸)

metal 1
pez15:10:51

I think it is quite fine as a default.

seancorfield16:10:50

I really like that if I double-click in :foo-bar it selects foo-bar so I can use it as a binding in :keys and as a symbol name. If I want a keyword I can easily type : ctrl+v -- and I think : inside a symbol or keyword is weird enough that you kind of should be inconvenienced a bit if you do that 🙂

pez16:10:32

That double-click behaviour is the main reason why it's kept as a default word separator. Since it is also easy to select it as a form.

1
skylize01:10:22

Do you use Ctrl-D to duplicate selections? Code actually has 2 different behaviors based on whether the initial selection is also created by Ctrl-D. | --> cursor >text< --> selection of "text" So if you have your cursor at the beginning of

|foo foo-bar foo
and type Ctrl-D twice, it will select the word "foo", and then search for that word. The result is selecting foo and foo.
>foo< foo-bar >foo<|
But if you select foo some other way first, e.g. double click or Ctrl-Shift-➡, and type Ctrl-D twice, it will search for the string "foo", finding all 3 foos in the example.
>foo< >foo<-bar >foo<|
If you have : as a word-separator, then neither of these will work to select multiple symbols without also selecting keywords. Both methods lead to the same result.
|foo :foo foo
>foo< :>foo< >foo<|
💡 We could expand the behavior of the Shrink Selection to continue shrinking further, by dropping any prefix colons, when the selection is a keyword.

pez10:10:46

Ah, good to know of those two different ctrl+d modes. I'm a heavy user of ctrl+d. 😃 > 💡 We could expand the behavior of the Shrink Selection to continue shrinking further, by dropping any prefix colons, when the selection is a keyword. That would make things a bit weird in another way, since shrink selection is defined in terms of expand selection. There is currently no way to shrink something that hasn't previously been expanded, and I don't think it should. And expand selection, as all Paredit selection commands, work in terms of forms.

pez10:10:26

@U90R0EPHA a way to adress this glitch (or whatever we should call it) is to write something in the docs about the implications of this detail of the default settings. So a subheading (or maybe note) on that page about the : as part of word separators or not could help people know about the issue and take an informed decisions about their own settings.

skylize13:10:41

Fair enough... ... The shrink selection idea could just as easily be a separate command. Just struck me as a logical extension of one that already exists. We could have a full suite of push/pop and shift/unsift selection ... ... hmm ... Maybe it should be a separate extension entirely. Nothing particularly specific about Clojure for such a feature ... There is already an extension that flips a selection, which would then let you do that with just <shift>-<left/right> ... https://marketplace.visualstudio.com/items?itemName=mlewand.vscode-selection-flip

skylize13:10:25

> Ah, good to know of those two different ctrl+d modes. I'm a heavy user of ctrl+d. 😃 Just discovered Ctrl-Shift-L or Select All Occurrences of Find Match. It's like pressing Ctrl-D all of the times, except with only one key press. And just like Ctrl-D, does a word search instead of a string search if nothing is selected.

metal 1
JR19:10:26

Is it normal for the debugger to be really slow when debugging clojure-lsp? I'm using the calva debugger to try to walk through some methods and it's very slow to step through a function. Actually, something usually crashes before I get all the way though. Just wondering if I'm doing something wrong or if I should switch to using logging to debug?

ericdallo19:10:55

I don't use debugger, but this is the way I code on clojure-lsp and it's pretty easy/fast to test it: https://clojure-lsp.io/development/#the-clojure-way

JR19:10:49

@UKFSJSM38 Ah, I was following that page. And yeah, it's fast to modify a function following that recipe. I guess the debugger falls over with too much thrown at it. When you want to figure out how something in a function is behaving, do you sprinkle (logger/info ...) around?

ericdallo20:10:34

yes 😅

😅 2
JR20:10:57

At least I'm not doing it totally wrong 🙂

ericdallo20:10:07

On Emacs/lsp-mode, I created a lsp-clojure-nrepl-connect which autoamtically connects nrepl to the running clojure-lsp in that project, then I just add the logger/info, eval, and things start to work

✔️ 1
bringe03:10:25

@U02PB3ZMAHH The debugger was developed based on cider’s debugger, but its breakpoint finding logic is not perfect (that could be what’s causing crashes with certain code). I added the debugger some time ago, but to be honest, I don’t use it, which puts it low on my personal priority list for Calva work. I’d be open to helping someone get familiar with the code if they wanted to work on it though. In terms of debugging, I use logging as well as inline defs. Using inline defs with the same name as local variables can be pretty handy for debugging, since you can then use the command to eval the current form to eval different parts of the function you’re debugging with the local var names bound to global vars. For example, if you have a web API function that takes in a request argument, you could add (def request request) in the function, run your API endpoint with whatever situation you’re debugging, then you can do whatever you want with request in your repl (examine values, or evaluate forms that use request in your API function to make sure they do what you expect).

bringe03:10:11

Of course, you’ll want to remove the inline defs later, but clj-kondo (via clojure-lsp) helps remind you. simple_smile

Dallas Surewood20:10:15

Is there a way to evaluate a form in Calva while preserving the meta :file property? clojure.repl/source doesn't work after evaluating a function definition again

seancorfield20:10:20

Otherwise you're just sending an isolated form over to the REPL and I wouldn't expect it to have any metadata about where it originated.

pez20:10:18

I just tried. It seems loading the file also loses the meta...

Dallas Surewood20:10:24

"Load/Evaluate file" loses the meta, indeed. On all the functions

pez20:10:09

@U051BLM8F is this something Calva does wrong, you think?

seancorfield20:10:27

Hmm, I would have expected load file to "load the file" and therefore have access to all the metadata.

seancorfield20:10:53

Confirmed, yeah, (source foo) after loading a file containing (defn foo ..) says Source not found. I'm a bit surprised by that.

pez20:10:54

But same thing using just clj and (load-file ...) when I try, maybe I am not thinking correctly around it.

seancorfield20:10:43

clj and require works tho'

seancorfield20:10:18

Ah, confirmed, load-file does not preserve that information it seems.

dpsutton20:10:53

Load file is equivalent to just repeatedly evaluating forms at the repl right?

pez20:10:10

Seems so. 😃

seancorfield20:10:11

I guess I just hit F12 to go to the definition and use that as my "view source" so I've never noticed before 🙂 and I only actually use (source foo) in a REPL where I use require and never load-file

seancorfield21:10:01

@U042LKM3WCW How/where are you calling source with Calva?

Dallas Surewood21:10:33

It was another flow-storm integration thing. Flow-storm has a browser and you can instrument functions with it, but it relies on source

seancorfield21:10:47

I just tried

(comment
  (require 'honey.sql.helpers-test :reload)
  (clojure.repl/source issue-324)
  )
in that same file and source works like that.

seancorfield21:10:28

So flow-storm is assuming require and not load-file or plain ol' eval...

pez21:10:56

(require 'some-ns :reload) restores the meta.

seancorfield21:10:06

(I haven't used a step-debugger of any kind for about twenty years at this point...)

seancorfield21:10:21

I relied on step debuggers a lot when I did C and C++ back in the '80s and '90s. And some with Java at the beginning (late '90s).

Dallas Surewood21:10:50

That does indeed work. Since tap> only passes the result of an expression to the tap functions, how do you handle rerunning functions? Isn't this just a fancy way of putting print everywhere?

Dallas Surewood21:10:16

For example, if I'm debugging an api endpoint, I find I just have to keep adding taps and rerunning the request until I find the problem

seancorfield21:10:19

I'm not sure what you mean about "rerunning functions"? I just eval code forms.

Dallas Surewood21:10:47

Sure, is it a pain to set up the context for the form that was causing the bug?

pez21:10:15

A keyboard shortcut like so, might help, @U042LKM3WCW?

{
        "key": "ctrl+alt+r enter",
        "command": "calva.runCustomREPLCommand",
        "args": {
            "snippet": "(require '$ns :reload)"
        }
    },

Dallas Surewood21:10:36

Thanks pez, I'll definitely use that too!

seancorfield21:10:11

Occasionally, I'll run into a hard-to-find bug where I have to re-eval an expression multiple times as I add more tap> calls in -- but I tend to put calls into RCFs to debug them so I have complete control over the arguments.

seancorfield21:10:46

Rich Comment Form.

pez21:10:00

RCF, not RFC 😃

seancorfield21:10:07

Stu H coined the phrase because Rich uses them a lot.

Dallas Surewood21:10:34

And then putting them in comments does what, makes it more convenient to keep calling it?

Dallas Surewood21:10:41

Or leave it in code?

seancorfield21:10:06

I also have a hot key bound to a snippet that def's bindings from let expressions to make it easier to re-run code in-situ.

pez21:10:52

It makes it easy to keep calling it and to leave it in the code.

seancorfield21:10:56

I copy/paste bits of code into (comment ..) forms when debugging so I can control the context and then alt+enter re-evaluates the form inside the comment.

seancorfield21:10:01

Then my RCF can become a trail of how I debugged the issue and it stays in the file. Calva has a nice option to eval a form and put the result in a ;; comment below it which is great for "documentation" in RCFs.

dpsutton21:10:02

my memory was load-file was defined in clojure code and was essentially a doseq eval. But its defined in the compiler

seancorfield21:10:16

@U0ETXRFEW Is there an easy way to have a custom snippet prompt for some text to put in some code to be evaluated? That's something I "miss" as a convenience for setting up def for function arguments when debugging?

pez21:10:23

Hmmm, let me try a thing...

Dallas Surewood21:10:35

So essentially your RCF is a scratch pad for debugging a form?

seancorfield21:10:05

My RCFs are also often the history of how I designed and built a series of functions.

pez21:10:34

@U04V70XH6

{
        "key": "ctrl+alt+r p",
        "command": "calva.runCustomREPLCommand",
        "args": {
            "snippet": "(eval (read-string (read-line)))"
        }
    },
If I understood your question correctly?

seancorfield21:10:42

I often start writing code inside (comment ..) to flesh out an idea and refactor it into actual functions as I figure stuff out.

Dallas Surewood21:10:05

I saw a bit of Stuart's talk explaining that. Not sure I understand his particular expedition log, but I'm sure he understands it

seancorfield21:10:41

@U0ETXRFEW where does that prompt for the input? Does it require typing into the REPL window (which I usually have hidden)?

Dallas Surewood21:10:05

Thanks, I'll watch that now!

seancorfield21:10:58

Oh, it pops up a prompt over the main window! That's awesome @U0ETXRFEW! Thank you. Exactly what I wanted!

🙏 1
pez21:10:13

That video reveals a bug in Calva that I have since fixed, @U042LKM3WCW 😃

Dallas Surewood21:10:49

One last question. I am structuring clojure programs to keep I/O at the edges of the system and everything else pure. Say you're using the app locally and you suddenly have unexpected behavior. What's the fastest way to get those I/O inputs and debug your functions pure with an RCF? What's the best way to capture the variables coming into your I/O and setup a pseudo environment? Just tap> and maybe sending your taps to the repl? Smaller question: Is anyone logging I/O in production environments?

pez21:10:01

@U042LKM3WCW, are you familiar with the inline def technique? Maybe it can be employed for some of the cases you describe there. Let's say you have a function like so

(defn multiply [x y]
  (* x y))
And you want to capture the inputs. Then you can temporarily redefine your function as
(defn multiply [x y]
  (def x x)
  (def y y)
  (* x y))
Then when your app has called this function, you have x and y in the global namespace scope, so you can evaluate expressions in the function with whatever inputs you got.

pez21:10:24

These two libraries are worth looking at if you like this technique and want to automate it for yourself. • https://github.com/vvvvalvalval/scope-capturehttps://github.com/AbhinavOmprakash/snitch scope-capture is a bit more advanced and can be used for more cases than snitch, but the latter has an api that is easier/less typing to use.

Dallas Surewood21:10:45

Yes, I was actually trying to write a macro using scope-capture that would make this whole process a lot easier. Where it would auto-capture and then let me replay the function. but I only got about 80% of the way there.

Dallas Surewood22:10:40

For now I'm gonna try a combo of rich comments and taps with flow-storm for the best of both worlds. That might have the least thinking and friction for now. I can look at taps, send them to the repl, and evaluate forms in an RCF. If I want to step through something, I can instrument a function with flow-storm and do it.

pez22:10:53

Cool! I'm right now trying to figure on how I could add some scope-capture support into Calva.

Dallas Surewood22:10:04

Oh that would be awesome

pez22:10:57

There is also a debugger in Calva, in case you've missed it. It will let you evaluate forms in the frame of the breakpoint. I don't use it very often, but sometimes it comes in handy.

pez22:10:38

And I should take a closer look at flow-storm. I've had this on my todo-list for way too long now.

Dallas Surewood22:10:50

I have had trouble with debugger getting hung up after stepping out of a breakpoint. Not sure why

seancorfield22:10:32

So I just updated my Calva/Portal setup so it tracks the last tap>'d value and I can now eval arbitrary code on that last value https://github.com/seancorfield/vscode-calva-setup/blob/develop/settings.json#L249-L258 -- it uses the (read-line) trick @U0ETXRFEW showed above and a custom tap> listener/submit that @U1G869VNV suggested in the #portal channel. Bit of a tangent to this thread but it's something I've been missing in my workflow so thanks to everyone involved for spurring this discussion!

metal 1
bringe22:10:01

> I have had trouble with debugger getting hung up after stepping out of a breakpoint. Not sure why The breakpoint finding logic is not perfect and fails in some situations. I added that code some time ago and I was earlier in my Clojure journey. I now don’t use the debugger, so I don’t prioritize working on it, but would be open to helping others do so if they wanted. My workflow for debugging involves inline defs and RCFs.