Compiler-based Completion

How Completion Works

The IntelliJ-Haxe plug-in tries its best to give useful completions.  It does this by scanning all of the files in the project and its libraries, and keeping an index of those types.  When completion is requested (normally, via the Ctrl+Space key combination) on a partial word, the plug-in compiles a list of variable names and types that can occur that the caret (cursor) position, using any available characters at the left of the caret as a filter (e.g. to limit the list to those that match the typed characters).  There are several types of completions that are normally completed: Exact match, partial match (for mis-spellings), and CamelCase matches (e.g. use capitalized characters as if they were each the first letter in a sequence of words — allows “CH” to match “CamelHump”).  The plug-in tries to put the five most likely matches at the beginning of the list, and the rest are sorted alphabetically.

In practice this all works fairly well.  However, the plug-in doesn’t have “typing” information; it doesn’t know about unification, monomorphing, and the current type of a dynamic variable.  That sort of information is determined by the compiler.  Fortunately, the compiler team has realized that it’s difficult for IDEs to do such a thing and has created a mode of the compiler that will do the typing and return this information.  You can read about it in the Haxe Manual.

Compiler-based Completions

As of release 0.11.0, the Haxe plug-in can use the compiler to determine the typing results and give a better completion list.  However, it is at the cost of computation time and thus is disabled by default.  You can turn it on via the Haxe SDK sub-dialog (“File->Project Structure->SDKs-><HaxeSDK>”) in the completion section: check the “Use Compiler” checkbox.  If you would like to see all of the plug-in and compiler suggestions, then uncheck the “Remove Duplicates” check box.

Compiler Completions Check Box

(Note: Sometimes — especially on MacOS — the completion section of the dialog does not appear.  It normally appears if you change focus to another subsection, then return.)

Errors

There are a few errors that can occur when using compiler completion.  The first is simply that the project is not set up correctly.  In this case, when completion is attempted you will the error displayed in the status bar and see one of two types of messages inside of the editor, depending upon whether the plug-in itself has any results.  If it does not, then you will see a tooltip message like so:

Tooltip shown when an error occurs and there are no other suggestions.
Completion error from the compiler.

If the plug-in does have suggestions, then the message will be displayed in the bottom of the suggestion box:

Completion error when there are suggestions.
Completion error when other suggestions are available.

In this particular case, the problem is that the plug-in doesn’t have a project file to present to the compiler.  That can be fixed in the Project Structure dialog (“File->Project Structure->Module->Haxe”):

Where to place the project file path name.
Project file position for OpenFL projects.

Other errors can certainly occur, and when they do, the first message from the compiler is displayed, along with the source file and line number that caused the compiler to stop:

Error message from compiler when completion fails.
Error message from compiler when completion fails.

The same message will display at the bottom of the suggestion list if the plug-in was able to generate some completions.  (Unfortunately, creating a hyperlink out of the message turned out to be impossible using IDEA’s tooltip/dialog implementation.)

Haxe 3.2 issues

Completion was experimental and incomplete with Haxe versions between 3.2 and 3.4.  Many of the error messages are incomplete and/or incorrect.  For instance, you may see the message “package Foo should be src/Foo.”  There is really another error with the compilation, but the compiler had bugs that prevented correct messages from being returned.  With Haxe version 3.4, much effort was put into better completion services and getting better error messages.  If you can upgrade, you will have a much better experience with completion.

Better performance by using the compiler’s cache for completions

When compiler completion was introduced in 0.11.0, the plug-in did not try to take advantage of the compiler’s completion cache to get better performance, but you can set it up yourself.  The important things to know are:

  • The completion cache needs to be started independently.
  • The cache needs to be warmed up.
  • It doesn’t work with OpenFL.

Starting the compiler cache

To start the cache independently, run the compiler as described in Section 8.3.8 of the Haxe manual.  Externally to IDEA, start the compiler in --wait mode:

haxe -v --wait 6000

Then, add the following to your project file (modify as appropriate for the target type):

--connect 6000

Or, you can add it to the command line in the project structure dialog:

Adding completion server parameters.
Where to manually add completion server parameters.

Warming the cache

Like all caches, the compiler’s completion cache can only improve performance if it already has the information requested.  It doesn’t start out with that information; that has to be generated and loaded at some point.  That makes the initial request slower (but no slower than not using a cache at all).  The concept of pre-loading the cache is known as cache warming.  Some of the other IDEs that use a compiler cache — notably vshaxe — warm the cache by performing a complete compile when the IDE starts.  You can do the same by adding the --connect parameter to your project file and performing a full compile.  Just be sure to make the compile from within IDEA, or ensure that there are no differences between the parameters used in your external build and the ones specified in the project structure dialog.  If the parameters are different, then the compiler will determine that the cached data is invalid and will ignore the data it has already cached (and will try to save the new results in the cache).

This leads us to why OpenFL is problematic…

Why OpenFL breaks the cache

IDEA attempts to determine the set of arguments that are necessary for a completion request to the compiler.  For OpenFL projects, it relies upon the display functionality of the openfl command. display doesn’t create the same set of parameters as it does for a compile run, and you can’t get openfl to call the compiler for completion results. So, OpenFL projects can’t be sped up in this fashion. (At least until the OpenFL project fixes display. Once they do, then IDEA will “magically” start using the proper parameters.)