diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/nvim/eval.c | 24 | ||||
-rw-r--r-- | src/nvim/eval.lua | 1 | ||||
-rw-r--r-- | src/nvim/ex_cmds.lua | 24 | ||||
-rw-r--r-- | src/nvim/ex_cmds2.c | 120 | ||||
-rw-r--r-- | src/nvim/ex_docmd.c | 4 | ||||
-rw-r--r-- | src/nvim/option.c | 4 | ||||
-rw-r--r-- | src/nvim/option_defs.h | 1 | ||||
-rw-r--r-- | src/nvim/options.lua | 8 | ||||
-rw-r--r-- | src/nvim/testdir/pyxfile/py2_magic.py | 4 | ||||
-rw-r--r-- | src/nvim/testdir/pyxfile/py2_shebang.py | 4 | ||||
-rw-r--r-- | src/nvim/testdir/pyxfile/py3_magic.py | 4 | ||||
-rw-r--r-- | src/nvim/testdir/pyxfile/py3_shebang.py | 4 | ||||
-rw-r--r-- | src/nvim/testdir/pyxfile/pyx.py | 2 | ||||
-rw-r--r-- | src/nvim/testdir/test_pyx2.vim | 74 | ||||
-rw-r--r-- | src/nvim/testdir/test_pyx3.vim | 74 |
15 files changed, 351 insertions, 1 deletions
diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 3a231ab8f1..f1cce716e0 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -10704,6 +10704,7 @@ static void f_has(typval_T *argvars, typval_T *rettv, FunPtr fptr) "postscript", "printer", "profile", + "pythonx", "reltime", "quickfix", "rightleft", @@ -13026,6 +13027,10 @@ static void f_pumvisible(typval_T *argvars, typval_T *rettv, FunPtr fptr) */ static void f_pyeval(typval_T *argvars, typval_T *rettv, FunPtr fptr) { + if (p_pyx == 0) { + p_pyx = 2; + } + script_host_eval("python", argvars, rettv); } @@ -13034,9 +13039,24 @@ static void f_pyeval(typval_T *argvars, typval_T *rettv, FunPtr fptr) */ static void f_py3eval(typval_T *argvars, typval_T *rettv, FunPtr fptr) { + if (p_pyx == 0) { + p_pyx = 3; + } + script_host_eval("python3", argvars, rettv); } +// "pyxeval()" function +static void f_pyxeval(typval_T *argvars, typval_T *rettv, FunPtr fptr) +{ + init_pyxversion(); + if (p_pyx == 2) { + f_pyeval(argvars, rettv, NULL); + } else { + f_py3eval(argvars, rettv, NULL); + } +} + /* * "range()" function */ @@ -20133,7 +20153,9 @@ void ex_function(exarg_T *eap) arg = skipwhite(skiptowhite(p)); if (arg[0] == '<' && arg[1] =='<' && ((p[0] == 'p' && p[1] == 'y' - && (!ASCII_ISALPHA(p[2]) || p[2] == 't')) + && (!ASCII_ISALNUM(p[2]) || p[2] == 't' + || ((p[2] == '3' || p[2] == 'x') + && !ASCII_ISALPHA(p[3])))) || (p[0] == 'p' && p[1] == 'e' && (!ASCII_ISALPHA(p[2]) || p[2] == 'r')) || (p[0] == 't' && p[1] == 'c' diff --git a/src/nvim/eval.lua b/src/nvim/eval.lua index e72bb7b870..78cac4878d 100644 --- a/src/nvim/eval.lua +++ b/src/nvim/eval.lua @@ -226,6 +226,7 @@ return { pumvisible={}, py3eval={args=1}, pyeval={args=1}, + pyxeval={args=1}, range={args={1, 3}}, readfile={args={1, 3}}, reltime={args={0, 2}}, diff --git a/src/nvim/ex_cmds.lua b/src/nvim/ex_cmds.lua index 79ca5363e0..4806eff1b4 100644 --- a/src/nvim/ex_cmds.lua +++ b/src/nvim/ex_cmds.lua @@ -2067,6 +2067,30 @@ return { func='ex_py3file', }, { + command='pyx', + flags=bit.bor(RANGE, EXTRA, NEEDARG, CMDWIN), + addr_type=ADDR_LINES, + func='ex_pyx', + }, + { + command='pyxdo', + flags=bit.bor(RANGE, DFLALL, EXTRA, NEEDARG, CMDWIN), + addr_type=ADDR_LINES, + func='ex_pyxdo', + }, + { + command='pythonx', + flags=bit.bor(RANGE, EXTRA, NEEDARG, CMDWIN), + addr_type=ADDR_LINES, + func='ex_pyx', + }, + { + command='pyxfile', + flags=bit.bor(RANGE, FILE1, NEEDARG, CMDWIN), + addr_type=ADDR_LINES, + func='ex_pyxfile', + }, + { command='quit', flags=bit.bor(BANG, RANGE, COUNT, NOTADR, TRLBAR, CMDWIN), addr_type=ADDR_WINDOWS, diff --git a/src/nvim/ex_cmds2.c b/src/nvim/ex_cmds2.c index 1ffcf67ef7..51d20c746a 100644 --- a/src/nvim/ex_cmds2.c +++ b/src/nvim/ex_cmds2.c @@ -2809,6 +2809,126 @@ void ex_options(exarg_T *eap) cmd_source((char_u *)SYS_OPTWIN_FILE, NULL); } +// Detect Python 3 or 2, and initialize 'pyxversion'. +void init_pyxversion(void) +{ + if (p_pyx == 0) { + if (!eval_has_provider("python3")) { + p_pyx = 3; + } else if (!eval_has_provider("python")) { + p_pyx = 2; + } + } +} + +// Does a file contain one of the following strings at the beginning of any +// line? +// "#!(any string)python2" => returns 2 +// "#!(any string)python3" => returns 3 +// "# requires python 2.x" => returns 2 +// "# requires python 3.x" => returns 3 +// otherwise return 0. +static int requires_py_version(char_u *filename) +{ + FILE *file; + int requires_py_version = 0; + int i, lines; + + lines = (int)p_mls; + if (lines < 0) { + lines = 5; + } + + file = mch_fopen((char *)filename, "r"); + if (file != NULL) { + for (i = 0; i < lines; i++) { + if (vim_fgets(IObuff, IOSIZE, file)) { + break; + } + if (i == 0 && IObuff[0] == '#' && IObuff[1] == '!') { + // Check shebang. + if (strstr((char *)IObuff + 2, "python2") != NULL) { + requires_py_version = 2; + break; + } + if (strstr((char *)IObuff + 2, "python3") != NULL) { + requires_py_version = 3; + break; + } + } + IObuff[21] = '\0'; + if (STRCMP("# requires python 2.x", IObuff) == 0) { + requires_py_version = 2; + break; + } + if (STRCMP("# requires python 3.x", IObuff) == 0) { + requires_py_version = 3; + break; + } + } + fclose(file); + } + return requires_py_version; +} + + +// Source a python file using the requested python version. +static void source_pyx_file(exarg_T *eap, char_u *fname) +{ + exarg_T ex; + long int v = requires_py_version(fname); + + init_pyxversion(); + if (v == 0) { + // user didn't choose a preference, 'pyx' is used + v = p_pyx; + } + + // now source, if required python version is not supported show + // unobtrusive message. + if (eap == NULL) { + memset(&ex, 0, sizeof(ex)); + } else { + ex = *eap; + } + ex.arg = fname; + ex.cmd = (char_u *)(v == 2 ? "pyfile" : "pyfile3"); + + if (v == 2) { + ex_pyfile(&ex); + } else { + ex_py3file(&ex); + } +} + +// ":pyxfile {fname}" +void ex_pyxfile(exarg_T *eap) +{ + source_pyx_file(eap, eap->arg); +} + +// ":pyx" +void ex_pyx(exarg_T *eap) +{ + init_pyxversion(); + if (p_pyx == 2) { + ex_python(eap); + } else { + ex_python3(eap); + } +} + +// ":pyxdo" +void ex_pyxdo(exarg_T *eap) +{ + init_pyxversion(); + if (p_pyx == 2) { + ex_pydo(eap); + } else { + ex_pydo3(eap); + } +} + /// ":source {fname}" void ex_source(exarg_T *eap) { diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index 8bc6193d08..ffa913efcf 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -2158,6 +2158,10 @@ static char_u * do_one_cmd(char_u **cmdlinep, case CMD_python: case CMD_py3: case CMD_python3: + case CMD_pythonx: + case CMD_pyx: + case CMD_pyxdo: + case CMD_pyxfile: case CMD_return: case CMD_rightbelow: case CMD_ruby: diff --git a/src/nvim/option.c b/src/nvim/option.c index 8c692f9f42..6b1c5c998f 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -4322,6 +4322,10 @@ static char *set_num_option(int opt_idx, char_u *varp, long value, if (p_uc && !old_value) { ml_open_files(); } + } else if (pp == &p_pyx) { + if (p_pyx != 0 && p_pyx != 2 && p_pyx != 3) { + errmsg = e_invarg; + } } else if (pp == &p_ul || pp == &curbuf->b_p_ul) { // sync undo before 'undolevels' changes // use the old value, otherwise u_sync() may not work properly diff --git a/src/nvim/option_defs.h b/src/nvim/option_defs.h index 6a0d0e32e0..7b99b6f266 100644 --- a/src/nvim/option_defs.h +++ b/src/nvim/option_defs.h @@ -516,6 +516,7 @@ EXTERN char_u *p_pex; // 'patchexpr' EXTERN char_u *p_pm; // 'patchmode' EXTERN char_u *p_path; // 'path' EXTERN char_u *p_cdpath; // 'cdpath' +EXTERN long p_pyx; // 'pyxversion' EXTERN long p_rdt; // 'redrawtime' EXTERN int p_remap; // 'remap' EXTERN long p_re; // 'regexpengine' diff --git a/src/nvim/options.lua b/src/nvim/options.lua index 0cc6f58c5f..aba8f8b893 100644 --- a/src/nvim/options.lua +++ b/src/nvim/options.lua @@ -1810,6 +1810,14 @@ return { defaults={if_true={vi=0}} }, { + full_name='pyxversion', abbreviation='pyx', + type='number', scope={'global'}, + secure=true, + vi_def=true, + varname='p_pyx', + defaults={if_true={vi=0}} + }, + { full_name='quoteescape', abbreviation='qe', type='string', scope={'buffer'}, vi_def=true, diff --git a/src/nvim/testdir/pyxfile/py2_magic.py b/src/nvim/testdir/pyxfile/py2_magic.py new file mode 100644 index 0000000000..819892fd16 --- /dev/null +++ b/src/nvim/testdir/pyxfile/py2_magic.py @@ -0,0 +1,4 @@ +# requires python 2.x + +import sys +print(sys.version) diff --git a/src/nvim/testdir/pyxfile/py2_shebang.py b/src/nvim/testdir/pyxfile/py2_shebang.py new file mode 100644 index 0000000000..13bfc491ec --- /dev/null +++ b/src/nvim/testdir/pyxfile/py2_shebang.py @@ -0,0 +1,4 @@ +#!/usr/bin/python2 + +import sys +print(sys.version) diff --git a/src/nvim/testdir/pyxfile/py3_magic.py b/src/nvim/testdir/pyxfile/py3_magic.py new file mode 100644 index 0000000000..d4b7ee0071 --- /dev/null +++ b/src/nvim/testdir/pyxfile/py3_magic.py @@ -0,0 +1,4 @@ +# requires python 3.x + +import sys +print(sys.version) diff --git a/src/nvim/testdir/pyxfile/py3_shebang.py b/src/nvim/testdir/pyxfile/py3_shebang.py new file mode 100644 index 0000000000..ec05808ca4 --- /dev/null +++ b/src/nvim/testdir/pyxfile/py3_shebang.py @@ -0,0 +1,4 @@ +#!/usr/bin/python3 + +import sys +print(sys.version) diff --git a/src/nvim/testdir/pyxfile/pyx.py b/src/nvim/testdir/pyxfile/pyx.py new file mode 100644 index 0000000000..261a6512c0 --- /dev/null +++ b/src/nvim/testdir/pyxfile/pyx.py @@ -0,0 +1,2 @@ +import sys +print(sys.version) diff --git a/src/nvim/testdir/test_pyx2.vim b/src/nvim/testdir/test_pyx2.vim new file mode 100644 index 0000000000..50e57c3bfb --- /dev/null +++ b/src/nvim/testdir/test_pyx2.vim @@ -0,0 +1,74 @@ +" Test for pyx* commands and functions with Python 2. + +set pyx=2 +if !has('python') + finish +endif + +let s:py2pattern = '^2\.[0-7]\.\d\+' +let s:py3pattern = '^3\.\d\+\.\d\+' + + +func Test_has_pythonx() + call assert_true(has('pythonx')) +endfunc + + +func Test_pyx() + redir => var + pyx << EOF +import sys +print(sys.version) +EOF + redir END + call assert_match(s:py2pattern, split(var)[0]) +endfunc + + +func Test_pyxdo() + pyx import sys + enew + pyxdo return sys.version.split("\n")[0] + call assert_match(s:py2pattern, split(getline('.'))[0]) +endfunc + + +func Test_pyxeval() + pyx import sys + call assert_match(s:py2pattern, split(pyxeval('sys.version'))[0]) +endfunc + + +func Test_pyxfile() + " No special comments nor shebangs + redir => var + pyxfile pyxfile/pyx.py + redir END + call assert_match(s:py2pattern, split(var)[0]) + + " Python 2 special comment + redir => var + pyxfile pyxfile/py2_magic.py + redir END + call assert_match(s:py2pattern, split(var)[0]) + + " Python 2 shebang + redir => var + pyxfile pyxfile/py2_shebang.py + redir END + call assert_match(s:py2pattern, split(var)[0]) + + if has('python3') + " Python 3 special comment + redir => var + pyxfile pyxfile/py3_magic.py + redir END + call assert_match(s:py3pattern, split(var)[0]) + + " Python 3 shebang + redir => var + pyxfile pyxfile/py3_shebang.py + redir END + call assert_match(s:py3pattern, split(var)[0]) + endif +endfunc diff --git a/src/nvim/testdir/test_pyx3.vim b/src/nvim/testdir/test_pyx3.vim new file mode 100644 index 0000000000..64546b4688 --- /dev/null +++ b/src/nvim/testdir/test_pyx3.vim @@ -0,0 +1,74 @@ +" Test for pyx* commands and functions with Python 3. + +set pyx=3 +if !has('python3') + finish +endif + +let s:py2pattern = '^2\.[0-7]\.\d\+' +let s:py3pattern = '^3\.\d\+\.\d\+' + + +func Test_has_pythonx() + call assert_true(has('pythonx')) +endfunc + + +func Test_pyx() + redir => var + pyx << EOF +import sys +print(sys.version) +EOF + redir END + call assert_match(s:py3pattern, split(var)[0]) +endfunc + + +func Test_pyxdo() + pyx import sys + enew + pyxdo return sys.version.split("\n")[0] + call assert_match(s:py3pattern, split(getline('.'))[0]) +endfunc + + +func Test_pyxeval() + pyx import sys + call assert_match(s:py3pattern, split(pyxeval('sys.version'))[0]) +endfunc + + +func Test_pyxfile() + " No special comments nor shebangs + redir => var + pyxfile pyxfile/pyx.py + redir END + call assert_match(s:py3pattern, split(var)[0]) + + " Python 3 special comment + redir => var + pyxfile pyxfile/py3_magic.py + redir END + call assert_match(s:py3pattern, split(var)[0]) + + " Python 3 shebang + redir => var + pyxfile pyxfile/py3_shebang.py + redir END + call assert_match(s:py3pattern, split(var)[0]) + + if has('python') + " Python 2 special comment + redir => var + pyxfile pyxfile/py2_magic.py + redir END + call assert_match(s:py2pattern, split(var)[0]) + + " Python 2 shebang + redir => var + pyxfile pyxfile/py2_shebang.py + redir END + call assert_match(s:py2pattern, split(var)[0]) + endif +endfunc |