]> granicus.if.org Git - vim/commitdiff
patch 8.2.0427: it is not possible to check for a typo in a feature name v8.2.0427
authorBram Moolenaar <Bram@vim.org>
Sun, 22 Mar 2020 15:17:14 +0000 (16:17 +0100)
committerBram Moolenaar <Bram@vim.org>
Sun, 22 Mar 2020 15:17:14 +0000 (16:17 +0100)
Problem:    It is not possible to check for a typo in a feature name.
Solution:   Add an extra argument to has().

runtime/doc/eval.txt
src/evalfunc.c
src/testdir/check.vim
src/testdir/test_functions.vim
src/version.c

index 6c7435c9a44df3476b9e38bd949ffc8464d30f6f..00df404785909cf2d1b24589f874554c39c69634 100644 (file)
@@ -1,4 +1,4 @@
-*eval.txt*     For Vim version 8.2.  Last change: 2020 Mar 16
+*eval.txt*     For Vim version 8.2.  Last change: 2020 Mar 22
 
 
                  VIM REFERENCE MANUAL    by Bram Moolenaar
@@ -2515,7 +2515,7 @@ glob({expr} [, {nosuf} [, {list} [, {alllinks}]]])
 glob2regpat({expr})            String  convert a glob pat into a search pat
 globpath({path}, {expr} [, {nosuf} [, {list} [, {alllinks}]]])
                                String  do glob({expr}) for all dirs in {path}
-has({feature})                 Number  |TRUE| if feature {feature} supported
+has({feature} [, {check}])     Number  |TRUE| if feature {feature} supported
 has_key({dict}, {key})         Number  |TRUE| if {dict} has entry {key}
 haslocaldir([{winnr} [, {tabnr}]])
                                Number  |TRUE| if the window executed |:lcd|
@@ -4358,8 +4358,8 @@ feedkeys({string} [, {mode}])                             *feedkeys()*
                'L'     Lowlevel input.  Only works for Unix or when using the
                        GUI. Keys are used as if they were coming from the
                        terminal.  Other flags are not used.  *E980*
-                       When a CTRL-C interrupts it sets the internal
-                       "got_int" flag.
+                       When a CTRL-C interrupts and 't' is included it sets
+                       the internal "got_int" flag.
                'i'     Insert the string instead of appending (see above).
                'x'     Execute commands until typeahead is empty.  This is
                        similar to using ":normal!".  You can call feedkeys()
@@ -5828,10 +5828,20 @@ globpath({path}, {expr} [, {nosuf} [, {list} [, {alllinks}]]])
                        GetExpr()->globpath(&rtp)
 <
                                                        *has()*
-has({feature}) The result is a Number, which is 1 if the feature {feature} is
-               supported, zero otherwise.  The {feature} argument is a
-               string.  See |feature-list| below.
+has({feature} [, {check}])
+               When {check} is omitted or is zero: The result is a Number,
+               which is 1 if the feature {feature} is supported, zero
+               otherwise.  The {feature} argument is a string, case is
+               ignored.  See |feature-list| below.
+
+               When {check} is present and not zero: The result is a Number,
+               which is 1 if the feature {feature} could ever be supported,
+               zero otherwise.  This is useful to check for a typo in
+               {feature}.  Keep in mind that an older Vim version will not
+               know about a feature added later.
+
                Also see |exists()|.
+
                Note that to skip code that has a syntax error when the
                feature is not available, Vim may skip the rest of the line
                and miss a following `endif`.  Therfore put the `endif` on a
index 0f99c6dab8e835300ec26b3c57be400364f049f5..acb0702316cea3f166a221114416125dd56519b3 100644 (file)
@@ -566,7 +566,7 @@ static funcentry_T global_functions[] =
     {"glob",           1, 4, FEARG_1,    ret_any,      f_glob},
     {"glob2regpat",    1, 1, FEARG_1,    ret_string,   f_glob2regpat},
     {"globpath",       2, 5, FEARG_2,    ret_any,      f_globpath},
-    {"has",            1, 1, 0,          ret_number,   f_has},
+    {"has",            1, 2, 0,          ret_number,   f_has},
     {"has_key",                2, 2, FEARG_1,    ret_number,   f_has_key},
     {"haslocaldir",    0, 2, FEARG_1,    ret_number,   f_haslocaldir},
     {"hasmapto",       1, 3, FEARG_1,    ret_number,   f_hasmapto},
