[vim/vim] Vim9: cannot compare "getenv()" to null (#7943)

22 views
Skip to first unread message

nicsig

unread,
Mar 9, 2021, 6:39:15 PM3/9/21
to vim/vim, Subscribed

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

  • Vim version: 8.2 Included patches: 1-2580
  • OS: Ubuntu 16.04.7 LTS
  • Terminal: xterm(366)

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.

nicsig

unread,
Mar 9, 2021, 7:07:24 PM3/9/21
to vim/vim, Subscribed

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.

nicsig

unread,
Mar 9, 2021, 10:06:34 PM3/9/21
to vim/vim, Subscribed

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.

Bram Moolenaar

unread,
Mar 10, 2021, 10:02:42 AM3/10/21
to vim/vim, Subscribed

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.

Bram Moolenaar

unread,
Mar 10, 2021, 10:09:20 AM3/10/21
to vim/vim, Subscribed

Closed #7943 via 7ad67d1.

Reply all
Reply to author
Forward
0 new messages