Compare commits

...

6 Commits

Author SHA1 Message Date
Bram Moolenaar
e7a74d5375 patch 8.2.4591: cursor line not updated when a callback moves the cursor
Problem:    Cursor line not updated when a callback moves the cursor.
Solution:   Check if the cursor moved. (closes #9970)
2022-03-19 11:10:15 +00:00
Bram Moolenaar
2995e5cf4e patch 8.2.4590: Vim9: range type check has wrong offset
Problem:    Vim9: range type check has wrong offset.
Solution:   Adjust offset for CHECKTYPE.  Remove other type check.
2022-03-18 21:41:47 +00:00
Bram Moolenaar
2e17fef225 patch 8.2.4589: cannot index the g: dictionary
Problem:    Cannot index the g: dictionary.
Solution:   Recognize using "g:[key]". (closes #9969)
2022-03-18 19:44:48 +00:00
Bram Moolenaar
f35fd8e5d4 patch 8.2.4588: mapping with key after other matching mapping does not work
Problem:    Mapping with key code after other matching mapping does not work.
Solution:   Change ">" to ">=". (closes #9903)
2022-03-18 15:41:17 +00:00
Bram Moolenaar
61efa16932 patch 8.2.4587: Vim9: double free after unpacking a list
Problem:    Vim9: double free after unpacking a list.
Solution:   Make a copy of the value instead of moving it. (closes #9968)
2022-03-18 13:10:48 +00:00
Bram Moolenaar
1d9cef769d patch 8.2.4586: Vim9: no error for using lower case name for "func" argument
Problem:    Vim9: no error for using lower case name for "func" argument.
            (Ernie Rael)
Solution:   Check the name as soon as the type is known.
2022-03-17 16:30:03 +00:00
16 changed files with 182 additions and 88 deletions

View File

@@ -1463,11 +1463,14 @@ win_update(win_T *wp)
#ifdef FEAT_SYN_HL
// remember what happened to the previous line, to know if
// check_visual_highlight() can be used
#define DID_NONE 1 // didn't update a line
#define DID_LINE 2 // updated a normal line
#define DID_FOLD 3 // updated a folded line
# define DID_NONE 1 // didn't update a line
# define DID_LINE 2 // updated a normal line
# define DID_FOLD 3 // updated a folded line
int did_update = DID_NONE;
linenr_T syntax_last_parsed = 0; // last parsed text line
// remember the current w_last_cursorline, it changes when drawing the new
// cursor line
linenr_T last_cursorline = wp->w_last_cursorline;
#endif
linenr_T mod_top = 0;
linenr_T mod_bot = 0;
@@ -2244,7 +2247,7 @@ win_update(win_T *wp)
))))
#ifdef FEAT_SYN_HL
|| (wp->w_p_cul && (lnum == wp->w_cursor.lnum
|| lnum == wp->w_last_cursorline))
|| lnum == last_cursorline))
#endif
)
{
@@ -3027,6 +3030,23 @@ redraw_asap(int type)
}
#endif
#if defined(FEAT_SYN_HL) || defined(PROTO)
/*
* Check if the cursor moved and 'cursorline' is set. Mark for a VALID redraw
* if needed.
*/
void
check_redraw_cursorline(void)
{
// When 'cursorlineopt' is "screenline" need to redraw always.
if (curwin->w_p_cul
&& (curwin->w_last_cursorline != curwin->w_cursor.lnum
|| (curwin->w_p_culopt_flags & CULOPT_SCRLINE))
&& !char_avail())
redraw_later(VALID);
}
#endif
/*
* Invoked after an asynchronous callback is called.
* If an echo command was used the cursor needs to be put back where
@@ -3071,6 +3091,10 @@ redraw_after_callback(int call_update_screen, int do_message)
}
else if (State & (NORMAL | INSERT | TERMINAL))
{
#ifdef FEAT_SYN_HL
// might need to update for 'cursorline'
check_redraw_cursorline();
#endif
// keep the command line if possible
update_screen(VALID_NO_UPDATE);
setcursor();

View File

@@ -929,7 +929,8 @@ get_lval(
if (vim9script)
{
// "a: type" is declaring variable "a" with a type, not "a:".
if (p == name + 2 && p[-1] == ':')
// However, "g:[key]" is indexing a dictionary.
if (p == name + 2 && p[-1] == ':' && *p != '[')
{
--p;
lp->ll_name_end = p;

View File

@@ -3523,12 +3523,14 @@ find_ex_command(
return eap->cmd;
}
if (p != eap->cmd && (
if ((p != eap->cmd && (
// "varname[]" is an expression.
*p == '['
// "varname.key" is an expression.
|| (*p == '.' && (ASCII_ISALPHA(p[1])
|| p[1] == '_'))))
|| (*p == '.'
&& (ASCII_ISALPHA(p[1]) || p[1] == '_'))))
// g:[key] is an expression
|| STRNCMP(eap->cmd, "g:[", 3) == 0)
{
char_u *after = eap->cmd;

View File

@@ -2416,6 +2416,7 @@ handle_mapping(
mapblock_T *mp_match;
int mp_match_len = 0;
int max_mlen = 0;
int want_termcode = 0; // 1 if termcode expected after max_mlen
int tb_c1;
int mlen;
#ifdef FEAT_LANGMAP
@@ -2591,9 +2592,16 @@ handle_mapping(
}
else
// No match; may have to check for termcode at next
// character.
// character. If the first character that didn't match is
// K_SPECIAL then check for a termcode. This isn't perfect
// but should work in most cases.
if (max_mlen < mlen)
{
max_mlen = mlen;
want_termcode = mp->m_keys[mlen] == K_SPECIAL;
}
else if (max_mlen == mlen && mp->m_keys[mlen] == K_SPECIAL)
want_termcode = 1;
}
}
@@ -2646,7 +2654,7 @@ handle_mapping(
// May check for a terminal code when there is no mapping or only a partial
// mapping. Also check if there is a full mapping with <Esc>, unless timed
// out, since that is nearly always a partial match with a terminal code.
if ((mp == NULL || max_mlen > mp_match_len
if ((mp == NULL || max_mlen + want_termcode > mp_match_len
|| (mp_match_len == 1 && *mp->m_keys == ESC && !*timedout))
&& keylen != KEYLEN_PART_MAP)
{

View File

@@ -1386,12 +1386,7 @@ main_loop(
#ifdef FEAT_SYN_HL
// Might need to update for 'cursorline'.
// When 'cursorlineopt' is "screenline" need to redraw always.
if (curwin->w_p_cul
&& (curwin->w_last_cursorline != curwin->w_cursor.lnum
|| (curwin->w_p_culopt_flags & CULOPT_SCRLINE))
&& !char_avail())
redraw_later(VALID);
check_redraw_cursorline();
#endif
if (VIsual_active)
update_curbuf(INVERTED); // update inverted part

View File

@@ -8,6 +8,7 @@ void update_curbuf(int type);
void update_debug_sign(buf_T *buf, linenr_T lnum);
void updateWindow(win_T *wp);
int redraw_asap(int type);
void check_redraw_cursorline(void);
void redraw_after_callback(int call_update_screen, int do_message);
void redraw_later(int type);
void redraw_win_later(win_T *wp, int type);

View File

@@ -0,0 +1,8 @@
|a+0&#ffffff0@4| @69
>b+8&&@4| @69
|c+0&&@4| @69
|d@4| @69
|~+0#4040ff13&| @73
|~| @73
|~| @73
| +0#0000000&@56|4|,|1| @10|A|l@1|

View File

@@ -247,4 +247,30 @@ END
call delete('Xtextfile')
endfunc
func Test_cursorline_callback()
CheckScreendump
CheckFeature timers
let lines =<< trim END
call setline(1, ['aaaaa', 'bbbbb', 'ccccc', 'ddddd'])
set cursorline
call cursor(4, 1)
func Func(timer)
call cursor(2, 1)
endfunc
call timer_start(300, 'Func')
END
call writefile(lines, 'Xcul_timer')
let buf = RunVimInTerminal('-S Xcul_timer', #{rows: 8})
call TermWait(buf, 310)
call VerifyScreenDump(buf, 'Test_cursorline_callback_1', {})
call StopVimInTerminal(buf)
call delete('Xcul_timer')
endfunc
" vim: shiftwidth=2 sts=2 expandtab

View File

@@ -2111,6 +2111,15 @@ func Test_modifyOtherKeys_ambiguous_mapping()
unmap <C-J>
unmap <C-J>x
" if a special character is following there should be a check for a termcode
nnoremap s aX<Esc>
nnoremap s<BS> aY<Esc>
set t_kb=
call setline(1, 'x')
call feedkeys("s\x08", 'Lx!')
call assert_equal('xY', getline(1))
set timeoutlen&
bwipe!
endfunc

View File

@@ -1116,6 +1116,14 @@ def Test_assignment_dict()
END
v9.CheckDefAndScriptSuccess(lines)
lines =<< trim END
var key = 'foo'
g:[key] = 'value'
assert_equal('value', g:foo)
unlet g:foo
END
v9.CheckDefAndScriptSuccess(lines)
lines =<< trim END
var dd = {one: 1}
dd.one) = 2
@@ -1594,7 +1602,7 @@ def Test_assign_list()
l[g:idx : 1] = [0]
echo l
END
v9.CheckDefExecAndScriptFailure(lines, 'E1030: Using a String as a Number: "x"')
v9.CheckDefExecAndScriptFailure(lines, ['E1012: Type mismatch; expected number but got string', 'E1030: Using a String as a Number: "x"'])
lines =<< trim END
var l = [1, 2]

View File

@@ -1479,12 +1479,12 @@ def Test_pass_legacy_lambda_to_def_func()
lines =<< trim END
vim9script
def g:TestFunc(f: func)
def g:TestFunc(F: func)
enddef
legacy call g:TestFunc({-> 0})
delfunc g:TestFunc
def g:TestFunc(f: func(number))
def g:TestFunc(F: func(number))
enddef
legacy call g:TestFunc({nr -> 0})
delfunc g:TestFunc
@@ -3788,8 +3788,8 @@ def Test_check_func_arg_types()
return x + 1
enddef
def G(g: func): dict<func>
return {f: g}
def G(Fg: func): dict<func>
return {f: Fg}
enddef
def H(d: dict<func>): string
@@ -3799,6 +3799,8 @@ def Test_check_func_arg_types()
v9.CheckScriptSuccess(lines + ['echo H(G(F1))'])
v9.CheckScriptFailure(lines + ['echo H(G(F2))'], 'E1013:')
v9.CheckScriptFailure(lines + ['def SomeFunc(ff: func)', 'enddef'], 'E704:')
enddef
def Test_call_func_with_null()

View File

@@ -2253,6 +2253,13 @@ def Test_for_loop_unpack()
res->add(n)
endfor
assert_equal([2, 5], res)
var text: list<string> = ["hello there", "goodbye now"]
var splitted = ''
for [first; next] in mapnew(text, (i, v) => split(v))
splitted ..= string(first) .. string(next) .. '/'
endfor
assert_equal("'hello'['there']/'goodbye'['now']/", splitted)
END
v9.CheckDefAndScriptSuccess(lines)

View File

@@ -429,6 +429,12 @@ parse_argument_types(ufunc_T *fp, garray_T *argtypes, int varargs)
if (type == NULL)
return FAIL;
fp->uf_arg_types[i] = type;
if (i < fp->uf_args.ga_len
&& (type->tt_type == VAR_FUNC
|| type->tt_type == VAR_PARTIAL)
&& var_wrong_func_name(
((char_u **)fp->uf_args.ga_data)[i], TRUE))
return FAIL;
}
}
}

View File

@@ -750,6 +750,18 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
4591,
/**/
4590,
/**/
4589,
/**/
4588,
/**/
4587,
/**/
4586,
/**/
4585,
/**/

