Merge #10655 'environ(), getenv(), setenv()'

close #10655
This commit is contained in:
Justin M. Keyes 2019-08-06 01:23:49 +02:00
commit a29358dc58
7 changed files with 147 additions and 8 deletions

View File

@ -1180,6 +1180,13 @@ $VAR environment variable
The String value of any environment variable. When it is not defined, the The String value of any environment variable. When it is not defined, the
result is an empty string. result is an empty string.
The functions `getenv()` and `setenv()` can also be used and work for
environment variables with non-alphanumeric names.
The function `environ()` can be used to get a Dict with all environment
variables.
*expr-env-expand* *expr-env-expand*
Note that there is a difference between using $VAR directly and using Note that there is a difference between using $VAR directly and using
expand("$VAR"). Using it directly will only expand environment variables that expand("$VAR"). Using it directly will only expand environment variables that
@ -2061,6 +2068,7 @@ did_filetype() Number |TRUE| if FileType autocommand event used
diff_filler({lnum}) Number diff filler lines about {lnum} diff_filler({lnum}) Number diff filler lines about {lnum}
diff_hlID({lnum}, {col}) Number diff highlighting at {lnum}/{col} diff_hlID({lnum}, {col}) Number diff highlighting at {lnum}/{col}
empty({expr}) Number |TRUE| if {expr} is empty empty({expr}) Number |TRUE| if {expr} is empty
environ() Dict return environment variables
escape({string}, {chars}) String escape {chars} in {string} with '\' escape({string}, {chars}) String escape {chars} in {string} with '\'
eval({string}) any evaluate {string} into its value eval({string}) any evaluate {string} into its value
eventhandler() Number |TRUE| if inside an event handler eventhandler() Number |TRUE| if inside an event handler
@ -2118,6 +2126,7 @@ getcompletion({pat}, {type} [, {filtered}])
List list of cmdline completion matches List list of cmdline completion matches
getcurpos() List position of the cursor getcurpos() List position of the cursor
getcwd([{winnr} [, {tabnr}]]) String get the current working directory getcwd([{winnr} [, {tabnr}]]) String get the current working directory
getenv({name}) String return environment variable
getfontname([{name}]) String name of font being used getfontname([{name}]) String name of font being used
getfperm({fname}) String file permissions of file {fname} getfperm({fname}) String file permissions of file {fname}
getfsize({fname}) Number size in bytes of file {fname} getfsize({fname}) Number size in bytes of file {fname}
@ -2298,6 +2307,7 @@ setbufline( {expr}, {lnum}, {line})
setbufvar({expr}, {varname}, {val}) set {varname} in buffer {expr} to {val} setbufvar({expr}, {varname}, {val}) set {varname} in buffer {expr} to {val}
setcharsearch({dict}) Dict set character search from {dict} setcharsearch({dict}) Dict set character search from {dict}
setcmdpos({pos}) Number set cursor position in command-line setcmdpos({pos}) Number set cursor position in command-line
setenv({name}, {val}) none set environment variable
setfperm({fname}, {mode} Number set {fname} file permissions to {mode} setfperm({fname}, {mode} Number set {fname} file permissions to {mode}
setline({lnum}, {line}) Number set line {lnum} to {line} setline({lnum}, {line}) Number set line {lnum} to {line}
setloclist({nr}, {list}[, {action}[, {what}]]) setloclist({nr}, {list}[, {action}[, {what}]])
@ -3344,6 +3354,14 @@ diff_hlID({lnum}, {col}) *diff_hlID()*
The highlight ID can be used with |synIDattr()| to obtain The highlight ID can be used with |synIDattr()| to obtain
syntax information about the highlighting. syntax information about the highlighting.
environ() *environ()*
Return all of environment variables as dictionary. You can
check if an environment variable exists like this: >
:echo has_key(environ(), 'HOME')
< Note that the variable name may be CamelCase; to ignore case
use this: >
:echo index(keys(environ()), 'HOME', 0, 1) != -1
empty({expr}) *empty()* empty({expr}) *empty()*
Return the Number 1 if {expr} is empty, zero otherwise. Return the Number 1 if {expr} is empty, zero otherwise.
A |List| or |Dictionary| is empty when it does not have any A |List| or |Dictionary| is empty when it does not have any
@ -4333,14 +4351,11 @@ getcwd([{winnr}[, {tabnr}]]) *getcwd()*
< If {winnr} is -1 it is ignored, only the tab is resolved. < If {winnr} is -1 it is ignored, only the tab is resolved.
{winnr} can be the window number or the |window-ID|. {winnr} can be the window number or the |window-ID|.
getenv({name}) *getenv()*
getfsize({fname}) *getfsize()* Return the value of environment variable {name}.
The result is a Number, which is the size in bytes of the When the variable does not exist |v:null| is returned. That
given file {fname}. is different from a variable set to an empty string.
If {fname} is a directory, 0 is returned. See also |expr-env|.
If the file {fname} can't be found, -1 is returned.
If the size of {fname} is too big to fit in a Number then -2
is returned.
getfontname([{name}]) *getfontname()* getfontname([{name}]) *getfontname()*
Without an argument returns the name of the normal font being Without an argument returns the name of the normal font being
@ -4371,6 +4386,14 @@ getfperm({fname}) *getfperm()*
For setting permissions use |setfperm()|. For setting permissions use |setfperm()|.
getfsize({fname}) *getfsize()*
The result is a Number, which is the size in bytes of the
given file {fname}.
If {fname} is a directory, 0 is returned.
If the file {fname} can't be found, -1 is returned.
If the size of {fname} is too big to fit in a Number then -2
is returned.
getftime({fname}) *getftime()* getftime({fname}) *getftime()*
The result is a Number, which is the last modification time of The result is a Number, which is the last modification time of
the given file {fname}. The value is measured as seconds the given file {fname}. The value is measured as seconds
@ -7079,6 +7102,11 @@ setcmdpos({pos}) *setcmdpos()*
Returns 0 when successful, 1 when not editing the command Returns 0 when successful, 1 when not editing the command
line. line.
setenv({name}, {val}) *setenv()*
Set environment variable {name} to {val}.
When {val} is |v:null| the environment variable is deleted.
See also |expr-env|.
setfperm({fname}, {mode}) *setfperm()* *chmod* setfperm({fname}, {mode}) *setfperm()* *chmod*
Set the file permissions for {fname} to {mode}. Set the file permissions for {fname} to {mode}.
{mode} must be a string with 9 characters. It is of the form {mode} must be a string with 9 characters. It is of the form

View File

@ -770,6 +770,9 @@ System functions and manipulation of files:
rename() rename a file rename() rename a file
system() get the result of a shell command as a string system() get the result of a shell command as a string
systemlist() get the result of a shell command as a list systemlist() get the result of a shell command as a list
environ() get all environment variables
getenv() get one environment variable
setenv() set an environment variable
hostname() name of the system hostname() name of the system
readfile() read a file into a List of lines readfile() read a file into a List of lines
readdir() get a List of file names in a directory readdir() get a List of file names in a directory
@ -899,6 +902,7 @@ GUI: *gui-functions*
getwinposy() Y position of the Vim window getwinposy() Y position of the Vim window
balloon_show() set the balloon content balloon_show() set the balloon content
balloon_split() split a message for a balloon balloon_split() split a message for a balloon
balloon_gettext() get the text in the balloon
Vim server: *server-functions* Vim server: *server-functions*
serverlist() return the list of server names serverlist() return the list of server names

View File

@ -8495,6 +8495,25 @@ static void f_empty(typval_T *argvars, typval_T *rettv, FunPtr fptr)
rettv->vval.v_number = n; rettv->vval.v_number = n;
} }
/// "environ()" function
static void f_environ(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
tv_dict_alloc_ret(rettv);
for (int i = 0; ; i++) {
// TODO(justinmk): use os_copyfullenv from #7202 ?
char *envname = os_getenvname_at_index((size_t)i);
if (envname == NULL) {
break;
}
const char *value = os_getenv(envname);
tv_dict_add_str(rettv->vval.v_dict,
(char *)envname, STRLEN((char *)envname),
value == NULL ? "" : value);
xfree(envname);
}
}
/* /*
* "escape({string}, {chars})" function * "escape({string}, {chars})" function
*/ */
@ -8508,6 +8527,20 @@ static void f_escape(typval_T *argvars, typval_T *rettv, FunPtr fptr)
rettv->v_type = VAR_STRING; rettv->v_type = VAR_STRING;
} }
/// "getenv()" function
static void f_getenv(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
char_u *p = (char_u *)vim_getenv(tv_get_string(&argvars[0]));
if (p == NULL) {
rettv->v_type = VAR_SPECIAL;
rettv->vval.v_number = kSpecialVarNull;
return;
}
rettv->vval.v_string = p;
rettv->v_type = VAR_STRING;
}
/* /*
* "eval()" function * "eval()" function
*/ */
@ -15319,6 +15352,20 @@ static void f_setcmdpos(typval_T *argvars, typval_T *rettv, FunPtr fptr)
} }
} }
/// "setenv()" function
static void f_setenv(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
char namebuf[NUMBUFLEN];
char valbuf[NUMBUFLEN];
const char *name = tv_get_string_buf(&argvars[0], namebuf);
if (argvars[1].v_type == VAR_SPECIAL
&& argvars[1].vval.v_number == kSpecialVarNull) {
os_unsetenv(name);
} else {
vim_setenv(name, tv_get_string_buf(&argvars[1], valbuf));
}
}
/// "setfperm({fname}, {mode})" function /// "setfperm({fname}, {mode})" function
static void f_setfperm(typval_T *argvars, typval_T *rettv, FunPtr fptr) static void f_setfperm(typval_T *argvars, typval_T *rettv, FunPtr fptr)

