diff options
35 files changed, 342 insertions, 145 deletions
diff --git a/runtime/colors/README.txt b/runtime/colors/README.txt index 7e845680a9..4636979ef1 100644 --- a/runtime/colors/README.txt +++ b/runtime/colors/README.txt @@ -42,7 +42,16 @@ this autocmd might be useful: Replace "blue_sky" with the name of the colorscheme. In case you want to tweak a colorscheme after it was loaded, check out the -ColorScheme autocmd event. +ColorScheme autocommand event. + +To clean up just before loading another colorscheme, use the ColorSchemePre +autocommand event. For example: + let g:term_ansi_colors = ... + augroup MyColorscheme + au! + au ColorSchemePre * unlet g:term_ansi_colors + au ColorSchemePre * au! MyColorscheme + augroup END To customize a colorscheme use another name, e.g. "~/.vim/colors/mine.vim", and use `:runtime` to load the original colorscheme: diff --git a/src/nvim/auevents.lua b/src/nvim/auevents.lua index d002aaae43..e6285c5c76 100644 --- a/src/nvim/auevents.lua +++ b/src/nvim/auevents.lua @@ -27,6 +27,7 @@ return { 'CmdWinEnter', -- after entering the cmdline window 'CmdWinLeave', -- before leaving the cmdline window 'ColorScheme', -- after loading a colorscheme + 'ColorSchemePre', -- before loading a colorscheme 'CompleteDone', -- after finishing insert complete 'CursorHold', -- cursor in same position for a while 'CursorHoldI', -- idem, in Insert mode diff --git a/src/nvim/buffer_updates.c b/src/nvim/buffer_updates.c index 18b53a0685..9d9c998a68 100644 --- a/src/nvim/buffer_updates.c +++ b/src/nvim/buffer_updates.c @@ -180,7 +180,7 @@ void buf_updates_send_changes(buf_T *buf, // change notifications are so frequent that many dead channels will be // cleared up quickly. if (badchannelid != 0) { - ELOG("Disabling buffer updates for dead channel %llu", badchannelid); + ELOG("Disabling buffer updates for dead channel %"PRIu64, badchannelid); buf_updates_unregister(buf, badchannelid); } } diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 2aab2d72a7..515dd0e69f 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -1943,7 +1943,7 @@ static char_u *ex_let_one(char_u *arg, typval_T *const tv, emsgf(_(e_letwrong), op); } else if (endchars != NULL && vim_strchr(endchars, *skipwhite(arg + 1)) == NULL) { - emsgf(_(e_letunexp)); + EMSG(_(e_letunexp)); } else { char_u *s; @@ -2152,7 +2152,7 @@ static char_u *get_lval(char_u *const name, typval_T *const rettv, if (rettv != NULL && (rettv->v_type != VAR_LIST || rettv->vval.v_list == NULL)) { if (!quiet) { - emsgf(_("E709: [:] requires a List value")); + EMSG(_("E709: [:] requires a List value")); } tv_clear(&var1); return NULL; @@ -2179,7 +2179,7 @@ static char_u *get_lval(char_u *const name, typval_T *const rettv, if (*p != ']') { if (!quiet) { - emsgf(_(e_missbrac)); + EMSG(_(e_missbrac)); } tv_clear(&var1); tv_clear(&var2); @@ -3325,7 +3325,7 @@ static int eval1(char_u **arg, typval_T *rettv, int evaluate) * Check for the ":". */ if ((*arg)[0] != ':') { - emsgf(_("E109: Missing ':' after '?'")); + EMSG(_("E109: Missing ':' after '?'")); if (evaluate && result) { tv_clear(rettv); } @@ -4433,7 +4433,7 @@ eval_index( /* Check for the ']'. */ if (**arg != ']') { if (verbose) { - emsgf(_(e_missbrac)); + EMSG(_(e_missbrac)); } tv_clear(&var1); if (range) { @@ -4545,7 +4545,7 @@ eval_index( case VAR_DICT: { if (range) { if (verbose) { - emsgf(_(e_dictrange)); + EMSG(_(e_dictrange)); } if (len == -1) { tv_clear(&var1); @@ -7795,7 +7795,7 @@ static void f_deepcopy(typval_T *argvars, typval_T *rettv, FunPtr fptr) noref = tv_get_number_chk(&argvars[1], NULL); } if (noref < 0 || noref > 1) { - emsgf(_(e_invarg)); + EMSG(_(e_invarg)); } else { var_item_copy(NULL, &argvars[0], rettv, true, (noref == 0 ? get_copyID() @@ -7835,7 +7835,7 @@ static void f_delete(typval_T *argvars, typval_T *rettv, FunPtr fptr) // delete a directory recursively rettv->vval.v_number = delete_recursive(name); } else { - EMSG2(_(e_invexpr2), flags); + emsgf(_(e_invexpr2), flags); } } @@ -8963,7 +8963,7 @@ static void common_function(typval_T *argvars, typval_T *rettv, } else if (trans_name != NULL && (is_funcref ? find_func(trans_name) == NULL : !translated_function_exists((const char *)trans_name))) { - EMSG2(_("E700: Unknown function: %s"), s); + emsgf(_("E700: Unknown function: %s"), s); } else { int dict_idx = 0; int arg_idx = 0; @@ -11190,7 +11190,7 @@ void get_user_input(const typval_T *const argvars, char def[1] = { 0 }; if (argvars[0].v_type == VAR_DICT) { if (argvars[1].v_type != VAR_UNKNOWN) { - emsgf(_("E5050: {opts} must be the only argument")); + EMSG(_("E5050: {opts} must be the only argument")); return; } dict_T *const dict = argvars[0].vval.v_dict; @@ -11499,7 +11499,7 @@ static void dict_list(typval_T *const tv, typval_T *const rettv, const DictListType what) { if (tv->v_type != VAR_DICT) { - emsgf(_(e_dictreq)); + EMSG(_(e_dictreq)); return; } if (tv->vval.v_dict == NULL) { @@ -11929,7 +11929,7 @@ static void f_json_decode(typval_T *argvars, typval_T *rettv, FunPtr fptr) } } if (json_decode_string(s, len, rettv) == FAIL) { - emsgf(_("E474: Failed to parse %.*s"), (int) len, s); + emsgf(_("E474: Failed to parse %.*s"), (int)len, s); rettv->v_type = VAR_NUMBER; rettv->vval.v_number = 0; } @@ -12919,7 +12919,7 @@ static void f_nr2char(typval_T *argvars, typval_T *rettv, FunPtr fptr) return; } if (num < 0) { - emsgf(_("E5070: Character number must not be less than zero")); + EMSG(_("E5070: Character number must not be less than zero")); return; } if (num > INT_MAX) { @@ -13065,9 +13065,9 @@ static void f_range(typval_T *argvars, typval_T *rettv, FunPtr fptr) return; // Type error; errmsg already given. } if (stride == 0) { - emsgf(_("E726: Stride is zero")); + EMSG(_("E726: Stride is zero")); } else if (stride > 0 ? end + 1 < start : end - 1 > start) { - emsgf(_("E727: Start past end")); + EMSG(_("E727: Start past end")); } else { tv_list_alloc_ret(rettv, (end - start) / stride); for (i = start; stride > 0 ? i <= end : i >= end; i += stride) { @@ -13404,7 +13404,7 @@ static void f_remove(typval_T *argvars, typval_T *rettv, FunPtr fptr) } } if (li == NULL) { // Didn't find "item2" after "item". - emsgf(_(e_invrange)); + EMSG(_(e_invrange)); } else { tv_list_move_items(l, item, item2, tv_list_alloc_ret(rettv, cnt), cnt); @@ -14719,7 +14719,7 @@ static void set_qf_ll_list(win_T *wp, typval_T *args, typval_T *rettv) } else if (title_arg->v_type == VAR_DICT) { d = title_arg->vval.v_dict; } else { - emsgf(_(e_dictreq)); + EMSG(_(e_dictreq)); return; } @@ -16217,7 +16217,7 @@ static void f_submatch(typval_T *argvars, typval_T *rettv, FunPtr fptr) } if (no < 0 || no >= NSUBEXP) { - EMSGN(_("E935: invalid submatch number: %d"), no); + emsgf(_("E935: invalid submatch number: %d"), no); return; } int retList = 0; @@ -17581,7 +17581,7 @@ static void f_winrestview(typval_T *argvars, typval_T *rettv, FunPtr fptr) if (argvars[0].v_type != VAR_DICT || (dict = argvars[0].vval.v_dict) == NULL) { - emsgf(_(e_invarg)); + EMSG(_(e_invarg)); } else { dictitem_T *di; if ((di = tv_dict_find(dict, S_LEN("lnum"))) != NULL) { @@ -19367,7 +19367,7 @@ static bool var_check_fixed(const int flags, const char *name, } else if (name_len == TV_CSTRING) { name_len = strlen(name); } - emsgf(_("E795: Cannot delete variable %.*s"), (int)name_len, name); + EMSG3(_("E795: Cannot delete variable %.*s"), (int)name_len, name); return true; } return false; @@ -19976,7 +19976,7 @@ void ex_function(exarg_T *eap) if (*p == '\n') { line_arg = p + 1; } else if (*p != NUL && *p != '"' && !eap->skip && !did_emsg) { - emsgf(_(e_trailing)); + EMSG(_(e_trailing)); } /* @@ -21797,15 +21797,15 @@ void ex_return(exarg_T *eap) } else { tv_clear(&rettv); } - } - /* It's safer to return also on error. */ - else if (!eap->skip) { - /* - * Return unless the expression evaluation has been cancelled due to an - * aborting error, an interrupt, or an exception. - */ - if (!aborting()) - returning = do_return(eap, FALSE, TRUE, NULL); + } else if (!eap->skip) { // It's safer to return also on error. + // In return statement, cause_abort should be force_abort. + update_force_abort(); + + // Return unless the expression evaluation has been cancelled due to an + // aborting error, an interrupt, or an exception. + if (!aborting()) { + returning = do_return(eap, false, true, NULL); + } } /* When skipping or the return gets pending, advance to the next command diff --git a/src/nvim/eval/encode.c b/src/nvim/eval/encode.c index 9bae436e3d..2563e38258 100644 --- a/src/nvim/eval/encode.c +++ b/src/nvim/eval/encode.c @@ -609,14 +609,14 @@ static inline int convert_to_json_string(garray_T *const gap, if (ch > 0x7F && shift == 1) { emsgf(_("E474: String \"%.*s\" contains byte that does not start " "any UTF-8 character"), - utf_len - (i - shift), utf_buf + i - shift); + (int)(utf_len - (i - shift)), utf_buf + i - shift); xfree(tofree); return FAIL; } else if ((SURROGATE_HI_START <= ch && ch <= SURROGATE_HI_END) || (SURROGATE_LO_START <= ch && ch <= SURROGATE_LO_END)) { emsgf(_("E474: UTF-8 string contains code point which belongs " "to a surrogate pair: %.*s"), - utf_len - (i - shift), utf_buf + i - shift); + (int)(utf_len - (i - shift)), utf_buf + i - shift); xfree(tofree); return FAIL; } else if (ENCODE_RAW(ch)) { diff --git a/src/nvim/eval/typval.c b/src/nvim/eval/typval.c index 55dcfcc198..6a93b20345 100644 --- a/src/nvim/eval/typval.c +++ b/src/nvim/eval/typval.c @@ -991,7 +991,7 @@ const char *tv_list_find_str(list_T *const l, const int n) { const listitem_T *const li = tv_list_find(l, n); if (li == NULL) { - emsgf(_(e_listidx), (int64_t)n); + EMSG2(_(e_listidx), (int64_t)n); return NULL; } return tv_get_string(TV_LIST_ITEM_TV(li)); @@ -1532,7 +1532,7 @@ bool tv_dict_get_callback(dict_T *const d, } if (!tv_is_func(di->di_tv) && di->di_tv.v_type != VAR_STRING) { - emsgf(_("E6000: Argument is not a function or function name")); + EMSG(_("E6000: Argument is not a function or function name")); return false; } @@ -2298,7 +2298,7 @@ void tv_item_lock(typval_T *const tv, const int deep, const bool lock) static int recurse = 0; if (recurse >= DICT_MAXNEST) { - emsgf(_("E743: variable nested too deep for (un)lock")); + EMSG(_("E743: variable nested too deep for (un)lock")); return; } if (deep == 0) { @@ -2546,28 +2546,28 @@ bool tv_check_str_or_nr(const typval_T *const tv) return true; } case VAR_FLOAT: { - emsgf(_("E805: Expected a Number or a String, Float found")); + EMSG(_("E805: Expected a Number or a String, Float found")); return false; } case VAR_PARTIAL: case VAR_FUNC: { - emsgf(_("E703: Expected a Number or a String, Funcref found")); + EMSG(_("E703: Expected a Number or a String, Funcref found")); return false; } case VAR_LIST: { - emsgf(_("E745: Expected a Number or a String, List found")); + EMSG(_("E745: Expected a Number or a String, List found")); return false; } case VAR_DICT: { - emsgf(_("E728: Expected a Number or a String, Dictionary found")); + EMSG(_("E728: Expected a Number or a String, Dictionary found")); return false; } case VAR_SPECIAL: { - emsgf(_("E5300: Expected a Number or a String")); + EMSG(_("E5300: Expected a Number or a String")); return false; } case VAR_UNKNOWN: { - emsgf(_(e_intern2), "tv_check_str_or_nr(UNKNOWN)"); + EMSG2(_(e_intern2), "tv_check_str_or_nr(UNKNOWN)"); return false; } } @@ -2611,7 +2611,7 @@ bool tv_check_num(const typval_T *const tv) case VAR_DICT: case VAR_FLOAT: case VAR_UNKNOWN: { - emsgf(_(num_errors[tv->v_type])); + EMSG(_(num_errors[tv->v_type])); return false; } } @@ -2655,7 +2655,7 @@ bool tv_check_str(const typval_T *const tv) case VAR_DICT: case VAR_FLOAT: case VAR_UNKNOWN: { - emsgf(_(str_errors[tv->v_type])); + EMSG(_(str_errors[tv->v_type])); return false; } } @@ -2702,7 +2702,7 @@ varnumber_T tv_get_number_chk(const typval_T *const tv, bool *const ret_error) case VAR_LIST: case VAR_DICT: case VAR_FLOAT: { - emsgf(_(num_errors[tv->v_type])); + EMSG(_(num_errors[tv->v_type])); break; } case VAR_NUMBER: { @@ -2778,23 +2778,23 @@ float_T tv_get_float(const typval_T *const tv) } case VAR_PARTIAL: case VAR_FUNC: { - emsgf(_("E891: Using a Funcref as a Float")); + EMSG(_("E891: Using a Funcref as a Float")); break; } case VAR_STRING: { - emsgf(_("E892: Using a String as a Float")); + EMSG(_("E892: Using a String as a Float")); break; } case VAR_LIST: { - emsgf(_("E893: Using a List as a Float")); + EMSG(_("E893: Using a List as a Float")); break; } case VAR_DICT: { - emsgf(_("E894: Using a Dictionary as a Float")); + EMSG(_("E894: Using a Dictionary as a Float")); break; } case VAR_SPECIAL: { - emsgf(_("E907: Using a special value as a Float")); + EMSG(_("E907: Using a special value as a Float")); break; } case VAR_UNKNOWN: { @@ -2840,7 +2840,7 @@ const char *tv_get_string_buf_chk(const typval_T *const tv, char *const buf) case VAR_DICT: case VAR_FLOAT: case VAR_UNKNOWN: { - emsgf(_(str_errors[tv->v_type])); + EMSG(_(str_errors[tv->v_type])); return false; } } diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c index a091862e42..4710ae669b 100644 --- a/src/nvim/ex_cmds.c +++ b/src/nvim/ex_cmds.c @@ -1353,6 +1353,25 @@ do_shell( apply_autocmds(EVENT_SHELLCMDPOST, NULL, NULL, FALSE, curbuf); } +#if !defined(UNIX) +static char *find_pipe(const char *cmd) +{ + bool inquote = false; + + for (const char *p = cmd; *p != NUL; p++) { + if (!inquote && *p == '|') { + return p; + } + if (*p == '"') { + inquote = !inquote; + } else if (rem_backslash((const char_u *)p)) { + p++; + } + } + return NULL; +} +#endif + /// Create a shell command from a command string, input redirection file and /// output redirection file. /// @@ -1406,7 +1425,7 @@ char_u *make_filter_cmd(char_u *cmd, char_u *itmp, char_u *otmp) // Don't do this when 'shellquote' is not empty, otherwise the // redirection would be inside the quotes. if (*p_shq == NUL) { - char *const p = strchr(buf, '|'); + char *const p = find_pipe(buf); if (p != NULL) { *p = NUL; } @@ -1414,7 +1433,7 @@ char_u *make_filter_cmd(char_u *cmd, char_u *itmp, char_u *otmp) xstrlcat(buf, " < ", len); xstrlcat(buf, (const char *)itmp, len); if (*p_shq == NUL) { - const char *const p = strchr((const char *)cmd, '|'); + const char *const p = find_pipe((const char *)cmd); if (p != NULL) { xstrlcat(buf, " ", len - 1); // Insert a space before the '|' for DOS xstrlcat(buf, p, len - 1); diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index 4d6720ef23..247b9175aa 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -2696,7 +2696,7 @@ static bool color_cmdline(CmdlineInfo *colored_ccline) } const list_T *const l = TV_LIST_ITEM_TV(li)->vval.v_list; if (tv_list_len(l) != 3) { - PRINT_ERRMSG(_("E5402: List item %i has incorrect length: %li /= 3"), + PRINT_ERRMSG(_("E5402: List item %i has incorrect length: %d /= 3"), i, tv_list_len(l)); goto color_cmdline_error; } @@ -3522,10 +3522,28 @@ void gotocmdline(int clr) */ static int ccheck_abbr(int c) { - if (p_paste || no_abbr) /* no abbreviations or in paste mode */ - return FALSE; + int spos = 0; + + if (p_paste || no_abbr) { // no abbreviations or in paste mode + return false; + } + + // Do not consider '<,'> be part of the mapping, skip leading whitespace. + // Actually accepts any mark. + while (ascii_iswhite(ccline.cmdbuff[spos]) && spos < ccline.cmdlen) { + spos++; + } + if (ccline.cmdlen - spos > 5 + && ccline.cmdbuff[spos] == '\'' + && ccline.cmdbuff[spos + 2] == ',' + && ccline.cmdbuff[spos + 3] == '\'') { + spos += 5; + } else { + // check abbreviation from the beginning of the commandline + spos = 0; + } - return check_abbr(c, ccline.cmdbuff, ccline.cmdpos, 0); + return check_abbr(c, ccline.cmdbuff, ccline.cmdpos, spos); } static int sort_func_compare(const void *s1, const void *s2) diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c index ae0b24f3c8..a5ff13552b 100644 --- a/src/nvim/fileio.c +++ b/src/nvim/fileio.c @@ -3686,7 +3686,7 @@ nofail: } else if (errmsgarg != 0) { emsgf(errmsg, os_strerror(errmsgarg)); } else { - emsgf(errmsg); + EMSG(errmsg); } if (errmsg_allocated) { xfree(errmsg); @@ -6216,8 +6216,8 @@ static int do_autocmd_event(event_T event, char_u *pat, int nested, char_u *cmd, /* refuse to add buffer-local ap if buffer number is invalid */ if (is_buflocal && (buflocal_nr == 0 || buflist_findnr(buflocal_nr) == NULL)) { - EMSGN(_("E680: <buffer=%d>: invalid buffer number "), - buflocal_nr); + emsgf(_("E680: <buffer=%d>: invalid buffer number "), + buflocal_nr); return FAIL; } @@ -6779,7 +6779,9 @@ static bool apply_autocmds_group(event_T event, char_u *fname, char_u *fname_io, * invalid. */ if (fname_io == NULL) { - if (event == EVENT_COLORSCHEME || event == EVENT_OPTIONSET) { + if (event == EVENT_COLORSCHEME + || event == EVENT_COLORSCHEMEPRE + || event == EVENT_OPTIONSET) { autocmd_fname = NULL; } else if (fname != NULL && !ends_excmd(*fname)) { autocmd_fname = fname; @@ -6830,6 +6832,7 @@ static bool apply_autocmds_group(event_T event, char_u *fname, char_u *fname_io, sfname = vim_strsave(fname); // Don't try expanding the following events. if (event == EVENT_COLORSCHEME + || event == EVENT_COLORSCHEMEPRE || event == EVENT_DIRCHANGED || event == EVENT_FILETYPE || event == EVENT_FUNCUNDEFINED diff --git a/src/nvim/garray.h b/src/nvim/garray.h index 94e1b61671..58738df691 100644 --- a/src/nvim/garray.h +++ b/src/nvim/garray.h @@ -37,7 +37,7 @@ typedef struct growarray { static inline void *ga_append_via_ptr(garray_T *gap, size_t item_size) { if ((int)item_size != gap->ga_itemsize) { - WLOG("wrong item size (%d), should be %d", item_size, gap->ga_itemsize); + WLOG("wrong item size (%zu), should be %d", item_size, gap->ga_itemsize); } ga_grow(gap, 1); return ((char *)gap->ga_data) + (item_size * (size_t)gap->ga_len++); diff --git a/src/nvim/getchar.c b/src/nvim/getchar.c index 2eb2df399e..94702a9a3a 100644 --- a/src/nvim/getchar.c +++ b/src/nvim/getchar.c @@ -420,7 +420,7 @@ void typeahead_noflush(int c) * typeahead buffer (used in case of an error). If "flush_typeahead" is true, * flush all typeahead characters (used when interrupted by a CTRL-C). */ -void flush_buffers(int flush_typeahead) +void flush_buffers(flush_buffers_T flush_typeahead) { init_typebuf(); @@ -428,22 +428,24 @@ void flush_buffers(int flush_typeahead) while (read_readbuffers(TRUE) != NUL) { } - if (flush_typeahead) { /* remove all typeahead */ - /* - * We have to get all characters, because we may delete the first part - * of an escape sequence. - * In an xterm we get one char at a time and we have to get them all. - */ - while (inchar(typebuf.tb_buf, typebuf.tb_buflen - 1, 10L) != 0) { + if (flush_typeahead == FLUSH_MINIMAL) { + // remove mapped characters at the start only + typebuf.tb_off += typebuf.tb_maplen; + typebuf.tb_len -= typebuf.tb_maplen; + } else { + // remove typeahead + if (flush_typeahead == FLUSH_INPUT) { + // We have to get all characters, because we may delete the first + // part of an escape sequence. In an xterm we get one char at a + // time and we have to get them all. + while (inchar(typebuf.tb_buf, typebuf.tb_buflen - 1, 10L) != 0) { + } } typebuf.tb_off = MAXMAPLEN; typebuf.tb_len = 0; // Reset the flag that text received from a client or from feedkeys() // was inserted in the typeahead buffer. typebuf_was_filled = false; - } else { // remove mapped characters at the start only - typebuf.tb_off += typebuf.tb_maplen; - typebuf.tb_len -= typebuf.tb_maplen; } typebuf.tb_maplen = 0; typebuf.tb_silent = 0; @@ -1538,6 +1540,7 @@ int plain_vgetc(void) * Check if a character is available, such that vgetc() will not block. * If the next character is a special character or multi-byte, the returned * character is not valid!. + * Returns NUL if no character is available. */ int vpeekc(void) { @@ -1602,7 +1605,8 @@ vungetc ( /* unget one character (can only be done once!) */ /// KeyTyped is set to TRUE in the case the user typed the key. /// KeyStuffed is TRUE if the character comes from the stuff buffer. /// if "advance" is FALSE (vpeekc()): -/// just look whether there is a character available. +/// Just look whether there is a character available. +/// Return NUL if not. /// /// When `no_mapping` (global) is zero, checks for mappings in the current mode. /// Only returns one byte (of a multi-byte character). @@ -1709,7 +1713,7 @@ static int vgetorpeek(int advance) } else { c = Ctrl_C; } - flush_buffers(true); // flush all typeahead + flush_buffers(FLUSH_INPUT); // flush all typeahead if (advance) { /* Also record this character, it might be needed to @@ -1970,8 +1974,8 @@ static int vgetorpeek(int advance) redrawcmdline(); else setcursor(); - flush_buffers(FALSE); - mapdepth = 0; /* for next one */ + flush_buffers(FLUSH_MINIMAL); + mapdepth = 0; // for next one c = -1; break; } diff --git a/src/nvim/getchar.h b/src/nvim/getchar.h index 38a2e75663..4f548d975a 100644 --- a/src/nvim/getchar.h +++ b/src/nvim/getchar.h @@ -16,6 +16,13 @@ enum { REMAP_SKIP = -3, ///< No remapping for first char. } RemapValues; +// Argument for flush_buffers(). +typedef enum { + FLUSH_MINIMAL, + FLUSH_TYPEAHEAD, // flush current typebuf contents + FLUSH_INPUT // flush typebuf and inchar() input +} flush_buffers_T; + #define KEYLEN_PART_KEY -1 /* keylen value for incomplete key-code */ #define KEYLEN_PART_MAP -2 /* keylen value for incomplete mapping */ #define KEYLEN_REMOVED 9999 /* keylen value for removed sequence */ diff --git a/src/nvim/log.c b/src/nvim/log.c index 719f0da340..4d912c452b 100644 --- a/src/nvim/log.c +++ b/src/nvim/log.c @@ -103,7 +103,7 @@ void log_unlock(void) /// @param line_num source line number, or -1 bool logmsg(int log_level, const char *context, const char *func_name, int line_num, bool eol, const char *fmt, ...) - FUNC_ATTR_UNUSED + FUNC_ATTR_UNUSED FUNC_ATTR_PRINTF(6, 7) { if (log_level < MIN_LOG_LEVEL) { return false; @@ -245,7 +245,8 @@ end: static bool do_log_to_file(FILE *log_file, int log_level, const char *context, const char *func_name, int line_num, bool eol, - const char* fmt, ...) + const char *fmt, ...) + FUNC_ATTR_PRINTF(7, 8) { va_list args; va_start(args, fmt); diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c index 02eabb9c89..a7bda9d037 100644 --- a/src/nvim/lua/executor.c +++ b/src/nvim/lua/executor.c @@ -291,7 +291,7 @@ static int nlua_print(lua_State *const lstate) return 0; nlua_print_error: emsgf(_("E5114: Error while converting print argument #%i: %.*s"), - curargidx, errmsg_len, errmsg); + curargidx, (int)errmsg_len, errmsg); ga_clear(&msg_ga); lua_pop(lstate, lua_gettop(lstate)); return 0; diff --git a/src/nvim/main.c b/src/nvim/main.c index 1db988b5f4..af54e62393 100644 --- a/src/nvim/main.c +++ b/src/nvim/main.c @@ -840,7 +840,7 @@ static void command_line_scan(mparm_T *parmp) } if (p == NULL) { - emsgf(_(e_outofmem)); + EMSG(_(e_outofmem)); } Object md = DICTIONARY_OBJ(api_metadata()); diff --git a/src/nvim/memline.c b/src/nvim/memline.c index ec0238e7c9..51f99db0de 100644 --- a/src/nvim/memline.c +++ b/src/nvim/memline.c @@ -49,6 +49,7 @@ #include "nvim/buffer.h" #include "nvim/cursor.h" #include "nvim/eval.h" +#include "nvim/getchar.h" #include "nvim/fileio.h" #include "nvim/func_attr.h" #include "nvim/main.h" @@ -3358,12 +3359,16 @@ static char *findswapname(buf_T *buf, char **dirp, char *old_fname, choice = do_swapexists(buf, (char_u *) fname); if (choice == 0) { - /* Show info about the existing swap file. */ - attention_message(buf, (char_u *) fname); + // Show info about the existing swap file. + attention_message(buf, (char_u *)fname); - /* We don't want a 'q' typed at the more-prompt - * interrupt loading a file. */ - got_int = FALSE; + // We don't want a 'q' typed at the more-prompt + // interrupt loading a file. + got_int = false; + + // If vimrc has "simalt ~x" we don't want it to + // interfere with the prompt here. + flush_buffers(FLUSH_TYPEAHEAD); } if (swap_exists_action != SEA_NONE && choice == 0) { diff --git a/src/nvim/message.c b/src/nvim/message.c index fc7e96ac2c..1778e0048f 100644 --- a/src/nvim/message.c +++ b/src/nvim/message.c @@ -331,6 +331,7 @@ void trunc_string(char_u *s, char_u *buf, int room_in, int buflen) */ int smsg(char *s, ...) + FUNC_ATTR_PRINTF(1, 2) { va_list arglist; @@ -341,6 +342,7 @@ int smsg(char *s, ...) } int smsg_attr(int attr, char *s, ...) + FUNC_ATTR_PRINTF(2, 3) { va_list arglist; @@ -550,7 +552,7 @@ int emsg(const char_u *s_) if (p_eb) { beep_flush(); // also includes flush_buffers() } else { - flush_buffers(false); // flush internal buffers + flush_buffers(FLUSH_MINIMAL); // flush internal buffers } did_emsg = true; // flag for DoOneCmd() } @@ -581,6 +583,7 @@ void emsg_invreg(int name) /// Print an error message with unknown number of arguments bool emsgf(const char *const fmt, ...) + FUNC_ATTR_PRINTF(1, 2) { bool ret; @@ -644,6 +647,7 @@ static void msg_emsgf_event(void **argv) } void msg_schedule_emsgf(const char *const fmt, ...) + FUNC_ATTR_PRINTF(1, 2) { va_list ap; va_start(ap, fmt); @@ -1672,7 +1676,7 @@ void msg_puts_attr_len(const char *const str, const ptrdiff_t len, int attr) /// @param[in] attr Highlight attributes. /// @param[in] fmt Format string. void msg_printf_attr(const int attr, const char *const fmt, ...) - FUNC_ATTR_NONNULL_ARG(2) + FUNC_ATTR_NONNULL_ARG(2) FUNC_ATTR_PRINTF(2, 3) { static char msgbuf[IOSIZE]; diff --git a/src/nvim/misc1.c b/src/nvim/misc1.c index 2e7fe4d7a9..7e9d68a4b4 100644 --- a/src/nvim/misc1.c +++ b/src/nvim/misc1.c @@ -2548,7 +2548,7 @@ void msgmore(long n) void beep_flush(void) { if (emsg_silent == 0) { - flush_buffers(false); + flush_buffers(FLUSH_MINIMAL); vim_beep(BO_ERROR); } } diff --git a/src/nvim/ops.c b/src/nvim/ops.c index e902127a40..5a6e56299d 100644 --- a/src/nvim/ops.c +++ b/src/nvim/ops.c @@ -2159,9 +2159,17 @@ void op_insert(oparg_T *oap, long count1) * Subsequent calls to ml_get() flush the firstline data - take a * copy of the required string. */ - firstline = ml_get(oap->start.lnum) + bd.textcol; - if (oap->op_type == OP_APPEND) - firstline += bd.textlen; + firstline = ml_get(oap->start.lnum); + const size_t len = STRLEN(firstline); + colnr_T add = bd.textcol; + if (oap->op_type == OP_APPEND) { + add += bd.textlen; + } + if ((size_t)add > len) { + firstline += len; // short line, point to the NUL + } else { + firstline += add; + } ins_len = (long)STRLEN(firstline) - pre_textlen; if (pre_textlen >= 0 && ins_len > 0) { ins_text = vim_strnsave(firstline, (size_t)ins_len); diff --git a/src/nvim/regexp_nfa.c b/src/nvim/regexp_nfa.c index 65ddcf3b07..fe18cb4389 100644 --- a/src/nvim/regexp_nfa.c +++ b/src/nvim/regexp_nfa.c @@ -1384,8 +1384,8 @@ static int nfa_regatom(void) re_has_z = REX_SET; break; default: - EMSGN(_("E867: (NFA) Unknown operator '\\z%c'"), - no_Magic(c)); + emsgf(_("E867: (NFA) Unknown operator '\\z%c'"), + no_Magic(c)); return FAIL; } break; @@ -1524,8 +1524,8 @@ static int nfa_regatom(void) break; } } - EMSGN(_("E867: (NFA) Unknown operator '\\%%%c'"), - no_Magic(c)); + emsgf(_("E867: (NFA) Unknown operator '\\%%%c'"), + no_Magic(c)); return FAIL; } break; @@ -1937,7 +1937,7 @@ static int nfa_regpiece(void) break; } if (i == 0) { - EMSGN(_("E869: (NFA) Unknown operator '\\@%c'"), op); + emsgf(_("E869: (NFA) Unknown operator '\\@%c'"), op); return FAIL; } EMIT(i); diff --git a/src/nvim/shada.c b/src/nvim/shada.c index f4454504a4..11da7195bf 100644 --- a/src/nvim/shada.c +++ b/src/nvim/shada.c @@ -884,7 +884,7 @@ static int shada_read_file(const char *const file, const int flags) if (p_verbose > 0) { verbose_enter(); - smsg(_("Reading ShaDa file \"%s\"%s%s%s"), + smsg(_("Reading ShaDa file \"%s\"%s%s%s%s"), fname, (flags & kShaDaWantInfo) ? _(" info") : "", (flags & kShaDaWantMarks) ? _(" marks") : "", @@ -2033,7 +2033,7 @@ static const char *shada_format_entry(const ShadaEntry entry) { static char ret[1024]; ret[0] = 0; - vim_snprintf(S_LEN(ret), "[ ] ts=%" PRIu64 " "); + vim_snprintf(S_LEN(ret), "%s", "[ ] ts=%" PRIu64 " "); // ^ Space for `can_free_entry` switch (entry.type) { case kSDItemMissing: { @@ -2091,7 +2091,7 @@ static const char *shada_format_entry(const ShadaEntry entry) entry.data.filemark.mark.lnum, \ entry.data.filemark.mark.col, \ entry.data.filemark.mark.coladd, \ - entry.data.filemark.additional_data, \ + (void *)entry.data.filemark.additional_data, \ ad_len, \ ad); \ } while (0) diff --git a/src/nvim/spellfile.c b/src/nvim/spellfile.c index f52ae61534..8be8d24b9f 100644 --- a/src/nvim/spellfile.c +++ b/src/nvim/spellfile.c @@ -3096,8 +3096,8 @@ static int spell_read_dic(spellinfo_T *spin, char_u *fname, afffile_T *affile) if (spin->si_verbose && spin->si_msg_count > 10000) { spin->si_msg_count = 0; vim_snprintf((char *)message, sizeof(message), - _("line %6d, word %6d - %s"), - lnum, spin->si_foldwcount + spin->si_keepwcount, w); + _("line %6d, word %6ld - %s"), + lnum, spin->si_foldwcount + spin->si_keepwcount, w); msg_start(); msg_puts_long_attr(message, 0); msg_clr_eos(); @@ -3570,7 +3570,7 @@ static int spell_read_wordfile(spellinfo_T *spin, char_u *fname) if (spin->si_conv.vc_type != CONV_NONE) { pc = string_convert(&spin->si_conv, rline, NULL); if (pc == NULL) { - smsg(_("Conversion failure for word in %s line %d: %s"), + smsg(_("Conversion failure for word in %s line %ld: %s"), fname, lnum, rline); continue; } @@ -3583,13 +3583,13 @@ static int spell_read_wordfile(spellinfo_T *spin, char_u *fname) if (*line == '/') { ++line; if (STRNCMP(line, "encoding=", 9) == 0) { - if (spin->si_conv.vc_type != CONV_NONE) - smsg(_("Duplicate /encoding= line ignored in %s line %d: %s"), + if (spin->si_conv.vc_type != CONV_NONE) { + smsg(_("Duplicate /encoding= line ignored in %s line %ld: %s"), fname, lnum, line - 1); - else if (did_word) - smsg(_("/encoding= line after word ignored in %s line %d: %s"), + } else if (did_word) { + smsg(_("/encoding= line after word ignored in %s line %ld: %s"), fname, lnum, line - 1); - else { + } else { char_u *enc; // Setup for conversion to 'encoding'. @@ -3607,13 +3607,13 @@ static int spell_read_wordfile(spellinfo_T *spin, char_u *fname) } if (STRNCMP(line, "regions=", 8) == 0) { - if (spin->si_region_count > 1) - smsg(_("Duplicate /regions= line ignored in %s line %d: %s"), + if (spin->si_region_count > 1) { + smsg(_("Duplicate /regions= line ignored in %s line %ld: %s"), fname, lnum, line); - else { + } else { line += 8; if (STRLEN(line) > MAXREGIONS * 2) { - smsg(_("Too many regions in %s line %d: %s"), + smsg(_("Too many regions in %s line %ld: %s"), fname, lnum, line); } else { spin->si_region_count = (int)STRLEN(line) / 2; @@ -3626,7 +3626,7 @@ static int spell_read_wordfile(spellinfo_T *spin, char_u *fname) continue; } - smsg(_("/ line ignored in %s line %d: %s"), + smsg(_("/ line ignored in %s line %ld: %s"), fname, lnum, line - 1); continue; } @@ -3652,13 +3652,13 @@ static int spell_read_wordfile(spellinfo_T *spin, char_u *fname) l = *p - '0'; if (l == 0 || l > spin->si_region_count) { - smsg(_("Invalid region nr in %s line %d: %s"), + smsg(_("Invalid region nr in %s line %ld: %s"), fname, lnum, p); break; } regionmask |= 1 << (l - 1); } else { - smsg(_("Unrecognized flags in %s line %d: %s"), + smsg(_("Unrecognized flags in %s line %ld: %s"), fname, lnum, p); break; } @@ -5136,7 +5136,7 @@ mkspell ( } else if (vim_strchr(path_tail(wfname), '_') != NULL) { EMSG(_("E751: Output file name must not have region name")); } else if (incount > MAXREGIONS) { - EMSGN(_("E754: Only up to %ld regions supported"), MAXREGIONS); + emsgf(_("E754: Only up to %d regions supported"), MAXREGIONS); } else { // Check for overwriting before doing things that may take a lot of // time. diff --git a/src/nvim/strings.c b/src/nvim/strings.c index 17c4a75a64..3b0a950ff2 100644 --- a/src/nvim/strings.c +++ b/src/nvim/strings.c @@ -693,6 +693,7 @@ static float_T tv_float(typval_T *const tvs, int *const idxp) /// /// @see vim_vsnprintf(). int vim_snprintf_add(char *str, size_t str_m, char *fmt, ...) + FUNC_ATTR_PRINTF(3, 4) { const size_t len = strlen(str); size_t space; @@ -718,6 +719,7 @@ int vim_snprintf_add(char *str, size_t str_m, char *fmt, ...) /// @return Number of bytes excluding NUL byte that would be written to the /// string if str_m was greater or equal to the return value. int vim_snprintf(char *str, size_t str_m, const char *fmt, ...) + FUNC_ATTR_PRINTF(3, 4) { va_list ap; va_start(ap, fmt); diff --git a/src/nvim/syntax.c b/src/nvim/syntax.c index e0e1897b88..5c8b5899df 100644 --- a/src/nvim/syntax.c +++ b/src/nvim/syntax.c @@ -6326,6 +6326,7 @@ int load_colors(char_u *name) recursive = true; size_t buflen = STRLEN(name) + 12; buf = xmalloc(buflen); + apply_autocmds(EVENT_COLORSCHEMEPRE, name, curbuf->b_fname, false, curbuf); snprintf((char *)buf, buflen, "colors/%s.vim", name); retval = source_runtime(buf, DIP_START + DIP_OPT); xfree(buf); diff --git a/src/nvim/testdir/test_blockedit.vim b/src/nvim/testdir/test_blockedit.vim index 4a8d59952e..527224ccd2 100644 --- a/src/nvim/testdir/test_blockedit.vim +++ b/src/nvim/testdir/test_blockedit.vim @@ -16,5 +16,18 @@ func Test_blockinsert_indent() bwipe! endfunc +func Test_blockinsert_delete() + new + let _bs = &bs + set bs=2 + call setline(1, ['case Arg is ', ' when Name_Async,', ' when Name_Num_Gangs,', 'end if;']) + exe "norm! ggjVj\<c-v>$o$A\<bs>\<esc>" + "call feedkeys("Vj\<c-v>$o$A\<bs>\<esc>", 'ti') + call assert_equal(["case Arg is ", " when Name_Async", " when Name_Num_Gangs,", "end if;"], + \ getline(1,'$')) + " reset to sane state + let &bs = _bs + bwipe! +endfunc " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/nvim/testdir/test_eval_stuff.vim b/src/nvim/testdir/test_eval_stuff.vim new file mode 100644 index 0000000000..92e1ec5335 --- /dev/null +++ b/src/nvim/testdir/test_eval_stuff.vim @@ -0,0 +1,13 @@ +" Tests for various eval things. + +function s:foo() abort + try + return [] == 0 + catch + return 1 + endtry +endfunction + +func Test_catch_return_with_error() + call assert_equal(1, s:foo()) +endfunc diff --git a/src/nvim/testdir/test_filter_cmd.vim b/src/nvim/testdir/test_filter_cmd.vim index 5aa5fa64df..86347ab77f 100644 --- a/src/nvim/testdir/test_filter_cmd.vim +++ b/src/nvim/testdir/test_filter_cmd.vim @@ -74,3 +74,16 @@ func Test_filter_cmd_completion() call assert_equal('filter /pat/ print', s:complete_filter_cmd('filter /pat/ pri')) call assert_equal('filter #pat# print', s:complete_filter_cmd('filter #pat# pri')) endfunc + +func Test_filter_cmd_with_filter() + new + set shelltemp + %!echo "a|b" + let out = getline(1) + bw! + if has('win32') + let out = trim(out, '" ') + endif + call assert_equal('a|b', out) + set shelltemp& +endfunction diff --git a/src/nvim/testdir/test_functions.vim b/src/nvim/testdir/test_functions.vim index 8fde63b55f..b1138bfc96 100644 --- a/src/nvim/testdir/test_functions.vim +++ b/src/nvim/testdir/test_functions.vim @@ -189,6 +189,52 @@ func Test_strftime() call assert_fails('call strftime("%Y", [])', 'E745:') endfunc +func Test_resolve() + if !has('unix') + return + endif + + " Xlink1 -> Xlink2 + " Xlink2 -> Xlink3 + silent !ln -s -f Xlink2 Xlink1 + silent !ln -s -f Xlink3 Xlink2 + call assert_equal('Xlink3', resolve('Xlink1')) + call assert_equal('./Xlink3', resolve('./Xlink1')) + call assert_equal('Xlink3/', resolve('Xlink2/')) + " FIXME: these tests result in things like "Xlink2/" instead of "Xlink3/"?! + "call assert_equal('Xlink3/', resolve('Xlink1/')) + "call assert_equal('./Xlink3/', resolve('./Xlink1/')) + "call assert_equal(getcwd() . '/Xlink3/', resolve(getcwd() . '/Xlink1/')) + call assert_equal(getcwd() . '/Xlink3', resolve(getcwd() . '/Xlink1')) + + " Test resolve() with a symlink cycle. + " Xlink1 -> Xlink2 + " Xlink2 -> Xlink3 + " Xlink3 -> Xlink1 + silent !ln -s -f Xlink1 Xlink3 + call assert_fails('call resolve("Xlink1")', 'E655:') + call assert_fails('call resolve("./Xlink1")', 'E655:') + call assert_fails('call resolve("Xlink2")', 'E655:') + call assert_fails('call resolve("Xlink3")', 'E655:') + call delete('Xlink1') + call delete('Xlink2') + call delete('Xlink3') + + silent !ln -s -f Xdir//Xfile Xlink + call assert_equal('Xdir/Xfile', resolve('Xlink')) + call delete('Xlink') + + silent !ln -s -f Xlink2/ Xlink1 + call assert_equal('Xlink2', resolve('Xlink1')) + call assert_equal('Xlink2/', resolve('Xlink1/')) + call delete('Xlink1') + + silent !ln -s -f ./Xlink2 Xlink1 + call assert_equal('Xlink2', resolve('Xlink1')) + call assert_equal('./Xlink2', resolve('./Xlink1')) + call delete('Xlink1') +endfunc + func Test_simplify() call assert_equal('', simplify('')) call assert_equal('/', simplify('/')) @@ -818,6 +864,19 @@ func Test_filewritable() bw! endfunc +func Test_Executable() + if has('win32') + call assert_equal(1, executable('notepad')) + call assert_equal(1, executable('notepad.exe')) + call assert_equal(0, executable('notepad.exe.exe')) + call assert_equal(1, executable('shell32.dll')) + call assert_equal(1, executable('win.ini')) + elseif has('unix') + call assert_equal(1, executable('cat')) + call assert_equal(0, executable('nodogshere')) + endif +endfunc + func Test_hostname() let hostname_vim = hostname() if has('unix') diff --git a/src/nvim/testdir/test_mapping.vim b/src/nvim/testdir/test_mapping.vim index f4fe1c2705..071b8b369b 100644 --- a/src/nvim/testdir/test_mapping.vim +++ b/src/nvim/testdir/test_mapping.vim @@ -198,3 +198,19 @@ func Test_map_timeout() set timeoutlen& delfunc ExitInsert endfunc + +func Test_cabbr_visual_mode() + cabbr s su + call feedkeys(":s \<c-B>\"\<CR>", 'itx') + call assert_equal('"su ', getreg(':')) + call feedkeys(":'<,'>s \<c-B>\"\<CR>", 'itx') + let expected = '"'. "'<,'>su " + call assert_equal(expected, getreg(':')) + call feedkeys(": '<,'>s \<c-B>\"\<CR>", 'itx') + let expected = '" '. "'<,'>su " + call assert_equal(expected, getreg(':')) + call feedkeys(":'a,'bs \<c-B>\"\<CR>", 'itx') + let expected = '"'. "'a,'bsu " + call assert_equal(expected, getreg(':')) + cunabbr s +endfunc diff --git a/src/nvim/testdir/test_options.vim b/src/nvim/testdir/test_options.vim index 66acb79206..7b640ee2ff 100644 --- a/src/nvim/testdir/test_options.vim +++ b/src/nvim/testdir/test_options.vim @@ -262,7 +262,7 @@ func Test_set_ttytype() " in travis on some builds. Why? Catch both for now try set ttytype= - call assert_report('set ttype= did not fail') + call assert_report('set ttytype= did not fail') catch /E529\|E522/ endtry @@ -270,7 +270,7 @@ func Test_set_ttytype() " check for failure of finding the entry and for missing 'cm' entry. try set ttytype=xxx - call assert_report('set ttype=xxx did not fail') + call assert_report('set ttytype=xxx did not fail') catch /E522\|E437/ endtry diff --git a/src/nvim/tui/terminfo.c b/src/nvim/tui/terminfo.c index c3dc4124b9..ad86dd928b 100644 --- a/src/nvim/tui/terminfo.c +++ b/src/nvim/tui/terminfo.c @@ -144,7 +144,7 @@ void terminfo_info_msg(const unibi_term *const ut) for (enum unibi_numeric i = unibi_numeric_begin_ + 1; i < unibi_numeric_end_; i++) { int n = unibi_get_num(ut, i); // -1 means "empty" - msg_printf_attr(0, " %-25s %-10s = %hd\n", unibi_name_num(i), + msg_printf_attr(0, " %-25s %-10s = %d\n", unibi_name_num(i), unibi_short_name_num(i), n); } @@ -173,7 +173,7 @@ void terminfo_info_msg(const unibi_term *const ut) if (unibi_count_ext_num(ut)) { msg_puts("Extended numeric capabilities:\n"); for (size_t i = 0; i < unibi_count_ext_num(ut); i++) { - msg_printf_attr(0, " %-25s = %hd\n", + msg_printf_attr(0, " %-25s = %d\n", unibi_get_ext_num_name(ut, i), unibi_get_ext_num(ut, i)); } diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c index 3ed0fe0cd6..dd22f00de0 100644 --- a/src/nvim/tui/tui.c +++ b/src/nvim/tui/tui.c @@ -88,7 +88,6 @@ typedef struct { bool cont_received; UGrid grid; kvec_t(Rect) invalid_regions; - bool did_resize; int row, col; int out_fd; bool scroll_region_is_full_screen; @@ -577,7 +576,7 @@ static void final_column_wrap(UI *ui) { TUIData *data = ui->data; UGrid *grid = &data->grid; - if (grid->col == ui->width) { + if (grid->row != -1 && grid->col == ui->width) { grid->col = 0; if (grid->row < MIN(ui->height, grid->height - 1)) { grid->row++; @@ -647,6 +646,9 @@ static void cursor_goto(UI *ui, int row, int col) ugrid_goto(grid, row, col); return; } + if (grid->row == -1) { + goto safe_move; + } if (0 == col ? col != grid->col : row != grid->row ? false : 1 == col ? 2 < grid->col && cheap_to_print(ui, grid->row, 0, col) : @@ -725,6 +727,8 @@ static void cursor_goto(UI *ui, int row, int col) return; } } + +safe_move: unibi_goto(ui, row, col); ugrid_goto(grid, row, col); } @@ -773,18 +777,7 @@ static void clear_region(UI *ui, int top, int bot, int left, int right, cursor_goto(ui, row, col); print_cell(ui, cell); }); - - if (data->did_resize && top == 0) { - // TODO(bfredl): the first line of the screen doesn't gets properly - // cleared after resize by the loop above, so redraw the final state - // after the next flush. - invalidate(ui, 0, bot, left, right); - data->did_resize = false; - } } - - // restore cursor - cursor_goto(ui, data->row, data->col); } static void set_scroll_region(UI *ui, int top, int bot, int left, int right) @@ -808,7 +801,7 @@ static void set_scroll_region(UI *ui, int top, int bot, int left, int right) unibi_out(ui, unibi_set_right_margin_parm); } } - unibi_goto(ui, grid->row, grid->col); + grid->row = -1; } static void reset_scroll_region(UI *ui, bool fullwidth) @@ -836,7 +829,7 @@ static void reset_scroll_region(UI *ui, bool fullwidth) } unibi_out_ext(ui, data->unibi_ext.disable_lr_margin); } - unibi_goto(ui, grid->row, grid->col); + grid->row = -1; } static void tui_grid_resize(UI *ui, Integer g, Integer width, Integer height) @@ -844,7 +837,6 @@ static void tui_grid_resize(UI *ui, Integer g, Integer width, Integer height) TUIData *data = ui->data; UGrid *grid = &data->grid; ugrid_resize(grid, (int)width, (int)height); - data->did_resize = true; // resize might not always be followed by a clear before flush // so clip the invalid region @@ -864,6 +856,7 @@ static void tui_grid_resize(UI *ui, Integer g, Integer width, Integer height) } } else { // Already handled the SIGWINCH signal; avoid double-resize. got_winch = false; + grid->row = -1; } } @@ -880,9 +873,10 @@ static void tui_grid_clear(UI *ui, Integer g) static void tui_grid_cursor_goto(UI *ui, Integer grid, Integer row, Integer col) { TUIData *data = ui->data; + + // cursor position is validated in tui_flush data->row = (int)row; data->col = (int)col; - cursor_goto(ui, (int)row, (int)col); } CursorShape tui_cursor_decode_shape(const char *shape_str) @@ -1070,7 +1064,6 @@ static void tui_grid_scroll(UI *ui, Integer g, Integer startrow, Integer endrow, if (!data->scroll_region_is_full_screen) { reset_scroll_region(ui, fullwidth); } - cursor_goto(ui, data->row, data->col); if (!(data->bce || no_bg(ui, data->clear_attrs))) { // Scrolling will leave wrong background in the cleared area on non-BCE diff --git a/src/nvim/ugrid.c b/src/nvim/ugrid.c index e2b92d7112..b741a61d8c 100644 --- a/src/nvim/ugrid.c +++ b/src/nvim/ugrid.c @@ -32,7 +32,6 @@ void ugrid_resize(UGrid *grid, int width, int height) grid->cells[i] = xcalloc((size_t)width, sizeof(UCell)); } - grid->row = grid->col = 0; grid->width = width; grid->height = height; } diff --git a/src/nvim/undo.c b/src/nvim/undo.c index 7dd101cb90..df0507ed41 100644 --- a/src/nvim/undo.c +++ b/src/nvim/undo.c @@ -2503,8 +2503,8 @@ void ex_undolist(exarg_T *eap) while (uhp != NULL) { if (uhp->uh_prev.ptr == NULL && uhp->uh_walk != nomark && uhp->uh_walk != mark) { - vim_snprintf((char *)IObuff, IOSIZE, "%6ld %7ld ", - uhp->uh_seq, changes); + vim_snprintf((char *)IObuff, IOSIZE, "%6ld %7d ", + uhp->uh_seq, changes); u_add_time(IObuff + STRLEN(IObuff), IOSIZE - STRLEN(IObuff), uhp->uh_time); if (uhp->uh_save_nr > 0) { diff --git a/test/functional/terminal/tui_spec.lua b/test/functional/terminal/tui_spec.lua index 09f80ca849..834720edc6 100644 --- a/test/functional/terminal/tui_spec.lua +++ b/test/functional/terminal/tui_spec.lua @@ -17,7 +17,6 @@ local nvim_prog = helpers.nvim_prog local nvim_set = helpers.nvim_set local ok = helpers.ok local read_file = helpers.read_file -local wait = helpers.wait if helpers.pending_win32(pending) then return end @@ -473,14 +472,24 @@ describe("tui 't_Co' (terminal colors)", function() nvim_prog, nvim_set)) - feed_data(":echo &t_Co\n") - wait() local tline if maxcolors == 8 or maxcolors == 16 then tline = "~ " else tline = "{4:~ }" end + + screen:expect(string.format([[ + {1: } | + %s| + %s| + %s| + %s| + | + {3:-- TERMINAL --} | + ]], tline, tline, tline, tline)) + + feed_data(":echo &t_Co\n") screen:expect(string.format([[ {1: } | %s| |