0
0
mirror of https://github.com/vim/vim.git synced 2025-07-26 11:04:33 -04:00

patch 8.1.1305: there is no easy way to manipulate environment variables

Problem:    There is no easy way to manipulate environment variables.
Solution:   Add environ(), getenv() and setenv(). (Yasuhiro Matsumoto,
            closes #2875)
This commit is contained in:
Bram Moolenaar 2019-05-09 14:52:41 +02:00
parent 68cbb14bae
commit 691ddeefb5
6 changed files with 185 additions and 7 deletions

View File

@ -1369,6 +1369,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
@ -2303,6 +2310,7 @@ did_filetype() Number |TRUE| if FileType autocmd 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
@ -2360,6 +2368,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}
@ -2568,6 +2577,7 @@ setbufvar({expr}, {varname}, {val})
none set {varname} in buffer {expr} to {val} none 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}]])
@ -3905,6 +3915,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
@ -4970,13 +4988,11 @@ getcwd([{winnr} [, {tabnr}]])
" Get the working directory of current tabpage " Get the working directory of current tabpage
:echo getcwd(-1, 0) :echo getcwd(-1, 0)
< <
getfsize({fname}) *getfsize()* getenv({name}) *getenv()*
The result is a Number, which is the size in bytes of the Return the value of environment variable {name}.
given file {fname}. When the variable does not exist |v:null| is returned. That
If {fname} is a directory, 0 is returned. is different from a variable set to an empty string.
If the file {fname} can't be found, -1 is returned. See also |expr-env|.
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
@ -5009,6 +5025,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
@ -8012,6 +8036,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

@ -774,6 +774,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
@ -903,6 +906,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

