]> granicus.if.org Git - vim/commitdiff
patch 8.0.0251: not easy to select Python 2 or 3 v8.0.0251
authorBram Moolenaar <Bram@vim.org>
Sat, 28 Jan 2017 15:06:38 +0000 (16:06 +0100)
committerBram Moolenaar <Bram@vim.org>
Sat, 28 Jan 2017 15:06:38 +0000 (16:06 +0100)
Problem:    It is not so easy to write a script that works with both Python 2
            and Python 3, even when the Python code works with both.
Solution:   Add 'pyxversion', :pyx, etc. (Marc Weber, Ken Takata)

27 files changed:
Filelist
runtime/doc/eval.txt
runtime/doc/if_pyth.txt
runtime/doc/index.txt
runtime/doc/options.txt
runtime/doc/quickref.txt
runtime/optwin.vim
src/Makefile
src/evalfunc.c
src/ex_cmds.h
src/ex_cmds2.c
src/ex_docmd.c
src/if_python.c
src/if_python3.c
src/option.c
src/option.h
src/proto/ex_cmds2.pro
src/testdir/Make_all.mak
src/testdir/pyxfile/py2_magic.py [new file with mode: 0644]
src/testdir/pyxfile/py2_shebang.py [new file with mode: 0644]
src/testdir/pyxfile/py3_magic.py [new file with mode: 0644]
src/testdir/pyxfile/py3_shebang.py [new file with mode: 0644]
src/testdir/pyxfile/pyx.py [new file with mode: 0644]
src/testdir/test_pyx2.vim [new file with mode: 0644]
src/testdir/test_pyx3.vim [new file with mode: 0644]
src/userfunc.c
src/version.c

