Fork me on GitHub
#vim
<
2023-01-10
>
Hukka12:01:44

I haven't spent much time configuring my editor, mostly just whatever exists as plugins. But looking at https://youtu.be/2nH59edD5Uo?t=622 I got some tool envy. In that part Juan Monetta tells his emacs to Java decompile, and then disassemble a form. Also has some profiling and linting there. All without changing the source, which is what I do currently. What would be the sensible way to get something like this working on vim? For now I'm using conjure with neovim

Hukka12:01:30

Bonus points for the menu that shows the options, since I likely would forget whatever fancy shortcuts I would make for anything I don't use weekly, if not even daily

lispyclouds12:01:21

this is pretty much a direct port of the emacs thing

Hukka12:01:17

https://github.com/jpmonettas/elisp-utils/blob/master/clojure.el seems to be what was loaded, though I'm not at all versed with elisp

lispyclouds12:01:06

pretty sure its which key is what being used to show the menu: https://github.com/jpmonettas/dotFiles/blob/master/emacs/init.el#L354

lispyclouds12:01:03

as for the decompilation, i use https://github.com/clojure-goes-fast/clj-java-decompiler as a dependency in the dev alias in deps edn and call via the REPL. maybe there is a way to bind it to a key in conjure

Hukka12:01:05

Yeah, something that would let me evaluate the form inside another predefined form would be needed, and I could then write the usual stuff I now copypaste into the source when needed

Hukka12:01:52

https://github.com/Olical/conjure/blob/master/fnl/conjure/client/clojure/nrepl/action.fnl#L89-L100 hm, perhaps modify the opts in the right way, or just make different versions of eval-str

lispyclouds12:01:30

@U38J3881W could have knowledge to drop here maybe 🙏:skin-tone-5:

Hukka12:01:42

opts.code seems to be the right place

lispyclouds12:01:30

also for the decompiler in emacs, https://github.com/bsless/clj-decompiler.el seems to be used. could look at the way its sending stuff?

lispyclouds12:01:15

yep, something similar is needed for conjure. not sure of its config options at this point

Hukka12:01:42

I guess it either means learning how to work with lua and neovim, or perhaps how to extend conjure with fennel

lispyclouds12:01:49

yeah, hence hoping that Olical could have some points!

Martynas Maciulevičius12:01:40

> something similar is needed for conjure But as I understood Olical didn't want to hardcode CIDER middlewares into Conjure. I implemented this plugin which does that for tests: http://github.com/invertisment/conjure-clj-additions-cider-nrepl-mw If you can figure out how Emacs does it then I could have a PR or something. I don't have a good PR workflow for that plugin so I don't yet know how useful my suggestion would be. I think Conjure is about integrating with many languages, not about a deep integration with a single one. So this is why he didn't want to hardcode the JVM middleware and instead implemented his own test runner and parser. Or he just did the parser and didn't want to reimplement it again once I made my plugin to add onto Conjure. Also NREPL way doesn't work for CLJS. 🤷 For instance I have this function that I sometimes use: https://github.com/Invertisment/conjure-clj-additions-cider-nrepl-mw/blob/master/fnl/conjure-clj-additions-nrepl/additional-fns.fnl#L37 So there is no problem to add more if you already have the dependencies into your dev profile of your project.

Martynas Maciulevičius13:01:41

I really liked the bit where he clicked one button and outputted a flame graph. That one was really good notbad

emilaasa04:01:14

I also got a bit inspired by that interview with jpmonettas!

Hukka07:01:05

But does this have anything to do with cider middleware? The middleware is already running in the nrepl server, and the question is just how to fiddle with the code that is sent to be evaluated (by wrapping it with extras)

Martynas Maciulevičius07:01:39

> and the question is just how to fiddle with the code that is sent to be evaluated For instance the debugging bit is delving deeper into that middleware but it's somewhat implemented but I didn't try it. But then there is no such middleware for CLJS and CommonLISP. And then Olical would need to maintain it too. At this very moment I'm implementing the oneliners that produce flame graphs into my own plugin because I don't want to wait until Olical would add them :thinking_face:

Hukka07:01:48

At least I could make a modified copy of the eval-str function that does the string modification before passing the opts, but I need to think if there's a way to neatly tie that with the existing <ll>er, <ll>ee etc commands

Hukka07:01:52

Hm, ok. Hadn't thought about debugging yet. Running criterium, async-profiler etc is pretty straightforward

Hukka07:01:39

I sure wouldn't mind, if your additions would offer that, and I could go back to just loading plugins!

