5

I have a plugin which exports a couple of functions. These functions depend on a few script-local functions. I want to test these script-local functions.

The best way I can think of to do that, without simply exporting every function, is to conditionally export a wrapper if an environment variable is set.

vim9script

export def MyPublicFunction(foo: string): string
  # ...
enddef

def SomeHelperFunction(bar: string): string
  # ...
enddef

if exists("$TEST")
  export def SomeHelperFunction__(bar: string): string
    return SomeHelperFunction(bar)
  enddef
endif

This works fine when $TEST is set. But when it isn't, which it isn't in normal operation, I get the error:

E133: :return not inside a function

– with a line number pointing to the line return SomeHelperFunction(bar).

How can I avoid this error?

1 Answer 1

2

I got a different error message:

E1044: export with invalid argument: export def SomeHelperFunction__(bar: string): string

Which led me to assume this was some form of bug, where either it isn't allowed and the message was garbage, or there's a bug with exports, as the line itself is completely valid in any other context, and the error message makes zero sense in that regard.

The answer is the latter. As of Vim 9.0.1806, your code is valid, and arguably the intended way to conditionally export stuff. There still doesn't appear to be a cleaner way to conditionally export without defining a second function wrapper, but that isn't really the end of the world.

However, if your code needs to work before 9.0.1806 (though I would strongly recommend you just bump the minimum version requirements if this is used in a plugin), you can use something like this, which bypasses export entirely:

vim9script

export def MyPublicFunction(foo: string): string
    return "a"
enddef

def SomeHelperFunction(bar: string): string
    return "b"
enddef

if exists("$TEST")
    g:ConditionalAutoload#SomeHelperFunction = funcref("SomeHelperFunction")
endif

Where you then invoke it as g:ConditionalAutoload#SomeHelperFunction("string 1234") - this applies to both Vimscript and Vim9script. Global variables are not required to be exported, and they live outside the script scope. This is functionally identical to an export, though it's a nasty workaround; you get no existence safety, and the variable can be modified by any other plugin. How big of a problem that is depends on the application, and is something you'll have to judge on your own.

1
  • Thank you! That explains everything very clearly. I also quite like the hacky workaround – nice lateral thinking. Commented Aug 28, 2023 at 11:05

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.