View File

@ -89,6 +89,7 @@ return {
diff_filler={args=1}, diff_filler={args=1},
diff_hlID={args=2}, diff_hlID={args=2},
empty={args=1}, empty={args=1},
environ={},
escape={args=2}, escape={args=2},
eval={args=1}, eval={args=1},
eventhandler={}, eventhandler={},
@ -135,6 +136,7 @@ return {
getcompletion={args={2, 3}}, getcompletion={args={2, 3}},
getcurpos={}, getcurpos={},
getcwd={args={0,2}}, getcwd={args={0,2}},
getenv={args={1}},
getfontname={args={0, 1}}, getfontname={args={0, 1}},
getfperm={args=1}, getfperm={args=1},
getfsize={args=1}, getfsize={args=1},
@ -274,6 +276,7 @@ return {
setbufvar={args=3}, setbufvar={args=3},
setcharsearch={args=1}, setcharsearch={args=1},
setcmdpos={args=1}, setcmdpos={args=1},
setenv={args=2},
setfperm={args=2}, setfperm={args=2},
setline={args=2}, setline={args=2},
setloclist={args={2, 4}}, setloclist={args={2, 4}},

View File

@ -45,6 +45,7 @@ void env_init(void)
} }
/// Like getenv(), but returns NULL if the variable is empty. /// Like getenv(), but returns NULL if the variable is empty.
/// @see os_env_exists
const char *os_getenv(const char *name) const char *os_getenv(const char *name)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_ALL
{ {

View File

@ -0,0 +1,44 @@
scriptencoding utf-8
func Test_environ()
unlet! $TESTENV
call assert_equal(0, has_key(environ(), 'TESTENV'))
let $TESTENV = 'foo'
call assert_equal(1, has_key(environ(), 'TESTENV'))
let $TESTENV = 'こんにちわ'
call assert_equal('こんにちわ', environ()['TESTENV'])
endfunc
func Test_getenv()
unlet! $TESTENV
call assert_equal(v:null, getenv('TESTENV'))
let $TESTENV = 'foo'
call assert_equal('foo', getenv('TESTENV'))
endfunc
func Test_setenv()
unlet! $TESTENV
call setenv('TEST ENV', 'foo')
call assert_equal('foo', getenv('TEST ENV'))
call setenv('TEST ENV', v:null)
call assert_equal(v:null, getenv('TEST ENV'))
endfunc
func Test_external_env()
call setenv('FOO', 'HelloWorld')
if has('win32')
let result = system('echo %FOO%')
else
let result = system('echo $FOO')
endif
let result = substitute(result, '[ \r\n]', '', 'g')
call assert_equal('HelloWorld', result)
call setenv('FOO', v:null)
if has('win32')
let result = system('set | grep ^FOO=')
else
let result = system('env | grep ^FOO=')
endif
call assert_equal('', result)
endfunc

View File

@ -0,0 +1,12 @@
local helpers = require('test.functional.helpers')(after_each)
local clear = helpers.clear
local eq = helpers.eq
local environ = helpers.funcs.environ
describe('environ()', function()
it('handles empty env variable', function()
clear({env={EMPTY_VAR=""}})
eq("", environ()['EMPTY_VAR'])
eq(nil, environ()['DOES_NOT_EXIST'])
end)
end)