diff options
Diffstat (limited to 'src')
31 files changed, 439 insertions, 423 deletions
diff --git a/src/nvim/api/buffer.c b/src/nvim/api/buffer.c index 6f74ec905c..e77870dcf3 100644 --- a/src/nvim/api/buffer.c +++ b/src/nvim/api/buffer.c @@ -1393,15 +1393,17 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, } if (col2 >= 0) { - if (line2 >= 0) { - len = STRLEN(ml_get_buf(buf, (linenr_T)line2+1, false)); + if (line2 >= 0 && line2 < buf->b_ml.ml_line_count) { + len = STRLEN(ml_get_buf(buf, (linenr_T)line2 + 1, false)); + } else if (line2 == buf->b_ml.ml_line_count) { + // We are trying to add an extmark past final newline + len = 0; } else { // reuse len from before line2 = (int)line; } if (col2 > (Integer)len) { - api_set_error(err, kErrorTypeValidation, - "end_col value outside range"); + api_set_error(err, kErrorTypeValidation, "end_col value outside range"); goto error; } } else if (line2 >= 0) { diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c index 4648631ebe..6f1d9b2365 100644 --- a/src/nvim/buffer.c +++ b/src/nvim/buffer.c @@ -1941,6 +1941,7 @@ void free_buf_options(buf_T *buf, int free_p_ff) vim_regfree(buf->b_s.b_cap_prog); buf->b_s.b_cap_prog = NULL; clear_string_option(&buf->b_s.b_p_spl); + clear_string_option(&buf->b_s.b_p_spo); clear_string_option(&buf->b_p_sua); clear_string_option(&buf->b_p_ft); clear_string_option(&buf->b_p_cink); diff --git a/src/nvim/buffer_defs.h b/src/nvim/buffer_defs.h index bd9cd2f5ec..ea968d9592 100644 --- a/src/nvim/buffer_defs.h +++ b/src/nvim/buffer_defs.h @@ -451,6 +451,7 @@ typedef struct { regprog_T *b_cap_prog; // program for 'spellcapcheck' char_u *b_p_spf; // 'spellfile' char_u *b_p_spl; // 'spelllang' + char_u *b_p_spo; // 'spelloptions' int b_cjk; // all CJK letters as OK char_u b_syn_chartab[32]; // syntax iskeyword option char_u *b_syn_isk; // iskeyword option diff --git a/src/nvim/change.c b/src/nvim/change.c index b8bc08b747..71614363d2 100644 --- a/src/nvim/change.c +++ b/src/nvim/change.c @@ -362,8 +362,7 @@ void changed_bytes(linenr_T lnum, colnr_T col) /// insert/delete bytes at column /// /// Like changed_bytes() but also adjust extmark for "new" bytes. -/// When "new" is negative text was deleted. -static void inserted_bytes(linenr_T lnum, colnr_T col, int old, int new) +void inserted_bytes(linenr_T lnum, colnr_T col, int old, int new) { if (curbuf_splice_pending == 0) { extmark_splice_cols(curbuf, (int)lnum-1, col, old, new, kExtmarkUndo); @@ -1677,9 +1676,16 @@ int open_line( truncate_spaces(saved_line); } ml_replace(curwin->w_cursor.lnum, saved_line, false); - extmark_splice_cols( - curbuf, (int)curwin->w_cursor.lnum, - 0, curwin->w_cursor.col, (int)STRLEN(saved_line), kExtmarkUndo); + + int new_len = (int)STRLEN(saved_line); + + // TODO(vigoux): maybe there is issues there with expandtabs ? + if (new_len < curwin->w_cursor.col) { + extmark_splice_cols( + curbuf, (int)curwin->w_cursor.lnum, + new_len, curwin->w_cursor.col - new_len, 0, kExtmarkUndo); + } + saved_line = NULL; if (did_append) { changed_lines(curwin->w_cursor.lnum, curwin->w_cursor.col, diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 32830c5d7f..00542e3766 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -4518,7 +4518,6 @@ int get_option_tv(const char **const arg, typval_T *const rettv, static int get_string_tv(char_u **arg, typval_T *rettv, int evaluate) { char_u *p; - char_u *name; unsigned int extra = 0; /* @@ -4526,11 +4525,14 @@ static int get_string_tv(char_u **arg, typval_T *rettv, int evaluate) */ for (p = *arg + 1; *p != NUL && *p != '"'; MB_PTR_ADV(p)) { if (*p == '\\' && p[1] != NUL) { - ++p; - /* A "\<x>" form occupies at least 4 characters, and produces up - * to 6 characters: reserve space for 2 extra */ - if (*p == '<') - extra += 2; + p++; + // A "\<x>" form occupies at least 4 characters, and produces up + // to 21 characters (3 * 6 for the char and 3 for a modifier): + // reserve space for 18 extra. + // Each byte in the char could be encoded as K_SPECIAL K_EXTRA x. + if (*p == '<') { + extra += 18; + } } } @@ -4549,7 +4551,8 @@ static int get_string_tv(char_u **arg, typval_T *rettv, int evaluate) * Copy the string into allocated memory, handling backslashed * characters. */ - name = xmalloc(p - *arg + extra); + const int len = (int)(p - *arg + extra); + char_u *name = xmalloc(len); rettv->v_type = VAR_STRING; rettv->vval.v_string = name; @@ -4616,6 +4619,9 @@ static int get_string_tv(char_u **arg, typval_T *rettv, int evaluate) extra = trans_special((const char_u **)&p, STRLEN(p), name, true, true); if (extra != 0) { name += extra; + if (name >= rettv->vval.v_string + len) { + iemsg("get_string_tv() used more space than allocated"); + } break; } FALLTHROUGH; @@ -6962,9 +6968,10 @@ void set_buffer_lines(buf_T *buf, linenr_T lnum_arg, bool append, if (!append && lnum <= curbuf->b_ml.ml_line_count) { // Existing line, replace it. + int old_len = (int)STRLEN(ml_get(lnum)); if (u_savesub(lnum) == OK && ml_replace(lnum, (char_u *)line, true) == OK) { - changed_bytes(lnum, 0); + inserted_bytes(lnum, 0, old_len, STRLEN(line)); if (is_curbuf && lnum == curwin->w_cursor.lnum) { check_cursor_col(); } diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 3a4b4f2a50..bd77a3b7e2 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -2584,8 +2584,6 @@ static void f_foldtextresult(typval_T *argvars, typval_T *rettv, FunPtr fptr) { char_u *text; char_u buf[FOLD_TEXT_LEN]; - foldinfo_T foldinfo; - int fold_count; static bool entered = false; rettv->v_type = VAR_STRING; @@ -2599,9 +2597,10 @@ static void f_foldtextresult(typval_T *argvars, typval_T *rettv, FunPtr fptr) if (lnum < 0) { lnum = 0; } - fold_count = foldedCount(curwin, lnum, &foldinfo); - if (fold_count > 0) { - text = get_foldtext(curwin, lnum, lnum + fold_count - 1, &foldinfo, buf); + + foldinfo_T info = fold_info(curwin, lnum); + if (info.fi_lines > 0) { + text = get_foldtext(curwin, lnum, lnum + info.fi_lines - 1, info, buf); if (text == buf) { text = vim_strsave(text); } diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index 8f2d536e63..f9ca7bfa42 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -288,6 +288,7 @@ static bool do_incsearch_highlighting(int firstc, incsearch_state_T *s, exarg_T ea; pos_T save_cursor; bool use_last_pat; + bool retval = false; *skiplen = 0; *patlen = ccline.cmdlen; @@ -307,6 +308,7 @@ static bool do_incsearch_highlighting(int firstc, incsearch_state_T *s, return false; } + emsg_off++; memset(&ea, 0, sizeof(ea)); ea.line1 = 1; ea.line2 = 1; @@ -318,13 +320,13 @@ static bool do_incsearch_highlighting(int firstc, incsearch_state_T *s, cmd = skip_range(ea.cmd, NULL); if (vim_strchr((char_u *)"sgvl", *cmd) == NULL) { - return false; + goto theend; } // Skip over "substitute" to find the pattern separator. for (p = cmd; ASCII_ISALPHA(*p); p++) {} if (*skipwhite(p) == NUL) { - return false; + goto theend; } if (STRNCMP(cmd, "substitute", p - cmd) == 0 @@ -337,12 +339,15 @@ static bool do_incsearch_highlighting(int firstc, incsearch_state_T *s, p_magic = false; } } else if (STRNCMP(cmd, "sort", MAX(p - cmd, 3)) == 0) { - // skip over flags. + // skip over ! and flags + if (*p == '!') { + p = skipwhite(p + 1); + } while (ASCII_ISALPHA(*(p = skipwhite(p)))) { p++; } if (*p == NUL) { - return false; + goto theend; } } else if (STRNCMP(cmd, "vimgrep", MAX(p - cmd, 3)) == 0 || STRNCMP(cmd, "vimgrepadd", MAX(p - cmd, 8)) == 0 @@ -353,14 +358,14 @@ static bool do_incsearch_highlighting(int firstc, incsearch_state_T *s, if (*p == '!') { p++; if (*skipwhite(p) == NUL) { - return false; + goto theend; } } if (*cmd != 'g') { delim_optional = true; } } else { - return false; + goto theend; } p = skipwhite(p); @@ -369,7 +374,7 @@ static bool do_incsearch_highlighting(int firstc, incsearch_state_T *s, use_last_pat = end == p && *end == delim; if (end == p && !use_last_pat) { - return false; + goto theend; } // Don't do 'hlsearch' highlighting if the pattern matches everything. @@ -381,7 +386,7 @@ static bool do_incsearch_highlighting(int firstc, incsearch_state_T *s, empty = empty_pattern(p); *end = c; if (empty) { - return false; + goto theend; } } @@ -409,7 +414,10 @@ static bool do_incsearch_highlighting(int firstc, incsearch_state_T *s, } curwin->w_cursor = save_cursor; - return true; + retval = true; +theend: + emsg_off--; + return retval; } // May do 'incsearch' highlighting if desired. @@ -549,6 +557,7 @@ static void may_do_incsearch_highlighting(int firstc, long count, } update_screen(SOME_VALID); + highlight_match = false; restore_last_search_pattern(); // Leave it at the end to make CTRL-R CTRL-W work. But not when beyond the @@ -1541,6 +1550,7 @@ static int may_do_command_line_next_incsearch(int firstc, long count, highlight_match = true; save_viewstate(&s->old_viewstate); update_screen(NOT_VALID); + highlight_match = false; redrawcmdline(); curwin->w_cursor = s->match_end; } else { @@ -6463,12 +6473,15 @@ static int open_cmdwin(void) // Save the command line info, can be used recursively. save_cmdline(&save_ccline); - /* No Ex mode here! */ + // No Ex mode here! exmode_active = 0; State = NORMAL; setmouse(); + // Reset here so it can be set by a CmdWinEnter autocommand. + cmdwin_result = 0; + // Trigger CmdwinEnter autocommands. typestr[0] = (char_u)cmdwin_type; typestr[1] = NUL; @@ -6484,7 +6497,6 @@ static int open_cmdwin(void) /* * Call the main loop until <CR> or CTRL-C is typed. */ - cmdwin_result = 0; normal_enter(true, false); RedrawingDisabled = i; diff --git a/src/nvim/extmark.c b/src/nvim/extmark.c index ba94f55a50..17141f12fd 100644 --- a/src/nvim/extmark.c +++ b/src/nvim/extmark.c @@ -568,8 +568,18 @@ void extmark_splice(buf_T *buf, int new_row, colnr_T new_col, bcount_t new_byte, ExtmarkOp undo) { - long offset = ml_find_line_or_offset(buf, start_row+1, NULL, true); - extmark_splice_impl(buf, start_row, start_col, offset+start_col, + long offset = ml_find_line_or_offset(buf, start_row + 1, NULL, true); + + // On empty buffers, when editing the first line, the line is buffered, + // causing offset to be < 0. While the buffer is not actually empty, the + // buffered line has not been flushed (and should not be) yet, so the call is + // valid but an edge case. + // + // TODO(vigoux): maybe the is a better way of testing that ? + if (offset < 0 && buf->b_ml.ml_chunksize == NULL) { + offset = 0; + } + extmark_splice_impl(buf, start_row, start_col, offset + start_col, old_row, old_col, old_byte, new_row, new_col, new_byte, undo); } diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c index 286f2b4fca..ed8b72e2be 100644 --- a/src/nvim/fileio.c +++ b/src/nvim/fileio.c @@ -210,7 +210,8 @@ void filemess(buf_T *buf, char_u *name, char_u *s, int attr) if (msg_silent != 0) { return; } - add_quoted_fname((char *)IObuff, IOSIZE - 80, buf, (const char *)name); + add_quoted_fname((char *)IObuff, IOSIZE - 100, buf, (const char *)name); + // Avoid an over-long translation to cause trouble. xstrlcat((char *)IObuff, (const char *)s, IOSIZE); // For the first message may have to start a new line. // For further ones overwrite the previous one, reset msg_scroll before diff --git a/src/nvim/fold.c b/src/nvim/fold.c index 9994ad3ea8..9188ae6571 100644 --- a/src/nvim/fold.c +++ b/src/nvim/fold.c @@ -280,26 +280,31 @@ int foldLevel(linenr_T lnum) // Return false if line is not folded. bool lineFolded(win_T *const win, const linenr_T lnum) { - return foldedCount(win, lnum, NULL) != 0; + return fold_info(win, lnum).fi_lines != 0; } -/* foldedCount() {{{2 */ -/* - * Count the number of lines that are folded at line number "lnum". - * Normally "lnum" is the first line of a possible fold, and the returned - * number is the number of lines in the fold. - * Doesn't use caching from the displayed window. - * Returns number of folded lines from "lnum", or 0 if line is not folded. - * When "infop" is not NULL, fills *infop with the fold level info. - */ -long foldedCount(win_T *win, linenr_T lnum, foldinfo_T *infop) +/// fold_info() {{{2 +/// +/// Count the number of lines that are folded at line number "lnum". +/// Normally "lnum" is the first line of a possible fold, and the returned +/// number is the number of lines in the fold. +/// Doesn't use caching from the displayed window. +/// +/// @return with the fold level info. +/// fi_lines = number of folded lines from "lnum", +/// or 0 if line is not folded. +foldinfo_T fold_info(win_T *win, linenr_T lnum) { + foldinfo_T info; linenr_T last; - if (hasFoldingWin(win, lnum, NULL, &last, false, infop)) { - return (long)(last - lnum + 1); + if (hasFoldingWin(win, lnum, NULL, &last, false, &info)) { + info.fi_lines = (long)(last - lnum + 1); + } else { + info.fi_lines = 0; } - return 0; + + return info; } /* foldmethodIsManual() {{{2 */ @@ -1755,7 +1760,7 @@ static void foldDelMarker( /// When 'foldtext' isn't set puts the result in "buf[FOLD_TEXT_LEN]". /// Otherwise the result is in allocated memory. char_u *get_foldtext(win_T *wp, linenr_T lnum, linenr_T lnume, - foldinfo_T *foldinfo, char_u *buf) + foldinfo_T foldinfo, char_u *buf) FUNC_ATTR_NONNULL_ARG(1) { char_u *text = NULL; @@ -1783,11 +1788,12 @@ char_u *get_foldtext(win_T *wp, linenr_T lnum, linenr_T lnume, set_vim_var_nr(VV_FOLDSTART, (varnumber_T) lnum); set_vim_var_nr(VV_FOLDEND, (varnumber_T) lnume); - /* Set "v:folddashes" to a string of "level" dashes. */ - /* Set "v:foldlevel" to "level". */ - level = foldinfo->fi_level; - if (level > (int)sizeof(dashes) - 1) + // Set "v:folddashes" to a string of "level" dashes. + // Set "v:foldlevel" to "level". + level = foldinfo.fi_level; + if (level > (int)sizeof(dashes) - 1) { level = (int)sizeof(dashes) - 1; + } memset(dashes, '-', (size_t)level); dashes[level] = NUL; set_vim_var_string(VV_FOLDDASHES, dashes, -1); diff --git a/src/nvim/fold.h b/src/nvim/fold.h index f35b328fb1..95c4b0c1dc 100644 --- a/src/nvim/fold.h +++ b/src/nvim/fold.h @@ -18,6 +18,7 @@ typedef struct foldinfo { other fields are invalid */ int fi_low_level; /* lowest fold level that starts in the same line */ + long fi_lines; } foldinfo_T; diff --git a/src/nvim/log.h b/src/nvim/log.h index 17ff095473..d92b4629ed 100644 --- a/src/nvim/log.h +++ b/src/nvim/log.h @@ -5,6 +5,7 @@ #include <stdbool.h> #include "auto/config.h" +#include "nvim/macros.h" #define DEBUG_LOG_LEVEL 0 #define INFO_LOG_LEVEL 1 @@ -68,6 +69,10 @@ # define LOG_CALLSTACK_TO_FILE(fp) log_callstack_to_file(fp, __func__, __LINE__) #endif +#if NVIM_HAS_INCLUDE("sanitizer/asan_interface.h") +# include "sanitizer/asan_interface.h" +#endif + #ifdef INCLUDE_GENERATED_DECLARATIONS # include "log.h.generated.h" #endif diff --git a/src/nvim/macros.h b/src/nvim/macros.h index 0bbaa87aba..07dcb4a8e8 100644 --- a/src/nvim/macros.h +++ b/src/nvim/macros.h @@ -152,6 +152,12 @@ #define STR_(x) #x #define STR(x) STR_(x) +#ifndef __has_include +# define NVIM_HAS_INCLUDE(x) 0 +#else +# define NVIM_HAS_INCLUDE __has_include +#endif + #ifndef __has_attribute # define NVIM_HAS_ATTRIBUTE(x) 0 #elif defined(__clang__) && __clang__ == 1 \ diff --git a/src/nvim/ops.c b/src/nvim/ops.c index 1f55d2c315..6209dd6492 100644 --- a/src/nvim/ops.c +++ b/src/nvim/ops.c @@ -1544,10 +1544,10 @@ int op_delete(oparg_T *oap) oap->line_count = 0; // no lines deleted } else if (oap->motion_type == kMTLineWise) { if (oap->op_type == OP_CHANGE) { - /* Delete the lines except the first one. Temporarily move the - * cursor to the next line. Save the current line number, if the - * last line is deleted it may be changed. - */ + // Delete the lines except the first one. Temporarily move the + // cursor to the next line. Save the current line number, if the + // last line is deleted it may be changed. + if (oap->line_count > 1) { lnum = curwin->w_cursor.lnum; ++curwin->w_cursor.lnum; @@ -1560,12 +1560,21 @@ int op_delete(oparg_T *oap) beginline(BL_WHITE); // cursor on first non-white did_ai = true; // delete the indent when ESC hit ai_col = curwin->w_cursor.col; - } else - beginline(0); /* cursor in column 0 */ - truncate_line(FALSE); /* delete the rest of the line */ - /* leave cursor past last char in line */ - if (oap->line_count > 1) - u_clearline(); /* "U" command not possible after "2cc" */ + } else { + beginline(0); // cursor in column 0 + } + + int old_len = (int)STRLEN(ml_get(curwin->w_cursor.lnum)); + truncate_line(false); // delete the rest of the line + + extmark_splice_cols(curbuf, + (int)curwin->w_cursor.lnum-1, curwin->w_cursor.col, + old_len - curwin->w_cursor.col, 0, kExtmarkUndo); + + // leave cursor past last char in line + if (oap->line_count > 1) { + u_clearline(); // "U" command not possible after "2cc" + } } else { del_lines(oap->line_count, TRUE); beginline(BL_WHITE | BL_FIX); diff --git a/src/nvim/option.c b/src/nvim/option.c index 8d74cead8d..6ae9378236 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -174,6 +174,7 @@ static char_u *p_syn; static char_u *p_spc; static char_u *p_spf; static char_u *p_spl; +static char_u *p_spo; static long p_ts; static long p_tw; static int p_udf; @@ -2285,6 +2286,7 @@ void check_buf_options(buf_T *buf) check_string_option(&buf->b_s.b_p_spc); check_string_option(&buf->b_s.b_p_spf); check_string_option(&buf->b_s.b_p_spl); + check_string_option(&buf->b_s.b_p_spo); check_string_option(&buf->b_p_sua); check_string_option(&buf->b_p_cink); check_string_option(&buf->b_p_cino); @@ -3090,6 +3092,10 @@ ambw_end: } else if (varp == &(curwin->w_s->b_p_spc)) { // When 'spellcapcheck' is set compile the regexp program. errmsg = compile_cap_prog(curwin->w_s); + } else if (varp == &(curwin->w_s->b_p_spo)) { // 'spelloptions' + if (**varp != NUL && STRCMP("camel", *varp) != 0) { + errmsg = e_invarg; + } } else if (varp == &p_sps) { // 'spellsuggest' if (spell_check_sps() != OK) { errmsg = e_invarg; @@ -5896,6 +5902,7 @@ static char_u *get_varp(vimoption_T *p) case PV_SPC: return (char_u *)&(curwin->w_s->b_p_spc); case PV_SPF: return (char_u *)&(curwin->w_s->b_p_spf); case PV_SPL: return (char_u *)&(curwin->w_s->b_p_spl); + case PV_SPO: return (char_u *)&(curwin->w_s->b_p_spo); case PV_SW: return (char_u *)&(curbuf->b_p_sw); case PV_TFU: return (char_u *)&(curbuf->b_p_tfu); case PV_TS: return (char_u *)&(curbuf->b_p_ts); @@ -6175,6 +6182,7 @@ void buf_copy_options(buf_T *buf, int flags) (void)compile_cap_prog(&buf->b_s); buf->b_s.b_p_spf = vim_strsave(p_spf); buf->b_s.b_p_spl = vim_strsave(p_spl); + buf->b_s.b_p_spo = vim_strsave(p_spo); buf->b_p_inde = vim_strsave(p_inde); buf->b_p_indk = vim_strsave(p_indk); buf->b_p_fp = empty_option; diff --git a/src/nvim/option_defs.h b/src/nvim/option_defs.h index 02fa7ac216..a09811c8fb 100644 --- a/src/nvim/option_defs.h +++ b/src/nvim/option_defs.h @@ -787,6 +787,7 @@ enum { , BV_SPC , BV_SPF , BV_SPL + , BV_SPO , BV_STS , BV_SUA , BV_SW diff --git a/src/nvim/options.lua b/src/nvim/options.lua index f1221a52a2..02df0ab276 100644 --- a/src/nvim/options.lua +++ b/src/nvim/options.lua @@ -2320,6 +2320,16 @@ return { defaults={if_true={vi="best"}} }, { + full_name='spelloptions', abbreviation='spo', + type='string', list='onecomma', scope={'buffer'}, + deny_duplicates=true, + secure=true, + vi_def=true, + expand=true, + varname='p_spo', + defaults={if_true={vi="", vim=""}} + }, + { full_name='splitbelow', abbreviation='sb', type='bool', scope={'global'}, vi_def=true, diff --git a/src/nvim/screen.c b/src/nvim/screen.c index 5ac5306dd9..f3fdafcc70 100644 --- a/src/nvim/screen.c +++ b/src/nvim/screen.c @@ -133,8 +133,6 @@ static sattr_T *linebuf_attr = NULL; static match_T search_hl; /* used for 'hlsearch' highlight matching */ -static foldinfo_T win_foldinfo; /* info for 'foldcolumn' */ - StlClickDefinition *tab_page_click_defs = NULL; long tab_page_click_defs_size = 0; @@ -702,7 +700,6 @@ static void win_update(win_T *wp) long j; static int recursive = FALSE; /* being called recursively */ int old_botline = wp->w_botline; - long fold_count; // Remember what happened to the previous line. #define DID_NONE 1 // didn't update a line #define DID_LINE 2 // updated a normal line @@ -713,6 +710,7 @@ static void win_update(win_T *wp) linenr_T mod_bot = 0; int save_got_int; + // If we can compute a change in the automatic sizing of the sign column // under 'signcolumn=auto:X' and signs currently placed in the buffer, better // figuring it out here so we can redraw the entire screen for it. @@ -1229,7 +1227,6 @@ static void win_update(win_T *wp) // Set the time limit to 'redrawtime'. proftime_T syntax_tm = profile_setlimit(p_rdt); syn_set_timeout(&syntax_tm); - win_foldinfo.fi_level = 0; /* * Update all the window rows. @@ -1459,24 +1456,19 @@ static void win_update(win_T *wp) * Otherwise, display normally (can be several display lines when * 'wrap' is on). */ - fold_count = foldedCount(wp, lnum, &win_foldinfo); - if (fold_count != 0) { - fold_line(wp, fold_count, &win_foldinfo, lnum, row); - ++row; - --fold_count; - wp->w_lines[idx].wl_folded = TRUE; - wp->w_lines[idx].wl_lastlnum = lnum + fold_count; - did_update = DID_FOLD; - } else if (idx < wp->w_lines_valid - && wp->w_lines[idx].wl_valid - && wp->w_lines[idx].wl_lnum == lnum - && lnum > wp->w_topline - && !(dy_flags & (DY_LASTLINE | DY_TRUNCATE)) - && srow + wp->w_lines[idx].wl_size > wp->w_grid.Rows - && diff_check_fill(wp, lnum) == 0 - ) { - /* This line is not going to fit. Don't draw anything here, - * will draw "@ " lines below. */ + foldinfo_T foldinfo = fold_info(wp, lnum); + + if (foldinfo.fi_lines == 0 + && idx < wp->w_lines_valid + && wp->w_lines[idx].wl_valid + && wp->w_lines[idx].wl_lnum == lnum + && lnum > wp->w_topline + && !(dy_flags & (DY_LASTLINE | DY_TRUNCATE)) + && srow + wp->w_lines[idx].wl_size > wp->w_grid.Rows + && diff_check_fill(wp, lnum) == 0 + ) { + // This line is not going to fit. Don't draw anything here, + // will draw "@ " lines below. row = wp->w_grid.Rows + 1; } else { prepare_search_hl(wp, lnum); @@ -1485,14 +1477,21 @@ static void win_update(win_T *wp) && syntax_present(wp)) syntax_end_parsing(syntax_last_parsed + 1); - /* - * Display one line. - */ - row = win_line(wp, lnum, srow, wp->w_grid.Rows, mod_top == 0, false); + // Display one line + row = win_line(wp, lnum, srow, + foldinfo.fi_lines ? srow : wp->w_grid.Rows, + mod_top == 0, false, foldinfo); - wp->w_lines[idx].wl_folded = FALSE; + wp->w_lines[idx].wl_folded = foldinfo.fi_lines != 0; wp->w_lines[idx].wl_lastlnum = lnum; did_update = DID_LINE; + + if (foldinfo.fi_lines > 0) { + did_update = DID_FOLD; + foldinfo.fi_lines--; + wp->w_lines[idx].wl_lastlnum = lnum + foldinfo.fi_lines; + } + syntax_last_parsed = lnum; } @@ -1507,20 +1506,17 @@ static void win_update(win_T *wp) idx++; break; } - if (dollar_vcol == -1) + if (dollar_vcol == -1) { wp->w_lines[idx].wl_size = row - srow; - ++idx; - lnum += fold_count + 1; + } + idx++; + lnum += foldinfo.fi_lines + 1; } else { if (wp->w_p_rnu) { // 'relativenumber' set: The text doesn't need to be drawn, but // the number column nearly always does. - fold_count = foldedCount(wp, lnum, &win_foldinfo); - if (fold_count != 0) { - fold_line(wp, fold_count, &win_foldinfo, lnum, row); - } else { - (void)win_line(wp, lnum, srow, wp->w_grid.Rows, true, true); - } + foldinfo_T info = fold_info(wp, lnum); + (void)win_line(wp, lnum, srow, wp->w_grid.Rows, true, true, info); } // This line does not need to be drawn, advance to the next one. @@ -1752,31 +1748,6 @@ static int advance_color_col(int vcol, int **color_cols) return **color_cols >= 0; } -// Returns the next grid column. -static int text_to_screenline(win_T *wp, char_u *text, int col, int off) - FUNC_ATTR_NONNULL_ALL -{ - int idx = wp->w_p_rl ? off : off + col; - LineState s = LINE_STATE(text); - - while (*s.p != NUL) { - // TODO(bfredl): cargo-culted from the old Vim code: - // if(col + cells > wp->w_width - (wp->w_p_rl ? col : 0)) { break; } - // This is obvious wrong. If Vim ever fixes this, solve for "cells" again - // in the correct condition. - const int maxcells = wp->w_grid.Columns - col - (wp->w_p_rl ? col : 0); - const int cells = line_putchar(&s, &linebuf_char[idx], maxcells, - wp->w_p_rl); - if (cells == -1) { - break; - } - col += cells; - idx += cells; - } - - return col; -} - // Compute the width of the foldcolumn. Based on 'foldcolumn' and how much // space is available for window "wp", minus "col". static int compute_foldcolumn(win_T *wp, int col) @@ -1841,271 +1812,6 @@ static int line_putchar(LineState *s, schar_T *dest, int maxcells, bool rl) return cells; } -/* - * Display one folded line. - */ -static void fold_line(win_T *wp, long fold_count, foldinfo_T *foldinfo, linenr_T lnum, int row) -{ - char_u buf[FOLD_TEXT_LEN]; - pos_T *top, *bot; - linenr_T lnume = lnum + fold_count - 1; - int len; - char_u *text; - int fdc; - int col; - int txtcol; - int off; - - /* Build the fold line: - * 1. Add the cmdwin_type for the command-line window - * 2. Add the 'foldcolumn' - * 3. Add the 'number' or 'relativenumber' column - * 4. Compose the text - * 5. Add the text - * 6. set highlighting for the Visual area an other text - */ - col = 0; - off = 0; - - /* - * 1. Add the cmdwin_type for the command-line window - * Ignores 'rightleft', this window is never right-left. - */ - if (cmdwin_type != 0 && wp == curwin) { - schar_from_ascii(linebuf_char[off], cmdwin_type); - linebuf_attr[off] = win_hl_attr(wp, HLF_AT); - col++; - } - -# define RL_MEMSET(p, v, l) \ - do { \ - if (wp->w_p_rl) { \ - for (int ri = 0; ri < l; ri++) { \ - linebuf_attr[off + (wp->w_grid.Columns - (p) - (l)) + ri] = v; \ - } \ - } else { \ - for (int ri = 0; ri < l; ri++) { \ - linebuf_attr[off + (p) + ri] = v; \ - } \ - } \ - } while (0) - - // 2. Add the 'foldcolumn' - // Reduce the width when there is not enough space. - fdc = compute_foldcolumn(wp, col); - if (fdc > 0) { - fill_foldcolumn(buf, wp, true, lnum); - const char_u *it = &buf[0]; - for (int i = 0; i < fdc; i++) { - int mb_c = mb_ptr2char_adv(&it); - if (wp->w_p_rl) { - schar_from_char(linebuf_char[off + wp->w_grid.Columns - i - 1 - col], - mb_c); - } else { - schar_from_char(linebuf_char[off + col + i], mb_c); - } - } - RL_MEMSET(col, win_hl_attr(wp, HLF_FC), fdc); - col += fdc; - } - - /* Set all attributes of the 'number' or 'relativenumber' column and the - * text */ - RL_MEMSET(col, win_hl_attr(wp, HLF_FL), wp->w_grid.Columns - col); - - // If signs are being displayed, add spaces. - if (win_signcol_count(wp) > 0) { - len = wp->w_grid.Columns - col; - if (len > 0) { - int len_max = win_signcol_width(wp) * win_signcol_count(wp); - if (len > len_max) { - len = len_max; - } - char_u space_buf[18] = " "; - assert((size_t)len_max <= sizeof(space_buf)); - copy_text_attr(off + col, space_buf, len, - win_hl_attr(wp, HLF_FL)); - col += len; - } - } - - /* - * 3. Add the 'number' or 'relativenumber' column - */ - if (wp->w_p_nu || wp->w_p_rnu) { - len = wp->w_grid.Columns - col; - if (len > 0) { - int w = number_width(wp); - long num; - char *fmt = "%*ld "; - - if (len > w + 1) - len = w + 1; - - if (wp->w_p_nu && !wp->w_p_rnu) - /* 'number' + 'norelativenumber' */ - num = (long)lnum; - else { - /* 'relativenumber', don't use negative numbers */ - num = labs((long)get_cursor_rel_lnum(wp, lnum)); - if (num == 0 && wp->w_p_nu && wp->w_p_rnu) { - /* 'number' + 'relativenumber': cursor line shows absolute - * line number */ - num = lnum; - fmt = "%-*ld "; - } - } - - snprintf((char *)buf, FOLD_TEXT_LEN, fmt, w, num); - if (wp->w_p_rl) { - // the line number isn't reversed - copy_text_attr(off + wp->w_grid.Columns - len - col, buf, len, - win_hl_attr(wp, HLF_FL)); - } else { - copy_text_attr(off + col, buf, len, win_hl_attr(wp, HLF_FL)); - } - col += len; - } - } - - /* - * 4. Compose the folded-line string with 'foldtext', if set. - */ - text = get_foldtext(wp, lnum, lnume, foldinfo, buf); - - txtcol = col; /* remember where text starts */ - - // 5. move the text to linebuf_char[off]. Fill up with "fold". - // Right-left text is put in columns 0 - number-col, normal text is put - // in columns number-col - window-width. - col = text_to_screenline(wp, text, col, off); - - /* Fill the rest of the line with the fold filler */ - if (wp->w_p_rl) - col -= txtcol; - - schar_T sc; - schar_from_char(sc, wp->w_p_fcs_chars.fold); - while (col < wp->w_grid.Columns - - (wp->w_p_rl ? txtcol : 0) - ) { - schar_copy(linebuf_char[off+col++], sc); - } - - if (text != buf) - xfree(text); - - /* - * 6. set highlighting for the Visual area an other text. - * If all folded lines are in the Visual area, highlight the line. - */ - if (VIsual_active && wp->w_buffer == curwin->w_buffer) { - if (ltoreq(curwin->w_cursor, VIsual)) { - /* Visual is after curwin->w_cursor */ - top = &curwin->w_cursor; - bot = &VIsual; - } else { - /* Visual is before curwin->w_cursor */ - top = &VIsual; - bot = &curwin->w_cursor; - } - if (lnum >= top->lnum - && lnume <= bot->lnum - && (VIsual_mode != 'v' - || ((lnum > top->lnum - || (lnum == top->lnum - && top->col == 0)) - && (lnume < bot->lnum - || (lnume == bot->lnum - && (bot->col - (*p_sel == 'e')) - >= (colnr_T)STRLEN(ml_get_buf(wp->w_buffer, lnume, - FALSE))))))) { - if (VIsual_mode == Ctrl_V) { - // Visual block mode: highlight the chars part of the block - if (wp->w_old_cursor_fcol + txtcol < (colnr_T)wp->w_grid.Columns) { - if (wp->w_old_cursor_lcol != MAXCOL - && wp->w_old_cursor_lcol + txtcol - < (colnr_T)wp->w_grid.Columns) { - len = wp->w_old_cursor_lcol; - } else { - len = wp->w_grid.Columns - txtcol; - } - RL_MEMSET(wp->w_old_cursor_fcol + txtcol, win_hl_attr(wp, HLF_V), - len - (int)wp->w_old_cursor_fcol); - } - } else { - // Set all attributes of the text - RL_MEMSET(txtcol, win_hl_attr(wp, HLF_V), wp->w_grid.Columns - txtcol); - } - } - } - - // Show colorcolumn in the fold line, but let cursorcolumn override it. - if (wp->w_p_cc_cols) { - int i = 0; - int j = wp->w_p_cc_cols[i]; - int old_txtcol = txtcol; - - while (j > -1) { - txtcol += j; - if (wp->w_p_wrap) { - txtcol -= wp->w_skipcol; - } else { - txtcol -= wp->w_leftcol; - } - if (txtcol >= 0 && txtcol < wp->w_grid.Columns) { - linebuf_attr[off + txtcol] = - hl_combine_attr(linebuf_attr[off + txtcol], win_hl_attr(wp, HLF_MC)); - } - txtcol = old_txtcol; - j = wp->w_p_cc_cols[++i]; - } - } - - /* Show 'cursorcolumn' in the fold line. */ - if (wp->w_p_cuc) { - txtcol += wp->w_virtcol; - if (wp->w_p_wrap) - txtcol -= wp->w_skipcol; - else - txtcol -= wp->w_leftcol; - if (txtcol >= 0 && txtcol < wp->w_grid.Columns) { - linebuf_attr[off + txtcol] = hl_combine_attr( - linebuf_attr[off + txtcol], win_hl_attr(wp, HLF_CUC)); - } - } - - grid_put_linebuf(&wp->w_grid, row, 0, wp->w_grid.Columns, wp->w_grid.Columns, - false, wp, wp->w_hl_attr_normal, false); - - /* - * Update w_cline_height and w_cline_folded if the cursor line was - * updated (saves a call to plines() later). - */ - if (wp == curwin - && lnum <= curwin->w_cursor.lnum - && lnume >= curwin->w_cursor.lnum) { - curwin->w_cline_row = row; - curwin->w_cline_height = 1; - curwin->w_cline_folded = true; - curwin->w_valid |= (VALID_CHEIGHT|VALID_CROW); - conceal_cursor_used = conceal_cursor_line(curwin); - } -} - - -/// Copy "buf[len]" to linebuf_char["off"] and set attributes to "attr". -/// -/// Only works for ASCII text! -static void copy_text_attr(int off, char_u *buf, int len, int attr) -{ - int i; - - for (i = 0; i < len; i++) { - schar_from_ascii(linebuf_char[off + i], buf[i]); - linebuf_attr[off + i] = attr; - } -} /// Fills the foldcolumn at "p" for window "wp". /// Only to be called when 'foldcolumn' > 0. @@ -2120,7 +1826,7 @@ static size_t fill_foldcolumn( char_u *p, win_T *wp, - int closed, + foldinfo_T foldinfo, linenr_T lnum ) { @@ -2131,10 +1837,11 @@ fill_foldcolumn( size_t char_counter = 0; int symbol = 0; int len = 0; + bool closed = foldinfo.fi_lines > 0; // Init to all spaces. memset(p, ' ', MAX_MCO * fdc + 1); - level = win_foldinfo.fi_level; + level = foldinfo.fi_level; // If the column is too narrow, we start at the lowest level that // fits and use numbers to indicated the depth. @@ -2144,8 +1851,8 @@ fill_foldcolumn( } for (i = 0; i < MIN(fdc, level); i++) { - if (win_foldinfo.fi_lnum == lnum - && first_level + i >= win_foldinfo.fi_low_level) { + if (foldinfo.fi_lnum == lnum + && first_level + i >= foldinfo.fi_low_level) { symbol = wp->w_p_fcs_chars.foldopen; } else if (first_level == 1) { symbol = wp->w_p_fcs_chars.foldsep; @@ -2176,21 +1883,27 @@ fill_foldcolumn( return MAX(char_counter + (fdc-i), (size_t)fdc); } -/* - * Display line "lnum" of window 'wp' on the screen. - * Start at row "startrow", stop when "endrow" is reached. - * wp->w_virtcol needs to be valid. - * - * Return the number of last row the line occupies. - */ + +/// Display line "lnum" of window 'wp' on the screen. +/// Start at row "startrow", stop when "endrow" is reached. +/// wp->w_virtcol needs to be valid. +/// +/// @param lnum line to display +/// @param endrow stop drawing once reaching this row +/// @param nochange not updating for changed text +/// @param number_only only update the number column +/// @param foldinfo fold info for this line +/// +/// @return the number of last row the line occupies. static int win_line ( win_T *wp, linenr_T lnum, int startrow, int endrow, - bool nochange, // not updating for changed text - bool number_only // only update the number column + bool nochange, + bool number_only, + foldinfo_T foldinfo ) { int c = 0; // init for GCC @@ -2295,6 +2008,8 @@ win_line ( bool has_decorations = false; // this buffer has decorations bool do_virttext = false; // draw virtual text for this line + char_u buf_fold[FOLD_TEXT_LEN + 1]; // Hold value returned by get_foldtext + /* draw_state: items that are drawn in sequence: */ #define WL_START 0 /* nothing done yet */ # define WL_CMDLINE WL_START + 1 /* cmdline window column */ @@ -2846,7 +2561,7 @@ win_line ( // already be in use. xfree(p_extra_free); p_extra_free = xmalloc(MAX_MCO * fdc + 1); - n_extra = fill_foldcolumn(p_extra_free, wp, false, lnum); + n_extra = fill_foldcolumn(p_extra_free, wp, foldinfo, lnum); p_extra_free[n_extra] = NUL; p_extra = p_extra_free; c_extra = NUL; @@ -3072,6 +2787,41 @@ win_line ( break; } + if (draw_state == WL_LINE + && foldinfo.fi_level != 0 + && foldinfo.fi_lines > 0 + && vcol == 0 + && n_extra == 0 + && row == startrow) { + char_attr = win_hl_attr(wp, HLF_FL); + + linenr_T lnume = lnum + foldinfo.fi_lines - 1; + memset(buf_fold, ' ', FOLD_TEXT_LEN); + p_extra = get_foldtext(wp, lnum, lnume, foldinfo, buf_fold); + n_extra = STRLEN(p_extra); + + if (p_extra != buf_fold) { + xfree(p_extra_free); + p_extra_free = p_extra; + } + c_extra = NUL; + c_final = NUL; + p_extra[n_extra] = NUL; + } + + if (draw_state == WL_LINE + && foldinfo.fi_level != 0 + && foldinfo.fi_lines > 0 + && col < grid->Columns + && n_extra == 0 + && row == startrow) { + // fill rest of line with 'fold' + c_extra = wp->w_p_fcs_chars.fold; + c_final = NUL; + + n_extra = wp->w_p_rl ? (col + 1) : (grid->Columns - col); + } + if (draw_state == WL_LINE && (area_highlighting || has_spell)) { // handle Visual or match highlighting in this line if (vcol == fromcol @@ -3300,6 +3050,10 @@ win_line ( p_extra++; } n_extra--; + } else if (foldinfo.fi_lines > 0) { + // skip writing the buffer line itself + c = NUL; + XFREE_CLEAR(p_extra_free); } else { int c0; @@ -3868,7 +3622,7 @@ win_line ( // not showing the '>', put pointer back to avoid getting stuck ptr++; } - } + } // end of printing from buffer content /* In the cursor line and we may be concealing characters: correct * the cursor column when we reach its position. */ @@ -4178,11 +3932,10 @@ win_line ( if (wp == curwin && lnum == curwin->w_cursor.lnum) { curwin->w_cline_row = startrow; curwin->w_cline_height = row - startrow; - curwin->w_cline_folded = false; + curwin->w_cline_folded = foldinfo.fi_lines > 0; curwin->w_valid |= (VALID_CHEIGHT|VALID_CROW); conceal_cursor_used = conceal_cursor_line(curwin); } - break; } @@ -4371,6 +4124,7 @@ win_line ( * so far. If there is no more to display it is caught above. */ if ((wp->w_p_rl ? (col < 0) : (col >= grid->Columns)) + && foldinfo.fi_lines == 0 && (*ptr != NUL || filler_todo > 0 || (wp->w_p_list && wp->w_p_lcs_chars.eol != NUL diff --git a/src/nvim/spell.c b/src/nvim/spell.c index dc1bfe25b4..f036d7fe04 100644 --- a/src/nvim/spell.c +++ b/src/nvim/spell.c @@ -362,6 +362,8 @@ size_t spell_check( size_t wrongcaplen = 0; int lpi; bool count_word = docount; + bool use_camel_case = *wp->w_s->b_p_spo != NUL; + bool camel_case = false; // A word never starts at a space or a control character. Return quickly // then, skipping over the character. @@ -394,9 +396,24 @@ size_t spell_check( mi.mi_word = ptr; mi.mi_fend = ptr; if (spell_iswordp(mi.mi_fend, wp)) { + int prev_upper; + int this_upper; + + if (use_camel_case) { + c = PTR2CHAR(mi.mi_fend); + this_upper = SPELL_ISUPPER(c); + } + do { MB_PTR_ADV(mi.mi_fend); - } while (*mi.mi_fend != NUL && spell_iswordp(mi.mi_fend, wp)); + if (use_camel_case) { + prev_upper = this_upper; + c = PTR2CHAR(mi.mi_fend); + this_upper = SPELL_ISUPPER(c); + camel_case = !prev_upper && this_upper; + } + } while (*mi.mi_fend != NUL && spell_iswordp(mi.mi_fend, wp) + && !camel_case); if (capcol != NULL && *capcol == 0 && wp->w_s->b_cap_prog != NULL) { // Check word starting with capital letter. @@ -428,6 +445,11 @@ size_t spell_check( (void)spell_casefold(ptr, (int)(mi.mi_fend - ptr), mi.mi_fword, MAXWLEN + 1); mi.mi_fwordlen = (int)STRLEN(mi.mi_fword); + if (camel_case) { + // introduce a fake word end space into the folded word. + mi.mi_fword[mi.mi_fwordlen - 1] = ' '; + } + // The word is bad unless we recognize it. mi.mi_result = SP_BAD; mi.mi_result2 = SP_BAD; diff --git a/src/nvim/syntax.c b/src/nvim/syntax.c index 4aa7c21ce4..9a9cc45c6b 100644 --- a/src/nvim/syntax.c +++ b/src/nvim/syntax.c @@ -5588,9 +5588,11 @@ void ex_ownsyntax(exarg_T *eap) hash_init(&curwin->w_s->b_keywtab_ic); // TODO: Keep the spell checking as it was. NOLINT(readability/todo) curwin->w_p_spell = false; // No spell checking + // make sure option values are "empty_option" instead of NULL clear_string_option(&curwin->w_s->b_p_spc); clear_string_option(&curwin->w_s->b_p_spf); clear_string_option(&curwin->w_s->b_p_spl); + clear_string_option(&curwin->w_s->b_p_spo); clear_string_option(&curwin->w_s->b_syn_isk); } diff --git a/src/nvim/testdir/check.vim b/src/nvim/testdir/check.vim index 073873bcb0..e0ebe8fd49 100644 --- a/src/nvim/testdir/check.vim +++ b/src/nvim/testdir/check.vim @@ -65,3 +65,11 @@ func CheckCanRunGui() throw 'Skipped: cannot start the GUI' endif endfunc + +" Command to check that not currently using the GUI +command CheckNotGui call CheckNotGui() +func CheckNotGui() + if has('gui_running') + throw 'Skipped: only works in the terminal' + endif +endfunc diff --git a/src/nvim/testdir/test_autocmd.vim b/src/nvim/testdir/test_autocmd.vim index 3dd68873d4..094bb3ebd1 100644 --- a/src/nvim/testdir/test_autocmd.vim +++ b/src/nvim/testdir/test_autocmd.vim @@ -1,6 +1,8 @@ " Tests for autocommands source shared.vim +source check.vim +source term_util.vim func! s:cleanup_buffers() abort for bnr in range(1, bufnr('$')) @@ -1735,6 +1737,35 @@ func Test_throw_in_BufWritePre() au! throwing endfunc +func Test_autocmd_CmdWinEnter() + CheckRunVimInTerminal + " There is not cmdwin switch, so + " test for cmdline_hist + " (both are available with small builds) + CheckFeature cmdline_hist + let lines =<< trim END + let b:dummy_var = 'This is a dummy' + autocmd CmdWinEnter * quit + let winnr = winnr('$') + END + let filename='XCmdWinEnter' + call writefile(lines, filename) + let buf = RunVimInTerminal('-S '.filename, #{rows: 6}) + + call term_sendkeys(buf, "q:") + call term_wait(buf) + call term_sendkeys(buf, ":echo b:dummy_var\<cr>") + call WaitForAssert({-> assert_match('^This is a dummy', term_getline(buf, 6))}, 1000) + call term_sendkeys(buf, ":echo &buftype\<cr>") + call WaitForAssert({-> assert_notmatch('^nofile', term_getline(buf, 6))}, 1000) + call term_sendkeys(buf, ":echo winnr\<cr>") + call WaitForAssert({-> assert_match('^1', term_getline(buf, 6))}, 1000) + + " clean up + call StopVimInTerminal(buf) + call delete(filename) +endfunc + func Test_FileChangedShell_reload() if !has('unix') return diff --git a/src/nvim/testdir/test_edit.vim b/src/nvim/testdir/test_edit.vim index 12d5d9790e..7f456ffbce 100644 --- a/src/nvim/testdir/test_edit.vim +++ b/src/nvim/testdir/test_edit.vim @@ -1,9 +1,11 @@ " Test for edit functions -" + if exists("+t_kD") let &t_kD="[3;*~" endif +source check.vim + " Needed for testing basic rightleft: Test_edit_rightleft source view_util.vim @@ -733,17 +735,16 @@ func! Test_edit_CTRL_O() endfunc func! Test_edit_CTRL_R() - throw 'skipped: Nvim does not support test_override()' " Insert Register new - call test_override("ALL", 1) + " call test_override("ALL", 1) set showcmd call feedkeys("AFOOBAR eins zwei\<esc>", 'tnix') call feedkeys("O\<c-r>.", 'tnix') call feedkeys("O\<c-r>=10*500\<cr>\<esc>", 'tnix') call feedkeys("O\<c-r>=getreg('=', 1)\<cr>\<esc>", 'tnix') call assert_equal(["getreg('=', 1)", '5000', "FOOBAR eins zwei", "FOOBAR eins zwei"], getline(1, '$')) - call test_override("ALL", 0) + " call test_override("ALL", 0) set noshowcmd bw! endfunc @@ -955,7 +956,6 @@ func! Test_edit_DROP() endfunc func! Test_edit_CTRL_V() - throw 'skipped: Nvim does not support test_override()' if has("ebcdic") return endif @@ -965,7 +965,7 @@ func! Test_edit_CTRL_V() " force some redraws set showmode showcmd "call test_override_char_avail(1) - call test_override('ALL', 1) + " call test_override('ALL', 1) call feedkeys("A\<c-v>\<c-n>\<c-v>\<c-l>\<c-v>\<c-b>\<esc>", 'tnix') call assert_equal(["abc\x0e\x0c\x02"], getline(1, '$')) @@ -978,7 +978,7 @@ func! Test_edit_CTRL_V() set norl endif - call test_override('ALL', 0) + " call test_override('ALL', 0) set noshowmode showcmd bw! endfunc @@ -1514,3 +1514,23 @@ func Test_edit_startinsert() set backspace& bwipe! endfunc + +func Test_edit_noesckeys() + CheckNotGui + new + + " <Left> moves cursor when 'esckeys' is set + exe "set t_kl=\<Esc>OD" + " set esckeys + call feedkeys("axyz\<Esc>ODX", "xt") + " call assert_equal("xyXz", getline(1)) + + " <Left> exits Insert mode when 'esckeys' is off + " set noesckeys + call setline(1, '') + call feedkeys("axyz\<Esc>ODX", "xt") + call assert_equal(["DX", "xyz"], getline(1, 2)) + + bwipe! + " set esckeys +endfunc diff --git a/src/nvim/testdir/test_filetype.vim b/src/nvim/testdir/test_filetype.vim index 617e3dfe41..9f8939f2f6 100644 --- a/src/nvim/testdir/test_filetype.vim +++ b/src/nvim/testdir/test_filetype.vim @@ -326,7 +326,7 @@ let s:filename_checks = { \ 'pamconf': ['/etc/pam.conf'], \ 'pamenv': ['/etc/security/pam_env.conf', '/home/user/.pam_environment'], \ 'papp': ['file.papp', 'file.pxml', 'file.pxsl'], - \ 'pascal': ['file.pas', 'file.dpr'], + \ 'pascal': ['file.pas', 'file.pp', 'file.dpr', 'file.lpr'], \ 'passwd': ['any/etc/passwd', 'any/etc/passwd-', 'any/etc/passwd.edit', 'any/etc/shadow', 'any/etc/shadow-', 'any/etc/shadow.edit', 'any/var/backups/passwd.bak', 'any/var/backups/shadow.bak'], \ 'pccts': ['file.g'], \ 'pdf': ['file.pdf'], @@ -455,7 +455,7 @@ let s:filename_checks = { \ 'texmf': ['texmf.cnf'], \ 'text': ['file.text', 'README'], \ 'tf': ['file.tf', '.tfrc', 'tfrc'], - \ 'tidy': ['.tidyrc', 'tidyrc'], + \ 'tidy': ['.tidyrc', 'tidyrc', 'tidy.conf'], \ 'tilde': ['file.t.html'], \ 'tli': ['file.tli'], \ 'tmux': ['tmuxfile.conf', '.tmuxfile.conf'], diff --git a/src/nvim/testdir/test_functions.vim b/src/nvim/testdir/test_functions.vim index 6b45ac61d1..8fa70a5313 100644 --- a/src/nvim/testdir/test_functions.vim +++ b/src/nvim/testdir/test_functions.vim @@ -1221,6 +1221,24 @@ func Test_reg_executing_and_recording() unlet s:reg_stat endfunc +func Test_getchar() + call feedkeys('a', '') + call assert_equal(char2nr('a'), getchar()) + + " call test_setmouse(1, 3) + " let v:mouse_win = 9 + " let v:mouse_winid = 9 + " let v:mouse_lnum = 9 + " let v:mouse_col = 9 + " call feedkeys("\<S-LeftMouse>", '') + call nvim_input_mouse('left', 'press', 'S', 0, 0, 2) + call assert_equal("\<S-LeftMouse>", getchar()) + call assert_equal(1, v:mouse_win) + call assert_equal(win_getid(1), v:mouse_winid) + call assert_equal(1, v:mouse_lnum) + call assert_equal(3, v:mouse_col) +endfunc + func Test_libcall_libcallnr() if !has('libcall') return @@ -1341,3 +1359,22 @@ func Test_readdir() call delete('Xdir', 'rf') endfunc + +" Test for the eval() function +func Test_eval() + call assert_fails("call eval('5 a')", 'E488:') +endfunc + +" Test for the nr2char() function +func Test_nr2char() + " set encoding=latin1 + call assert_equal('@', nr2char(64)) + set encoding=utf8 + call assert_equal('a', nr2char(97, 1)) + call assert_equal('a', nr2char(97, 0)) + + call assert_equal("\x80\xfc\b\xf4\x80\xfeX\x80\xfeX\x80\xfeX", eval('"\<M-' .. nr2char(0x100000) .. '>"')) + call assert_equal("\x80\xfc\b\xfd\x80\xfeX\x80\xfeX\x80\xfeX\x80\xfeX\x80\xfeX", eval('"\<M-' .. nr2char(0x40000000) .. '>"')) +endfunc + +" vim: shiftwidth=2 sts=2 expandtab diff --git a/src/nvim/testdir/test_gf.vim b/src/nvim/testdir/test_gf.vim index 4a4ffcefa1..ee548037ba 100644 --- a/src/nvim/testdir/test_gf.vim +++ b/src/nvim/testdir/test_gf.vim @@ -1,3 +1,4 @@ +" Test for the gf and gF (goto file) commands " This is a test if a URL is recognized by "gf", with the cursor before and " after the "://". Also test ":\\". @@ -109,7 +110,7 @@ func Test_gf() endfunc func Test_gf_visual() - call writefile([], "Xtest_gf_visual") + call writefile(['one', 'two', 'three', 'four'], "Xtest_gf_visual") new call setline(1, 'XXXtest_gf_visualXXX') set hidden @@ -118,6 +119,30 @@ func Test_gf_visual() norm! ttvtXgf call assert_equal('Xtest_gf_visual', bufname('%')) + " if multiple lines are selected, then gf should fail + call setline(1, ["one", "two"]) + normal VGgf + call assert_equal('Xtest_gf_visual', @%) + + " following line number is used for gF + bwipe! + new + call setline(1, 'XXXtest_gf_visual:3XXX') + norm! 0ttvt:gF + call assert_equal('Xtest_gf_visual', bufname('%')) + call assert_equal(3, getcurpos()[1]) + + " line number in visual area is used for file name + if has('unix') + bwipe! + call writefile([], "Xtest_gf_visual:3") + new + call setline(1, 'XXXtest_gf_visual:3XXX') + norm! 0ttvtXgF + call assert_equal('Xtest_gf_visual:3', bufname('%')) + call delete('Xtest_gf_visual:3') + endif + bwipe! call delete('Xtest_gf_visual') set hidden& diff --git a/src/nvim/testdir/test_search.vim b/src/nvim/testdir/test_search.vim index e3a0fce5a6..211fc73562 100644 --- a/src/nvim/testdir/test_search.vim +++ b/src/nvim/testdir/test_search.vim @@ -708,6 +708,19 @@ func Test_incsearch_substitute_dump() call VerifyScreenDump(buf, 'Test_incsearch_substitute_12', {}) call term_sendkeys(buf, "\<Esc>") call VerifyScreenDump(buf, 'Test_incsearch_substitute_13', {}) + call term_sendkeys(buf, ":%bwipe!\<CR>") + call term_sendkeys(buf, ":only!\<CR>") + + " get :'<,'>s command in history + call term_sendkeys(buf, ":set cmdheight=2\<CR>") + call term_sendkeys(buf, "aasdfasdf\<Esc>") + call term_sendkeys(buf, "V:s/a/b/g\<CR>") + " Using '<,'> does not give E20 + call term_sendkeys(buf, ":new\<CR>") + call term_sendkeys(buf, "aasdfasdf\<Esc>") + call term_sendkeys(buf, ":\<Up>\<Up>") + call VerifyScreenDump(buf, 'Test_incsearch_substitute_14', {}) + call term_sendkeys(buf, "<Esc>") call StopVimInTerminal(buf) call delete('Xis_subst_script') @@ -730,11 +743,14 @@ func Test_incsearch_sort_dump() " the 'ambiwidth' check. sleep 100m - " Need to send one key at a time to force a redraw. call term_sendkeys(buf, ':sort ni u /on') call VerifyScreenDump(buf, 'Test_incsearch_sort_01', {}) call term_sendkeys(buf, "\<Esc>") + call term_sendkeys(buf, ':sort! /on') + call VerifyScreenDump(buf, 'Test_incsearch_sort_02', {}) + call term_sendkeys(buf, "\<Esc>") + call StopVimInTerminal(buf) call delete('Xis_sort_script') endfunc diff --git a/src/nvim/testdir/test_spell.vim b/src/nvim/testdir/test_spell.vim index 414c7278eb..64e030426d 100644 --- a/src/nvim/testdir/test_spell.vim +++ b/src/nvim/testdir/test_spell.vim @@ -79,6 +79,11 @@ func Test_spellbadword() call assert_equal(['bycycle', 'bad'], spellbadword('My bycycle.')) call assert_equal(['another', 'caps'], spellbadword('A sentence. another sentence')) + call assert_equal(['TheCamelWord', 'bad'], spellbadword('TheCamelWord asdf')) + set spelloptions=camel + call assert_equal(['asdf', 'bad'], spellbadword('TheCamelWord asdf')) + set spelloptions= + set spelllang=en call assert_equal(['', ''], spellbadword('centre')) call assert_equal(['', ''], spellbadword('center')) diff --git a/src/nvim/testdir/test_syntax.vim b/src/nvim/testdir/test_syntax.vim index 85ee42420e..2404f113d9 100644 --- a/src/nvim/testdir/test_syntax.vim +++ b/src/nvim/testdir/test_syntax.vim @@ -369,7 +369,11 @@ func Test_ownsyntax() call setline(1, '#define FOO') syntax on set filetype=c + ownsyntax perl + " this should not crash + set + call assert_equal('perlComment', synIDattr(synID(line('.'), col('.'), 1), 'name')) call assert_equal('c', b:current_syntax) call assert_equal('perl', w:current_syntax) diff --git a/src/nvim/testdir/test_timers.vim b/src/nvim/testdir/test_timers.vim index cffd80ff4f..d5ea54b764 100644 --- a/src/nvim/testdir/test_timers.vim +++ b/src/nvim/testdir/test_timers.vim @@ -233,16 +233,17 @@ func Test_timer_catch_error() endfunc func FeedAndPeek(timer) - call test_feedinput('a') + " call test_feedinput('a') + call nvim_input('a') call getchar(1) endfunc func Interrupt(timer) - call test_feedinput("\<C-C>") + " call test_feedinput("\<C-C>") + call nvim_input("\<C-C>") endfunc func Test_peek_and_get_char() - throw 'skipped: Nvim does not support test_feedinput()' if !has('unix') && !has('gui_running') return endif diff --git a/src/nvim/window.c b/src/nvim/window.c index cec0dfd67f..6608deb231 100644 --- a/src/nvim/window.c +++ b/src/nvim/window.c @@ -6019,6 +6019,12 @@ char_u *grab_file_name(long count, linenr_T *file_lnum) char_u *ptr; if (get_visual_text(NULL, &ptr, &len) == FAIL) return NULL; + // Only recognize ":123" here + if (file_lnum != NULL && ptr[len] == ':' && isdigit(ptr[len + 1])) { + char_u *p = ptr + len + 1; + + *file_lnum = getdigits_long(&p, false, 0); + } return find_file_name_in_path(ptr, len, options, count, curbuf->b_ffname); } return file_name_at_cursor(options | FNAME_HYP, count, file_lnum); |