vim

Hukka 2023-01-10T12:02:44.622639Z

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

Hukka 2023-01-10T12:03:30.492939Z

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

lispyclouds 2023-01-10T12:04:51.018589Z

menu showing options: https://github.com/folke/which-key.nvim

lispyclouds 2023-01-10T12:05:21.297699Z

this is pretty much a direct port of the emacs thing

Hukka 2023-01-10T12:06:17.664359Z

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

lispyclouds 2023-01-10T12:08:06.271079Z

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

lispyclouds 2023-01-10T12:11:03.354599Z

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

Hukka 2023-01-10T12:12:05.483159Z

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

Hukka 2023-01-10T12:15:52.367289Z

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

lispyclouds 2023-01-10T12:16:30.678799Z

@olical could have knowledge to drop here maybe šŸ™šŸ¾

Hukka 2023-01-10T12:17:42.836889Z

opts.code seems to be the right place

lispyclouds 2023-01-10T12:18:30.986789Z

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?

Hukka 2023-01-10T12:22:44.768099Z

Apart from the emacs wrangling, seems to build a string https://github.com/bsless/clj-decompiler.el/blob/master/clj-decompiler.el#L123 and https://github.com/bsless/clj-decompiler.el/blob/master/clj-decompiler.el#L94 send it wrapped as the right kind of op to nrepl

lispyclouds 2023-01-10T12:24:15.935279Z

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

Hukka 2023-01-10T12:30:42.850459Z

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

lispyclouds 2023-01-10T12:31:49.026339Z

yeah, hence hoping that Olical could have some points!

Martynas Maciulevičius 2023-01-10T12:58:40.942529Z

> 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čius 2023-01-10T13:46:41.711359Z

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

emilaasa 2023-01-11T04:32:14.674049Z

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

Hukka 2023-01-11T07:41:05.086499Z

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čius 2023-01-11T07:43:39.652599Z

> 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 šŸ¤”

Hukka 2023-01-11T07:43:48.568269Z

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

Hukka 2023-01-11T07:44:52.432859Z

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

Hukka 2023-01-11T07:45:39.518449Z

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

Martynas Maciulevičius 2023-01-11T07:47:00.259009Z

> 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.

Hukka 2023-01-11T07:50:25.814079Z

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

Martynas Maciulevičius 2023-01-11T07:53:15.970859Z

> 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.

Hukka 2023-01-11T07:53:34.493929Z

Ah yes, that's neat

Hukka 2023-01-11T07:54:50.540569Z

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

Hukka 2023-01-11T07:56:27.314509Z

github's search doesn't show it from either šŸ˜•

Martynas Maciulevičius 2023-01-11T08:05:09.077049Z

> get-current-form-content!

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

Hukka 2023-01-11T08:07:22.537869Z

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

Hukka 2023-01-11T08:08:00.814089Z

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čius 2023-01-11T08:10:57.153429Z

> 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čius 2023-01-11T08:52:21.597439Z

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

Hukka 2023-01-11T08:55:06.179789Z

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

Hukka 2023-01-11T08:55:41.148129Z

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

Martynas Maciulevičius 2023-01-11T08:55:56.001939Z

> 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.

Hukka 2023-01-11T08:57:50.237239Z

https://luapower.com/proc ?

Martynas Maciulevičius 2023-01-11T09:00:15.592369Z

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

Hukka 2023-01-11T09:00:56.652239Z

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

Hukka 2023-01-11T09:01:30.790179Z

But hey, imagine doing it in vimscript šŸ™‚

šŸ™Œ 1
Martynas Maciulevičius 2023-01-11T09:03:32.040459Z

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

Martynas Maciulevičius 2023-01-11T09:38:47.740529Z

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.

Martynas Maciulevičius 2023-01-11T09:39:31.741549Z

Screenshot:

Hukka 2023-01-11T09:41:16.161289Z

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

Martynas Maciulevičius 2023-01-11T09:42:54.456169Z

> 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

Hukka 2023-01-11T09:43:54.095149Z

Yeah, which-key was mentioned earlier too. Seems like the popular solution šŸ™‚

Martynas Maciulevičius 2023-01-11T09:44:59.921009Z

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.

Hukka 2023-01-11T09:52:05.994169Z

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

Hukka 2023-01-11T09:53:41.361909Z

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

Martynas Maciulevičius 2023-01-11T09:55:33.234229Z

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 šŸ¤”

Martynas Maciulevičius 2023-01-11T10:40:12.812899Z

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

Olical 2023-01-11T13:15:57.760039Z

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.

Olical 2023-01-11T13:16:17.930579Z

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

Olical 2023-01-11T13:21:35.751429Z

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čius 2023-01-11T13:32:06.868079Z

@olical 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...

emilaasa 2023-01-11T14:49:12.605359Z

Great thread! I'm eager to try some of this stuff šŸ™‚