IntelliJ Postfix Completion

Tools to fix things

Recently I wrote about which Essential IntelliJ Shortcuts our team is using the most. Shortcuts like the ones listed help you keep into the flow of programming without the need to jump around your code. To help you even further, a helpful but often overlooked feature is IntelliJ’s postfix completion, a feature which has been around since 2014 and improved in 2018.1. Unfortunately, not many people use this feature. In this blog post, I’ll dive a bit deeper into IntelliJ’s postfix completion and show which benefits it can provide.

How to use IntelliJ Postfix Completion

I’m assuming that most developers are aware of basic code completion; you type something, press Control + Space, and IntelliJ will do its best to provide helpful completions. However, when typing a variable name and you want to do something at the beginning of the line (like adding an if statement or a null check) there’s no need to navigate to the beginning of the line, but instead, you can use postfix completion, and let IntelliJ fix it.

Getting started with Postfix Completion

To get started with IntelliJ Postfix Completion, type in the following Java code:

"Hello World".<cursor here>

At the cursor here, type .sout, and then the Postfix Completions will show up. Selecting the sout option will replace the above into:

System.out.println("Hello World");

For another example, consider the following code in which we want to loop while the process flag is true. To do so, you can write the following:

boolean process = true;
process<cursor here>

Then typing .while will complete the code after the process variable, which will result in the following code:

boolean process = true;
while (process) {
   <cursor here>     
}

While there’s a long list of postfix completions available, I’ve listed a few below which I personally found the most useful:

NameDescription
.ifChecks boolean expression to be ‘true’.
.notNegates boolean expression.
.returnReturns value from the containing method.
.iterIterates over an enumerable collection.
.soutSystem.out.println

To see the complete list of Postfix Completions, either go to Settings -> Editor -> General -> Postfix completion, or type the name of the variable with a dot, and then press Ctrl + J (Cmd + J on Mac).

Note that some of the postfix completions are depending on the type of the variable you want to complete on. For example, if the type of the variable is a String, there’s a .format postfix completion available.

Downsides of Postfix Completion

While postfix completion might save a bit of navigation while coding, there are a couple of downsides of postfix completion. Some of these could explain partially the lack of adoption.

One of the downsides of postfix completion is that there are quite some missing templates. For example, using live templates, it’s possible to tokenize a String. However, when using a String type, there is no ‘tokenize’ postfix completion.

Another disadvantage is that it’s impossible to customize the completions and adding new ones is very limited. While live templates provide a way to customize their behavior, this is not possible for postfix completion.

Another downside is that the naming of live templates is different from postfix completion. For example, while both provide a way to check for null, live templates provide this as “ifn”, while the postfix completion calls it “.null”. This increases the mental overhead to remember both, which depending on your viewpoint, might not be worth it.

The last big downside is that it’s only possible to create postfix completion for Java, Javascript/TypeScript and SQL, and not for any other languages such as Kotlin.

Custom Postfix Plugin

To see how we can address some of the issues above, let’s look at the Custom Postfix Templates plugin. Stefan Endrullis created this plugin, and according to the plugin documentation it “lets you define your own postfix templates for Java, Scala, SQL, PHP, Kotlin, Python, Dart, JavaScript, Rust, Go and Groovy”. Besides that, it comes with many postfix templates which are automatically downloaded from several Github repositories.

Let’s have a look at the Custom Postfix Plugin and see how we can define our postfix. In this example, we’ll make a map and filter postfix, which will map and filter a Java Stream.

First, install the plugin using IntelliJ’s plugin manager (Settings -> Plugins -> search for Custom Postfix Plugin). Once we have installed the plugin and we’ve restarted IntelliJ, open either a Kotlin, Groovy or Java file and go to Tools -> Custom Postfix Templates -> Edit Templates of Current Templates. Then, choose to create a new user template file.

Since the built-in functionality of IntelliJ, unfortunately, doesn’t provide support for custom Kotlin Postfix completion, the plugin can help in that.

Kotlin

For our Kotlin Postfix Completion, we’ll create a Postfix which will map to .req, and which will be transformed into a require statement.

Let’s replace the example file which has been created for us by the plugin with the following code:

.req: require
	ANY  →  require($expr$$END$)

When using the above, the following code:

fun process(input : String) {
    input.req<cursor here>
}

Will be replaced with the following:

fun process(input : String) {
    require(input<cursor here>)
}

This will allow you to write a custom require based on the input.

Java

Alternatively, when using Java, we can create a custom Postfix Completion which will operate on stream. Again, we will replace the example file created by the plugin and replace it with the following content:

.smap : map a stream
	java.lang.Iterable  →  $expr$.stream().map(e -> $END$).collect(Collectors.toList());

.sfilter : filter a stream
	java.lang.Iterable  →  $expr$.stream().filter(e -> $END$).collect(Collectors.toList());

The above will create two postfixes, .smap and .sfilter, which will work on a type of java.lang.Iterable. IntelliJ will execute the postfix and will replace the instance on which this postfix will be executed ($expr$) by the stream code. In practice, we can use the above like this:

List<Integer> numbers = List.of(1, 2, 3);
number.smap<cursor here>

IntelliJ will replace the above with the resulting code:

numbers.stream().map(element -> <cursor here>).collect(Collectors.toList());

Conclusion

As we have seen in the examples above, IntelliJ Postfix Completion can, with a bit of training, be a handy tool. The Custom Postfix Plugin makes things even better, and defining your code for popular languages other than Java is trivial. I hope the above helped in making Postfix Completion a bit more popular, and as always, leave a comment below if you have questions or feedback!

Leave a Reply

Your email address will not be published. Required fields are marked *