Skip to content

Commit 8cebd43

Browse files
committed
patch 8.2.1968: Vim9: has() assumes a feature does not change dynamically
Problem: Vim9: has() assumes a feature does not change dynamically. Solution: Check whether a feature may change dynamically. (closes #7265)
1 parent 59d8e56 commit 8cebd43

5 files changed

Lines changed: 141 additions & 1 deletion

File tree

src/evalfunc.c

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5483,6 +5483,73 @@ f_has(typval_T *argvars, typval_T *rettv)
54835483
rettv->vval.v_number = n;
54845484
}
54855485

5486+
/*
5487+
* Return TRUE if "feature" can change later.
5488+
* Also when checking for the feature has side effects, such as loading a DLL.
5489+
*/
5490+
int
5491+
dynamic_feature(char_u *feature)
5492+
{
5493+
return (feature == NULL
5494+
#if defined(FEAT_BEVAL) && defined(FEAT_GUI_MSWIN)
5495+
|| STRICMP(feature, "balloon_multiline") == 0
5496+
#endif
5497+
#if defined(FEAT_GUI) && defined(FEAT_BROWSE)
5498+
|| (STRICMP(feature, "browse") == 0 && !gui.in_use)
5499+
#endif
5500+
#ifdef VIMDLL
5501+
|| STRICMP(feature, "filterpipe") == 0
5502+
#endif
5503+
#if defined(FEAT_GUI) && !defined(ALWAYS_USE_GUI)
5504+
// this can only change on Unix where the ":gui" command could be
5505+
// used.
5506+
|| (STRICMP(feature, "gui_running") == 0 && !gui.in_use)
5507+
#endif
5508+
#if defined(USE_ICONV) && defined(DYNAMIC_ICONV)
5509+
|| STRICMP(feature, "iconv") == 0
5510+
#endif
5511+
#ifdef DYNAMIC_LUA
5512+
|| STRICMP(feature, "lua") == 0
5513+
#endif
5514+
#ifdef FEAT_MOUSE_GPM
5515+
|| (STRICMP(feature, "mouse_gpm_enabled") == 0 && !gpm_enabled())
5516+
#endif
5517+
#ifdef DYNAMIC_MZSCHEME
5518+
|| STRICMP(feature, "mzscheme") == 0
5519+
#endif
5520+
#ifdef FEAT_NETBEANS_INTG
5521+
|| STRICMP(feature, "netbeans_enabled") == 0
5522+
#endif
5523+
#ifdef DYNAMIC_PERL
5524+
|| STRICMP(feature, "perl") == 0
5525+
#endif
5526+
#ifdef DYNAMIC_PYTHON
5527+
|| STRICMP(feature, "python") == 0
5528+
#endif
5529+
#ifdef DYNAMIC_PYTHON3
5530+
|| STRICMP(feature, "python3") == 0
5531+
#endif
5532+
#if defined(DYNAMIC_PYTHON) || defined(DYNAMIC_PYTHON3)
5533+
|| STRICMP(feature, "pythonx") == 0
5534+
#endif
5535+
#ifdef DYNAMIC_RUBY
5536+
|| STRICMP(feature, "ruby") == 0
5537+
#endif
5538+
#ifdef FEAT_SYN_HL
5539+
|| STRICMP(feature, "syntax_items") == 0
5540+
#endif
5541+
#ifdef DYNAMIC_TCL
5542+
|| STRICMP(feature, "tcl") == 0
5543+
#endif
5544+
// once "starting" is zero it will stay that way
5545+
|| (STRICMP(feature, "vim_starting") == 0 && starting != 0)
5546+
|| STRICMP(feature, "multi_byte_encoding") == 0
5547+
#if defined(FEAT_TERMINAL) && defined(MSWIN)
5548+
|| STRICMP(feature, "conpty") == 0
5549+
#endif
5550+
);
5551+
}
5552+
54865553
/*
54875554
* "haslocaldir()" function
54885555
*/

src/proto/evalfunc.pro

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ win_T *get_optional_window(typval_T *argvars, int idx);
1616
void execute_redir_str(char_u *value, int value_len);
1717
void execute_common(typval_T *argvars, typval_T *rettv, int arg_off);
1818
void f_has(typval_T *argvars, typval_T *rettv);
19+
int dynamic_feature(char_u *feature);
1920
void mzscheme_call_vim(char_u *name, typval_T *args, typval_T *rettv);
2021
void range_list_materialize(list_T *list);
2122
float_T vim_round(float_T f);

