Autopopup code completion in custom language

Need to trigger the code completion in my custom language after certain characters (like "dot").
The default "after dot" setting for Java does not seem to work for custom languages.
Any idea how to solve that?

14 comments
Official comment

Use com.intellij.codeInsight.editorActions.TypedHandlerDelegate

Need to trigger the code completion in my custom language after certain characters (like "dot").
The default "after dot" setting for Java does not seem to work for custom languages.
Any idea how to solve that?


Not OpenAPI, but... In your own InsertHandler invoke later:
new DotAutoLookupHandler().invoke(project, editor, file);
Should work.

0

Thanks Peter! Looks like a feasible solution.

Yet, i didn't find out how to register my implementation of InsertHandler. Can you please give me some more hints? Didn't find any documentation on this.
Cheers, Dan

0

Yet, i didn't find out how to register my implementation of InsertHandler. Can you please give me some more hints? Didn't find any documentation on this.


Sorry, I've misunderstood you. I thought that you want to invoke this
list automatically after completing something with dot... Then you
should have the LookupItem you're completing and
lookupItem.setAttribute(LookupItem.INSERT_HANDLER_ATTR, new
MyInsertHandler())

And as for simple typing in the editor. Suppose you have typed "foo."
and want to see "bar" in the popup. Then your language should have a
construction "foo.bar". Does it have a reference on "bar" word, and does
it return anything interesting? If yes, then it seems to me that the
popup should appear automatically. Does any reference completion work in
your language?

0

Hi Peter,

my code-completion approach is a very dynamic implementation of PsiElement.getVariants().
Code completion is trying to suggest only variants which are applicable for the current caret position. For this, it is checking information coming from a jdbc connection against my language patern construct. To be more specific, the language is SQL.

e.g. If my SQL statement looks like this:

select * from MY_SCHEMA.<cursor position>

When I trigger code completion (Ctrl-Space) here, the list will display only datasets of the schema MY_SCHEMA. This works fine.
The only thing I want to do is to trigger the code completion dropdown automatically, after typing certain characters (like DOT or even COMMA)

I don't think I can use the InsertHandler here, since the DOT or COMMA are not necessarily result of code completion, but of plain typing.

I'm using an implementation of LookupValueWithUIHint, PresentableLookupValue, Iconable for the array returned by PsiElement.getVariants().

0

Is your language injected? Seems there's really a problem in such a case.

0

No. It is not an injected language. I identified some other issues while injecting it thru IntelliLang, but that's something different.

My approach is quite different than suggested in the openapi specifications. I identify the PsiElement prior to cursor, identify its position I my language tree, and build a list of "next possible tokens".
If the next token is a database object of type TABLE for example, then I build the list of tables as code completion variants.

I wonder if there is something like an input listener in the editor implementation, which responds on certain inputs and triggers the code completion popup.

0

Hi Peter,
have finally solved this with the editor-event api. (com.intellij.openapi.editor.event.*)

Have defined and registered my own DocumentListener within my custom EditorFactoryListener. This gives me now even more flexibility than only "after dot" completion.

Thanks anyhow for your help and time.
Regards,
Dan

0

And, as for me, I've fixed this behaviour so that it works in injected
languages, too... But I still don't understand how your completion
works. If it's PsiReference.getVariants(), then it should work. In other
ways, debug is needed...

0

I implemented the getVariants only for one specific PsiElement, the one which is representing one executable sql statement. This is also the scope I use for certain decisions.

In this implementation I check as I said the element before caret, and this contains enough information about what tokens should follow (that's how i built the language-pattern and parser). If the next possible token is a keyword this will be added to the array, if the token is an identifier of some database object, it will add all the applicable database objects to that array.

This may not be very conform to the specifications for custom ij languages implementation, but it works fine so far. ...besides of that DOT issue.. :)

0

I implemented the getVariants only for one specific PsiElement, the one which is representing one executable sql statement. This is also the scope I use for certain decisions.

In this implementation I check as I said the element before caret, and this contains enough information about what tokens should follow (that's how i built the language-pattern and parser). If the next possible token is a keyword this will be added to the array, if the token is an identifier of some database object, it will add all the applicable database objects to that array.

This may not be very conform to the specifications for custom ij languages implementation, but it works fine so far. ...besides of that DOT issue.. :)

Ghm. Do you mean you have only ONE PsiElement for the whole sql
statement? And you don't use PSI tree for its internals? In such a case
I wouldn't be surprised that some features didn't work. I'd be surprised
if some features worked! Or I've misunderstood you once again?

0

No. Of course not. I have a proper Psi structure.

While debugging the code completion i found out that getVariants is called progressively from the virtual IJRulezzzz element, up to the containing PsiFile.

Sometimes my virtual parsing can not concretely identify the element to be completed (due to multiple variants) and than i decided to follow the other approach i described above.

So I only implemented the getVariants in my own "ExecutableStatementPsiElement". The other nested calls simply return empty arrays.

0

No. Of course not. I have a proper Psi structure.

While debugging the code completion i found out that getVariants is called progressively from the virtual IJRulezzzz element, up to the containing PsiFile.

Sometimes my virtual parsing can not concretely identify the element to be completed (due to multiple variants) and than i decided to follow the other approach i described above.

So I only implemented the getVariants in my own "ExecutableStatementPsiElement". The other nested calls simply return empty arrays.


select * from foo.bar ......

I'd have (and I do) the following structure for the "foo.bar" element:

MyReferenceExpression
.MyReferenceExpression
..Token(foo)
.Token(.)
.bar

make MyReferenceExpression implement both PsiElement and PsiReference,
implement getVariants() there, analyze the context, the qualifier, Life,
Universe and everything and produce the necessary variants. During the
completion you have the same situation (except that you have Rulezz
instead bar, which doesn't affect the PSI tree). And this is imho very
natural, our JPA and Hibernate quaeries work precisely in this way.

I've tried to test autopopup in the QL and found another bug: it didn't
work in the end of file. Maybe this was also your problem. Fixed.



0

You may be right. I may need to review my implementation of code completion and make it more conform to the open-api specifications. But for now it is working fine with both 6.0 and 7.0, so i'll look into it later. Thanks a lot for your hints so far.

0

Please sign in to leave a comment.