lsp

:clojure-lsp: Clojure implementation of the Language Server Protocol: https://clojure-lsp.io/
pithyless 2021-05-10T09:39:55.171400Z

There was a thread sometime ago about porting potemkin/import-vars like functionality to clojure-lsp. I'd actually like to see a LSP action that can one-time import a defn/defmacro from a different ns/var (just copy over the meta/docstring/args/etc and call the original for the actual implementation). Is this something that would be interesting to others and/or maybe something that is on the roadmap already? (Prior art I'm aware of is @lee's templates: https://github.com/lread/rewrite-clj/blob/main/script/lread/apply_import_vars.clj)

👍 1
pithyless 2021-05-10T09:44:36.171800Z

The way I envision it is just a nicer integrated editor/REPL experience for copying over and providing indirection for a certain var. The use-case I envision is that I may not want a carbon-copy; I may want to actually modify the docstring or e.g. do some pre-check assertions or modification of args before passing to the underlying implementation.

pithyless 2021-05-10T09:46:04.172Z

I wonder if there are others who have tried to create these kind of layers of indirection (e.g. to smooth over some API libraries or provide additional logic in a centralized location); or if I'm just an odd-duck and maybe this is a terrible idea. 🙂

ericdallo 2021-05-10T11:19:25.172200Z

Looks valid, do you have any tiny/minimal example of how the experience would be?

anonimitoraf 2021-05-10T11:28:03.172400Z

I read over potemkin's readme for import-vars but I don't think I understand it fully. So does it basically resolve the sequential dependencies between the vars/functions you import from other namespaces?

ericdallo 2021-05-10T11:30:47.172600Z

Yeah, AFAIK it's pretty common to expose functions for an public API

pithyless 2021-05-10T11:40:55.172800Z

@nicdaoraf the common use-case for import-vars is to create a public-facing api that re-exports vars from some internal (possibly multiple) namespaces. If you were to just refer to x in public-ns from impl-ns then someone importing public-ns would not have access to x. The way import-vars works, though, has some controversy because it works really hard to keep those two vars in sync (between ns-refresh, etc.) which has issues with AOT but also static tool analysis (frequently tools like Cursive or clj-kondo ended up writing custom hooks to deal with import-vars specifically)

👍 1
pithyless 2021-05-10T11:42:33.173Z

A different approach, as per the rewrite-clj example above, is to create a template that will be evaluated (eg by some babashka script) and it will generate real new source code - that can be statically analyzed, etc. The thing to watch out for, of course, is not to modify the generated file, since it can be overwritten at any point.

ericdallo 2021-05-10T11:43:12.173200Z

Yeah, my doubt here is how should be the user experience for that feature

pithyless 2021-05-10T11:44:33.173400Z

I was leaning towards the rewrite-clj templating approach, but I was finding more and more edge-cases that would need to be handled with further code (i.e. perhaps allowing custom hooks for overwriting docstrings, args, or function bodies). This is all dependent on the idea that we want to keep an automated way of syncing between the public-facing api code and the internal implementation. This is totally valid when just re-exporting existing functionality like rewrite-clj, but doesn't work well for me.

pithyless 2021-05-10T11:46:54.173600Z

What I find useful time and time again, is to provide a layer of indirection between my codebase and libraries that are used extensively in the internals (eg. malli, manifold, etc) - because (1) sometimes I want to add helpers that are not provided by the library, or (2) I want to wrap the logic in additional behavior before calling the underlying implmentation, or (3) perhaps modify docstrings etc (this one is kind of a stretch, but I can see how this could be applied in a team setting).

👍 1
pithyless 2021-05-10T11:50:01.173800Z

For these use-cases, I'm finding the need to keep the two-way sync is not as important, and often more confusing than if I just created a new var. So the flow I imagine is some way of typing ;; some.ns.foo/bar and then running a clojure-lsp action that will replace it with the actual form (docstrings, args, etc.) and replace the body with something ala (apply some.ns.foo/bar args) (bonus points for taking into account the existing nses already aliased)

ericdallo 2021-05-10T11:50:23.174Z

It makes sense, still would mind creating a issue for this with a repro showing a minimal code and how would you expect clojure-lsp do that for you? It's not clear to me how user would start that, via a code action or custom command, and if we should have multiple of those or a single sync one

pithyless 2021-05-10T11:55:29.174200Z

sure thing, I'll play around with the idea and submit an issue for discussion. Right now, this is already feasible by literally copy-pasting the code into your own namespaces. So I'm wondering, if even without the automation, this is something people would consider useful or are currently doing in their own projects.

ericdallo 2021-05-10T12:07:41.174400Z

yeah, I think the copy-paste is the most common case :man-shrugging:

Ed 2021-05-10T14:45:44.174700Z

Hi. I've just installed clojure lsp in emacs, and am playing around with it. It looks nice for working with code without setting up a repl. However, I'm having trouble convincing the breadcrumbs header to go away. I've done (setq lsp-headerline-breadcrumb-enable nil) and that doesn't seem to actually disable it, which confused me (is it buffer local or something??). So I did (add-hook 'lsp-mode-hook '(lambda () (lsp-headerline-breadcrumb-mode 0))) which mostly works until I open file from a new project and am prompted for a decision as to how to create the project (which I just answered i) and the header reappears until I reopen the file with find-alternate-file. This seems like a bug to me. Sometimes it seems like there's a delay between me opening the file and the breadcrumbs appearing, which implies to me that maybe it's got something to do with the server starting and it enabling the breadcrumbs when it comes up. Is this a known bug?

Ed 2021-05-11T13:22:37.175900Z

ah cool ... yes I didn't run lsp-workspace-restart... I assumed the delay was the server starting, and the fact that the breadcrumbs appear after the server starts implies to me that something is turning the mode on after I've turned it off with the mode hook. I didn't know about having to restart the workspace too - I'll try that and see if that fixes my problem. Many thanks

👍 1
ericdallo 2021-05-10T15:21:30.174800Z

Hey, (setq lsp-headerline-breadcrumb-enable nil) should disable it, but you need to restart the emacs or server via lsp-workspace-restart

ericdallo 2021-05-10T15:22:18.175300Z

To disable to a single buffer, disabling lsp-headerline-breadcrumb-mode should be enough

ericdallo 2021-05-10T15:23:12.175500Z

About the delay, it will only show after server startup, but this delays only when starting the project, after that each buffer open should be really quickly