Completion and IDE Support

Compiler-based Completion

Because of the high number of Haxe features and its powerful type inference, IDE and code editors cannot easily handle completion by parsing the Haxe files.

Haxe provides completion support for IDE directly built in the compiler thanks to the --display commandline parameter.

Let's have a look at the following example :

class Test {
    public static function main() {
        trace("Hello".|
    }
}

The vertical bar indicates the cursor position after the dot has been pressed. At this time, this is the job of the IDE to call the Haxe compiler with usual compilation parameters, plus an additional one --display Test.hx@73.

This parameter tells the file in which we want some completion and the byte position of the cursor in the file. In that example if you count characters with windows CRLF lines ending, you should get 73.

Haxe will perform all the parsing and typing as it would do for normal compilation, except that it will not generate any code. If during its compilation it is reaching the byte 73 in file Test.hx it will output the informations about the type of the expression that is on the left of the dot.

In our case, that would be String. Except that in the cases of an anonymous object or a class instance, the compiler will instead list the different fields in an XML and print them to the standard error output. Here's an example of output :

<list>
<i n="length"><t>Int</t><d>...</d></i>
<i n="charAt"><t>index : Int -> String</t><d>...</d></i>
<i n="charCodeAt"><t>index : Int -> Int</t><d>...</d></i>
<i n="indexOf">
  <t>value : String -> ?startIndex : Int -> Int</t>
  <d>...</d>
</i>
...
</list>

In that case, all public methods and fields of String are listed. This information can directly be used by the IDE to provide code hints and completion.

Functions completion

This completion mechanism works with both dot and opening parenthesis, so you can get type informations about fields list and function call arguments types :

class Test {
    public static function main() {
        trace("Hello".split(|
    }
}

This will give you the following result :

<type>delimiter : String -> Array<String></type>

(Please note that in real output, the content of the type not is html-escaped)

Package completion

It also works with packages, by scanning the .hx files available in the classpath :

import haxe.|

Will return :

<list>
    <i n="BaseCode"><t></t><d></d></i>
    <i n="EnumFlags"><t></t><d></d></i>
    ...
    <i n="io"><t></t><d></d></i>
    <i n="macro"><t></t><d></d></i>
    <i n="remoting"><t></t><d></d></i>
    ...
</list>

Error Handling

When run in completion mode, the compiler will not display errors but instead try to ignore them or recover from them.

In case a not recoverable error occur while getting completion, the Haxe compiler will print the error message instead of the completion output. You can then treat any not-XML output as an error message which prevent the completion from being performed.

Compilation cache server

new in 2.09

To get best speed for both compilation and completion, you can use the --wait commandline parameter to start a Haxe compilation server. You can also use -v to have the server printing the log. Here's an example :

haxe -v --wait 6000
Waiting on 127.0.0.1:6000

You can then connect to the Haxe server, send commandline parameters followed by a 0 byte, then read the response (either completion result or errors).

You can use the --connect commandline parameter to have haxe send its compilation commands to the server instead of executing them directly :

haxe --connect 6000 myproject.hxml

Please notice that you can use --cwd as the first sent commandline parameter in order to change the Haxe server current working directory, since usually class paths and other files are relative to your project.

How it works

The compilation server will cache the following things :

  • parsed files : the files will only get parsed again if they are modified, or if there was a parse error
  • haxelib calls : the previous results of haxelib calls will be reused (only for completion : they are ignored when doing a compilation)
  • typed modules : compilation modules will be cached after a successful compilation, and can be reused in later compilation/completions if none of their dependencies have been modified

You can get precise timing of the times spent by the compiler and how using the compilation server affects it by adding the --times command line.

Protocol

As the following Haxe/Neko example show, you can simply connect on the server port and send all commands (one per line) ending with a 0 binary char. You can then read the results.

Few additional things however :

  • macros and other commands can log some data which are not errors. In command line we can make the difference between what is printed on stdout and what is print on stderr, but this is not the case in socket mode. In order to differentiate between the two, log messages (not errors) are prefixed with a \x01 character, and all newlines in the message are replaced by the same \x01 character.
  • warnings and other messages can also be considered errors, but are not fatal ones, if a fatal error occurred, we will send a single \x02 message-line

Here's some code that will treat connect to the server and handle the protocol details :

class Test {
    static function main() {
        var s = new neko.net.Socket();
        s.connect(new neko.net.Host("127.0.0.1"),6000);
        s.write("--cwd /my/project\n");
        s.write("myproject.hxml\n");
        s.write("\000");
        var hasError = false;
        for( line in s.read().split("\n") )
            switch( line.charCodeAt(0) ) {
            case 0x01: neko.Lib.print(line.substr(1).split("\x01").join("\n"));
            case 0x02: hasError = true;
            default: neko.io.File.stderr().writeString(line+"\n");
            }
        if( hasError ) neko.Sys.exit(1);
    }
}

Effect on macros

The compilation server can have some side effects on macro execution, read this page for more detailed informations.

version #19356, modified 2013-05-10 09:29:15 by jason