@@ -7760,214 +7760,217 @@ f_has(typval_T *argvars, typval_T *rettv)
77607760 return ;
77617761
77627762 name = tv_get_string (& argvars [0 ]);
7763- for (i = 0 ; has_list [i ].name != NULL ; ++ i )
7764- if (STRICMP (name , has_list [i ].name ) == 0 )
7763+
7764+ // Fast-path: check features not in has_list[] first to avoid the full
7765+ // linear scan for very common queries like has('patch-...').
7766+ if (STRNICMP (name , "patch" , 5 ) == 0 )
7767+ {
7768+ x = TRUE;
7769+ if (name [5 ] == '-'
7770+ && STRLEN (name ) >= 11
7771+ && (name [6 ] >= '1' && name [6 ] <= '9' ))
77657772 {
7766- x = TRUE;
7767- n = has_list [i ].present ;
7768- break ;
7773+ char * end ;
7774+ int major , minor ;
7775+
7776+ // This works for patch-8.1.2, patch-9.0.3, patch-10.0.4, etc.
7777+ // Not for patch-9.10.5.
7778+ major = (int )strtoul ((char * )name + 6 , & end , 10 );
7779+ if (* end == '.' && vim_isdigit (end [1 ])
7780+ && end [2 ] == '.' && vim_isdigit (end [3 ]))
7781+ {
7782+ minor = atoi (end + 1 );
7783+
7784+ // Expect "patch-9.9.01234".
7785+ n = (major < VIM_VERSION_MAJOR
7786+ || (major == VIM_VERSION_MAJOR
7787+ && (minor < VIM_VERSION_MINOR
7788+ || (minor == VIM_VERSION_MINOR
7789+ && has_patch (atoi (end + 3 ))))));
7790+ }
77697791 }
7792+ else if (SAFE_isdigit (name [5 ]))
7793+ n = has_patch (atoi ((char * )name + 5 ));
7794+ }
7795+ else if (STRICMP (name , "vim_starting" ) == 0 )
7796+ {
7797+ x = TRUE;
7798+ n = (starting != 0 );
7799+ }
7800+ else if (STRICMP (name , "ttyin" ) == 0 )
7801+ {
7802+ x = TRUE;
7803+ n = mch_input_isatty ();
7804+ }
7805+ else if (STRICMP (name , "ttyout" ) == 0 )
7806+ {
7807+ x = TRUE;
7808+ n = stdout_isatty ;
7809+ }
7810+ else if (STRICMP (name , "multi_byte_encoding" ) == 0 )
7811+ {
7812+ x = TRUE;
7813+ n = has_mbyte ;
7814+ }
7815+ else if (STRICMP (name , "gui_running" ) == 0 )
7816+ {
7817+ x = TRUE;
7818+ #ifdef FEAT_GUI
7819+ n = (gui .in_use || gui .starting );
7820+ #endif
7821+ }
7822+ else if (STRICMP (name , "browse" ) == 0 )
7823+ {
7824+ x = TRUE;
7825+ #if defined(FEAT_GUI ) && defined(FEAT_BROWSE )
7826+ n = gui .in_use ; // gui_mch_browse() works when GUI is running
7827+ #endif
7828+ }
7829+ else if (STRICMP (name , "syntax_items" ) == 0 )
7830+ {
7831+ x = TRUE;
7832+ #ifdef FEAT_SYN_HL
7833+ n = syntax_present (curwin );
7834+ #endif
7835+ }
7836+ else if (STRICMP (name , "vcon" ) == 0 )
7837+ {
7838+ x = TRUE;
7839+ #ifdef FEAT_VTP
7840+ n = is_term_win32 () && has_vtp_working ();
7841+ #endif
7842+ }
7843+ else if (STRICMP (name , "netbeans_enabled" ) == 0 )
7844+ {
7845+ x = TRUE;
7846+ #ifdef FEAT_NETBEANS_INTG
7847+ n = netbeans_active ();
7848+ #endif
7849+ }
7850+ else if (STRICMP (name , "mouse_gpm_enabled" ) == 0 )
7851+ {
7852+ x = TRUE;
7853+ #ifdef FEAT_MOUSE_GPM
7854+ n = gpm_enabled ();
7855+ #endif
7856+ }
7857+ else if (STRICMP (name , "conpty" ) == 0 )
7858+ {
7859+ x = TRUE;
7860+ #if defined(FEAT_TERMINAL ) && defined(MSWIN )
7861+ n = use_conpty ();
7862+ #endif
7863+ }
7864+ else if (STRICMP (name , "clipboard_working" ) == 0 )
7865+ {
7866+ x = TRUE;
7867+ #ifdef FEAT_CLIPBOARD
7868+ n = clipmethod == CLIPMETHOD_PROVIDER ? TRUE : clip_star .available ;
7869+ #endif
7870+ }
7871+ else if (STRICMP (name , "unnamedplus" ) == 0 )
7872+ {
7873+ x = TRUE;
7874+ #ifdef FEAT_CLIPBOARD
7875+ // The + register is available when clipmethod is set to a provider,
7876+ // but becomes unavailable if on a platform that doesn't support it
7877+ // and clipmethod is "none".
7878+ // (Windows, MacOS).
7879+ # if defined(FEAT_X11 ) || defined(FEAT_WAYLAND_CLIPBOARD )
7880+ n = TRUE;
7881+ # elif defined(FEAT_EVAL )
7882+ if (clipmethod == CLIPMETHOD_PROVIDER )
7883+ n = TRUE;
7884+ else
7885+ n = FALSE;
7886+ # else
7887+ n = FALSE;
7888+ # endif
7889+ #endif
7890+ }
77707891
7771- // features also in has_list[] but sometimes enabled at runtime
7772- if (x == TRUE && n == FALSE)
7892+ // Look up in has_list[] only if not already handled above.
7893+ if (x == FALSE)
77737894 {
7774- if (0 )
7895+ for (i = 0 ; has_list [i ].name != NULL ; ++ i )
7896+ if (STRICMP (name , has_list [i ].name ) == 0 )
7897+ {
7898+ x = TRUE;
7899+ n = has_list [i ].present ;
7900+ break ;
7901+ }
7902+
7903+ // features also in has_list[] but sometimes enabled at runtime
7904+ if (x == TRUE && n == FALSE)
77757905 {
7776- // intentionally empty
7777- }
7906+ if (0 )
7907+ {
7908+ // intentionally empty
7909+ }
77787910#ifdef VIMDLL
7779- else if (STRICMP (name , "filterpipe ") == 0 )
7780- n = gui .in_use || gui .starting ;
7911+ else if (STRICMP (name , "filterpipe ") == 0 )
7912+ n = gui .in_use || gui .starting ;
77817913#endif
77827914#if defined(USE_ICONV ) && defined(DYNAMIC_ICONV )
7783- else if (STRICMP (name , "iconv ") == 0 )
7784- n = iconv_enabled (FALSE);
7915+ else if (STRICMP (name , "iconv ") == 0 )
7916+ n = iconv_enabled (FALSE);
77857917#endif
77867918#ifdef DYNAMIC_LUA
7787- else if (STRICMP (name , "lua ") == 0 )
7788- n = lua_enabled (FALSE);
7919+ else if (STRICMP (name , "lua ") == 0 )
7920+ n = lua_enabled (FALSE);
77897921#endif
77907922#ifdef DYNAMIC_MZSCHEME
7791- else if (STRICMP (name , "mzscheme ") == 0 )
7792- n = mzscheme_enabled (FALSE);
7923+ else if (STRICMP (name , "mzscheme ") == 0 )
7924+ n = mzscheme_enabled (FALSE);
77937925#endif
77947926#ifdef DYNAMIC_PERL
7795- else if (STRICMP (name , "perl ") == 0 )
7796- n = perl_enabled (FALSE);
7927+ else if (STRICMP (name , "perl ") == 0 )
7928+ n = perl_enabled (FALSE);
77977929#endif
77987930#ifdef DYNAMIC_PYTHON
7799- else if (STRICMP (name , "python ") == 0 )
7800- n = python_enabled (FALSE);
7931+ else if (STRICMP (name , "python ") == 0 )
7932+ n = python_enabled (FALSE);
78017933#endif
78027934#ifdef DYNAMIC_PYTHON3
7803- else if (STRICMP (name , "python3 ") == 0 )
7804- n = python3_enabled (FALSE);
7935+ else if (STRICMP (name , "python3 ") == 0 )
7936+ n = python3_enabled (FALSE);
78057937#endif
78067938#if defined(DYNAMIC_PYTHON ) || defined(DYNAMIC_PYTHON3 )
7807- else if (STRICMP (name , "pythonx ") == 0 )
7808- {
7939+ else if (STRICMP (name , "pythonx ") == 0 )
7940+ {
78097941# if defined(DYNAMIC_PYTHON ) && defined(DYNAMIC_PYTHON3 )
7810- if (p_pyx == 0 )
7811- n = python3_enabled (FALSE) || python_enabled (FALSE);
7812- else if (p_pyx == 3 )
7813- n = python3_enabled (FALSE);
7814- else if (p_pyx == 2 )
7815- n = python_enabled (FALSE);
7942+ if (p_pyx == 0 )
7943+ n = python3_enabled (FALSE) || python_enabled (FALSE);
7944+ else if (p_pyx == 3 )
7945+ n = python3_enabled (FALSE);
7946+ else if (p_pyx == 2 )
7947+ n = python_enabled (FALSE);
78167948# elif defined(DYNAMIC_PYTHON )
7817- n = python_enabled (FALSE);
7949+ n = python_enabled (FALSE);
78187950# elif defined(DYNAMIC_PYTHON3 )
7819- n = python3_enabled (FALSE);
7951+ n = python3_enabled (FALSE);
78207952# endif
7821- }
7953+ }
78227954#endif
78237955#ifdef DYNAMIC_RUBY
7824- else if (STRICMP (name , "ruby ") == 0 )
7825- n = ruby_enabled (FALSE);
7956+ else if (STRICMP (name , "ruby ") == 0 )
7957+ n = ruby_enabled (FALSE);
78267958#endif
78277959#ifdef DYNAMIC_TCL
7828- else if (STRICMP (name , "tcl ") == 0 )
7829- n = tcl_enabled (FALSE);
7960+ else if (STRICMP (name , "tcl ") == 0 )
7961+ n = tcl_enabled (FALSE);
78307962#endif
78317963#ifdef DYNAMIC_SODIUM
7832- else if (STRICMP (name , "sodium ") == 0 )
7833- n = sodium_enabled (FALSE);
7964+ else if (STRICMP (name , "sodium ") == 0 )
7965+ n = sodium_enabled (FALSE);
78347966#endif
78357967#if defined(FEAT_TERMINAL ) && defined(MSWIN )
7836- else if (STRICMP (name , "terminal ") == 0 )
7837- n = terminal_enabled ();
7968+ else if (STRICMP (name , "terminal ") == 0 )
7969+ n = terminal_enabled ();
78387970#endif
78397971#ifdef DYNAMIC_GPM
7840- else if (STRICMP (name , "mouse_gpm ") == 0 )
7841- n = gpm_available ();
7842- #endif
7843- }
7844-
7845- // features not in has_list[]
7846- if (x == FALSE)
7847- {
7848- if (STRNICMP (name , "patch" , 5 ) == 0 )
7849- {
7850- x = TRUE;
7851- if (name [5 ] == '-'
7852- && STRLEN (name ) >= 11
7853- && (name [6 ] >= '1' && name [6 ] <= '9' ))
7854- {
7855- char * end ;
7856- int major , minor ;
7857-
7858- // This works for patch-8.1.2, patch-9.0.3, patch-10.0.4, etc.
7859- // Not for patch-9.10.5.
7860- major = (int )strtoul ((char * )name + 6 , & end , 10 );
7861- if (* end == '.' && vim_isdigit (end [1 ])
7862- && end [2 ] == '.' && vim_isdigit (end [3 ]))
7863- {
7864- minor = atoi (end + 1 );
7865-
7866- // Expect "patch-9.9.01234".
7867- n = (major < VIM_VERSION_MAJOR
7868- || (major == VIM_VERSION_MAJOR
7869- && (minor < VIM_VERSION_MINOR
7870- || (minor == VIM_VERSION_MINOR
7871- && has_patch (atoi (end + 3 ))))));
7872- }
7873- }
7874- else if (SAFE_isdigit (name [5 ]))
7875- n = has_patch (atoi ((char * )name + 5 ));
7876- }
7877- else if (STRICMP (name , "vim_starting" ) == 0 )
7878- {
7879- x = TRUE;
7880- n = (starting != 0 );
7881- }
7882- else if (STRICMP (name , "ttyin" ) == 0 )
7883- {
7884- x = TRUE;
7885- n = mch_input_isatty ();
7886- }
7887- else if (STRICMP (name , "ttyout" ) == 0 )
7888- {
7889- x = TRUE;
7890- n = stdout_isatty ;
7891- }
7892- else if (STRICMP (name , "multi_byte_encoding" ) == 0 )
7893- {
7894- x = TRUE;
7895- n = has_mbyte ;
7896- }
7897- else if (STRICMP (name , "gui_running" ) == 0 )
7898- {
7899- x = TRUE;
7900- #ifdef FEAT_GUI
7901- n = (gui .in_use || gui .starting );
7902- #endif
7903- }
7904- else if (STRICMP (name , "browse" ) == 0 )
7905- {
7906- x = TRUE;
7907- #if defined(FEAT_GUI ) && defined(FEAT_BROWSE )
7908- n = gui .in_use ; // gui_mch_browse() works when GUI is running
7909- #endif
7910- }
7911- else if (STRICMP (name , "syntax_items" ) == 0 )
7912- {
7913- x = TRUE;
7914- #ifdef FEAT_SYN_HL
7915- n = syntax_present (curwin );
7916- #endif
7917- }
7918- else if (STRICMP (name , "vcon" ) == 0 )
7919- {
7920- x = TRUE;
7921- #ifdef FEAT_VTP
7922- n = is_term_win32 () && has_vtp_working ();
7923- #endif
7924- }
7925- else if (STRICMP (name , "netbeans_enabled" ) == 0 )
7926- {
7927- x = TRUE;
7928- #ifdef FEAT_NETBEANS_INTG
7929- n = netbeans_active ();
7930- #endif
7931- }
7932- else if (STRICMP (name , "mouse_gpm_enabled" ) == 0 )
7933- {
7934- x = TRUE;
7935- #ifdef FEAT_MOUSE_GPM
7936- n = gpm_enabled ();
7937- #endif
7938- }
7939- else if (STRICMP (name , "conpty" ) == 0 )
7940- {
7941- x = TRUE;
7942- #if defined(FEAT_TERMINAL ) && defined(MSWIN )
7943- n = use_conpty ();
7944- #endif
7945- }
7946- else if (STRICMP (name , "clipboard_working" ) == 0 )
7947- {
7948- x = TRUE;
7949- #ifdef FEAT_CLIPBOARD
7950- n = clipmethod == CLIPMETHOD_PROVIDER ? TRUE : clip_star .available ;
7951- #endif
7952- }
7953- else if (STRICMP (name , "unnamedplus" ) == 0 )
7954- {
7955- x = TRUE;
7956- #ifdef FEAT_CLIPBOARD
7957- // The + register is available when clipmethod is set to a provider,
7958- // but becomes unavailable if on a platform that doesn't support it
7959- // and clipmethod is "none".
7960- // (Windows, MacOS).
7961- # if defined(FEAT_X11 ) || defined(FEAT_WAYLAND_CLIPBOARD )
7962- n = TRUE;
7963- # elif defined(FEAT_EVAL )
7964- if (clipmethod == CLIPMETHOD_PROVIDER )
7965- n = TRUE;
7966- else
7967- n = FALSE;
7968- # else
7969- n = FALSE;
7970- # endif
7972+ else if (STRICMP (name , "mouse_gpm ") == 0 )
7973+ n = gpm_available ();
79717974#endif
79727975 }
79737976 }
0 commit comments