src/testdir/test_vim9_disassemble.vim

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -629,6 +629,14 @@ def HasSomething()
629629
endif
630630
enddef
631631

632+
def HasGuiRunning()
633+
if has("gui_running")
634+
echo "yes"
635+
else
636+
echo "no"
637+
endif
638+
enddef
639+
632640
def Test_disassemble_const_expr()
633641
assert_equal("\nyes", execute('HasEval()'))
634642
var instr = execute('disassemble HasEval')
@@ -676,6 +684,67 @@ def Test_disassemble_const_expr()
676684
assert_notmatch('PUSHS "something"', instr)
677685
assert_notmatch('PUSHS "less"', instr)
678686
assert_notmatch('JUMP', instr)
687+
688+
var result: string
689+
var instr_expected: string
690+
if has('gui')
691+
if has('gui_running')
692+
# GUI already running, always returns "yes"
693+
result = "\nyes"
694+
instr_expected = 'HasGuiRunning.*' ..
695+
'if has("gui_running")\_s*' ..
696+
' echo "yes"\_s*' ..
697+
'\d PUSHS "yes"\_s*' ..
698+
'\d ECHO 1\_s*' ..
699+
'else\_s*' ..
700+
' echo "no"\_s*' ..
701+
'endif'
702+
else
703+
result = "\nno"
704+
if has('unix')
705+
# GUI not running but can start later, call has()
706+
instr_expected = 'HasGuiRunning.*' ..
707+
'if has("gui_running")\_s*' ..
708+
'\d PUSHS "gui_running"\_s*' ..
709+
'\d BCALL has(argc 1)\_s*' ..
710+
'\d JUMP_IF_FALSE -> \d\_s*' ..
711+
' echo "yes"\_s*' ..
712+
'\d PUSHS "yes"\_s*' ..
713+
'\d ECHO 1\_s*' ..
714+
'else\_s*' ..
715+
'\d JUMP -> \d\_s*' ..
716+
' echo "no"\_s*' ..
717+
'\d PUSHS "no"\_s*' ..
718+
'\d ECHO 1\_s*' ..
719+
'endif'
720+
else
721+
# GUI not running, always return "no"
722+
instr_expected = 'HasGuiRunning.*' ..
723+
'if has("gui_running")\_s*' ..
724+
' echo "yes"\_s*' ..
725+
'else\_s*' ..
726+
' echo "no"\_s*' ..
727+
'\d PUSHS "no"\_s*' ..
728+
'\d ECHO 1\_s*' ..
729+
'endif'
730+
endif
731+
endif
732+
else
733+
# GUI not supported, always return "no"
734+
result = "\nno"
735+
instr_expected = 'HasGuiRunning.*' ..
736+
'if has("gui_running")\_s*' ..
737+
' echo "yes"\_s*' ..
738+
'else\_s*' ..
739+
' echo "no"\_s*' ..
740+
'\d PUSHS "no"\_s*' ..
741+
'\d ECHO 1\_s*' ..
742+
'endif'
743+
endif
744+
745+
assert_equal(result, execute('HasGuiRunning()'))
746+
instr = execute('disassemble HasGuiRunning')
747+
assert_match(instr_expected, instr)
679748
enddef
680749

681750
def ReturnInIf(): string

src/version.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -750,6 +750,8 @@ static char *(features[]) =
750750

751751
static int included_patches[] =
752752
{ /* Add new patch number below this line */
753+
/**/
754+
1968,
753755
/**/
754756
1967,
755757
/**/

src/vim9compile.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2620,7 +2620,8 @@ compile_call(
26202620
else if (*s == '\'')
26212621
(void)eval_lit_string(&s, &argvars[0], TRUE);
26222622
s = skipwhite(s);
2623-
if (*s == ')' && argvars[0].v_type == VAR_STRING)
2623+
if (*s == ')' && argvars[0].v_type == VAR_STRING
2624+
&& !dynamic_feature(argvars[0].vval.v_string))
26242625
{
26252626
typval_T *tv = &ppconst->pp_tv[ppconst->pp_used];
26262627

0 commit comments

Comments
 (0)