@@ -3357,551 +3357,1148 @@ f_has(typval_T *argvars, typval_T *rettv)
 {
     int                i;
     char_u     *name;
+    int                x = FALSE;
     int                n = FALSE;
-    static char        *(has_list[]) =
+    typedef struct {
+       char *name;
+       short present;
+    } has_item_T;
+    static has_item_T has_list[] =
     {
+       {"amiga",
 #ifdef AMIGA
-       "amiga",
-# ifdef FEAT_ARP
-       "arp",
-# endif
+               1
+#else
+               0
+#endif
+               },
+       {"arp",
+#if defined(AMIGA) && defined(FEAT_ARP)
+               1
+#else
+               0
 #endif
+               },
+       {"beos",
 #ifdef __BEOS__
-       "beos",
+               1
+#else
+               0
 #endif
+               },
+       {"haiku",
 #ifdef __HAIKU__
-       "haiku",
+               1
+#else
+               0
 #endif
+               },
+       {"bsd",
 #if defined(BSD) && !defined(MACOS_X)
-       "bsd",
+               1
+#else
+               0
 #endif
+               },
+       {"hpux",
 #ifdef hpux
-       "hpux",
+               1
+#else
+               0
 #endif
+               },
+       {"linux",
 #ifdef __linux__
-       "linux",
+               1
+#else
+               0
 #endif
+               },
+       {"mac",         // Mac OS X (and, once, Mac OS Classic)
 #ifdef MACOS_X
-       "mac",          // Mac OS X (and, once, Mac OS Classic)
-       "osx",          // Mac OS X
-# ifdef MACOS_X_DARWIN
-       "macunix",      // Mac OS X, with the darwin feature
-       "osxdarwin",    // synonym for macunix
-# endif
+               1
+#else
+               0
 #endif
+               },
+       {"osx",         // Mac OS X
+#ifdef MACOS_X
+               1
+#else
+               0
+#endif
+               },
+       {"macunix",     // Mac OS X, with the darwin feature
+#if defined(MACOS_X) && defined(MACOS_X_DARWIN)
+               1
+#else
+               0
+#endif
+               },
+       {"osxdarwin",   // synonym for macunix
+#if defined(MACOS_X) && defined(MACOS_X_DARWIN)
+               1
+#else
+               0
+#endif
+               },
+       {"qnx",
 #ifdef __QNX__
-       "qnx",
+               1
+#else
+               0
 #endif
+               },
+       {"sun",
 #ifdef SUN_SYSTEM
-       "sun",
+               1
 #else
-       "moon",
+               0
 #endif
+               },
+       {"unix",
 #ifdef UNIX
-       "unix",
+               1
+#else
+               0
 #endif
+               },
+       {"vms",
 #ifdef VMS
-       "vms",
+               1
+#else
+               0
 #endif
+               },
+       {"win32",
 #ifdef MSWIN
-       "win32",
+               1
+#else
+               0
 #endif
+               },
+       {"win32unix",
 #if defined(UNIX) && defined(__CYGWIN__)
-       "win32unix",
+               1
+#else
+               0
 #endif
+               },
+       {"win64",
 #ifdef _WIN64
-       "win64",
+               1
+#else
+               0
 #endif
+               },
+       {"ebcdic",
 #ifdef EBCDIC
-       "ebcdic",
+               1
+#else
+               0
 #endif
+               },
+       {"fname_case",
 #ifndef CASE_INSENSITIVE_FILENAME
-       "fname_case",
+               1
+#else
+               0
 #endif
+               },
+       {"acl",
 #ifdef HAVE_ACL
-       "acl",
+               1
+#else
+               0
 #endif
+               },
+       {"arabic",
 #ifdef FEAT_ARABIC
-       "arabic",
+               1
+#else
+               0
 #endif
-       "autocmd",
+               },
+       {"autocmd", 1},
+       {"autochdir",
 #ifdef FEAT_AUTOCHDIR
-       "autochdir",
+               1
+#else
+               0
 #endif
+               },
+       {"autoservername",
 #ifdef FEAT_AUTOSERVERNAME
-       "autoservername",
+               1
+#else
+               0
 #endif
+               },
+       {"balloon_eval",
 #ifdef FEAT_BEVAL_GUI
-       "balloon_eval",
-# ifndef FEAT_GUI_MSWIN // other GUIs always have multiline balloons
-       "balloon_multiline",
-# endif
+               1
+#else
+               0
+#endif
+               },
+       {"balloon_multiline",
+#if defined(FEAT_BEVAL_GUI) && !defined(FEAT_GUI_MSWIN)
+                       // MS-Windows requires runtime check, see below
+               1
+#else
+               0
 #endif
+               },
+       {"balloon_eval_term",
 #ifdef FEAT_BEVAL_TERM
-       "balloon_eval_term",
+               1
+#else
+               0
 #endif
+               },
+       {"builtin_terms",
 #if defined(SOME_BUILTIN_TCAPS) || defined(ALL_BUILTIN_TCAPS)
-       "builtin_terms",
-# ifdef ALL_BUILTIN_TCAPS
-       "all_builtin_terms",
-# endif
+               1
+#else
+               0
+#endif
+               },
+       {"all_builtin_terms",
+#if defined(ALL_BUILTIN_TCAPS)
+               1
+#else
+               0
 #endif
+               },
+       {"browsefilter",
 #if defined(FEAT_BROWSE) && (defined(USE_FILE_CHOOSER) \
        || defined(FEAT_GUI_MSWIN) \
        || defined(FEAT_GUI_MOTIF))
-       "browsefilter",
+               1
+#else
+               0
 #endif
+               },
+       {"byte_offset",
 #ifdef FEAT_BYTEOFF
-       "byte_offset",
+               1
+#else
+               0
 #endif
+               },
+       {"channel",
 #ifdef FEAT_JOB_CHANNEL
-       "channel",
+               1
+#else
+               0
 #endif
+               },
+       {"cindent",
 #ifdef FEAT_CINDENT
-       "cindent",
+               1
+#else
+               0
 #endif
+               },
+       {"clientserver",
 #ifdef FEAT_CLIENTSERVER
-       "clientserver",
+               1
+#else
+               0
 #endif
+               },
+       {"clipboard",
 #ifdef FEAT_CLIPBOARD
-       "clipboard",
+               1
+#else
+               0
 #endif
-       "cmdline_compl",
-       "cmdline_hist",
-       "comments",
+               },
+       {"cmdline_compl", 1},
+       {"cmdline_hist", 1},
+       {"comments", 1},
+       {"conceal",
 #ifdef FEAT_CONCEAL
-       "conceal",
+               1
+#else
+               0
+#endif
+               },
+       {"cryptv",
+#ifdef FEAT_CRYPT
+               1
+#else
+               0
 #endif
+               },
+       {"crypt-blowfish",
 #ifdef FEAT_CRYPT
-       "cryptv",
-       "crypt-blowfish",
-       "crypt-blowfish2",
+               1
+#else
+               0
 #endif
+               },
+       {"crypt-blowfish2",
+#ifdef FEAT_CRYPT
+               1
+#else
+               0
+#endif
+               },
+       {"cscope",
 #ifdef FEAT_CSCOPE
-       "cscope",
+               1
+#else
+               0
 #endif
-       "cursorbind",
+               },
+       {"cursorbind", 1},
+       {"cursorshape",
 #ifdef CURSOR_SHAPE
-       "cursorshape",
+               1
+#else
+               0
 #endif
+               },
+       {"debug",
 #ifdef DEBUG
-       "debug",
+               1
+#else
+               0
 #endif
+               },
+       {"dialog_con",
 #ifdef FEAT_CON_DIALOG
-       "dialog_con",
+               1
+#else
+               0
 #endif
+               },
+       {"dialog_gui",
 #ifdef FEAT_GUI_DIALOG
-       "dialog_gui",
+               1
+#else
+               0
 #endif
+               },
+       {"diff",
 #ifdef FEAT_DIFF
-       "diff",
+               1
+#else
+               0
 #endif
+               },
+       {"digraphs",
 #ifdef FEAT_DIGRAPHS
-       "digraphs",
+               1
+#else
+               0
 #endif
+               },
+       {"directx",
 #ifdef FEAT_DIRECTX
-       "directx",
+               1
+#else
+               0
 #endif
+               },
+       {"dnd",
 #ifdef FEAT_DND
-       "dnd",
+               1
+#else
+               0
 #endif
+               },
+       {"emacs_tags",
 #ifdef FEAT_EMACS_TAGS
-       "emacs_tags",
+               1
+#else
+               0
 #endif
-       "eval",     // always present, of course!
-       "ex_extra", // graduated feature
+               },
+       {"eval", 1},            // always present, of course!
+       {"ex_extra", 1},        // graduated feature
+       {"extra_search",
 #ifdef FEAT_SEARCH_EXTRA
-       "extra_search",
+               1
+#else
+               0
 #endif
+               },
+       {"file_in_path",
 #ifdef FEAT_SEARCHPATH
-       "file_in_path",
+               1
+#else
+               0
 #endif
+               },
+       {"filterpipe",
 #if defined(FEAT_FILTERPIPE) && !defined(VIMDLL)
-       "filterpipe",
+               1
+#else
+               0
 #endif
+               },
+       {"find_in_path",
 #ifdef FEAT_FIND_ID
-       "find_in_path",
+               1
+#else
+               0
 #endif
+               },
+       {"float",
 #ifdef FEAT_FLOAT
-       "float",
+               1
+#else
+               0
 #endif
+               },
+       {"folding",
 #ifdef FEAT_FOLDING
-       "folding",
+               1
+#else
+               0
 #endif
+               },
+       {"footer",
 #ifdef FEAT_FOOTER
-       "footer",
+               1
+#else
+               0
 #endif
+               },
+       {"fork",
 #if !defined(USE_SYSTEM) && defined(UNIX)
-       "fork",
+               1
+#else
+               0
 #endif
+               },
+       {"gettext",
 #ifdef FEAT_GETTEXT
-       "gettext",
+               1
+#else
+               0
 #endif
+               },
+       {"gui",
 #ifdef FEAT_GUI
-       "gui",
+               1
+#else
+               0
 #endif
-#ifdef FEAT_GUI_ATHENA
-# ifdef FEAT_GUI_NEXTAW
-       "gui_neXtaw",
-# else
-       "gui_athena",
-# endif
+               },
+       {"gui_neXtaw",
+#if defined(FEAT_GUI_ATHENA) && defined(FEAT_GUI_NEXTAW)
+               1
+#else
+               0
+#endif
+               },
+       {"gui_athena",
+#if defined(FEAT_GUI_ATHENA) && !defined(FEAT_GUI_NEXTAW)
+               1
+#else
+               0
 #endif
+               },
+       {"gui_gtk",
 #ifdef FEAT_GUI_GTK
-       "gui_gtk",
-# ifdef USE_GTK3
-       "gui_gtk3",
-# else
-       "gui_gtk2",
-# endif
+               1
+#else
+               0
+#endif
+               },
+       {"gui_gtk2",
+#if defined(FEAT_GUI_GTK) && !defined(USE_GTK3)
+               1
+#else
+               0
 #endif
+               },
+       {"gui_gtk3",
+#if defined(FEAT_GUI_GTK) && defined(USE_GTK3)
+               1
+#else
+               0
+#endif
+               },
+       {"gui_gnome",
 #ifdef FEAT_GUI_GNOME
-       "gui_gnome",
+               1
+#else
+               0
 #endif
+               },
+       {"gui_haiku",
 #ifdef FEAT_GUI_HAIKU
-       "gui_haiku",
+               1
+#else
+               0
 #endif
+               },
+       {"gui_mac",
 #ifdef FEAT_GUI_MAC
-       "gui_mac",
+               1
+#else
+               0
 #endif
+               },
+       {"gui_motif",
 #ifdef FEAT_GUI_MOTIF
-       "gui_motif",
+               1
+#else
+               0
 #endif
+               },
+       {"gui_photon",
 #ifdef FEAT_GUI_PHOTON
-       "gui_photon",
+               1
+#else
+               0
 #endif
+               },
+       {"gui_win32",
 #ifdef FEAT_GUI_MSWIN
-       "gui_win32",
+               1
+#else
+               0
 #endif
+               },
+       {"iconv",
 #if defined(HAVE_ICONV_H) && defined(USE_ICONV)
-       "iconv",
+               1
+#else
+               0
 #endif
-       "insert_expand",
+               },
+       {"insert_expand", 1},
+       {"job",
 #ifdef FEAT_JOB_CHANNEL
-       "job",
+               1
+#else
+               0
 #endif
+               },
+       {"jumplist",
 #ifdef FEAT_JUMPLIST
-       "jumplist",
+               1
+#else
+               0
 #endif
+               },
+       {"keymap",
 #ifdef FEAT_KEYMAP
-       "keymap",
+               1
+#else
+               0
 #endif
-       "lambda", // always with FEAT_EVAL, since 7.4.2120 with closure
+               },
+       {"lambda", 1}, // always with FEAT_EVAL, since 7.4.2120 with closure
+       {"langmap",
 #ifdef FEAT_LANGMAP
-       "langmap",
+               1
+#else
+               0
 #endif
+               },
+       {"libcall",
 #ifdef FEAT_LIBCALL
-       "libcall",
+               1
+#else
+               0
 #endif
+               },
+       {"linebreak",
 #ifdef FEAT_LINEBREAK
-       "linebreak",
+               1
+#else
+               0
 #endif
+               },
+       {"lispindent",
 #ifdef FEAT_LISP
-       "lispindent",
-#endif
-       "listcmds",
-       "localmap",
-#ifdef FEAT_LUA
-# ifndef DYNAMIC_LUA
-       "lua",
-# endif
+               1
+#else
+               0
+#endif
+               },
+       {"listcmds", 1},
+       {"localmap", 1},
+       {"lua",
+#if defined(FEAT_LUA) && !defined(DYNAMIC_LUA)
+               1
+#else
+               0
 #endif
+               },
+       {"menu",
 #ifdef FEAT_MENU
-       "menu",
+               1
+#else
+               0
 #endif
+               },
+       {"mksession",
 #ifdef FEAT_SESSION
-       "mksession",
+               1
+#else
+               0
 #endif
-       "modify_fname",
-       "mouse",
+               },
+       {"modify_fname", 1},
+       {"mouse", 1},
+       {"mouseshape",
 #ifdef FEAT_MOUSESHAPE
-       "mouseshape",
+               1
+#else
+               0
 #endif
-#if defined(UNIX) || defined(VMS)
-# ifdef FEAT_MOUSE_DEC
-       "mouse_dec",
-# endif
-# ifdef FEAT_MOUSE_GPM
-       "mouse_gpm",
-# endif
-# ifdef FEAT_MOUSE_JSB
-       "mouse_jsbterm",
-# endif
-# ifdef FEAT_MOUSE_NET
-       "mouse_netterm",
-# endif
-# ifdef FEAT_MOUSE_PTERM
-       "mouse_pterm",
-# endif
-# ifdef FEAT_MOUSE_XTERM
-       "mouse_sgr",
-# endif
-# ifdef FEAT_SYSMOUSE
-       "mouse_sysmouse",
-# endif
-# ifdef FEAT_MOUSE_URXVT
-       "mouse_urxvt",
-# endif
-# ifdef FEAT_MOUSE_XTERM
-       "mouse_xterm",
-# endif
+               },
+       {"mouse_dec",
+#if (defined(UNIX) || defined(VMS)) && defined(FEAT_MOUSE_DEC)
+               1
+#else
+               0
+#endif
+               },
+       {"mouse_gpm",
+#if (defined(UNIX) || defined(VMS)) && defined(FEAT_MOUSE_GPM)
+               1
+#else
+               0
+#endif
+               },
+       {"mouse_jsbterm",
+#if (defined(UNIX) || defined(VMS)) && defined(FEAT_MOUSE_JSB)
+               1
+#else
+               0
+#endif
+               },
+       {"mouse_netterm",
+#if (defined(UNIX) || defined(VMS)) && defined(FEAT_MOUSE_NET)
+               1
+#else
+               0
+#endif
+               },
+       {"mouse_pterm",
+#if (defined(UNIX) || defined(VMS)) && defined(FEAT_MOUSE_PTERM)
+               1
+#else
+               0
+#endif
+               },
+       {"mouse_sgr",
+#if (defined(UNIX) || defined(VMS)) && defined(FEAT_MOUSE_XTERM)
+               1
+#else
+               0
+#endif
+               },
+       {"mouse_sysmouse",
+#if (defined(UNIX) || defined(VMS)) && defined(FEAT_SYSMOUSE)
+               1
+#else
+               0
+#endif
+               },
+       {"mouse_urxvt",
+#if (defined(UNIX) || defined(VMS)) && defined(FEAT_MOUSE_URXVT)
+               1
+#else
+               0
+#endif
+               },
+       {"mouse_xterm",
+#if (defined(UNIX) || defined(VMS)) && defined(FEAT_MOUSE_XTERM)
+               1
+#else
+               0
 #endif
-       "multi_byte",
+               },
+       {"multi_byte", 1},
+       {"multi_byte_ime",
 #ifdef FEAT_MBYTE_IME
-       "multi_byte_ime",
+               1
+#else
+               0
 #endif
+               },
+       {"multi_lang",
 #ifdef FEAT_MULTI_LANG
-       "multi_lang",
-#endif
-#ifdef FEAT_MZSCHEME
-#ifndef DYNAMIC_MZSCHEME
-       "mzscheme",
+               1
+#else
+               0
 #endif
+               },
+       {"mzscheme",
+#if defined(FEAT_MZSCHEME) && !defined(DYNAMIC_MZSCHEME)
+               1
+#else
+               0
 #endif
-       "num64",
+               },
+       {"num64", 1},
+       {"ole",
 #ifdef FEAT_OLE
-       "ole",
+               1
+#else
+               0
 #endif
+               },
+       {"packages",
 #ifdef FEAT_EVAL
-       "packages",
+               1
+#else
+               0
 #endif
+               },
+       {"path_extra",
 #ifdef FEAT_PATH_EXTRA
-       "path_extra",
-#endif
-#ifdef FEAT_PERL
-#ifndef DYNAMIC_PERL
-       "perl",
+               1
+#else
+               0
 #endif
+               },
+       {"perl",
+#if defined(FEAT_PERL) && !defined(DYNAMIC_PERL)
+               1
+#else
+               0
 #endif
+               },
+       {"persistent_undo",
 #ifdef FEAT_PERSISTENT_UNDO
-       "persistent_undo",
+               1
+#else
+               0
 #endif
+               },
+       {"python_compiled",
 #if defined(FEAT_PYTHON)
-       "python_compiled",
-# if defined(DYNAMIC_PYTHON)
-       "python_dynamic",
-# else
-       "python",
-       "pythonx",
-# endif
+               1
+#else
+               0
+#endif
+               },
+       {"python_dynamic",
+#if defined(FEAT_PYTHON) && defined(DYNAMIC_PYTHON)
+               1
+#else
+               0
 #endif
+               },
+       {"python",
+#if defined(FEAT_PYTHON) && !defined(DYNAMIC_PYTHON)
+               1
+#else
+               0
+#endif
+               },
+       {"pythonx",
+#if (defined(FEAT_PYTHON) && !defined(DYNAMIC_PYTHON)) \
+       || (defined(FEAT_PYTHON3) && !defined(DYNAMIC_PYTHON3))
+               1
+#else
+               0
+#endif
+               },
+       {"python3_compiled",
 #if defined(FEAT_PYTHON3)
-       "python3_compiled",
-# if defined(DYNAMIC_PYTHON3)
-       "python3_dynamic",
-# else
-       "python3",
-       "pythonx",
-# endif
+               1
+#else
+               0
+#endif
+               },
+       {"python3_dynamic",
+#if defined(FEAT_PYTHON3) && defined(DYNAMIC_PYTHON3)
+               1
+#else
+               0
+#endif
+               },
+       {"python3",
+#if defined(FEAT_PYTHON3) && !defined(DYNAMIC_PYTHON3)
+               1
+#else
+               0
 #endif
+               },
+       {"popupwin",
 #ifdef FEAT_PROP_POPUP
-       "popupwin",
+               1
+#else
+               0
 #endif
+               },
+       {"postscript",
 #ifdef FEAT_POSTSCRIPT
-       "postscript",
+               1
+#else
+               0
 #endif
+               },
+       {"printer",
 #ifdef FEAT_PRINTER
-       "printer",
+               1
+#else
+               0
 #endif
+               },
+       {"profile",
 #ifdef FEAT_PROFILE
-       "profile",
+               1
+#else
+               0
 #endif
+               },
+       {"reltime",
 #ifdef FEAT_RELTIME
-       "reltime",
+               1
+#else
+               0
 #endif
+               },
+       {"quickfix",
 #ifdef FEAT_QUICKFIX
-       "quickfix",
+               1
+#else
+               0
 #endif
+               },
+       {"rightleft",
 #ifdef FEAT_RIGHTLEFT
-       "rightleft",
+               1
+#else
+               0
 #endif
+               },
+       {"ruby",
 #if defined(FEAT_RUBY) && !defined(DYNAMIC_RUBY)
-       "ruby",
+               1
+#else
+               0
 #endif
-       "scrollbind",
+               },
+       {"scrollbind", 1},
+       {"showcmd",
 #ifdef FEAT_CMDL_INFO
-       "showcmd",
-       "cmdline_info",
+               1
+#else
+               0
 #endif
+               },
+       {"cmdline_info",
+#ifdef FEAT_CMDL_INFO
+               1
+#else
+               0
+#endif
+               },
+       {"signs",
 #ifdef FEAT_SIGNS
-       "signs",
+               1
+#else
+               0
 #endif
+               },
+       {"smartindent",
 #ifdef FEAT_SMARTINDENT
-       "smartindent",
+               1
+#else
+               0
 #endif
+               },
+       {"startuptime",
 #ifdef STARTUPTIME
-       "startuptime",
+               1
+#else
+               0
 #endif
+               },
+       {"statusline",
 #ifdef FEAT_STL_OPT
-       "statusline",
+               1
+#else
+               0
 #endif
+               },
+       {"netbeans_intg",
 #ifdef FEAT_NETBEANS_INTG
-       "netbeans_intg",
+               1
+#else
+               0
 #endif
+               },
+       {"sound",
 #ifdef FEAT_SOUND
-       "sound",
+               1
+#else
+               0
 #endif
+               },
+       {"spell",
 #ifdef FEAT_SPELL
-       "spell",
+               1
+#else
+               0
 #endif
+               },
+       {"syntax",
 #ifdef FEAT_SYN_HL
-       "syntax",
+               1
+#else
+               0
 #endif
+               },
+       {"system",
 #if defined(USE_SYSTEM) || !defined(UNIX)
-       "system",
+               1
+#else
+               0
 #endif
+               },
+       {"tag_binary",
 #ifdef FEAT_TAG_BINS
-       "tag_binary",
+               1
+#else
+               0
 #endif
-#ifdef FEAT_TCL
-# ifndef DYNAMIC_TCL
-       "tcl",
-# endif
+               },
+       {"tcl",
+#if defined(FEAT_TCL) && !defined(DYNAMIC_TCL)
+               1
+#else
+               0
 #endif
+               },
+       {"termguicolors",
 #ifdef FEAT_TERMGUICOLORS
-       "termguicolors",
+               1
+#else
+               0
 #endif
+               },
+       {"terminal",
 #if defined(FEAT_TERMINAL) && !defined(MSWIN)
-       "terminal",
+               1
+#else
+               0
 #endif
+               },
+       {"terminfo",
 #ifdef TERMINFO
-       "terminfo",
+               1
+#else
+               0
 #endif
+               },
+       {"termresponse",
 #ifdef FEAT_TERMRESPONSE
-       "termresponse",
+               1
+#else
+               0
 #endif
+               },
+       {"textobjects",
 #ifdef FEAT_TEXTOBJ
-       "textobjects",
+               1
+#else
+               0
 #endif
+               },
+       {"textprop",
 #ifdef FEAT_PROP_POPUP
-       "textprop",
+               1
+#else
+               0
 #endif
+               },
+       {"tgetent",
 #ifdef HAVE_TGETENT
-       "tgetent",
+               1
+#else
+               0
 #endif
+               },
+       {"timers",
 #ifdef FEAT_TIMERS
-       "timers",
+               1
+#else
+               0
 #endif
+               },
+       {"title",
 #ifdef FEAT_TITLE
-       "title",
+               1
+#else
+               0
 #endif
+               },
+       {"toolbar",
 #ifdef FEAT_TOOLBAR
-       "toolbar",
+               1
+#else
+               0
 #endif
+               },
+       {"unnamedplus",
 #if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
-       "unnamedplus",
+               1
+#else
+               0
 #endif
-       "user-commands",    // was accidentally included in 5.4
-       "user_commands",
+               },
+       {"user-commands", 1},    // was accidentally included in 5.4
+       {"user_commands", 1},
+       {"vartabs",
 #ifdef FEAT_VARTABS
-       "vartabs",
+               1
+#else
+               0
 #endif
-       "vertsplit",
+               },
+       {"vertsplit", 1},
+       {"viminfo",
 #ifdef FEAT_VIMINFO
-       "viminfo",
-#endif
-       "vimscript-1",
-       "vimscript-2",
-       "vimscript-3",
-       "vimscript-4",
-       "virtualedit",
-       "visual",
-       "visualextra",
-       "vreplace",
+               1
+#else
+               0
+#endif
+               },
+       {"vimscript-1", 1},
+       {"vimscript-2", 1},
+       {"vimscript-3", 1},
+       {"vimscript-4", 1},
+       {"virtualedit", 1},
+       {"visual", 1},
+       {"visualextra", 1},
+       {"vreplace", 1},
+       {"vtp",
 #ifdef FEAT_VTP
-       "vtp",
+               1
+#else
+               0
 #endif
+               },
+       {"wildignore",
 #ifdef FEAT_WILDIGN
-       "wildignore",
+               1
+#else
+               0
 #endif
+               },
+       {"wildmenu",
 #ifdef FEAT_WILDMENU
-       "wildmenu",
+               1
+#else
+               0
 #endif
-       "windows",
+               },
+       {"windows", 1},
+       {"winaltkeys",
 #ifdef FEAT_WAK
-       "winaltkeys",
+               1
+#else
+               0
 #endif
+               },
+       {"writebackup",
 #ifdef FEAT_WRITEBACKUP
-       "writebackup",
+               1
+#else
+               0
 #endif
+               },
+       {"xim",
 #ifdef FEAT_XIM
-       "xim",
+               1
+#else
+               0
 #endif
+               },
+       {"xfontset",
 #ifdef FEAT_XFONTSET
-       "xfontset",
+               1
+#else
+               0
 #endif
+               },
+       {"xpm",
+#if defined(FEAT_XPM_W32) || defined(HAVE_XPM)
+               1
+#else
+               0
+#endif
+               },
+       {"xpm_w32",     // for backward compatibility
 #ifdef FEAT_XPM_W32
-       "xpm",
-       "xpm_w32",      // for backward compatibility
+               1
 #else
-# if defined(HAVE_XPM)
-       "xpm",
-# endif
+               0
 #endif
+               },
+       {"xsmp",
 #ifdef USE_XSMP
-       "xsmp",
+               1
+#else
+               0
 #endif
+               },
+       {"xsmp_interact",
 #ifdef USE_XSMP_INTERACT
-       "xsmp_interact",
+               1
+#else
+               0
 #endif
+               },
+       {"xterm_clipboard",
 #ifdef FEAT_XCLIPBOARD
-       "xterm_clipboard",
+               1
+#else
+               0
 #endif
+               },
+       {"xterm_save",
 #ifdef FEAT_XTERM_SAVE
-       "xterm_save",
+               1
+#else
+               0
 #endif
+               },
+       {"X11",
 #if defined(UNIX) && defined(FEAT_X11)
-       "X11",
+               1
+#else
+               0
 #endif
-       NULL
+               },
+       {NULL, 0}
     };
 
     name = tv_get_string(&argvars[0]);
