ClassName completion in custom language

Let's assume I have a minimal custom language. The language actually only contains references to Java project/library classes, with some minimal syntax:
-


{
...java.lang.String,
...org.foo.Bar,
...java.util.LinkedList
}

-


(above snippet would be a valid example of the language)
Now, when I type a Java classname in this language, I'd like to have the convenience of ClassName completion:
-


{
...java.lang.String,
...SDF<Ctrl-Alt-Space> // Should suggest 'java.text.SimpleDateFormat' and other matches
}

-



It seems I'm looking for two pieces of functionality:

1) Given a CamelHumps pattern, find a list of matching types.
In addition, I'd like to filter in arbitrary ways, for example: "both abstract and concrete classes, but no interfaces or enums"

I suspect this is the OpenAPI somewhere.

2) A way to hook into the ClassNameCompletion action.
In this case, the custom language would not be injected (separate filetype), if that makes any difference.

If this is not possible at the moment, I'll take that for an answer.

Regards,

-tt

(apologies for any duplicate messages, seems posting to the openapi group is a bit unreliable today)

6 comments

1) Given a CamelHumps pattern, find a list of
matching types.
In addition, I'd like to filter in arbitrary ways,
for example: "both abstract and concrete classes, but
no interfaces or enums"

I suspect this is the OpenAPI somewhere.

2) A way to hook into the ClassNameCompletion
action.
In this case, the custom language would not be
injected (separate filetype), if that makes any
difference.


I don't think there's any dedicated API to extend the ClassNameCompletion (just the same as for SmartCompletion). The most promising approach might be to subclass com.intellij.codeInsight.completion.actions.ClassNameCompletionAction and to register the action either with a custom shortcut or to hook the original action.

You can probably post-process the result you get from the original completion handler (or the CompletionData it uses) to filter out stuff you don't want in a certain situation.

Sascha

0

2) A way to hook into the ClassNameCompletion
action.
In this case, the custom language would not be
injected (separate filetype), if that makes any
difference.


I don't think there's any dedicated API to extend the
ClassNameCompletion (just the same as for
SmartCompletion). The most promising approach might
be to subclass
com.intellij.codeInsight.completion.actions.ClassNameC
ompletionAction and to register the action either
with a custom shortcut or to hook the original
action.


How do I hook an existing action? (For a specific filetype only, if possible)

You can probably post-process the result you get from
the original completion handler (or the
CompletionData it uses) to filter out stuff you don't
want in a certain situation.


I have not done any tests yet, but the more I think about it the less likely it seems this will work. The original completion handler should not be able to do anything meaningful, because my language will be totally unknown to it.

In this case I have my own FileType, if I do CompletionUtil.registerCompletionData(), will that provide me with something usable?

I think that I can implement the actual work that "Class-Completion" does, in the context of my language. It seems the only thing I want do is: block the call to the regular ClassNameCompletionAction, and execute my own action instead, but only when the current editor has a file of my specific filetype.

0

How do I hook an existing action? (For a specific
filetype only, if possible)


See the XSLT support's refactoring actions implementation. The basic procedure is:

- Get old action from ActionManager
- Unregister old action
- Create a wrapper action that either executes custom logic (if the filetype matches) or delegates to the old action
- Register new action with same ID as the old one

I have not done any tests yet, but the more I think
about it the less likely it seems this will work. The
original completion handler should not be able to do
anything meaningful, because my language will be
totally unknown to it.


I forgot about that, but you should be able to supply your own CompletionData implementation to a subclass of ClassCompletionHandler.

In this case I have my own FileType, if I do
CompletionUtil.registerCompletionData(), will that
provide me with something usable?


Probably only for the "regular" ctrl-space completion.

Sascha

0

How do I hook an existing action? (For a specific
filetype only, if possible)


See the XSLT support's refactoring actions
implementation. The basic procedure is:

- Get old action from ActionManager
- Unregister old action
- Create a wrapper action that either executes custom
logic (if the filetype matches) or delegates to the
old action
- Register new action with same ID as the old one


Ok, this was my first idea: intercept the original action, do the CamelHump matching, filtering, showing popup, etc myself.


I have not done any tests yet, but the more I think

about it the less likely it seems this will work.

The

original completion handler should not be able to

do

anything meaningful, because my language will be
totally unknown to it.


I forgot about that, but you should be able to supply
your own CompletionData implementation to a subclass
of ClassCompletionHandler.


Did you mean to type "ClassNameCompletionHandler"? I suppose that that's the default action that runs when I type Ctrl-Alt-Space? I guess this class has a companion in ClassNameCompletionData...

Now, it seems that this duo works in XML attributes as well, so that's encouraging.

However, apart from not understanding what most of the methods on those classes do, don't they contain some dependenies on the Java filetype? Optimizing imports after class completion is one example I can think of.

0

Did you mean to type "ClassNameCompletionHandler"?


Yep.

However, apart from not understanding what most of
the methods on those classes do, don't they contain
some dependenies on the Java filetype? Optimizing
imports after class completion is one example I can
think of.


I don't think there are dependencies that would make your use-case impossible to imlpement. AFAIK, e.g. the generation of an import statement is done by PsiManager.getCodeStyleManager().shortenClassReferences().

Sascha

0

I'll certainly try to make your suggestion work.

Just for my own understanding, how does the ClassNameCompletionHandler operate? I mean, I have my own custom PSI, so that is out of the question.

Is it likely that it just looks at the caret position, and tries to match a CamelCase string up to certain terminal characters?

0

Please sign in to leave a comment.