index ea6f2e2eda0295508a796f935f2c3178e1f7426d..a97807ed28c73aed5dec5b86ee4c2265f6a23468 100644 (file)
--- a/Filelist
+++ b/Filelist
@@ -122,6 +122,7 @@ SRC_ALL =   \
                src/testdir/pythonx/topmodule/submodule/subsubmodule/subsubsubmodule.py \
                src/testdir/python_after/*.py \
                src/testdir/python_before/*.py \
+               src/testdir/pyxfile/*.py \
                src/testdir/bench*.in \
                src/testdir/bench*.vim \
                src/testdir/samples/*.txt \
index ec4030e2bba775377f49ab314a4afc60c8c613ca..687c60532de1e1a37b72892ba8e5ff2884d0bda8 100644 (file)
@@ -2239,6 +2239,7 @@ printf({fmt}, {expr1}...) String  format text
 pumvisible()                   Number  whether popup menu is visible
 pyeval({expr})                 any     evaluate |Python| expression
 py3eval({expr})                        any     evaluate |python3| expression
+pyxeval({expr})                        any     evaluate |python_x| expression
 range({expr} [, {max} [, {stride}]])
                                List    items from {expr} to {max}
 readfile({fname} [, {binary} [, {max}]])
@@ -6163,6 +6164,14 @@ pyeval({expr})                                           *pyeval()*
                non-string keys result in error.
                {only available when compiled with the |+python| feature}
 
+pyxeval({expr})                                                *pyxeval()*
+               Evaluate Python expression {expr} and return its result
+               converted to Vim data structures.
+               Uses Python 2 or 3, see |python_x| and 'pyxversion'.
+               See also: |pyeval()|, |py3eval()|
+               {only available when compiled with the |+python| or the
+               |+python3| feature}
+
                                                        *E726* *E727*
 range({expr} [, {max} [, {stride}]])                           *range()*
                Returns a |List| with Numbers:
@@ -8402,6 +8411,7 @@ printer                   Compiled with |:hardcopy| support.
 profile                        Compiled with |:profile| support.
 python                 Compiled with Python 2.x interface. |has-python|
 python3                        Compiled with Python 3.x interface. |has-python|
+pythonx                        Compiled with |python_x| interface. |has-pythonx|
 qnx                    QNX version of Vim.
 quickfix               Compiled with |quickfix| support.
 reltime                        Compiled with |reltime()| support.
index 5929bcf506a87b045d7c18bb0f9eb4f85ceafbe5..93788072716311a7661f29c0540e1bde117a4d73 100644 (file)
@@ -16,6 +16,7 @@ The Python Interface to Vim                           *python* *Python*
 8. pyeval(), py3eval() Vim functions           |python-pyeval|
 9. Dynamic loading                             |python-dynamic|
 10. Python 3                                   |python3|
+11. Python X                                   |python_x|
 
 {Vi does not have any of these commands}
 
@@ -711,6 +712,7 @@ vim.Function object                         *python-Function*
 
 To facilitate bi-directional interface, you can use |pyeval()| and |py3eval()| 
 functions to evaluate Python expressions and pass their values to VimL.
+|pyxeval()| is also available.
 
 ==============================================================================
 9. Dynamic loading                                     *python-dynamic*
@@ -811,5 +813,69 @@ dynamically, these has() calls will try to load them.  If only one can be
 loaded at a time, just checking if Python 2 or 3 are available will prevent
 the other one from being available.
 
+==============================================================================
+11. Python X                                           *python_x* *pythonx*
+
+Because most python code can be written so that it works with python 2.6+ and
+python 3 the pyx* functions and commands have been writen.  They work exactly
+the same as the Python 2 and 3 variants, but select the Python version using
+the 'pyxversion' setting.
+
+You should set 'pyxversion' in your |.vimrc| to prefer Python 2 or Python 3
+for Python commands. If you change this setting at runtime you may risk that
+state of plugins (such as initialization) may be lost.
+
+If you want to use a module, you can put it in the {rtp}/pythonx directory.
+See |pythonx-directory|.
+
+                                                       *:pyx* *:pythonx*
+The `:pyx` and `:pythonx` commands work similar to `:python`.  A simple check
+if the `:pyx` command is working: >
+       :pyx print("Hello")
+
+To see what version of Python is being used: >
+       :pyx import sys
+       :pyx print(sys.version)
+<
+                                       *:pyxfile* *python_x-special-comments*
+The `:pyxfile` command works similar to `:pyfile`.  However you can add one of
+these comments to force Vim using `:pyfile` or `:py3file`: >
+  #!/any string/python2                " Shebang. Must be the first line of the file.
+  #!/any string/python3                " Shebang. Must be the first line of the file.
+  # requires python 2.x                " Maximum lines depend on 'modelines'.
+  # requires python 3.x                " Maximum lines depend on 'modelines'.
+Unlike normal modelines, the bottom of the file is not checked.
+If none of them are found, the 'pyxversion' setting is used.
+                                                       *W20* *W21*
+If Vim does not support the selected Python version a silent message will be
+printed.  Use `:messages` to read them.
+
+                                                       *:pyxdo*
+The `:pyxdo` command works similar to `:pydo`.
+
+                                                       *has-pythonx*
+You can test if pyx* commands are available with: >
+       if has('pythonx')
+         echo 'pyx* commands are available. (Python ' . &pyx . ')'
+       endif
+
+When compiled with only one of |+python| or |+python3|, the has() returns 1.
+When compiled with both |+python| and |+python3|, the test depends on the
+'pyxversion' setting.  If 'pyxversion' is 0, it tests Python 3 first, and if
+it is not available then Python 2.  If 'pyxversion' is 2 or 3, it tests only
+Python 2 or 3 respectively.
+
+Note that for has('pythonx') to work it may try to dynamically load Python 3
+or 2.  This may have side effects, especially when Vim can only load one of
+the two.
+
+If a user prefers Python 2 and want to fallback to Python 3, he needs to set
+'pyxversion' explicitly in his |.vimrc|.  E.g.: >
+       if has('python')
+         set pyx=2
+       elseif has('python3')
+         set pyx=3
+       endif
+
 ==============================================================================
  vim:tw=78:ts=8:ft=help:norl:
index 4ebf99929a68c0dc5d01564d17d0f60da9dff8af..81b2eb63b6dc81ab02cd73a367ea098bec9ba01f 100644 (file)
@@ -1440,6 +1440,10 @@ tag            command         action ~
 |:python|      :py[thon]       execute Python command
 |:pydo|                :pyd[o]         execute Python command for each line
 |:pyfile|      :pyf[ile]       execute Python script file
+|:pyx|         :pyx            execute |python_x| command
+|:pythonx|     :pythonx        same as :pyx
+|:pyxdo|       :pyxd[o]        execute |python_x| command for each line
+|:pyxfile|     :pyxf[ile]      execute |python_x| script file
 |:quit|                :q[uit]         quit current window (when one window quit Vim)
 |:quitall|     :quita[ll]      quit Vim
 |:qall|                :qa[ll]         quit Vim
index a9a0cc4835a70e691a33c131060bc43d13cd81b8..4e9490223b4713ae7d27ac82e4dab6d2dc0cc245 100644 (file)
@@ -5786,6 +5786,34 @@ A jump table for the options with a short description can be found at |Q_op|.
        Specifies the name of the Python 3 shared library. The default is
        DYNAMIC_PYTHON3_DLL, which was specified at compile time.
        Environment variables are expanded |:set_env|.
+       This option cannot be set from a |modeline| or in the |sandbox|, for
+       security reasons.
+
+                                               *'pyxversion'* *'pyx'*
+'pyxversion' 'pyx'     number  (default depends on the build)
+                       global
+                       {not in Vi}
+                       {only available when compiled with the |+python| or
+                       the |+python3| feature}
+       Specifies the python version used for pyx* functions and commands
+       |python_x|.  The default value is as follows:
+
+               Compiled with                Default ~
+               |+python| and |+python3|        0
+               only |+python|                  2
+               only |+python3|                 3
+
+       Available values are 0, 2 and 3.
+       If 'pyxversion' is 0, it is set to 2 or 3 after the first execution of
+       any python2/3 commands or functions.  E.g. `:py` sets to 2, and `:py3`
+       sets to 3. `:pyx` sets it to 3 if Python 3 is available, otherwise sets
+       to 2 if Python 2 is available.
+       See also: |has-pythonx|
+
+       If Vim is compiled with only |+python| or |+python3| setting
+       'pyxversion' has no effect.  The pyx* functions and commands are
+       always the same as the compiled version.
+
        This option cannot be set from a |modeline| or in the |sandbox|, for
        security reasons.
 
index e0252f77bde175d9a4554a6002616dd58f3d2442..b55fce1ce96db1cf75d61cab7afcb0570c741953 100644 (file)
@@ -835,6 +835,7 @@ Short explanation of each option:           *option-list*
 'pumheight'      'ph'      maximum height of the popup menu
 'pythondll'                name of the Python 2 dynamic library
 'pythonthreedll'           name of the Python 3 dynamic library
+'pyxversion'     'pyx'     Python version used for pyx* commands
 'quoteescape'    'qe'      escape characters used in a string
 'readonly'       'ro'      disallow writing the buffer
 'redrawtime'     'rdt'     timeout for 'hlsearch' and |:match| highlighting
index d759c044a75260a9470cb2764136c4667830eadc..82f4838a6fab57ff51b7e3bb35271a6adf0bd774 100644 (file)
@@ -923,7 +923,7 @@ if has("folding")
   call append("$", "foldmarker\tmarkers used when 'foldmethod' is \"marker\"")
   call append("$", "\t(local to window)")
   call <SID>OptionL("fmr")
-  call append("$", "foldnestmax\tmaximum fold depth for when 'foldmethod is \"indent\" or \"syntax\"")
+  call append("$", "foldnestmax\tmaximum fold depth for when 'foldmethod' is \"indent\" or \"syntax\"")
   call append("$", "\t(local to window)")
   call <SID>OptionL("fdn")
 endif
@@ -1324,6 +1324,10 @@ if exists("&perldll")
   call append("$", "perldll\tname of the Perl dynamic library")
   call <SID>OptionG("perldll", &perldll)
 endif
+if has('pythonx')
+  call append("$", "pyxversion\twhether to use Python 2 or 3")
+  call append("$", " \tset pyx=" . &wd)
+endif
 if exists("&pythondll")
   call append("$", "pythondll\tname of the Python 2 dynamic library")
   call <SID>OptionG("pythondll", &pythondll)
index f993c852817f9a0fc7832a8687fcfd8e2f0f97ab..c675c06a5bedf4deda9be45359f1c494bb8a0c9d 100644 (file)
@@ -2151,6 +2151,8 @@ test_arglist \
        test_popup \
        test_profile \
        test_put \
+       test_pyx2 \
+       test_pyx3 \
        test_quickfix \
        test_regexp_latin \
        test_regexp_utf8 \
@@ -2754,6 +2756,7 @@ shadow:   runtime pixmaps
                                 ../../testdir/*.vim \
                                 ../../testdir/*.py \
                                 ../../testdir/python* \
+                                ../../testdir/pyxfile \
                                 ../../testdir/sautest \
                                 ../../testdir/samples \
                                 ../../testdir/test83-tags? \
index 99d01c42de69e33cf996c9401ad6fe613c65aeb4..a3441a0cc2064e9be549628f393a2aa988c880bb 100644 (file)
@@ -289,6 +289,9 @@ static void f_py3eval(typval_T *argvars, typval_T *rettv);
 #ifdef FEAT_PYTHON
 static void f_pyeval(typval_T *argvars, typval_T *rettv);
 #endif
+#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
+static void f_pyxeval(typval_T *argvars, typval_T *rettv);
+#endif
 static void f_range(typval_T *argvars, typval_T *rettv);
 static void f_readfile(typval_T *argvars, typval_T *rettv);
 static void f_reltime(typval_T *argvars, typval_T *rettv);
@@ -715,6 +718,9 @@ static struct fst
 #endif
 #ifdef FEAT_PYTHON
     {"pyeval",         1, 1, f_pyeval},
+#endif
+#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
+    {"pyxeval",                1, 1, f_pyxeval},
 #endif
     {"range",          1, 3, f_range},
     {"readfile",       1, 3, f_readfile},
@@ -5734,15 +5740,13 @@ f_has(typval_T *argvars, typval_T *rettv)
 #ifdef FEAT_PERSISTENT_UNDO
        "persistent_undo",
 #endif
-#ifdef FEAT_PYTHON
-#ifndef DYNAMIC_PYTHON
+#if defined(FEAT_PYTHON) && !defined(DYNAMIC_PYTHON)
        "python",
+       "pythonx",
 #endif
-#endif
-#ifdef FEAT_PYTHON3
-#ifndef DYNAMIC_PYTHON3
+#if defined(FEAT_PYTHON3) && !defined(DYNAMIC_PYTHON3)
        "python3",
-#endif
+       "pythonx",
 #endif
 #ifdef FEAT_POSTSCRIPT
        "postscript",
@@ -5972,17 +5976,30 @@ f_has(typval_T *argvars, typval_T *rettv)
        else if (STRICMP(name, "ruby") == 0)
            n = ruby_enabled(FALSE);
 #endif
-#ifdef FEAT_PYTHON
 #ifdef DYNAMIC_PYTHON
        else if (STRICMP(name, "python") == 0)
            n = python_enabled(FALSE);
 #endif
-#endif
-#ifdef FEAT_PYTHON3
 #ifdef DYNAMIC_PYTHON3
        else if (STRICMP(name, "python3") == 0)
            n = python3_enabled(FALSE);
 #endif
+#if defined(DYNAMIC_PYTHON) || defined(DYNAMIC_PYTHON3)
+       else if (STRICMP(name, "pythonx") == 0)
+       {
+# if defined(DYNAMIC_PYTHON) && defined(DYNAMIC_PYTHON3)
+           if (p_pyx == 0)
+               n = python3_enabled(FALSE) || python_enabled(FALSE);
+           else if (p_pyx == 3)
+               n = python3_enabled(FALSE);
+           else if (p_pyx == 2)
+               n = python_enabled(FALSE);
+# elif defined(DYNAMIC_PYTHON)
+           n = python_enabled(FALSE);
+# elif defined(DYNAMIC_PYTHON3)
+           n = python3_enabled(FALSE);
+# endif
+       }
 #endif
 #ifdef DYNAMIC_PERL
        else if (STRICMP(name, "perl") == 0)
@@ -8007,6 +8024,9 @@ f_py3eval(typval_T *argvars, typval_T *rettv)
     char_u     *str;
     char_u     buf[NUMBUFLEN];
 
+    if (p_pyx == 0)
+       p_pyx = 3;
+
     str = get_tv_string_buf(&argvars[0], buf);
     do_py3eval(str, rettv);
 }
@@ -8022,11 +8042,35 @@ f_pyeval(typval_T *argvars, typval_T *rettv)
     char_u     *str;
     char_u     buf[NUMBUFLEN];
 
+    if (p_pyx == 0)
+       p_pyx = 2;
+
     str = get_tv_string_buf(&argvars[0], buf);
     do_pyeval(str, rettv);
 }
 #endif
 
+#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
+/*
+ * "pyxeval()" function
+ */
+    static void
+f_pyxeval(typval_T *argvars, typval_T *rettv)
+{
+# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
+    init_pyxversion();
+    if (p_pyx == 2)
+       f_pyeval(argvars, rettv);
+    else
+       f_py3eval(argvars, rettv);
+# elif defined(FEAT_PYTHON)
+    f_pyeval(argvars, rettv);
+# elif defined(FEAT_PYTHON3)
+    f_py3eval(argvars, rettv);
+# endif
+}
+#endif
+
 /*
  * "range()" function
  */
index cb2fadcec065fbaa9963034b90546141945f82e2..d70ff6a7b709240ab1a9e1bade21f17cbc87fdaf 100644 (file)
@@ -1132,6 +1132,18 @@ EX(CMD_python3,          "python3",      ex_py3,
 EX(CMD_py3file,                "py3file",      ex_py3file,
                        RANGE|FILE1|NEEDARG|CMDWIN,
                        ADDR_LINES),
+EX(CMD_pyx,            "pyx",          ex_pyx,
+                       RANGE|EXTRA|NEEDARG|CMDWIN,
+                       ADDR_LINES),
+EX(CMD_pyxdo,          "pyxdo",        ex_pyxdo,
+                       RANGE|DFLALL|EXTRA|NEEDARG|CMDWIN,
+                       ADDR_LINES),
+EX(CMD_pythonx,                "pythonx",      ex_pyx,
+                       RANGE|EXTRA|NEEDARG|CMDWIN,
+                       ADDR_LINES),
+EX(CMD_pyxfile,                "pyxfile",      ex_pyxfile,
+                       RANGE|FILE1|NEEDARG|CMDWIN,
+                       ADDR_LINES),
 EX(CMD_quit,           "quit",         ex_quit,
                        BANG|RANGE|COUNT|NOTADR|TRLBAR|CMDWIN,
                        ADDR_WINDOWS),
index 7a6047a5bb725a79ed59bcafa302b5dcc4355558..59dc4d59759fb4093263c55f97299fd8fd7caa48 100644 (file)
@@ -3675,6 +3675,194 @@ ex_options(
 }
 #endif
 
+#if defined(FEAT_PYTHON3) || defined(FEAT_PYTHON) || defined(PROTO)
+
+# if (defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)) || defined(PROTO)
+/*
+ * Detect Python 3 or 2, and initialize 'pyxversion'.
+ */
+    void
+init_pyxversion(void)
+{
+    if (p_pyx == 0)
+    {
+       if (python3_enabled(FALSE))
+           p_pyx = 3;
+       else if (python_enabled(FALSE))
+           p_pyx = 2;
+    }
+}
+# endif
+
+/*
+ * 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;
+    int            v = requires_py_version(fname);
+
+# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
+    init_pyxversion();
+# endif
+    if (v == 0)
+    {
+# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
+       /* user didn't choose a preference, 'pyx' is used */
+       v = p_pyx;
+# elif defined(FEAT_PYTHON)
+       v = 2;
+# elif defined(FEAT_PYTHON3)
+       v = 3;
+# endif
+    }
+
+    /*
+     * now source, if required python version is not supported show
+     * unobtrusive message.
+     */
+    if (eap == NULL)
+       vim_memset(&ex, 0, sizeof(ex));
+    else
+       ex = *eap;
+    ex.arg = fname;
+    ex.cmd = (char_u *)(v == 2 ? "pyfile" : "pyfile3");
+
+    if (v == 2)
+    {
+# ifdef FEAT_PYTHON
+       ex_pyfile(&ex);
+# else
+       vim_snprintf((char *)IObuff, IOSIZE,
+               _("W20: Required python version 2.x not supported, ignoring file: %s"),
+               fname);
+       MSG(IObuff);
+# endif
+       return;
+    }
+    else
+    {
+# ifdef FEAT_PYTHON3
+       ex_py3file(&ex);
+# else
+       vim_snprintf((char *)IObuff, IOSIZE,
+               _("W21: Required python version 3.x not supported, ignoring file: %s"),
+               fname);
+       MSG(IObuff);
+# endif
+       return;
+    }
+}
+
+/*
+ * ":pyxfile {fname}"
+ */
+    void
+ex_pyxfile(exarg_T *eap)
+{
+    source_pyx_file(eap, eap->arg);
+}
+
+/*
+ * ":pyx"
+ */
+    void
+ex_pyx(exarg_T *eap)
+{
+# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
+    init_pyxversion();
+    if (p_pyx == 2)
+       ex_python(eap);
+    else
+       ex_py3(eap);
+# elif defined(FEAT_PYTHON)
+    ex_python(eap);
+# elif defined(FEAT_PYTHON3)
+    ex_py3(eap);
+# endif
+}
+
+/*
+ * ":pyxdo"
+ */
+    void
+ex_pyxdo(exarg_T *eap)
+{
+# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
+    init_pyxversion();
+    if (p_pyx == 2)
+       ex_pydo(eap);
+    else
+       ex_py3do(eap);
+# elif defined(FEAT_PYTHON)
+    ex_pydo(eap);
+# elif defined(FEAT_PYTHON3)
+    ex_py3do(eap);
+# endif
+}
+
+#endif
+
 /*
  * ":source {fname}"
  */
