Abstract. This post explains how code completion works in IntelliJ. It tells you how to implement it in your plugin, how to avoid common mistakes and how to handle advanced scenarios. You can also work through the code of a sample plugin which adds completions from a dictionary.
In this article you’ll learn how to implement code completion in your IntelliJ plugin.
Code completion is one of the most important features of your IDE. The IntelliJ help contains a lot of information about using it. But here, we’ll be looking at it from a developer’s point of view.
This article is about the extension point
completion.contributor and deals with:
- basic completion
- smart completion
- class name completion
It does not deal with:
- hippie completion – because it’s unrelated to the extension point we’re covering
- postfix completion – it’s more relevant than hippie completion, but still not covered by the extension point we’re discussing here
You’ll learn the most relevant points about the different types of completions. After that we’re going to implement word completion from a dictionary. This is what you’ll get:
There are several types of code completion: basic completion, smart completion, class name completion.
In code, these completion types are defined by the enum
The is the default completion type. It’s usually invoked by Ctrl + Space on Windows/Linux and ^ + Space on macOS.
This is the alternative completion mode, usually invoked by Ctrl + Shift + Space on Windows/Linux and ⌃ + ⇧ + Space on macOS.
For Java code, smart completion displays only those items which match the current context.
For example, when you invoke it after a
return keyword, only variables and methods which are compatible with the return type are shown.
It’s your call if you implement smart completion and how smart it’s going to be. Usually, basic completion would return completions which are syntactically valid. Smart completion would filter these to remove the semantically invalid items.
Class name completion
Used for the completion of class names. Within the IntelliJ Community Edition, this is only relevant for Java code, as far as I can tell.
The only reference I could find in the sources is the
You won’t need to implement this, unless you want to provide additional data in this specific context.
As you know, plugins implement extension points to tell the IDE what they’re capable of.
The extension point for code completions is called
This is the declaration and all attributes it supports. Check out the next section to learn how to use these attributes – and by the way, IntelliJ 2019.2 includes nice code completion for the attribute values.
- A class implementing
com.intellij.codeInsight.completion.CompletionContributor. Use the
factoryClassif you want to choose the implementation at runtime. You have to provide a value for either
- Class of a factory to return your implementation. It has to implement
com.intellij.openapi.extensions.ExtensionFactory. You’ll rarely need this. Use it to choose one of several implementations at runtime. Or use it to configure the implementation you return.
- An optional
Stringargument passed to the
createInstancemethod of your factory.
- This is the language for which your implementation provides the completions.
Most often it will provide completions that are only relevant for a certain file type, e.g.
Python. You don’t want to show names of Python functions in Java code, for example. Use the value
"any"if you want to enable your implementation for all types of files. If you need to support multiple languages, then add the
<completion.contributor … />element multiple times. Use IntelliJ’s code completion to see the available choices for the value.
- Contributors are called one after another.
Use this attribute to force your provider to be
before <id>, or
after <id>. You won’t need this most of the time. A use-case for
firstis when you’d like to filter completions of other completion contributors. See Filtering completions. A use-case for
afteris when you’d like to order two or more contributors of your plugin.
- The ID of your completion contributor. These IDs are referenced by
afterof other completion contributors.
- Enable your implementation only for the given operating system, e.g.
linux. IntelliJ’s code completion tells you about the supported values.
At this point you should decide a few things:
- which file types you want to support, i.e. the languages you’re supporting
- which completion types you want to support, i.e. basic and/or smart completion
- where completions should be shown in a file. You don’t want to suggest a class name where it’s not allowed, for example.
First, define a class which extends the base class of this extension point:
Now, you have a choice to make:
- You can override
- Or you can implement a
extend()in the constructor to tell IntelliJ which completion type(s) and context you’re supporting.
Both options are discussed in the subsections below.
How to implement
This is the generic approach.
IntelliJ’s implementation just iterates over the data which was added by
If you don’t want to use
extend(), then override this method.
This is a bit easier to implement than a
How to implement a
This is the recommended approach. It’s a bit more complicated to understand and to debug because it is an abstraction of common use-cases of code completion.
extend’s signature is:
- It defines which completion type you’re supporting. You’ll usually use
nullto support all.
- This defines the context which is supported by your provider. The SDK already comes with a lot of patterns you can use here. See below for more information on patterns and where to find them.
- This is your implementation to provide completions specifically for the given type and context. If you’re using
extend()multiple times, then each provider usually serves a subset of the possible completions.
For example, it could compute a list of all class names to show after the
extendskeyword in Java. Another provider could compute a list of interface names to suggest after the
Patterns are a bit hard to grasp at first. It always feels a bit over-engineered to me, but once you get it it’s a nice tool in your belt. But beware, getting used to it might take a while.
Let’s take a visual approach to understand how this thing works. Suppose you’d like to suggest a list of valid locale names in this code snippet:
A pattern starts with the PSI element at the text cursor’s position. The PSI structure of this code snippet looks like this:
We have to make sure that:
- we’re only completing a value in a string literal
- the literal is the first argument of
Now, a pattern which matches the innermost
String literal (highlighted in the illustration above), is
But this is matching all strings, not just the argument to
We have to make this pattern more restrictive.
Let’s take another look at the PSI structure. The parent of the literal is a
grandparent is a
PsiExpressionList. And the next ancestor finally is the
PsiMethodCallExpression we’re looking for.
You can use
withParent(...) on a
PsiElementPattern to check the hierarchy. You can add your own logic via
Chained calls of
withParent() all operate on the same element. Therefore we have to nest these calls.
With this knowledge we finally get this:
It’s still not good enough, though:
- It’s not checking that
java.util.Locale. It still could be another class of the same name.
- It’s not limiting the completion to the first argument.
After digging into the sources of the IntelliJ SDK, I was able to come up with this:
When I’m unable to get a pattern to work, then I usually add a call to
true with a breakpoint.
If you’d like to quickly iterate on this, then add a test case and incrementally fix the pattern logic.
Common patterns in the SDK
There’s a bunch of patterns available in the JetBrains SDK:
- Very basic patterns. This offers the useful utilities
- This offers PSI based patterns. Most useful are
Don’t forget that the patterns returned by these methods provide chainable methods. For example
- Most useful when you’re working with Java PSI. Before you write your own pattern for Java code, take a look at this class.
How to implement a test case
With a fixture-based test, testing completions isn’t difficult.
Here’s a simple test which tests basic completions:
Testing with automatic invocation
There’s a nice utility class
CompletionAutoPopupTester. It helps to test completions with the automatic
Here’s a simple test which makes use of
Example: Dictionary completion
Finally, we’re ready to implement our plugin!
We’d like to complete words with items from a dictionary. IntelliJ comes with built-in dictionaries, so we’re reusing this data. Accessing this data isn’t straight-forward, though.
But let’s get started!
The result should look similar to this:
For our plugin, we’d like to implement these features:
- automatic completion anywhere inside of plain text files
- automatic completion inside of string literals of any language
- manual completion at any place in any file
- support to complete upper-cased and lower-cased words, i.e. both
thehave to be supported
- no completion immediately after whitespace. We always require a prefix for completion as we don’t want to add the whole dictionary to the popup.
The code is available at jansorg/intellij-code-completion on GitHub.
First, let’s add the extension point to the
You now can use the quick-fix on
StringLiteralDictionaryContributor to create the missing class.
language=any to enable it in all file types, as we want to support completions in string literals of any language.
Add a test case
Let’s do it “test-first” and start with a test case. We’ll extend this later on.
Let’s implement the completion contributor next.
We’re starting with completions in plain text files. So, we need to find out about the internal structure of a plain text file.
Create a text file and check out the PSI structure via Tools → View PSI Structure of Current File.
You’ll see that this type of file does not display a PSI structure. Go and dig into the IntelliJ Community Edition sources to
find out more about the plain text type. Finally, you’ll come across
is always returning a single element which covers all of the content. Its type is
This means that you only need to check for this element type.
At this point you’ll have to create your
DictionaryCompletionProvider. We’re passing a flag to tell if it’s only
enabled in manual popup mode.
Accessing IntelliJ’s dictionaries
We want to access all built-in dictionaries.
After poking around in the sources of IntelliJ Community Edition, I finally encountered Dictionary.java. I’m not pasting the source here, because it’s not directly relevant. The source code is linked above.
We want to add dictionary data to the completion result:
Complete any string literal
We’re not yet showing completions in string literals of any language.
We have to implement our own pattern, because there’s no suitable implementation in the SDK.
We’re registering this pattern with another call to
We’re still missing the last piece of the puzzle: manual invocation should always display completions, no matter where. This is easy to add: use a pattern which accepts all elements.
You’re done! Make sure that your tests are passing and play around with it in your IDE.
You can find the full set of sources on GitHub:
originalFile or its
If you add
orignalFile or any of its PSI elements to the result, then IntelliJ will display
invalid element in the list of completions. This usually happens when the user modifies the file while
completions are displayed. Modifications invalidate PsiElements of your original file, which then become
unusable in the completion item you just added.
By default, a completion contributor is not called when indexing is in progress.
com.intellij.openapi.project.DumbAware to provide completions during indexing. Of course, you must not access
indexes or stubs to provide completions while indexing is in progress.
Completions based on the number of invocations
Code completion can be invoked multiple times in a row. The number of invocations is passed to the extension of your plugin. This means that you’re able to return more or different results for the 2nd or 3rd invocation, for example.
The number of invocations is provided by
Hiding other completions
You can use the method
stopHere() of your
CompletionResultSet to exclude all following contributors. Don’t do this unless you have very good reasons.
You wouldn’t like it either, if other plugins disabled completions of your own plugin.
If you only want to show your own completions, then you typically want to run your contributor first:
Filtering other completions
You can use
CompletionResultSet.runRemainingContributors(...) to filter the completions of the remaining contributors.
order="first" if you want to filter the results of all other contributors.
But this is rude. Always be nice and kind to other plugins in your runtime space 😉
Handle automatic invocation
Code completion is either automatically invoked while typing or manually by the user.
CompletionParameters.isAutoPopup() to find out it was invoked automatically.
Completions are wrapped with
If your completion contributor is doing a lot of work, then make sure to call
For example, when the user continues to type while completions are shown, the progress will be cancelled.
This method throws an exception when completions are cancelled. This exception is then caught by
ProgressManager, so you
don’t need to worry about it.
Custom presentation of items
LookupItem to customize the appearance.
The easiest way to create a
LookupElementBuilder. It provides chainable methods to configure
the different aspects of a
This is what you can do:
This will be rendered like this:
Resources on code completion
A few more articles on code completion:
- Writing a Completion Contributor: Documentation from the IntelliJ Platform SDK DevGuide.
- CompletionContributor.java: FAQ about writing a completion contributor in the IntelliJ Community Edition sources.
Use of patterns in the IntellJ Community Edition SDK:
More on code completion in the SDK: