Describe the bug
In Vim9 script, we cannot compare the output of getenv() to the null value.
To Reproduce
Run this shell command:
vim -Nu NONE -S <(cat <<'EOF'
vim9script
def Func()
if getenv('unset') == null
echo '"unset" is not set'
endif
enddef
defcompile
EOF
)
E1072 is raised:
E1072: Cannot compare string with special
Expected behavior
No error is raised because null is a valid value which can be given by getenv().
Environment
Additional context
The issue disappears at the script level:
vim9script if getenv('unset') == null echo '"unset" is not set' endif
"unset" is not set
I suspect the issue comes from the return type of getenv():
https://github.com/vim/vim/blob/e3ffcd9902efc756178900d9bd972c74a09c3fcd/src/evalfunc.c#L1023-L1024
Maybe we need something like ret_string_or_special, because getenv() can return a string, or a special value like null.
—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub, or unsubscribe.![]()
Workaround: use a null coalescing operator:
vim9script def Func() if !(getenv('unset') ?? false)
echo '"unset" is not set'
else
echo '"unset" is set'
endif
if !(getenv('HOME') ?? false)
echo '"HOME" is not set'
else
echo '"HOME" is set'
endif
enddef
Func()"unset" is not set
"HOME" is set
Unrelated to the current issue, but if anyone knows how to expand environment variables inside a filepath, as well as a leading tilde, without triggering an error if the latter contains square brackets, I'm all ears.
expand() can't be used:
vim9script def Func() $VAR = 'foo' var filepath = '~/[a-1]/$VAR/file.txt' echo expand(filepath) enddef Func()
E944: Reverse range in character class
So, I do it like this:
vim9script def Func() $VAR = 'foo' var filepath = '~/[a-1]/$VAR/file.txt' echo filepath ->substitute('$\w\+', (m: list<string>): string => getenv(m[0][1 :]) ?? m[0], 'g') ->substitute('^\~/', $HOME .. '/', '') enddef Func()
/home/user/[a-1]/foo/file.txt
But it looks brittle.
I know that including square brackets inside a directory name is asking for trouble, but when you write a fuzzy finder or a custom filename completion function, you have no control over how sensible the filenames are.
Workaround: use a null coalescing operator:
Ah no. That's most probably wrong. It wouldn't handle correctly the case where a variable is set to an empty string; the variable would be still wrongly considered as unset. Not that it matters on my system anyway, since for some reason getenv() outputs v:null for an environment variable set to an empty string.
Yeah, getenv() intentionally returns null when a variable is not defined, which is different from an empty string.
Having it return "any" seems to be the only solution. Maybe we could introduce the type "string or special", but that's complicated and still requires a runtime check.