index cff41cf1486b64197ca3dc44aee01d901c06c3cb..bfb4c88d4674ecd76b8f24e7e9ed4f4ec00f519d 100644 (file)
@@ -288,6 +288,11 @@ static void        ex_popup(exarg_T *eap);
 # define ex_py3do              ex_ni
 # define ex_py3file            ex_ni
 #endif
+#if !defined(FEAT_PYTHON) && !defined(FEAT_PYTHON3)
+# define ex_pyx                        ex_script_ni
+# define ex_pyxdo              ex_ni
+# define ex_pyxfile            ex_ni
+#endif
 #ifndef FEAT_TCL
 # define ex_tcl                        ex_script_ni
 # define ex_tcldo              ex_ni
index 622634da754fb3bd7818db479706269be011c03b..6b2ce56ef249831525dd10e10d6abd0041cc8b48 100644 (file)
@@ -1114,6 +1114,9 @@ ex_python(exarg_T *eap)
 {
     char_u *script;
 
+    if (p_pyx == 0)
+       p_pyx = 2;
+
     script = script_get(eap, eap->arg);
     if (!eap->skip)
     {
@@ -1137,6 +1140,9 @@ ex_pyfile(exarg_T *eap)
     const char *file = (char *)eap->arg;
     char *p;
 
+    if (p_pyx == 0)
+       p_pyx = 2;
+
     /* Have to do it like this. PyRun_SimpleFile requires you to pass a
      * stdio file pointer, but Vim and the Python DLL are compiled with
      * different options under Windows, meaning that stdio pointers aren't
@@ -1175,6 +1181,9 @@ ex_pyfile(exarg_T *eap)
     void
 ex_pydo(exarg_T *eap)
 {
+    if (p_pyx == 0)
+       p_pyx = 2;
+
     DoPyCommand((char *)eap->arg,
            (rangeinitializer) init_range_cmd,
            (runner)run_do,
index 53a1313488768e678f523098bcd70fe874bded56..d68ab85a864218dbd6500199438e5d03da5e99f2 100644 (file)
@@ -1004,6 +1004,9 @@ ex_py3(exarg_T *eap)
 {
     char_u *script;
 
+    if (p_pyx == 0)
+       p_pyx = 3;
+
     script = script_get(eap, eap->arg);
     if (!eap->skip)
     {
@@ -1028,6 +1031,9 @@ ex_py3file(exarg_T *eap)
     char *p;
     int i;
 
+    if (p_pyx == 0)
+       p_pyx = 3;
+
     /* Have to do it like this. PyRun_SimpleFile requires you to pass a
      * stdio file pointer, but Vim and the Python DLL are compiled with
      * different options under Windows, meaning that stdio pointers aren't
@@ -1080,6 +1086,9 @@ ex_py3file(exarg_T *eap)
     void
 ex_py3do(exarg_T *eap)
 {
+    if (p_pyx == 0)
+       p_pyx = 3;
+
     DoPyCommand((char *)eap->arg,
            (rangeinitializer)init_range_cmd,
            (runner)run_do,
index a987a4cdf88540752ca0901d496e552bcf63e5a0..b90d5fdfa22be2480902a9928e574f0aee3987eb 100644 (file)
@@ -479,6 +479,17 @@ struct vimoption
 # define HIGHLIGHT_INIT "8:SpecialKey,@:NonText,d:Directory,e:ErrorMsg,i:IncSearch,l:Search,m:MoreMsg,M:ModeMsg,n:LineNr,N:CursorLineNr,r:Question,s:StatusLine,S:StatusLineNC,t:Title,v:Visual,w:WarningMsg,W:WildMenu,>:SignColumn,*:TabLine,#:TabLineSel,_:TabLineFill"
 #endif
 
+/* Default python version for pyx* commands */
+#if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
+# define DEFAULT_PYTHON_VER    0
+#elif defined(FEAT_PYTHON3)
+# define DEFAULT_PYTHON_VER    3
+#elif defined(FEAT_PYTHON)
+# define DEFAULT_PYTHON_VER    2
+#else
+# define DEFAULT_PYTHON_VER    0
+#endif
+
 /*
  * options[] is initialized here.
  * The order of the options MUST be alphabetic for ":set all" and findoption().
@@ -2143,6 +2154,14 @@ static struct vimoption options[] =
                            {(char_u *)DYNAMIC_PYTHON_DLL, (char_u *)0L}
                            SCRIPTID_INIT},
 #endif
+    {"pyxversion", "pyx",   P_NUM|P_VI_DEF|P_SECURE,
+#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
+                           (char_u *)&p_pyx, PV_NONE,
+#else
+                           (char_u *)NULL, PV_NONE,
+#endif
+                           {(char_u *)DEFAULT_PYTHON_VER, (char_u *)0L}
+                           SCRIPTID_INIT},
     {"quoteescape", "qe",   P_STRING|P_ALLOCED|P_VI_DEF,
 #ifdef FEAT_TEXTOBJ
                            (char_u *)&p_qe, PV_QE,
@@ -8826,6 +8845,15 @@ set_num_option(
        mzvim_reset_timer();
 #endif
 
+#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
+    /* 'pyxversion' */
+    else if (pp == &p_pyx)
+    {
+       if (p_pyx != 0 && p_pyx != 2 && p_pyx != 3)
+           errmsg = e_invarg;
+    }
+#endif
+
     /* sync undo before 'undolevels' changes */
     else if (pp == &p_ul)
     {
index 0ad2fef64b2dce2f6442a2181cb58c84b4df91b2..62e66cd3dafd6e07611407d8cb5fd38fc1a8b03e 100644 (file)
@@ -694,6 +694,9 @@ EXTERN char_u       *p_py3dll;      /* 'pythonthreedll' */
 #if defined(DYNAMIC_PYTHON)
 EXTERN char_u  *p_pydll;       /* 'pythondll' */
 #endif
+#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
+EXTERN long    p_pyx;          /* 'pyxversion' */
+#endif
 #ifdef FEAT_RELTIME
 EXTERN long    p_rdt;          /* 'redrawtime' */
 #endif
index c1325a41e3bb432d2ce53980832d6c28d8867d35..4a40f0a767f58a24fbdf522cb2c5250d164165c8 100644 (file)
@@ -75,6 +75,10 @@ int do_in_runtimepath(char_u *name, int flags, void (*callback)(char_u *fname, v
 void ex_packloadall(exarg_T *eap);
 void ex_packadd(exarg_T *eap);
 void ex_options(exarg_T *eap);
+void init_pyxversion(void);
+void ex_pyxfile(exarg_T *eap);
+void ex_pyx(exarg_T *eap);
+void ex_pyxdo(exarg_T *eap);
 void ex_source(exarg_T *eap);
 linenr_T *source_breakpoint(void *cookie);
 int *source_dbg_tick(void *cookie);
index c3db6fe3032706f0a92ac8d7d3efa9b8588da015..12abb78bae205dc828341bbd920cd3f1a3b90eae 100644 (file)
@@ -176,6 +176,8 @@ NEW_TESTS = test_arglist.res \
            test_packadd.res \
            test_perl.res \
            test_profile.res \
+           test_pyx2.res \
+           test_pyx3.res \
            test_quickfix.res \
            test_retab.res \
            test_ruby.res \
diff --git a/src/testdir/pyxfile/py2_magic.py b/src/testdir/pyxfile/py2_magic.py
new file mode 100644 (file)
index 0000000..819892f
--- /dev/null
@@ -0,0 +1,4 @@
+# requires python 2.x
+
+import sys
+print(sys.version)
diff --git a/src/testdir/pyxfile/py2_shebang.py b/src/testdir/pyxfile/py2_shebang.py
new file mode 100644 (file)
index 0000000..13bfc49
--- /dev/null
@@ -0,0 +1,4 @@
+#!/usr/bin/python2
+
+import sys
+print(sys.version)
diff --git a/src/testdir/pyxfile/py3_magic.py b/src/testdir/pyxfile/py3_magic.py
new file mode 100644 (file)
index 0000000..d4b7ee0
--- /dev/null
@@ -0,0 +1,4 @@
+# requires python 3.x
+
+import sys
+print(sys.version)
diff --git a/src/testdir/pyxfile/py3_shebang.py b/src/testdir/pyxfile/py3_shebang.py
new file mode 100644 (file)
index 0000000..ec05808
--- /dev/null
@@ -0,0 +1,4 @@
+#!/usr/bin/python3
+
+import sys
+print(sys.version)
diff --git a/src/testdir/pyxfile/pyx.py b/src/testdir/pyxfile/pyx.py
new file mode 100644 (file)
index 0000000..261a651
--- /dev/null
@@ -0,0 +1,2 @@
+import sys
+print(sys.version)
diff --git a/src/testdir/test_pyx2.vim b/src/testdir/test_pyx2.vim
new file mode 100644 (file)
index 0000000..50e57c3
--- /dev/null
@@ -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/testdir/test_pyx3.vim b/src/testdir/test_pyx3.vim
new file mode 100644 (file)
index 0000000..64546b4
--- /dev/null
@@ -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
index 372c9bb860f677659c180e99d66353a3f4e2686a..6a6cc0689387083379f7ebe802c9ed6f6f233d8c 100644 (file)
@@ -2102,7 +2102,9 @@ 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'
index 94b47bb813f84968fcfcb8fd0c1d62f6b74119ac..38186475867d53209a672631ee3ccfc362d1c9a7 100644 (file)
@@ -764,6 +764,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    251,
 /**/
     250,
 /**/