How to prevent macro from running when using vshaxe and only run when actually compiling code?

How can i prevent my macro from being called because of the haxe LSP when coding my project in vscode with vshaxe and only run the function when we actually run haxe build.hxml?

1 Like

The display define indicates if the Haxe compiler is providing code completion or not.

#if !display

// code that shouldn't run when providing code completion

#end

Hmm weird, I’m having some troubles here, it appears that the display flag is never set for both final compilation or for completion. I wrote a very simple test Macro to test it out and I have set it to throw if we have the display flag, but it never throws:

#if macro
class Macroo
{
    public static function macroo()
    {
        #if display
        throw "Display!!";
        #end
    }
}
#end

Am I somehow using it wrong or am I encountering a real issue?

Tested on a Windows 11 and Linux (Arch) machines with Haxe 4.3.7 by the way.

You probably need to move it up a level, outside of the macro context.

#if display
throw "Display!!";
#else
Macroo.macroo();
#end
#end

Inside of a macro context, you might be able to check Context.defined("display"). Maybe. I haven’t tried.

Reflaxe (4.0.0-beta) has a check to prevent its reflect compiler from running if we’re running interpreted and the display flag is set, but as far as I can tell it still generates an output.

I did some testing and it appears that maybe the display flag define has been changed to be display_details instead? I don’t know if this is what happened but at least this new display_details flag get passed as a define ONLY when providing code completion so I guess it is what i’m looking for.

If this is unintended behavior let me know and I’ll file and issue over on github right away. Thanks for the help!

Yeah it doesn’t really work that well, it’s super unreliable. When compiling its never defined but when providing completion it sometimes is or isn’t…
I need a better solution.

There are three different modes in which vshaxe runs the compiler to provide IDE services:

  1. display: this is for completion, hover/goto definition and such … historically the first mode … it does a partial compilation, ingoring errors, trying to find the completion point, producing the required output for the IDE and then it is done … it has the display flag defined
  2. diagnostics: this compiles the full code, printing all errors but attempting to recover … to the best of my knowledge you cannot really detect this … IIRC a couple of years back @Simn gave some explanation why macro authors should not be able to detect this - I think it was along the lines of “macros should run the same in diagnostics and full completion to produce the same errors”
  3. “cache initialization”: not sure what else to call this, but this builds the full project when the language server boots, so that the two modes above can operate on a populated cache

In you particular case, I think it’s fair to say that mostly you want to be able to discern two cases:

  1. when the compiler is run to actually produce a build
  2. when the compiler is run for IDE services

There’s no sure fire way to detect the latter. But you can check haxe.macro.Compiler.getConfiguration().args. An easy check thing to check for is if it contains --no-output. All IDE service calls have that in common. It should be noted that this might also come from the user or some other library that acts as a backend. You can also look at the args more closely to determine if it’s an IDE service call, but then you’ll have the questionable pleasure of dealing with the different call conventions that different compiler versions have.

You should never use #if display or #if display_details as those won’t work as you’d think it would because #if is evaluated at parsing time. Context.defined might help there, but be cautious what you’re trying to avoid during display requests, as it’s very easy to trip the compilation server this way. Especially with Haxe < 5 where you can corrupt the cache, sometimes in a way that it cannot recover from.

IIRC a couple of years back @Simn gave some explanation why macro authors should not be able to detect this - I think it was along the lines of “macros should run the same in diagnostics and full completion to produce the same errors”

The main problem with doing something special during diagnostics is that (successful) diagnostics will update the cache, meaning any special thing you did there will stay for normal compilation and display requests until invalidated.