I'm working on a plugin that would add an inlay hint (via InlayHintsCollector.collectFromElement) to some of the :import clauses in an ns form. collectFromElement basically receives just an individual PsiElement at a time.
With help from https://clojurians.slack.com/archives/C0744GXCJ/p1638170040259600 I've been able to identify various Cursive elements, but trying to actually identify imports has eluded me. I've tried to look for a ClList whose getParent() is another ClList with first element :import (`ClKeyword`), and whose parent is another ClList with first element ns (`ClSymbol`). But not only is that very convoluted, but the results are maddeningly inconsistent. Is there a better way? If not, what am I doing wrong?
@cfleming can you offer any insight?
Sorry, I've had a busy couple of days, and this is an answer that requires some explanation. The issue is that Cursive doesn't model many language features in the PSI. To be reflected in the PSI, the parser has to know all the possible things it could parse up-front, which is impossible with macros. So what's in the PSI in Cursive is more like what you'd get back from the reader rather than an AST - collections, symbols, strings, lists etc. Then there's a higher-level Cursive-specific layer on top of that which does the language analysis dynamically over that layer. So Cursive is quite different to other IntelliJ plugins. Unfortunately that layer is much more difficult to plug into, and on top of that I'm gradually rewriting it at the moment since it was one of the first things I wrote way back in the day, and the current design makes many many things harder than they should be. So I think that right now, the way you're doing things is probably your best option, but you're right that it sucks. You could look into the IntelliJ Pattern stuff (https://plugins.jetbrains.com/docs/intellij/element-patterns.html), but honestly I just end up doing it by hand when I can't use my parsing infrastructure for whatever reason.
thank you for the explanation! I'd be happy enough to go with my current approach, but the problem is it doesn't seem to work consistently. I think sometimes the nodes are wrapped in LeafPsiElement, but not always? It would help if there were something that could easily print a whole Psi subtree for debugging
this is what I think should work, but doesn't:
if (element instanceof ClList singleImport
&& singleImport.getParent() instanceof ClList allImports
&& allImports.getFirstChild() instanceof ClKeyword importKw
&& "import".equals(importKw.getQualifiedName())
&& allImports.getParent() instanceof ClList nsForm
&& nsForm.getFirstChild() instanceof ClKeyword nsKw
&& "ns".equals(nsKw.getQualifiedName())) {oh derp, ns is a symbol not a keyword
Right. There are also a bunch of other forms that you might see, depending on how general you want this to be: (:import java.io.File), [:import ( etc.
What are you annotating, BTW?
ohhh, ClKeyword.getQualifiedName() returns ":import" rather than "import"
something similar to deprecation warnings, but for imports that aren't actually deprecated. We just want to slowly remove our uses of them from a large codebase
A simpler approach now that Cursive supports clj-kondo might be a custom kondo linter?
That will be marked in the editor, not in an inlay but as an inspection annotation.
that's a good option to keep in mind, but it's a bit more complicated than what I've described. Sorry I can't be more specific
oh my god, getFirstChild() on a ClList returns something different from getChildren()[0]. The former returns the opening paren, but the latter returns the "real" first child
That's.... possible? Seems weird though.
I just checked, that's all IntelliJ infrastructure at that level, not Cursive. I'd be surprised by that inconsistency, though.
I was also quite surprised, as it caused me several hours of headaches 😕
Are you managing to debug your plugin ok? Sometimes the setup can be tricky.
I actually build and manage deps with deps.edn and build.clj, just so I don't have to deal with Gradle. No-one has time for that.
eh, I've managed but it hasn't been pleasant. I have it working now anyway, at least this part of it