-    for (i = 0; has_list[i] != NULL; ++i)
-       if (STRICMP(name, has_list[i]) == 0)
+    for (i = 0; has_list[i].name != NULL; ++i)
+       if (STRICMP(name, has_list[i].name) == 0)
        {
-           n = TRUE;
+           x = TRUE;
+           n = has_list[i].present;
            break;
        }
 
-    if (n == FALSE)
+    // features also in has_list[] but sometimes enabled at runtime
+    if (x == TRUE && n == FALSE)
     {
-       if (STRNICMP(name, "patch", 5) == 0)
-       {
-           if (name[5] == '-'
-                   && STRLEN(name) >= 11
-                   && vim_isdigit(name[6])
-                   && vim_isdigit(name[8])
-                   && vim_isdigit(name[10]))
-           {
-               int major = atoi((char *)name + 6);
-               int minor = atoi((char *)name + 8);
-
-               // Expect "patch-9.9.01234".
-               n = (major < VIM_VERSION_MAJOR
-                    || (major == VIM_VERSION_MAJOR
-                        && (minor < VIM_VERSION_MINOR
-                            || (minor == VIM_VERSION_MINOR
-                                && has_patch(atoi((char *)name + 10))))));
-           }
-           else
-               n = has_patch(atoi((char *)name + 5));
-       }
-       else if (STRICMP(name, "vim_starting") == 0)
-           n = (starting != 0);
-       else if (STRICMP(name, "ttyin") == 0)
-           n = mch_input_isatty();
-       else if (STRICMP(name, "ttyout") == 0)
-           n = stdout_isatty;
-       else if (STRICMP(name, "multi_byte_encoding") == 0)
-           n = has_mbyte;
+       if (0)
+           ;
 #if defined(FEAT_BEVAL) && defined(FEAT_GUI_MSWIN)
        else if (STRICMP(name, "balloon_multiline") == 0)
            n = multiline_balloon_available();
 #endif
-#ifdef DYNAMIC_TCL
-       else if (STRICMP(name, "tcl") == 0)
-           n = tcl_enabled(FALSE);
+#ifdef VIMDLL
+       else if (STRICMP(name, "filterpipe") == 0)
+           n = gui.in_use || gui.starting;
 #endif
 #if defined(USE_ICONV) && defined(DYNAMIC_ICONV)
        else if (STRICMP(name, "iconv") == 0)
@@ -3915,9 +4512,9 @@ f_has(typval_T *argvars, typval_T *rettv)
        else if (STRICMP(name, "mzscheme") == 0)
            n = mzscheme_enabled(FALSE);
 #endif
-#ifdef DYNAMIC_RUBY
-       else if (STRICMP(name, "ruby") == 0)
-           n = ruby_enabled(FALSE);
+#ifdef DYNAMIC_PERL
+       else if (STRICMP(name, "perl") == 0)
+           n = perl_enabled(FALSE);
 #endif
 #ifdef DYNAMIC_PYTHON
        else if (STRICMP(name, "python") == 0)
@@ -3944,53 +4541,129 @@ f_has(typval_T *argvars, typval_T *rettv)
 # endif
        }
 #endif
