Fork me on GitHub

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:

👍 3

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.


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


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


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?


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


@UR37CBF8D 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)

👍 3

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.


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


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.


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

👍 3

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 ;; 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 args) (bonus points for taking into account the existing nses already aliased)


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


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.


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


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?


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


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


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


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

👍 3