Martynas Maciulevičius07:01:00

> I could go back to just loading plugins I'll simply add them as functions. You'll not need to use the test functionality to use them. I'll do it like this (this one already works but I want to add all of them):

:CcaCriteriumQuickBench

(defn criterium-quick-bench! []
  ;; Source: 
  (eval.command
    (.. "(do (when-let [add-libs (requiring-resolve 'clojure.tools.deps.alpha.repl/add-libs)]"
        "      (add-libs {'criterium {:mvn/version \"0.4.6\"}}))"
        "    (require 'criterium.core)"
        "    (criterium.core/quick-bench " (get-current-form-content!) "))")))
Then you'd simply bind them to what you like. If Olical would like this to be part of the main plugin then he'd only need to copy the code into Conjure as it's the same Fennel source.

Hukka07:01:25

That requires the special branch instead of release of tools deps alpha, right?

Martynas Maciulevičius07:01:15

> That requires the special branch instead of release of tools deps alpha, right? It requires add-deps3 BUT requiring-resolve returns nil if there is no such function 🥳 So no problems here. It will simply crash and should probably show errors.

Hukka07:01:34

Ah yes, that's neat

Hukka07:01:50

Is get-current-form-content! your code, or part of Conjure?

Hukka07:01:27

github's search doesn't show it from either 😕

Martynas Maciulevičius08:01:09

> get-current-form-content!

(defn get-current-form-content! []
  (a.get (extract.form {}) :content))

Hukka08:01:22

Hm. Reading the code at https://github.com/Olical/conjure/blob/master/fnl/conjure/extract.fnl#L11 but it's a bit beyond me. Don't know when opts.root is set etc. But no matter, I don't have very specific requirements, so I'm sure I'll be happy with it

Hukka08:01:00

And if I'm not, then I guess it's time to really start learning how conjure and aniseed works, since I don't really want to use lua either 😉

Martynas Maciulevičius08:01:57

> but it's a bit beyond me I didn't even do that. I used what Olical did. I needed the current form somewhere so I found what he used in his code. I don't really have a nice test and src separation in my project (my tests are in comments) but that doesn't matter as it's simply a large hack and I don't care 😄

Martynas Maciulevičius08:01:21

Opening a simple firefox is so hard in lua... why did they do this... https://lua-users.org/lists/lua-l/2013-08/msg00274.html I simply wanted to get stderr and stdout... 😞 Without hardcoding any fancy shell oneliners that redirect all of it around. I'll do this and won't care about success output then:

bad-command 2>&1 1>/dev/null

Hukka08:01:06

The answer sounds pretty reasonable; it's not that they did that, they just didn't do much at all and went with absolute base level of C api functionality

Hukka08:01:41

Surely in the last 9 years someone has made different api too?

Martynas Maciulevičius08:01:56

> Surely in the last 9 years someone has made different api too? Nope partyparrot io.fopen returns a single pipe, then I can use f:close to close that pipe and then I get one true as a result. I should get [true output err-code] but for some reason I can't get it in Fennel. I'm not sure why. Probably I don't know some syntax.

Martynas Maciulevičius09:01:15

I can download it... but should I require it to be downloaded? I don't think I want this. Oneliner it is:

`which open 2>/dev/null || which xdg-open 2>/dev/null` "file:///tmp/clj-async-profiler/results" 2>&1 1>/dev/null

Hukka09:01:56

Yeah, the whole luapower seems to be something else entirely… "Luapower is a binary+source module distribution for http://luajit.org/luajit.html and http://terralang.org and a way of deploying and sharing Lua modules." and deprecated too

Hukka09:01:30

But hey, imagine doing it in vimscript 🙂

🙌 2
Martynas Maciulevičius09:01:32

I'll have two functions. One for executing the profiler and another to open the directory of results.

Martynas Maciulevičius09:01:47

Unfortunately I had to add try-catch to the resolving-require 😄 So it wasn't just nil. But there they are: https://github.com/Invertisment/conjure-clj-additions-cider-nrepl-mw#flamegraphs-criterium-and-other-things Open the readme to see how to bind them.

Hukka09:01:16

Did you make that screenshot as custom work, or do you have something that shows the keybinds?

Martynas Maciulevičius09:01:54

> Did you make that screenshot as custom work, or do you have something that shows the keybinds? Plug 'folke/which-key.nvim' I bound the key bindings the same way as my README suggests and then I pressed <localleader>f. i.e. <localleader>fc executes :CcaFormClass

Hukka09:01:54