@ -137,6 +137,7 @@ static void f_did_filetype(typval_T *argvars, typval_T *rettv);
static void f_diff_filler(typval_T *argvars, typval_T *rettv); static void f_diff_filler(typval_T *argvars, typval_T *rettv);
static void f_diff_hlID(typval_T *argvars, typval_T *rettv); static void f_diff_hlID(typval_T *argvars, typval_T *rettv);
static void f_empty(typval_T *argvars, typval_T *rettv); static void f_empty(typval_T *argvars, typval_T *rettv);
static void f_environ(typval_T *argvars, typval_T *rettv);
static void f_escape(typval_T *argvars, typval_T *rettv); static void f_escape(typval_T *argvars, typval_T *rettv);
static void f_eval(typval_T *argvars, typval_T *rettv); static void f_eval(typval_T *argvars, typval_T *rettv);
static void f_eventhandler(typval_T *argvars, typval_T *rettv); static void f_eventhandler(typval_T *argvars, typval_T *rettv);
@ -187,6 +188,7 @@ static void f_getcmdpos(typval_T *argvars, typval_T *rettv);
static void f_getcmdtype(typval_T *argvars, typval_T *rettv); static void f_getcmdtype(typval_T *argvars, typval_T *rettv);
static void f_getcmdwintype(typval_T *argvars, typval_T *rettv); static void f_getcmdwintype(typval_T *argvars, typval_T *rettv);
static void f_getcwd(typval_T *argvars, typval_T *rettv); static void f_getcwd(typval_T *argvars, typval_T *rettv);
static void f_getenv(typval_T *argvars, typval_T *rettv);
static void f_getfontname(typval_T *argvars, typval_T *rettv); static void f_getfontname(typval_T *argvars, typval_T *rettv);
static void f_getfperm(typval_T *argvars, typval_T *rettv); static void f_getfperm(typval_T *argvars, typval_T *rettv);
static void f_getfsize(typval_T *argvars, typval_T *rettv); static void f_getfsize(typval_T *argvars, typval_T *rettv);
@ -365,6 +367,7 @@ static void f_setbufline(typval_T *argvars, typval_T *rettv);
static void f_setbufvar(typval_T *argvars, typval_T *rettv); static void f_setbufvar(typval_T *argvars, typval_T *rettv);
static void f_setcharsearch(typval_T *argvars, typval_T *rettv); static void f_setcharsearch(typval_T *argvars, typval_T *rettv);
static void f_setcmdpos(typval_T *argvars, typval_T *rettv); static void f_setcmdpos(typval_T *argvars, typval_T *rettv);
static void f_setenv(typval_T *argvars, typval_T *rettv);
static void f_setfperm(typval_T *argvars, typval_T *rettv); static void f_setfperm(typval_T *argvars, typval_T *rettv);
static void f_setline(typval_T *argvars, typval_T *rettv); static void f_setline(typval_T *argvars, typval_T *rettv);
static void f_setloclist(typval_T *argvars, typval_T *rettv); static void f_setloclist(typval_T *argvars, typval_T *rettv);
@ -629,6 +632,7 @@ static struct fst
{"diff_filler", 1, 1, f_diff_filler}, {"diff_filler", 1, 1, f_diff_filler},
{"diff_hlID", 2, 2, f_diff_hlID}, {"diff_hlID", 2, 2, f_diff_hlID},
{"empty", 1, 1, f_empty}, {"empty", 1, 1, f_empty},
{"environ", 0, 0, f_environ},
{"escape", 2, 2, f_escape}, {"escape", 2, 2, f_escape},
{"eval", 1, 1, f_eval}, {"eval", 1, 1, f_eval},
{"eventhandler", 0, 0, f_eventhandler}, {"eventhandler", 0, 0, f_eventhandler},
@ -681,6 +685,7 @@ static struct fst
#endif #endif
{"getcurpos", 0, 0, f_getcurpos}, {"getcurpos", 0, 0, f_getcurpos},
{"getcwd", 0, 2, f_getcwd}, {"getcwd", 0, 2, f_getcwd},
{"getenv", 1, 1, f_getenv},
{"getfontname", 0, 1, f_getfontname}, {"getfontname", 0, 1, f_getfontname},
{"getfperm", 1, 1, f_getfperm}, {"getfperm", 1, 1, f_getfperm},
{"getfsize", 1, 1, f_getfsize}, {"getfsize", 1, 1, f_getfsize},
@ -873,6 +878,7 @@ static struct fst
{"setbufvar", 3, 3, f_setbufvar}, {"setbufvar", 3, 3, f_setbufvar},
{"setcharsearch", 1, 1, f_setcharsearch}, {"setcharsearch", 1, 1, f_setcharsearch},
{"setcmdpos", 1, 1, f_setcmdpos}, {"setcmdpos", 1, 1, f_setcmdpos},
{"setenv", 2, 2, f_setenv},
{"setfperm", 2, 2, f_setfperm}, {"setfperm", 2, 2, f_setfperm},
{"setline", 2, 2, f_setline}, {"setline", 2, 2, f_setline},
{"setloclist", 2, 4, f_setloclist}, {"setloclist", 2, 4, f_setloclist},
@ -3339,6 +3345,59 @@ f_empty(typval_T *argvars, typval_T *rettv)
rettv->vval.v_number = n; rettv->vval.v_number = n;
} }
/*
* "environ()" function
*/
static void
f_environ(typval_T *argvars UNUSED, typval_T *rettv)
{
#if !defined(AMIGA)
int i = 0;
char_u *entry, *value;
# ifdef MSWIN
extern wchar_t **_wenviron;
# else
extern char **environ;
# endif
if (rettv_dict_alloc(rettv) != OK)
return;
# ifdef MSWIN
if (*_wenviron == NULL)
return;
# else
if (*environ == NULL)
return;
# endif
for (i = 0; ; ++i)
{
# ifdef MSWIN
short_u *p;
if ((p = (short_u *)_wenviron[i]) == NULL)
return;
entry = utf16_to_enc(p, NULL);
# else
if ((entry = (char_u *)environ[i]) == NULL)
return;
entry = vim_strsave(entry);
# endif
if (entry == NULL) // out of memory
return;
if ((value = vim_strchr(entry, '=')) == NULL)
{
vim_free(entry);
continue;
}
*value++ = NUL;
dict_add_string(rettv->vval.v_dict, (char *)entry, value);
vim_free(entry);
}
#endif
}
/* /*
* "escape({string}, {chars})" function * "escape({string}, {chars})" function
*/ */
@ -5260,6 +5319,27 @@ f_getcwd(typval_T *argvars, typval_T *rettv)
#endif #endif
} }
/*
* "getenv()" function
*/
static void
f_getenv(typval_T *argvars, typval_T *rettv)
{
int mustfree = FALSE;
char_u *p = vim_getenv(tv_get_string(&argvars[0]), &mustfree);
if (p == NULL)
{
rettv->v_type = VAR_SPECIAL;
rettv->vval.v_number = VVAL_NULL;
return;
}
if (!mustfree)
p = vim_strsave(p);
rettv->vval.v_string = p;
rettv->v_type = VAR_STRING;
}
/* /*
* "getfontname()" function * "getfontname()" function
*/ */
@ -11424,6 +11504,23 @@ f_setcmdpos(typval_T *argvars, typval_T *rettv)
rettv->vval.v_number = set_cmdline_pos(pos); rettv->vval.v_number = set_cmdline_pos(pos);
} }
/*
* "setenv()" function
*/
static void
f_setenv(typval_T *argvars, typval_T *rettv UNUSED)
{
char_u namebuf[NUMBUFLEN];
char_u valbuf[NUMBUFLEN];
char_u *name = tv_get_string_buf(&argvars[0], namebuf);
if (argvars[1].v_type == VAR_SPECIAL
&& argvars[1].vval.v_number == VVAL_NULL)
vim_unsetenv(name);
else
vim_setenv(name, tv_get_string_buf(&argvars[1], valbuf));
}
/* /*
* "setfperm({fname}, {mode})" function * "setfperm({fname}, {mode})" function
*/ */

View File

@ -104,6 +104,7 @@ NEW_TESTS = \
test_erasebackword \ test_erasebackword \
test_escaped_glob \ test_escaped_glob \
test_eval_stuff \ test_eval_stuff \
test_environ \
test_ex_equal \ test_ex_equal \
test_ex_undo \ test_ex_undo \
test_ex_z \ test_ex_z \
@ -320,6 +321,7 @@ NEW_TESTS_RES = \
test_digraph.res \ test_digraph.res \
test_display.res \ test_display.res \
test_edit.res \ test_edit.res \
test_environ.res \
test_erasebackword.res \ test_erasebackword.res \
test_escaped_glob.res \ test_escaped_glob.res \
test_eval_stuff.res \ test_eval_stuff.res \

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

@ -767,6 +767,8 @@ static char *(features[]) =
static int included_patches[] = static int included_patches[] =
{ /* Add new patch number below this line */ { /* Add new patch number below this line */
/**/
1305,
/**/ /**/
1304, 1304,
/**/ /**/