-#ifdef DYNAMIC_PERL
-       else if (STRICMP(name, "perl") == 0)
-           n = perl_enabled(FALSE);
+#ifdef DYNAMIC_RUBY
+       else if (STRICMP(name, "ruby") == 0)
+           n = ruby_enabled(FALSE);
 #endif
-#ifdef FEAT_GUI
+#ifdef DYNAMIC_TCL
+       else if (STRICMP(name, "tcl") == 0)
+           n = tcl_enabled(FALSE);
+#endif
+#if defined(FEAT_TERMINAL) && defined(MSWIN)
+       else if (STRICMP(name, "terminal") == 0)
+           n = terminal_enabled();
+#endif
+    }
+
+    // features not in has_list[]
+    if (x == FALSE)
+    {
+       if (STRNICMP(name, "patch", 5) == 0)
+       {
+           x = TRUE;
+           if (name[5] == '-'
+                   && STRLEN(name) >= 11
+                   && vim_isdigit(name[6])
+                   && vim_isdigit(name[8])
+                   && vim_isdigit(name[10]))
+           {
+               int major = atoi((char *)name + 6);
+               int minor = atoi((char *)name + 8);
+
+               // Expect "patch-9.9.01234".
+               n = (major < VIM_VERSION_MAJOR
+                    || (major == VIM_VERSION_MAJOR
+                        && (minor < VIM_VERSION_MINOR
+                            || (minor == VIM_VERSION_MINOR
+                                && has_patch(atoi((char *)name + 10))))));
+           }
+           else
+               n = has_patch(atoi((char *)name + 5));
+       }
+       else if (STRICMP(name, "vim_starting") == 0)
+       {
+           x = TRUE;
+           n = (starting != 0);
+       }
+       else if (STRICMP(name, "ttyin") == 0)
+       {
+           x = TRUE;
+           n = mch_input_isatty();
+       }
+       else if (STRICMP(name, "ttyout") == 0)
+       {
+           x = TRUE;
+           n = stdout_isatty;
+       }
+       else if (STRICMP(name, "multi_byte_encoding") == 0)
+       {
+           x = TRUE;
+           n = has_mbyte;
+       }
        else if (STRICMP(name, "gui_running") == 0)
+       {
+           x = TRUE;
+#ifdef FEAT_GUI
            n = (gui.in_use || gui.starting);
-# ifdef FEAT_BROWSE
+#endif
+       }
        else if (STRICMP(name, "browse") == 0)
+       {
+           x = TRUE;
+#if defined(FEAT_GUI) && defined(FEAT_BROWSE)
            n = gui.in_use;     // gui_mch_browse() works when GUI is running
-# endif
 #endif
-#ifdef FEAT_SYN_HL
+       }
        else if (STRICMP(name, "syntax_items") == 0)
+       {
+           x = TRUE;
+#ifdef FEAT_SYN_HL
            n = syntax_present(curwin);
 #endif
-#ifdef FEAT_VTP
+       }
        else if (STRICMP(name, "vcon") == 0)
+       {
+           x = TRUE;
+#ifdef FEAT_VTP
            n = is_term_win32() && has_vtp_working();
 #endif
-#ifdef FEAT_NETBEANS_INTG
+       }
        else if (STRICMP(name, "netbeans_enabled") == 0)
+       {
+           x = TRUE;
+#ifdef FEAT_NETBEANS_INTG
            n = netbeans_active();
 #endif
-#ifdef FEAT_MOUSE_GPM
+       }
        else if (STRICMP(name, "mouse_gpm_enabled") == 0)
+       {
+           x = TRUE;
+#ifdef FEAT_MOUSE_GPM
            n = gpm_enabled();
 #endif
-#if defined(FEAT_TERMINAL) && defined(MSWIN)
-       else if (STRICMP(name, "terminal") == 0)
-           n = terminal_enabled();
-#endif
-#if defined(FEAT_TERMINAL) && defined(MSWIN)
+       }
        else if (STRICMP(name, "conpty") == 0)
+       {
+           x = TRUE;
+#if defined(FEAT_TERMINAL) && defined(MSWIN)
            n = use_conpty();
 #endif
-#ifdef FEAT_CLIPBOARD
+       }
        else if (STRICMP(name, "clipboard_working") == 0)
+       {
+           x = TRUE;
+#ifdef FEAT_CLIPBOARD
            n = clip_star.available;
 #endif
-#ifdef VIMDLL
-       else if (STRICMP(name, "filterpipe") == 0)
-           n = gui.in_use || gui.starting;
-#endif
+       }
     }
 