View File

@@ -1000,7 +1000,12 @@ generate_loadvar(
break;
case dest_global:
if (vim_strchr(name, AUTOLOAD_CHAR) == NULL)
generate_LOAD(cctx, ISN_LOADG, 0, name + 2, type);
{
if (name[2] == NUL)
generate_instr_type(cctx, ISN_LOADGDICT, &t_dict_any);
else
generate_LOAD(cctx, ISN_LOADG, 0, name + 2, type);
}
else
generate_LOAD(cctx, ISN_LOADAUTO, 0, name, type);
break;
@@ -1797,7 +1802,7 @@ compile_assign_unlet(
{
type = get_type_on_stack(cctx, 1);
if (need_type(type, &t_number,
-1, 0, cctx, FALSE, FALSE) == FAIL)
-2, 0, cctx, FALSE, FALSE) == FAIL)
return FAIL;
}
type = get_type_on_stack(cctx, 0);
@@ -2413,17 +2418,19 @@ may_compile_assignment(exarg_T *eap, char_u **line, cctx_T *cctx)
// Recognize an assignment if we recognize the variable
// name:
// "g:var = expr"
// "local = expr" where "local" is a local var.
// "script = expr" where "script" is a script-local var.
// "import = expr" where "import" is an imported var
// "&opt = expr"
// "$ENV = expr"
// "@r = expr"
// "g:var = expr"
// "g:[key] = expr"
// "local = expr" where "local" is a local var.
// "script = expr" where "script" is a script-local var.
// "import = expr" where "import" is an imported var
if (*eap->cmd == '&'
|| *eap->cmd == '$'
|| *eap->cmd == '@'
|| ((len) > 2 && eap->cmd[1] == ':')
|| STRNCMP(eap->cmd, "g:[", 3) == 0
|| variable_exists(eap->cmd, len, cctx))
{
*line = compile_assignment(eap->cmd, eap, CMD_SIZE, cctx);

View File

@@ -1896,79 +1896,54 @@ execute_storerange(isn_T *iptr, ectx_T *ectx)
SOURCING_LNUM = iptr->isn_lnum;
if (tv_dest->v_type == VAR_LIST)
{
long n1;
long n2;
int error = FALSE;
long n1;
long n2;
listitem_T *li1;
n1 = (long)tv_get_number_chk(tv_idx1, &error);
if (error)
n1 = (long)tv_get_number_chk(tv_idx1, NULL);
if (tv_idx2->v_type == VAR_SPECIAL
&& tv_idx2->vval.v_number == VVAL_NONE)
n2 = list_len(tv_dest->vval.v_list) - 1;
else
n2 = (long)tv_get_number_chk(tv_idx2, NULL);
li1 = check_range_index_one(tv_dest->vval.v_list, &n1, FALSE);
if (li1 == NULL)
status = FAIL;
else
{
if (tv_idx2->v_type == VAR_SPECIAL
&& tv_idx2->vval.v_number == VVAL_NONE)
n2 = list_len(tv_dest->vval.v_list) - 1;
else
n2 = (long)tv_get_number_chk(tv_idx2, &error);
if (error)
status = FAIL; // cannot happen?
else
{
listitem_T *li1 = check_range_index_one(
tv_dest->vval.v_list, &n1, FALSE);
if (li1 == NULL)
status = FAIL;
else
{
status = check_range_index_two(
tv_dest->vval.v_list,
&n1, li1, &n2, FALSE);
if (status != FAIL)
status = list_assign_range(
tv_dest->vval.v_list,
tv->vval.v_list,
n1,
n2,
tv_idx2->v_type == VAR_SPECIAL,
(char_u *)"=",
(char_u *)"[unknown]");
}
}
status = check_range_index_two(tv_dest->vval.v_list,
&n1, li1, &n2, FALSE);
if (status != FAIL)
status = list_assign_range(
tv_dest->vval.v_list,
tv->vval.v_list,
n1,
n2,
tv_idx2->v_type == VAR_SPECIAL,
(char_u *)"=",
(char_u *)"[unknown]");
}
}
else if (tv_dest->v_type == VAR_BLOB)
{
varnumber_T n1;
varnumber_T n2;
int error = FALSE;
long bloblen;
n1 = tv_get_number_chk(tv_idx1, &error);
if (error)
n1 = tv_get_number_chk(tv_idx1, NULL);
if (tv_idx2->v_type == VAR_SPECIAL
&& tv_idx2->vval.v_number == VVAL_NONE)
n2 = blob_len(tv_dest->vval.v_blob) - 1;
else
n2 = tv_get_number_chk(tv_idx2, NULL);
bloblen = blob_len(tv_dest->vval.v_blob);
if (check_blob_index(bloblen, n1, FALSE) == FAIL
|| check_blob_range(bloblen, n1, n2, FALSE) == FAIL)
status = FAIL;
else
{
if (tv_idx2->v_type == VAR_SPECIAL
&& tv_idx2->vval.v_number == VVAL_NONE)
n2 = blob_len(tv_dest->vval.v_blob) - 1;
else
n2 = tv_get_number_chk(tv_idx2, &error);
if (error)
status = FAIL;
else
{
long bloblen = blob_len(tv_dest->vval.v_blob);
if (check_blob_index(bloblen,
n1, FALSE) == FAIL
|| check_blob_range(bloblen,
n1, n2, FALSE) == FAIL)
status = FAIL;
else
status = blob_set_range(
tv_dest->vval.v_blob, n1, n2, tv);
}
}
status = blob_set_range(tv_dest->vval.v_blob, n1, n2, tv);
}
else
{
@@ -4773,7 +4748,10 @@ exec_instructions(ectx_T *ectx)
li = li->li_next;
for (i = 0; li != NULL; ++i)
{
list_set_item(rem_list, i, &li->li_tv);
typval_T tvcopy;
copy_tv(&li->li_tv, &tvcopy);
list_set_item(rem_list, i, &tvcopy);
li = li->li_next;
}
--count;