Yeah, which-key was mentioned earlier too. Seems like the popular solution 🙂

Martynas Maciulevičius09:01:59

This is my setup for which key:

lua << EOF
require("which-key").setup {
  -- 
  plugins = {
    marks = false,
    registers = false
  },
  presets = {
    operators = false,
    motions = false,
    text_objects = false,
    windows = false,
    z = false,
    g = false,
  },
  show_help = false,
  -- 
  -- your configuration comes here
  -- or leave it empty to use the default settings
  -- refer to the configuration section below
  }
EOF
The EOF and the beginning markers are needed because I use this as a snippet inside Nvim's init.vim file directly without any other files. I didn't like some of which-key's defaults so I disabled them. It's sometimes distracting.

Hukka09:01:05

I'll have to consider switching to fennel based configuration, if I'm doing some larger changes anyway at the moment. https://github.com/Olical/magic-kit/ looks like a handy intro. Honestly I wasn't in lua based config either, yet, so might go with that kind of snippet too in init.vim

Hukka09:01:41

(If I'm doing lisp in vim, should I just consider vim in emacs again…)

Martynas Maciulevičius09:01:33

I didn't bother with any config migration because I'm lazy 😄 My config tries to be pretty light and I already have 916 lines of vimscript with quite a bit of Lua chunks. My old vim config was very small but when I came from Spacemacs to Nvim I configured a lot of things and Lua code is very long in lines. I was unhappy that Spacemacs + evil mode can't do vim motions in all its windows. This is why I switched. I didn't need much of the functionality of CIDER. I used it on a basic level :thinking_face:

Martynas Maciulevičius10:01:12

I had a typo in my function name. Fixed now. CcaFormDisasssemble -> CcaFormDisassemble

Olical13:01:57

Woah, long thread! Sorry for the slow reply, I've seen the notifications flying by but haven't had the time to look. (I'm in the run up to a move at the end of the month and lots of other life things going on, so time is hard to come by right now) So I'm open to adding more mappings to the Clojure client specifically that invokes ops in CIDER middleware, that's totally fine. I don't mind one client having some features that others don't have really, I treat Clojure as the first class client, the others are "best effort" since Clojure is the language I dogfood and have the most knowledge about / investment in. I leave the other clients up to the enthusiasm of their respective communities (after I get initial support working sometimes). A mapping that invokes some decompile nREPL op shouldn't be too hard to implement, it'll be very similar to some existing mappings inside the Clojure client. Feel free to open an issue describing the functionality and any info you can gather such as what op is required. All op calls are wrapped in a "maybe" guard that will fail cleanly if the op isn't present in the nREPL. I won't go injecting dependencies and middlewares on behalf of the user yet, but I will call ops if they exist and ignore them if they do not. I also apologise if I've said otherwise in the past, but this is my current stance on it 😅 I may have changed my mind since I last thought about these things. Also, having a 3rd party plugin that adds FAR more CIDER features on top of the Clojure client is a perfectly good situation. It allows other people to add and maintain that extension, growing it without the need for me gatekeeping commits as and when I get time. I really want to encourage 3rd party plugins / extensions / mods for Conjure that add stuff like this, but I'm still open to adding them to the core.

Olical13:01:17

I'm biased, but I massively prefer Fennel + Lua to elisp 😛 (mostly because Fennel smells like Clojure and I already knew some Lua stuff)

Olical13:01:35

Conjure's internal libraries include all the code required to: a) Create mappings b) Manage config values and defaults c) Extract code from under the cursor, either the current form or the root form d) Send code to an nREPL for eval e) Send non eval ops to the nREPL to perform other actions f) Async await the result of that op execution and print some sort of output to the log (the primary and only real UI for the plugin) So all of the building blocks are there to add this functionality. It'd mostly be a copy/paste/rename/edit exercise, not breaking new ground as such which is good news. I think we should get issues created with as much context as possible with all of the required nREPL ops. A pass over the client to add a bunch more ops could be fun if done all in one sweep. I still need to create my debugger DAP project to handle all of the debugger ops... I keep putting that one off.

Martynas Maciulevičius13:01:06

@U38J3881W For me the outcome of this thread was this: https://github.com/Invertisment/conjure-clj-additions-cider-nrepl-mw/blob/master/fnl/conjure-clj-additions-nrepl/additional-fns.fnl#L67 It's possible to add these into Conjure, it would be a copy-paste. It could also be a third library...

emilaasa14:01:12

Great thread! I'm eager to try some of this stuff 🙂