-    rettv->vval.v_number = n;
+    if (argvars[1].v_type != VAR_UNKNOWN && tv_get_number(&argvars[1]) != 0)
+       // return whether feature could ever be enabled
+       rettv->vval.v_number = x;
+    else
+       // return whether feature is enabled
+       rettv->vval.v_number = n;
 }
 
 /*
index 687610195b758a30392eda9b690a271f4cbb93c5..0bbe7caf94ea1dfc7d820850687e0ec8d8178dca 100644 (file)
@@ -6,6 +6,9 @@ command -nargs=1 MissingFeature throw 'Skipped: ' .. <args> .. ' feature missing
 " Command to check for the presence of a feature.
 command -nargs=1 CheckFeature call CheckFeature(<f-args>)
 func CheckFeature(name)
+  if !has(a:name, 1)
+    throw 'Checking for non-existent feature ' .. a:name
+  endif
   if !has(a:name)
     MissingFeature a:name
   endif
index f904cc056089e33db30a0ae38e27a7cf94cc000c..96d7f31f475514318aedd56413140af4c880cccc 100644 (file)
@@ -20,6 +20,14 @@ func Test_00_bufexists()
   call assert_equal(0, bufexists('Xfoo'))
 endfunc
 
+func Test_has()
+  call assert_equal(1, has('eval'))
+  call assert_equal(1, has('eval', 1))
+
+  call assert_equal(0, has('nonexistent'))
+  call assert_equal(0, has('nonexistent', 1))
+endfunc
+
 func Test_empty()
   call assert_equal(1, empty(''))
   call assert_equal(0, empty('a'))
@@ -1586,7 +1594,7 @@ func Test_confirm()
   call assert_equal(2, a)
 
   " confirm() should return 0 when pressing CTRL-C.
-  call feedkeys("\<C-c>", 'L')
+  call feedkeys("\<C-C>", 'L')
   let a = confirm('Are you sure?', "&Yes\n&No")
   call assert_equal(0, a)
 
index 8ef76dac4d5b33dbf2af065621d72901778be022..b9542437a9b59c9cf55ecbbcb96c4e43ba7168e4 100644 (file)
@@ -738,6 +738,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    427,
 /**/
     426,
 /**/