diff options
Diffstat (limited to 'src')
80 files changed, 3303 insertions, 2134 deletions
diff --git a/src/nvim/CMakeLists.txt b/src/nvim/CMakeLists.txt index a473f99278..0711642868 100644 --- a/src/nvim/CMakeLists.txt +++ b/src/nvim/CMakeLists.txt @@ -87,7 +87,6 @@ set(CONV_SOURCES ex_docmd.c ex_getln.c fileio.c - getchar.c mbyte.c memline.c message.c diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index 10110b0f62..46ac3c9022 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -116,8 +116,14 @@ String vim_replace_termcodes(String str, Boolean from_part, Boolean do_lt, } char *ptr = NULL; - replace_termcodes((char_u *)str.data, (char_u **)&ptr, - from_part, do_lt, special); + // Set 'cpoptions' the way we want it. + // FLAG_CPO_BSLASH set - backslashes are *not* treated specially + // FLAG_CPO_KEYCODE set - keycodes are *not* reverse-engineered + // FLAG_CPO_SPECI unset - <Key> sequences *are* interpreted + // The third from end parameter of replace_termcodes() is true so that the + // <lt> sequence is recognised - needed for a real backslash. + replace_termcodes((char_u *)str.data, str.size, (char_u **)&ptr, + from_part, do_lt, special, CPO_TO_CPO_FLAGS); return cstr_as_string(ptr); } @@ -291,7 +297,7 @@ void vim_change_directory(String dir, Error *err) return; } - post_chdir(false); + post_chdir(kCdScopeGlobal); try_end(err); } diff --git a/src/nvim/api/window.c b/src/nvim/api/window.c index a52f53a3e6..f644453358 100644 --- a/src/nvim/api/window.c +++ b/src/nvim/api/window.c @@ -57,8 +57,8 @@ void window_set_cursor(Window window, ArrayOf(Integer, 2) pos, Error *err) { win_T *win = find_window_by_handle(window, err); - if (pos.size != 2 || pos.items[0].type != kObjectTypeInteger || - pos.items[1].type != kObjectTypeInteger) { + if (pos.size != 2 || pos.items[0].type != kObjectTypeInteger + || pos.items[1].type != kObjectTypeInteger) { api_set_error(err, Validation, _("Argument \"pos\" must be a [row, col] array")); diff --git a/src/nvim/arabic.c b/src/nvim/arabic.c index b432e12c02..db97bd9dc4 100644 --- a/src/nvim/arabic.c +++ b/src/nvim/arabic.c @@ -1367,8 +1367,8 @@ int arabic_shape(int c, int *ccp, int *c1p, int prev_c, int prev_c1, int prev_laa = A_firstc_laa(prev_c, prev_c1); if (curr_laa) { - if (A_is_valid(prev_c) && !A_is_f(shape_c) && !A_is_s(shape_c) && - !prev_laa) { + if (A_is_valid(prev_c) && !A_is_f(shape_c) && !A_is_s(shape_c) + && !prev_laa) { curr_c = chg_c_laa2f(curr_laa); } else { curr_c = chg_c_laa2i(curr_laa); @@ -1454,19 +1454,19 @@ static bool A_is_harakat(int c) // (alphabet/number/punctuation) static bool A_is_iso(int c) { - return (c >= a_HAMZA && c <= a_GHAIN) || - (c >= a_TATWEEL && c <= a_HAMZA_BELOW) || - c == a_MINI_ALEF; + return ((c >= a_HAMZA && c <= a_GHAIN) + || (c >= a_TATWEEL && c <= a_HAMZA_BELOW) + || c == a_MINI_ALEF); } // A_is_formb returns true if 'c' is an Arabic 10646-1 FormB character. // (alphabet/number/punctuation) static bool A_is_formb(int c) { - return (c >= a_s_FATHATAN && c <= a_s_DAMMATAN) || - c == a_s_KASRATAN || - (c >= a_s_FATHA && c <= a_f_LAM_ALEF) || - c == a_BYTE_ORDER_MARK; + return ((c >= a_s_FATHATAN && c <= a_s_DAMMATAN) + || c == a_s_KASRATAN + || (c >= a_s_FATHA && c <= a_f_LAM_ALEF) + || c == a_BYTE_ORDER_MARK); } // A_is_ok returns true if 'c' is an Arabic 10646 (8859-6 or Form-B). diff --git a/src/nvim/assert.h b/src/nvim/assert.h index 0ce48e4766..2c43777858 100644 --- a/src/nvim/assert.h +++ b/src/nvim/assert.h @@ -46,10 +46,10 @@ #define STATIC_ASSERT_PRAGMA_START #define STATIC_ASSERT_PRAGMA_END -#define STATIC_ASSERT(...) \ +#define STATIC_ASSERT(cond, msg) \ do { \ STATIC_ASSERT_PRAGMA_START \ - STATIC_ASSERT_STATEMENT(__VA_ARGS__); \ + STATIC_ASSERT_STATEMENT(cond, msg); \ STATIC_ASSERT_PRAGMA_END \ } while (0) diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c index c514c4378e..72716daf0e 100644 --- a/src/nvim/buffer.c +++ b/src/nvim/buffer.c @@ -407,10 +407,9 @@ close_buffer ( buf->b_nwindows = nwindows; buf_freeall(buf, (del_buf ? BFA_DEL : 0) + (wipe_buf ? BFA_WIPE : 0)); - if ( - win_valid(win) && - win->w_buffer == buf) - win->w_buffer = NULL; /* make sure we don't use the buffer now */ + if (win_valid(win) && win->w_buffer == buf) { + win->w_buffer = NULL; // make sure we don't use the buffer now + } /* Autocommands may have deleted the buffer. */ if (!buf_valid(buf)) @@ -1294,14 +1293,15 @@ void enter_buffer(buf_T *buf) redraw_later(NOT_VALID); } -/* - * Change to the directory of the current buffer. - */ +// Change to the directory of the current buffer. +// Don't do this while still starting up. void do_autochdir(void) { if (p_acd) { - if (curbuf->b_ffname != NULL && vim_chdirfile(curbuf->b_ffname) == OK) { - shorten_fnames(TRUE); + if (starting == 0 + && curbuf->b_ffname != NULL + && vim_chdirfile(curbuf->b_ffname) == OK) { + shorten_fnames(true); } } } @@ -1339,8 +1339,8 @@ buflist_new ( /* We can use inode numbers when the file exists. Works better * for hard links. */ FileID file_id; - bool file_id_valid = (sfname != NULL && - os_fileid((char *)sfname, &file_id)); + bool file_id_valid = (sfname != NULL + && os_fileid((char *)sfname, &file_id)); if (ffname != NULL && !(flags & BLN_DUMMY) && (buf = buflist_findname_file_id(ffname, &file_id, file_id_valid)) != NULL) { @@ -1553,6 +1553,7 @@ void free_buf_options(buf_T *buf, int free_p_ff) clear_string_option(&buf->b_p_ep); clear_string_option(&buf->b_p_path); clear_string_option(&buf->b_p_tags); + clear_string_option(&buf->b_p_tc); clear_string_option(&buf->b_p_dict); clear_string_option(&buf->b_p_tsr); clear_string_option(&buf->b_p_qe); @@ -2194,15 +2195,16 @@ void buflist_list(exarg_T *eap) len = vim_snprintf((char *)IObuff, IOSIZE - 20, "%3d%c%c%c%c%c \"%s\"", buf->b_fnum, buf->b_p_bl ? ' ' : 'u', - buf == curbuf ? '%' : - (curwin->w_alt_fnum == buf->b_fnum ? '#' : ' '), - buf->b_ml.ml_mfp == NULL ? ' ' : - (buf->b_nwindows == 0 ? 'h' : 'a'), + buf == curbuf ? '%' : (curwin->w_alt_fnum == buf->b_fnum ? '#' : ' '), + buf->b_ml.ml_mfp == NULL ? ' ' : (buf->b_nwindows == 0 ? 'h' : 'a'), !MODIFIABLE(buf) ? '-' : (buf->b_p_ro ? '=' : ' '), - (buf->b_flags & BF_READERR) ? 'x' - : (bufIsChanged(buf) ? '+' : ' '), + (buf->b_flags & BF_READERR) ? 'x' : (bufIsChanged(buf) ? '+' : ' '), NameBuff); + if (len > IOSIZE - 20) { + len = IOSIZE - 20; + } + /* put "line 999" in column 40 or after the file name */ i = 40 - vim_strsize(IObuff); do { diff --git a/src/nvim/buffer_defs.h b/src/nvim/buffer_defs.h index 86e63eb52c..0324f6b88a 100644 --- a/src/nvim/buffer_defs.h +++ b/src/nvim/buffer_defs.h @@ -141,8 +141,8 @@ struct buffblock { struct buffheader { buffblock_T bh_first; // first (dummy) block of list buffblock_T *bh_curr; // buffblock for appending - int bh_index; // index for reading - int bh_space; // space in bh_curr for appending + size_t bh_index; // index for reading + size_t bh_space; // space in bh_curr for appending }; /* @@ -666,19 +666,21 @@ struct file_buffer { long b_p_wm_nopaste; ///< b_p_wm saved for paste mode char_u *b_p_keymap; ///< 'keymap' - /* local values for options which are normally global */ - char_u *b_p_gp; /* 'grepprg' local value */ - char_u *b_p_mp; /* 'makeprg' local value */ - char_u *b_p_efm; /* 'errorformat' local value */ - char_u *b_p_ep; /* 'equalprg' local value */ - char_u *b_p_path; /* 'path' local value */ - int b_p_ar; /* 'autoread' local value */ - char_u *b_p_tags; /* 'tags' local value */ - char_u *b_p_dict; /* 'dictionary' local value */ - char_u *b_p_tsr; /* 'thesaurus' local value */ - long b_p_ul; /* 'undolevels' local value */ - int b_p_udf; /* 'undofile' */ - char_u *b_p_lw; // 'lispwords' local value + // local values for options which are normally global + char_u *b_p_gp; ///< 'grepprg' local value + char_u *b_p_mp; ///< 'makeprg' local value + char_u *b_p_efm; ///< 'errorformat' local value + char_u *b_p_ep; ///< 'equalprg' local value + char_u *b_p_path; ///< 'path' local value + int b_p_ar; ///< 'autoread' local value + char_u *b_p_tags; ///< 'tags' local value + char_u *b_p_tc; ///< 'tagcase' local value + unsigned b_tc_flags; ///< flags for 'tagcase' + char_u *b_p_dict; ///< 'dictionary' local value + char_u *b_p_tsr; ///< 'thesaurus' local value + long b_p_ul; ///< 'undolevels' local value + int b_p_udf; ///< 'undofile' + char_u *b_p_lw; ///< 'lispwords' local value /* end of buffer options */ @@ -816,10 +818,12 @@ struct tabpage_S { was set */ diff_T *tp_first_diff; buf_T *(tp_diffbuf[DB_COUNT]); - int tp_diff_invalid; /* list of diffs is outdated */ - frame_T *(tp_snapshot[SNAP_COUNT]); /* window layout snapshots */ - dictitem_T tp_winvar; /* variable for "t:" Dictionary */ - dict_T *tp_vars; /* internal variables, local to tab page */ + int tp_diff_invalid; ///< list of diffs is outdated */ + frame_T *(tp_snapshot[SNAP_COUNT]); ///< window layout snapshots + dictitem_T tp_winvar; ///< variable for "t:" Dictionary + dict_T *tp_vars; ///< internal variables, local to tab page + char_u *localdir; ///< Absolute path of local directory or + ///< NULL }; /* @@ -953,16 +957,14 @@ struct window_S { time through cursupdate() to the current virtual column */ - /* - * the next six are used to update the visual part - */ - char w_old_visual_mode; /* last known VIsual_mode */ - linenr_T w_old_cursor_lnum; /* last known end of visual part */ - colnr_T w_old_cursor_fcol; /* first column for block visual part */ - colnr_T w_old_cursor_lcol; /* last column for block visual part */ - linenr_T w_old_visual_lnum; /* last known start of visual part */ - colnr_T w_old_visual_col; /* last known start of visual part */ - colnr_T w_old_curswant; /* last known value of Curswant */ + // the next seven are used to update the visual part + char w_old_visual_mode; ///< last known VIsual_mode + linenr_T w_old_cursor_lnum; ///< last known end of visual part + colnr_T w_old_cursor_fcol; ///< first column for block visual part + colnr_T w_old_cursor_lcol; ///< last column for block visual part + linenr_T w_old_visual_lnum; ///< last known start of visual part + colnr_T w_old_visual_col; ///< last known start of visual part + colnr_T w_old_curswant; ///< last known value of Curswant /* * "w_topline", "w_leftcol" and "w_skipcol" specify the offsets for diff --git a/src/nvim/charset.c b/src/nvim/charset.c index 83e2aaa6e6..d0dc7b66fc 100644 --- a/src/nvim/charset.c +++ b/src/nvim/charset.c @@ -1794,10 +1794,11 @@ bool vim_isblankline(char_u *lbuf) /// @param nptr Returns the signed result. /// @param unptr Returns the unsigned result. /// @param maxlen Max length of string to check. -void vim_str2nr(char_u *start, int *prep, int *len, int what, - long *nptr, unsigned long *unptr, int maxlen) +void vim_str2nr(const char_u *const start, int *const prep, int *const len, + const int what, long *const nptr, unsigned long *const unptr, + const int maxlen) { - char_u *ptr = start; + const char_u *ptr = start; int pre = 0; // default is decimal bool negative = false; unsigned long un = 0; diff --git a/src/nvim/diff.c b/src/nvim/diff.c index a3063de869..4826e70727 100644 --- a/src/nvim/diff.c +++ b/src/nvim/diff.c @@ -29,7 +29,6 @@ #include "nvim/path.h" #include "nvim/screen.h" #include "nvim/strings.h" -#include "nvim/tempfile.h" #include "nvim/undo.h" #include "nvim/window.h" #include "nvim/os/os.h" diff --git a/src/nvim/edit.c b/src/nvim/edit.c index 3a4b475bc8..e131da8fe0 100644 --- a/src/nvim/edit.c +++ b/src/nvim/edit.c @@ -1359,6 +1359,9 @@ ins_redraw ( update_screen(0); } if (has_event(EVENT_CURSORMOVEDI)) { + // Make sure curswant is correct, an autocommand may call + // getcurpos() + update_curswant(); apply_autocmds(EVENT_CURSORMOVEDI, NULL, NULL, false, curbuf); } if (curwin->w_p_cole > 0) { @@ -2319,6 +2322,22 @@ static int ins_compl_make_cyclic(void) return count; } + +// Set variables that store noselect and noinsert behavior from the +// 'completeopt' value. +void completeopt_was_set(void) +{ + compl_no_insert = false; + compl_no_select = false; + if (strstr((char *)p_cot, "noselect") != NULL) { + compl_no_select = true; + } + if (strstr((char *)p_cot, "noinsert") != NULL) { + compl_no_insert = true; + } +} + + /* * Start completion for the complete() function. * "startcol" is where the matched text starts (1 is first column). @@ -3097,17 +3116,6 @@ static bool ins_compl_prep(int c) } - if (strstr((char *)p_cot, "noselect") != NULL) { - compl_no_insert = FALSE; - compl_no_select = TRUE; - } else if (strstr((char *)p_cot, "noinsert") != NULL) { - compl_no_insert = TRUE; - compl_no_select = FALSE; - } else { - compl_no_insert = FALSE; - compl_no_select = FALSE; - } - if (ctrl_x_mode == CTRL_X_NOT_DEFINED_YET) { /* * We have just typed CTRL-X and aren't quite sure which CTRL-X mode @@ -3298,6 +3306,12 @@ static bool ins_compl_prep(int c) showmode(); } + // Avoid the popup menu remains displayed when leaving the + // command line window. + if (c == Ctrl_C && cmdwin_type != 0) { + update_screen(0); + } + /* * Indent now if a key was typed that is in 'cinkeys'. */ @@ -4416,11 +4430,10 @@ static int ins_complete(int c, bool enable_pum) prefix = (char_u *)""; STRCPY((char *)compl_pattern, prefix); (void)quote_meta(compl_pattern + STRLEN(prefix), - line + compl_col, compl_length); - } else if (--startcol < 0 || - !vim_iswordp(mb_prevptr(line, line + startcol + 1)) - ) { - /* Match any word of at least two chars */ + line + compl_col, compl_length); + } else if (--startcol < 0 + || !vim_iswordp(mb_prevptr(line, line + startcol + 1))) { + // Match any word of at least two chars compl_pattern = vim_strsave((char_u *)"\\<\\k\\k"); compl_col += curs_col; compl_length = 0; @@ -6676,8 +6689,8 @@ bool in_cinkeys(int keytyped, int when, bool line_is_empty) } else if (*look == 'e') { if (try_match && keytyped == 'e' && curwin->w_cursor.col >= 4) { p = get_cursor_line_ptr(); - if (skipwhite(p) == p + curwin->w_cursor.col - 4 && - STRNCMP(p + curwin->w_cursor.col - 4, "else", 4) == 0) { + if (skipwhite(p) == p + curwin->w_cursor.col - 4 + && STRNCMP(p + curwin->w_cursor.col - 4, "else", 4) == 0) { return true; } } @@ -7376,17 +7389,16 @@ static bool ins_bs(int c, int mode, int *inserted_space_p) * can't backup past starting point unless 'backspace' > 1 * can backup to a previous line if 'backspace' == 0 */ - if ( bufempty() - || ( - !revins_on && - ((curwin->w_cursor.lnum == 1 && curwin->w_cursor.col == 0) - || (!can_bs(BS_START) - && (arrow_used - || (curwin->w_cursor.lnum == Insstart_orig.lnum - && curwin->w_cursor.col <= Insstart_orig.col))) - || (!can_bs(BS_INDENT) && !arrow_used && ai_col > 0 - && curwin->w_cursor.col <= ai_col) - || (!can_bs(BS_EOL) && curwin->w_cursor.col == 0)))) { + if (bufempty() + || (!revins_on + && ((curwin->w_cursor.lnum == 1 && curwin->w_cursor.col == 0) + || (!can_bs(BS_START) + && (arrow_used + || (curwin->w_cursor.lnum == Insstart_orig.lnum + && curwin->w_cursor.col <= Insstart_orig.col))) + || (!can_bs(BS_INDENT) && !arrow_used && ai_col > 0 + && curwin->w_cursor.col <= ai_col) + || (!can_bs(BS_EOL) && curwin->w_cursor.col == 0)))) { vim_beep(BO_BS); return false; } @@ -7632,14 +7644,14 @@ static bool ins_bs(int c, int mode, int *inserted_space_p) if (revins_on && gchar_cursor() == NUL) break; } - /* Just a single backspace?: */ - if (mode == BACKSPACE_CHAR) + // Just a single backspace?: + if (mode == BACKSPACE_CHAR) { break; - } while ( - revins_on || - (curwin->w_cursor.col > mincol - && (curwin->w_cursor.lnum != Insstart_orig.lnum - || curwin->w_cursor.col != Insstart_orig.col))); + } + } while (revins_on + || (curwin->w_cursor.col > mincol + && (curwin->w_cursor.lnum != Insstart_orig.lnum + || curwin->w_cursor.col != Insstart_orig.col))); } did_backspace = true; } @@ -7741,6 +7753,8 @@ static void ins_mousescroll(int dir) (long)(curwin->w_botline - curwin->w_topline)); else scroll_redraw(dir, 3L); + } else { + mouse_scroll_horiz(dir); } did_scroll = TRUE; } diff --git a/src/nvim/edit.h b/src/nvim/edit.h index 0289b2c3a6..0d61f26bcc 100644 --- a/src/nvim/edit.h +++ b/src/nvim/edit.h @@ -36,12 +36,6 @@ typedef int (*IndentGetter)(void); #define INSCHAR_NO_FEX 8 /* don't use 'formatexpr' */ #define INSCHAR_COM_LIST 16 /* format comments with list/2nd line indent */ -/* direction for nv_mousescroll() and ins_mousescroll() */ -#define MSCR_DOWN 0 /* DOWN must be FALSE */ -#define MSCR_UP 1 -#define MSCR_LEFT -1 -#define MSCR_RIGHT -2 - #ifdef INCLUDE_GENERATED_DECLARATIONS # include "edit.h.generated.h" #endif diff --git a/src/nvim/eval.c b/src/nvim/eval.c index b51480afc6..d84bdfebfe 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -66,7 +66,6 @@ #include "nvim/strings.h" #include "nvim/syntax.h" #include "nvim/tag.h" -#include "nvim/tempfile.h" #include "nvim/ui.h" #include "nvim/mouse.h" #include "nvim/terminal.h" @@ -2267,8 +2266,8 @@ static void set_var_lval(lval_T *lp, char_u *endp, typval_T *rettv, int copy, ch if (get_var_tv(lp->ll_name, (int)STRLEN(lp->ll_name), &tv, &di, true, false) == OK) { if ((di == NULL - || (!var_check_ro(di->di_flags, lp->ll_name, false) && - !tv_check_lock(di->di_tv.v_lock, lp->ll_name, false))) + || (!var_check_ro(di->di_flags, lp->ll_name, false) + && !tv_check_lock(di->di_tv.v_lock, lp->ll_name, false))) && tv_op(&tv, rettv, op) == OK) { set_var(lp->ll_name, &tv, false); } @@ -4741,13 +4740,14 @@ static int get_string_tv(char_u **arg, typval_T *rettv, int evaluate) ++name; break; - /* Special key, e.g.: "\<C-W>" */ - case '<': extra = trans_special(&p, name, TRUE); + // Special key, e.g.: "\<C-W>" + case '<': + extra = trans_special((const char_u **) &p, STRLEN(p), name, true); if (extra != 0) { name += extra; break; } - /* FALLTHROUGH */ + // FALLTHROUGH default: MB_COPY_CHAR(p, name); break; @@ -6656,7 +6656,7 @@ static struct fst { } functions[] = { { "abs", 1, 1, f_abs }, - { "acos", 1, 1, f_acos }, // WJMc + { "acos", 1, 1, f_acos }, // WJMc { "add", 2, 2, f_add }, { "and", 2, 2, f_and }, { "append", 2, 2, f_append }, @@ -6666,6 +6666,7 @@ static struct fst { { "argv", 0, 1, f_argv }, { "asin", 1, 1, f_asin }, // WJMc { "assert_equal", 2, 3, f_assert_equal }, + { "assert_exception", 1, 2, f_assert_exception }, { "assert_false", 1, 2, f_assert_false }, { "assert_true", 1, 2, f_assert_true }, { "atan", 1, 1, f_atan }, @@ -6673,9 +6674,9 @@ static struct fst { { "browse", 4, 4, f_browse }, { "browsedir", 2, 2, f_browsedir }, { "bufexists", 1, 1, f_bufexists }, - { "buffer_exists", 1, 1, f_bufexists }, // obsolete - { "buffer_name", 1, 1, f_bufname }, // obsolete - { "buffer_number", 1, 1, f_bufnr }, // obsolete + { "buffer_exists", 1, 1, f_bufexists }, // obsolete + { "buffer_name", 1, 1, f_bufname }, // obsolete + { "buffer_number", 1, 1, f_bufnr }, // obsolete { "buflisted", 1, 1, f_buflisted }, { "bufloaded", 1, 1, f_bufloaded }, { "bufname", 1, 1, f_bufname }, @@ -6702,7 +6703,7 @@ static struct fst { { "cscope_connection", 0, 3, f_cscope_connection }, { "cursor", 1, 3, f_cursor }, { "deepcopy", 1, 2, f_deepcopy }, - { "delete", 1, 1, f_delete }, + { "delete", 1, 2, f_delete }, { "dictwatcheradd", 3, 3, f_dictwatcheradd }, { "dictwatcherdel", 3, 3, f_dictwatcherdel }, { "did_filetype", 0, 0, f_did_filetype }, @@ -6719,7 +6720,7 @@ static struct fst { { "expand", 1, 3, f_expand }, { "extend", 2, 3, f_extend }, { "feedkeys", 1, 2, f_feedkeys }, - { "file_readable", 1, 1, f_filereadable }, // obsolete + { "file_readable", 1, 1, f_filereadable }, // obsolete { "filereadable", 1, 1, f_filereadable }, { "filewritable", 1, 1, f_filewritable }, { "filter", 2, 2, f_filter }, @@ -6749,7 +6750,7 @@ static struct fst { { "getcmdtype", 0, 0, f_getcmdtype }, { "getcmdwintype", 0, 0, f_getcmdwintype }, { "getcurpos", 0, 0, f_getcurpos }, - { "getcwd", 0, 0, f_getcwd }, + { "getcwd", 0, 2, f_getcwd }, { "getfontname", 0, 1, f_getfontname }, { "getfperm", 1, 1, f_getfperm }, { "getfsize", 1, 1, f_getfsize }, @@ -6773,7 +6774,7 @@ static struct fst { { "globpath", 2, 5, f_globpath }, { "has", 1, 1, f_has }, { "has_key", 2, 2, f_has_key }, - { "haslocaldir", 0, 0, f_haslocaldir }, + { "haslocaldir", 0, 2, f_haslocaldir }, { "hasmapto", 1, 3, f_hasmapto }, { "highlightID", 1, 1, f_hlID }, // obsolete { "highlight_exists", 1, 1, f_hlexists }, // obsolete @@ -7628,14 +7629,35 @@ static void f_assert_equal(typval_T *argvars, typval_T *rettv) } } +/// "assert_exception(string[, msg])" function +static void f_assert_exception(typval_T *argvars, typval_T *rettv) +{ + garray_T ga; + + char *error = (char *)get_tv_string_chk(&argvars[0]); + if (vimvars[VV_EXCEPTION].vv_str == NULL) { + prepare_assert_error(&ga); + ga_concat(&ga, (char_u *)"v:exception is not set"); + assert_error(&ga); + ga_clear(&ga); + } else if (strstr((char *)vimvars[VV_EXCEPTION].vv_str, error) == NULL) { + prepare_assert_error(&ga); + fill_assert_error(&ga, &argvars[1], NULL, &argvars[0], + &vimvars[VV_EXCEPTION].vv_tv); + assert_error(&ga); + ga_clear(&ga); + } +} + // Common for assert_true() and assert_false(). static void assert_bool(typval_T *argvars, bool is_true) { int error = (int)false; garray_T ga; - if ((argvars[0].v_type != VAR_NUMBER || - (get_tv_number_chk(&argvars[0], &error) == 0) == is_true || error) + if ((argvars[0].v_type != VAR_NUMBER + || (get_tv_number_chk(&argvars[0], &error) == 0) == is_true + || error) && (argvars[0].v_type != VAR_SPECIAL || (argvars[0].vval.v_special != (SpecialVarValue) (is_true @@ -8305,12 +8327,12 @@ static void f_cscope_connection(typval_T *argvars, typval_T *rettv) rettv->vval.v_number = cs_connection(num, dbpath, prepend); } -/* - * "cursor(lnum, col)" function - * - * Moves the cursor to the specified line and column. - * Returns 0 when the position could be set, -1 otherwise. - */ +/// "cursor(lnum, col)" function, or +/// "cursor(list)" +/// +/// Moves the cursor to the specified line and column. +/// +/// @returns 0 when the position could be set, -1 otherwise. static void f_cursor(typval_T *argvars, typval_T *rettv) { long line, col; @@ -8322,8 +8344,10 @@ static void f_cursor(typval_T *argvars, typval_T *rettv) colnr_T curswant = -1; if (list2fpos(argvars, &pos, NULL, &curswant) == FAIL) { + EMSG(_(e_invarg)); return; } + line = pos.lnum; col = pos.col; coladd = pos.coladd; @@ -8374,15 +8398,42 @@ static void f_deepcopy(typval_T *argvars, typval_T *rettv) } } -/* - * "delete()" function - */ +// "delete()" function static void f_delete(typval_T *argvars, typval_T *rettv) { - if (check_restricted() || check_secure()) - rettv->vval.v_number = -1; - else - rettv->vval.v_number = os_remove((char *)get_tv_string(&argvars[0])); + char_u nbuf[NUMBUFLEN]; + char_u *name; + char_u *flags; + + rettv->vval.v_number = -1; + if (check_restricted() || check_secure()) { + return; + } + + name = get_tv_string(&argvars[0]); + if (name == NULL || *name == NUL) { + EMSG(_(e_invarg)); + return; + } + + if (argvars[1].v_type != VAR_UNKNOWN) { + flags = get_tv_string_buf(&argvars[1], nbuf); + } else { + flags = (char_u *)""; + } + + if (*flags == NUL) { + // delete a file + rettv->vval.v_number = os_remove((char *)name) == 0 ? 0 : -1; + } else if (STRCMP(flags, "d") == 0) { + // delete an empty directory + rettv->vval.v_number = os_rmdir((char *)name) == 0 ? 0 : -1; + } else if (STRCMP(flags, "rf") == 0) { + // delete a directory recursively + rettv->vval.v_number = delete_recursive(name); + } else { + EMSG2(_(e_invexpr2), flags); + } } // dictwatcheradd(dict, key, funcref) function @@ -8641,7 +8692,11 @@ static void f_eventhandler(typval_T *argvars, typval_T *rettv) */ static void f_executable(typval_T *argvars, typval_T *rettv) { - rettv->vval.v_number = os_can_exe(get_tv_string(&argvars[0]), NULL); + char_u *name = get_tv_string(&argvars[0]); + + // Check in $PATH and also check directly if there is a directory name + rettv->vval.v_number = os_can_exe(name, NULL, true) + || (gettail_dir(name) != name && os_can_exe(name, NULL, false)); } /// "exepath()" function @@ -8650,7 +8705,7 @@ static void f_exepath(typval_T *argvars, typval_T *rettv) char_u *arg = get_tv_string(&argvars[0]); char_u *path = NULL; - (void)os_can_exe(arg, &path); + (void)os_can_exe(arg, &path, true); rettv->v_type = VAR_STRING; rettv->vval.v_string = path; @@ -9758,22 +9813,130 @@ static void f_getcmdwintype(typval_T *argvars, typval_T *rettv) rettv->vval.v_string[0] = cmdwin_type; } -/* - * "getcwd()" function - */ +/// `getcwd([{win}[, {tab}]])` function +/// +/// Every scope not specified implies the currently selected scope object. +/// +/// @pre The arguments must be of type number. +/// @pre There may not be more than two arguments. +/// @pre An argument may not be -1 if preceding arguments are not all -1. +/// +/// @post The return value will be a string. static void f_getcwd(typval_T *argvars, typval_T *rettv) { - char_u *cwd; + // Possible scope of working directory to return. + CdScope scope = MIN_CD_SCOPE; + + // Numbers of the scope objects (window, tab) we want the working directory + // of. A `-1` means to skip this scope, a `0` means the current object. + int scope_number[] = { + [kCdScopeWindow] = 0, // Number of window to look at. + [kCdScopeTab ] = 0, // Number of tab to look at. + }; + + char_u *cwd = NULL; // Current working directory to print + char_u *from = NULL; // The original string to copy + + tabpage_T *tp = curtab; // The tabpage to look at. + win_T *win = curwin; // The window to look at. rettv->v_type = VAR_STRING; rettv->vval.v_string = NULL; + + // Pre-conditions and scope extraction together + for (int i = MIN_CD_SCOPE; i < MAX_CD_SCOPE; i++) { + // If there is no argument there are no more scopes after it, break out. + if (argvars[i].v_type == VAR_UNKNOWN) { + break; + } + if (argvars[i].v_type != VAR_NUMBER) { + EMSG(_(e_invarg)); + return; + } + scope_number[i] = argvars[i].vval.v_number; + // The scope is the current iteration step. + scope = i; + // It is an error for the scope number to be less than `-1`. + if (scope_number[i] < -1) { + EMSG(_(e_invarg)); + return; + } + } + + // Normalize scope, the number of the new scope will be 0. + if (scope_number[scope] < 0) { + // Arguments to `getcwd` always end at second-highest scope, so scope will + // always be <= `MAX_CD_SCOPE`. + scope++; + } + + // Find the tabpage by number + if (scope_number[kCdScopeTab] == -1) { + tp = NULL; + } else if (scope_number[kCdScopeTab] > 0) { + tp = find_tabpage(scope_number[kCdScopeTab]); + if (!tp) { + EMSG(_("E5000: Cannot find tab number.")); + return; + } + } + + // Find the window in `tp` by number, `NULL` if none. + if (scope_number[kCdScopeWindow] == -1) { + win = NULL; + } else if (scope_number[kCdScopeWindow] >= 0) { + if (!tp) { + EMSG(_("E5001: Higher scope cannot be -1 if lower scope is >= 0.")); + return; + } + + if (scope_number[kCdScopeWindow] > 0) { + win = find_win_by_nr(&argvars[0], curtab); + if (!win) { + EMSG(_("E5002: Cannot find window number.")); + return; + } + } + } + cwd = xmalloc(MAXPATHL); - if (os_dirname(cwd, MAXPATHL) != FAIL) { - rettv->vval.v_string = vim_strsave(cwd); + + switch (scope) { + case kCdScopeWindow: + assert(win); + from = win->w_localdir; + if (from) { + break; + } + case kCdScopeTab: // FALLTHROUGH + assert(tp); + from = tp->localdir; + if (from) { + break; + } + case kCdScopeGlobal: // FALLTHROUGH + // The `globaldir` variable is not always set. + if (globaldir) { + from = globaldir; + } else { + // We have to copy the OS path directly into output string. + if (os_dirname(cwd, MAXPATHL) == FAIL) { + EMSG(_("E41: Could not display path.")); + goto end; + } + } + break; + } + + if (from) { + xstrlcpy((char *)cwd, (char *)from, MAXPATHL); + } + + rettv->vval.v_string = vim_strsave(cwd); #ifdef BACKSLASH_IN_FILENAME - slash_adjust(rettv->vval.v_string); + slash_adjust(rettv->vval.v_string); #endif - } +end: xfree(cwd); } @@ -10024,6 +10187,7 @@ static void getpos_both(typval_T *argvars, typval_T *rettv, bool getcurpos) list_append_number(l, (fp != NULL) ? (varnumber_T)fp->coladd : (varnumber_T)0); if (getcurpos) { + update_curswant(); list_append_number(l, curwin->w_curswant == MAXCOL ? (varnumber_T)MAXCOL : (varnumber_T)curwin->w_curswant + 1); @@ -10131,7 +10295,7 @@ static void f_getregtype(typval_T *argvars, typval_T *rettv) colnr_T reglen = 0; char buf[NUMBUFLEN + 2]; - char_u reg_type = get_reg_type(regname, ®len); + MotionType reg_type = get_reg_type(regname, ®len); format_reg_type(reg_type, reglen, buf, ARRAY_SIZE(buf)); rettv->v_type = VAR_STRING; @@ -10593,12 +10757,103 @@ static void f_has_key(typval_T *argvars, typval_T *rettv) get_tv_string(&argvars[1]), -1) != NULL; } -/* - * "haslocaldir()" function - */ +/// `haslocaldir([{win}[, {tab}]])` function +/// +/// Returns `1` if the scope object has a local directory, `0` otherwise. If a +/// scope object is not specified the current one is implied. This function +/// share a lot of code with `f_getcwd`. +/// +/// @pre The arguments must be of type number. +/// @pre There may not be more than two arguments. +/// @pre An argument may not be -1 if preceding arguments are not all -1. +/// +/// @post The return value will be either the number `1` or `0`. static void f_haslocaldir(typval_T *argvars, typval_T *rettv) { - rettv->vval.v_number = (curwin->w_localdir != NULL); + // Possible scope of working directory to return. + CdScope scope = MIN_CD_SCOPE; + + // Numbers of the scope objects (window, tab) we want the working directory + // of. A `-1` means to skip this scope, a `0` means the current object. + int scope_number[] = { + [kCdScopeWindow] = 0, // Number of window to look at. + [kCdScopeTab ] = 0, // Number of tab to look at. + }; + + tabpage_T *tp = curtab; // The tabpage to look at. + win_T *win = curwin; // The window to look at. + + rettv->v_type = VAR_NUMBER; + rettv->vval.v_number = 0; + + // Pre-conditions and scope extraction together + for (int i = MIN_CD_SCOPE; i < MAX_CD_SCOPE; i++) { + if (argvars[i].v_type == VAR_UNKNOWN) { + break; + } + if (argvars[i].v_type != VAR_NUMBER) { + EMSG(_(e_invarg)); + return; + } + scope_number[i] = argvars[i].vval.v_number; + // The scope is the current iteration step. + scope = i; + if (scope_number[i] < -1) { + EMSG(_(e_invarg)); + return; + } + } + + // Normalize scope, the number of the new scope will be 0. + if (scope_number[scope] < 0) { + // Arguments to `haslocaldir` always end at second-highest scope, so scope + // will always be <= `MAX_CD_SCOPE`. + scope++; + } + + // Find the tabpage by number + if (scope_number[kCdScopeTab] == -1) { + tp = NULL; + } else if (scope_number[kCdScopeTab] > 0) { + tp = find_tabpage(scope_number[kCdScopeTab]); + if (!tp) { + EMSG(_("5000: Cannot find tab number.")); + return; + } + } + + // Find the window in `tp` by number, `NULL` if none. + if (scope_number[kCdScopeWindow] == -1) { + win = NULL; + } else if (scope_number[kCdScopeWindow] >= 0) { + if (!tp) { + EMSG(_("E5001: Higher scope cannot be -1 if lower scope is >= 0.")); + return; + } + + if (scope_number[kCdScopeWindow] > 0) { + win = find_win_by_nr(&argvars[0], curtab); + if (!win) { + EMSG(_("E5002: Cannot find window number.")); + return; + } + } + } + + switch (scope) { + case kCdScopeWindow: + assert(win); + rettv->vval.v_number = win->w_localdir ? 1 : 0; + break; + case kCdScopeTab: + assert(tp); + rettv->vval.v_number = tp->localdir ? 1 : 0; + break; + case kCdScopeGlobal: + // The global scope never has a local directory + rettv->vval.v_number = 0; + break; + } } /* @@ -10631,21 +10886,22 @@ static void f_hasmapto(typval_T *argvars, typval_T *rettv) */ static void f_histadd(typval_T *argvars, typval_T *rettv) { - int histype; + HistoryType histype; char_u *str; char_u buf[NUMBUFLEN]; - rettv->vval.v_number = FALSE; - if (check_restricted() || check_secure()) + rettv->vval.v_number = false; + if (check_restricted() || check_secure()) { return; - str = get_tv_string_chk(&argvars[0]); /* NULL on type error */ - histype = str != NULL ? get_histtype(str) : -1; - if (histype >= 0) { + } + str = get_tv_string_chk(&argvars[0]); // NULL on type error + histype = str != NULL ? get_histtype(str, STRLEN(str), false) : HIST_INVALID; + if (histype != HIST_INVALID) { str = get_tv_string_buf(&argvars[1], buf); if (*str != NUL) { init_history(); - add_to_history(histype, str, FALSE, NUL); - rettv->vval.v_number = TRUE; + add_to_history(histype, str, false, NUL); + rettv->vval.v_number = true; return; } } @@ -10660,20 +10916,21 @@ static void f_histdel(typval_T *argvars, typval_T *rettv) char_u buf[NUMBUFLEN]; char_u *str; - str = get_tv_string_chk(&argvars[0]); /* NULL on type error */ - if (str == NULL) + str = get_tv_string_chk(&argvars[0]); // NULL on type error + if (str == NULL) { n = 0; - else if (argvars[1].v_type == VAR_UNKNOWN) - /* only one argument: clear entire history */ - n = clr_history(get_histtype(str)); - else if (argvars[1].v_type == VAR_NUMBER) - /* index given: remove that entry */ - n = del_history_idx(get_histtype(str), - (int)get_tv_number(&argvars[1])); - else - /* string given: remove all matching entries */ - n = del_history_entry(get_histtype(str), - get_tv_string_buf(&argvars[1], buf)); + } else if (argvars[1].v_type == VAR_UNKNOWN) { + // only one argument: clear entire history + n = clr_history(get_histtype(str, STRLEN(str), false)); + } else if (argvars[1].v_type == VAR_NUMBER) { + // index given: remove that entry + n = del_history_idx(get_histtype(str, STRLEN(str), false), + (int) get_tv_number(&argvars[1])); + } else { + // string given: remove all matching entries + n = del_history_entry(get_histtype(str, STRLEN(str), false), + get_tv_string_buf(&argvars[1], buf)); + } rettv->vval.v_number = n; } @@ -10682,20 +10939,21 @@ static void f_histdel(typval_T *argvars, typval_T *rettv) */ static void f_histget(typval_T *argvars, typval_T *rettv) { - int type; + HistoryType type; int idx; char_u *str; - str = get_tv_string_chk(&argvars[0]); /* NULL on type error */ - if (str == NULL) + str = get_tv_string_chk(&argvars[0]); // NULL on type error + if (str == NULL) { rettv->vval.v_string = NULL; - else { - type = get_histtype(str); - if (argvars[1].v_type == VAR_UNKNOWN) + } else { + type = get_histtype(str, STRLEN(str), false); + if (argvars[1].v_type == VAR_UNKNOWN) { idx = get_history_idx(type); - else + } else { idx = (int)get_tv_number_chk(&argvars[1], NULL); - /* -1 on type error */ + } + // -1 on type error rettv->vval.v_string = vim_strsave(get_history_entry(type, idx)); } rettv->v_type = VAR_STRING; @@ -10710,11 +10968,13 @@ static void f_histnr(typval_T *argvars, typval_T *rettv) char_u *history = get_tv_string_chk(&argvars[0]); - i = history == NULL ? HIST_CMD - 1 : get_histtype(history); - if (i >= HIST_CMD && i < HIST_COUNT) + i = history == NULL ? HIST_CMD - 1 : get_histtype(history, STRLEN(history), + false); + if (i != HIST_INVALID) { i = get_history_idx(i); - else + } else { i = -1; + } rettv->vval.v_number = i; } @@ -11350,7 +11610,7 @@ static char **tv_to_argv(typval_T *cmd_tv, char **cmd) assert(argl->lv_first); const char_u *exe = get_tv_string_chk(&argl->lv_first->li_tv); - if (!exe || !os_can_exe(exe, NULL)) { + if (!exe || !os_can_exe(exe, NULL, true)) { // String is not executable if (exe) { EMSG2(e_jobexe, exe); @@ -11851,8 +12111,9 @@ static void get_maparg(typval_T *argvars, typval_T *rettv, int exact) mode = get_map_mode(&which, 0); - keys = replace_termcodes(keys, &keys_buf, TRUE, TRUE, FALSE); - rhs = check_map(keys, mode, exact, FALSE, abbr, &mp, &buffer_local); + keys = replace_termcodes(keys, STRLEN(keys), &keys_buf, true, true, false, + CPO_TO_CPO_FLAGS); + rhs = check_map(keys, mode, exact, false, abbr, &mp, &buffer_local); xfree(keys_buf); if (!get_dict) { @@ -13303,14 +13564,14 @@ static void f_reverse(typval_T *argvars, typval_T *rettv) } } -#define SP_NOMOVE 0x01 /* don't move cursor */ -#define SP_REPEAT 0x02 /* repeat to find outer pair */ -#define SP_RETCOUNT 0x04 /* return matchcount */ -#define SP_SETPCMARK 0x08 /* set previous context mark */ -#define SP_START 0x10 /* accept match at start position */ -#define SP_SUBPAT 0x20 /* return nr of matching sub-pattern */ -#define SP_END 0x40 /* leave cursor at end of match */ - +#define SP_NOMOVE 0x01 ///< don't move cursor +#define SP_REPEAT 0x02 ///< repeat to find outer pair +#define SP_RETCOUNT 0x04 ///< return matchcount +#define SP_SETPCMARK 0x08 ///< set previous context mark +#define SP_START 0x10 ///< accept match at start position +#define SP_SUBPAT 0x20 ///< return nr of matching sub-pattern +#define SP_END 0x40 ///< leave cursor at end of match +#define SP_COLUMN 0x80 ///< start at cursor column /* * Get flags for a search function. @@ -13336,13 +13597,14 @@ static int get_search_arg(typval_T *varp, int *flagsp) default: mask = 0; if (flagsp != NULL) switch (*flags) { - case 'c': mask = SP_START; break; - case 'e': mask = SP_END; break; - case 'm': mask = SP_RETCOUNT; break; - case 'n': mask = SP_NOMOVE; break; - case 'p': mask = SP_SUBPAT; break; - case 'r': mask = SP_REPEAT; break; - case 's': mask = SP_SETPCMARK; break; + case 'c': mask = SP_START; break; + case 'e': mask = SP_END; break; + case 'm': mask = SP_RETCOUNT; break; + case 'n': mask = SP_NOMOVE; break; + case 'p': mask = SP_SUBPAT; break; + case 'r': mask = SP_REPEAT; break; + case 's': mask = SP_SETPCMARK; break; + case 'z': mask = SP_COLUMN; break; } if (mask == 0) { EMSG2(_(e_invarg2), flags); @@ -13358,9 +13620,7 @@ static int get_search_arg(typval_T *varp, int *flagsp) return dir; } -/* - * Shared by search() and searchpos() functions - */ +// Shared by search() and searchpos() functions. static int search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp) { int flags; @@ -13381,10 +13641,15 @@ static int search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp) if (dir == 0) goto theend; flags = *flagsp; - if (flags & SP_START) + if (flags & SP_START) { options |= SEARCH_START; - if (flags & SP_END) + } + if (flags & SP_END) { options |= SEARCH_END; + } + if (flags & SP_COLUMN) { + options |= SEARCH_COL; + } /* Optional arguments: line number to stop searching and timeout. */ if (argvars[1].v_type != VAR_UNKNOWN && argvars[2].v_type != VAR_UNKNOWN) { @@ -14457,11 +14722,11 @@ static void f_setreg(typval_T *argvars, typval_T *rettv) char_u *strregname; char_u *stropt; bool append = false; - char_u yank_type; + MotionType yank_type; long block_len; block_len = -1; - yank_type = MAUTO; + yank_type = kMTUnknown; strregname = get_tv_string_chk(argvars); rettv->vval.v_number = 1; /* FAIL is default */ @@ -14478,17 +14743,17 @@ static void f_setreg(typval_T *argvars, typval_T *rettv) return; /* type error */ for (; *stropt != NUL; ++stropt) switch (*stropt) { - case 'a': case 'A': /* append */ + case 'a': case 'A': // append append = true; break; - case 'v': case 'c': /* character-wise selection */ - yank_type = MCHAR; + case 'v': case 'c': // character-wise selection + yank_type = kMTCharWise; break; - case 'V': case 'l': /* line-wise selection */ - yank_type = MLINE; + case 'V': case 'l': // line-wise selection + yank_type = kMTLineWise; break; - case 'b': case Ctrl_V: /* block-wise selection */ - yank_type = MBLOCK; + case 'b': case Ctrl_V: // block-wise selection + yank_type = kMTBlockWise; if (ascii_isdigit(stropt[1])) { ++stropt; block_len = getdigits_long(&stropt) - 1; @@ -14714,6 +14979,8 @@ typedef struct { static int item_compare_ic; static bool item_compare_numeric; +static bool item_compare_numbers; +static bool item_compare_float; static char_u *item_compare_func; static dict_T *item_compare_selfdict; static int item_compare_func_err; @@ -14735,6 +15002,21 @@ static int item_compare(const void *s1, const void *s2, bool keep_zero) si2 = (sortItem_T *)s2; typval_T *tv1 = &si1->item->li_tv; typval_T *tv2 = &si2->item->li_tv; + + if (item_compare_numbers) { + long v1 = get_tv_number(tv1); + long v2 = get_tv_number(tv2); + + return v1 == v2 ? 0 : v1 > v2 ? 1 : -1; + } + + if (item_compare_float) { + float_T v1 = get_tv_float(tv1); + float_T v2 = get_tv_float(tv2); + + return v1 == v2 ? 0 : v1 > v2 ? 1 : -1; + } + // encode_tv2string() puts quotes around a string and allocates memory. Don't // do that for string variables. Use a single quote when comparing with // a non-string to do what the docs promise. @@ -14863,12 +15145,12 @@ static void do_sort_uniq(typval_T *argvars, typval_T *rettv, bool sort) EMSG2(_(e_listarg), sort ? "sort()" : "uniq()"); } else { l = argvars[0].vval.v_list; - if (l == NULL || - tv_check_lock(l->lv_lock, - (char_u *)(sort - ? N_("sort() argument") - : N_("uniq() argument")), - true)) { + if (l == NULL + || tv_check_lock(l->lv_lock, + (char_u *)(sort + ? N_("sort() argument") + : N_("uniq() argument")), + true)) { return; } rettv->vval.v_list = l; @@ -14881,6 +15163,8 @@ static void do_sort_uniq(typval_T *argvars, typval_T *rettv, bool sort) item_compare_ic = FALSE; item_compare_numeric = false; + item_compare_numbers = false; + item_compare_float = false; item_compare_func = NULL; item_compare_selfdict = NULL; @@ -14902,6 +15186,12 @@ static void do_sort_uniq(typval_T *argvars, typval_T *rettv, bool sort) if (STRCMP(item_compare_func, "n") == 0) { item_compare_func = NULL; item_compare_numeric = true; + } else if (STRCMP(item_compare_func, "N") == 0) { + item_compare_func = NULL; + item_compare_numbers = true; + } else if (STRCMP(item_compare_func, "f") == 0) { + item_compare_func = NULL; + item_compare_float = true; } else if (STRCMP(item_compare_func, "i") == 0) { item_compare_func = NULL; item_compare_ic = TRUE; @@ -17603,6 +17893,33 @@ long get_tv_number_chk(typval_T *varp, int *denote) return n; } +static float_T get_tv_float(typval_T *varp) +{ + switch (varp->v_type) { + case VAR_NUMBER: + return (float_T)(varp->vval.v_number); + case VAR_FLOAT: + return varp->vval.v_float; + break; + case VAR_FUNC: + EMSG(_("E891: Using a Funcref as a Float")); + break; + case VAR_STRING: + EMSG(_("E892: Using a String as a Float")); + break; + case VAR_LIST: + EMSG(_("E893: Using a List as a Float")); + break; + case VAR_DICT: + EMSG(_("E894: Using a Dictionary as a Float")); + break; + default: + EMSG2(_(e_intern2), "get_tv_float()"); + break; + } + return 0; +} + /* * Get the lnum from the first argument. * Also accepts ".", "$", etc., but that only works for the current buffer. @@ -18953,9 +19270,10 @@ void ex_function(exarg_T *eap) if ((p[0] == 'a' && (!ASCII_ISALPHA(p[1]) || p[1] == 'p')) || (p[0] == 'i' && (!ASCII_ISALPHA(p[1]) || (p[1] == 'n' - && (!ASCII_ISALPHA(p[2]) || - (p[2] == 's')))))) + && (!ASCII_ISALPHA(p[2]) + || (p[2] == 's')))))) { skip_until = vim_strsave((char_u *)"."); + } // Check for ":python <<EOF", ":lua <<EOF", etc. arg = skipwhite(skiptowhite(p)); @@ -19222,11 +19540,12 @@ trans_function_name ( *pp = end; } else { if (!skip && !(flags & TFN_QUIET) && (fdp == NULL - || lv.ll_dict == NULL || - fdp->fd_newkey == NULL)) + || lv.ll_dict == NULL + || fdp->fd_newkey == NULL)) { EMSG(_(e_funcref)); - else + } else { *pp = end; + } name = NULL; } goto theend; @@ -20126,9 +20445,9 @@ call_user_func ( --RedrawingDisabled; - /* when the function was aborted because of an error, return -1 */ - if ((did_emsg && - (fp->uf_flags & FC_ABORT)) || rettv->v_type == VAR_UNKNOWN) { + // when the function was aborted because of an error, return -1 + if ((did_emsg + && (fp->uf_flags & FC_ABORT)) || rettv->v_type == VAR_UNKNOWN) { clear_tv(rettv); rettv->v_type = VAR_NUMBER; rettv->vval.v_number = -1; diff --git a/src/nvim/event/process.c b/src/nvim/event/process.c index e6012595fd..9bb62891c7 100644 --- a/src/nvim/event/process.c +++ b/src/nvim/event/process.c @@ -187,9 +187,9 @@ int process_wait(Process *proc, int ms, Queue *events) FUNC_ATTR_NONNULL_ARG(1) // being freed) before we have a chance to get the status. proc->refcount++; LOOP_PROCESS_EVENTS_UNTIL(proc->loop, events, ms, - // Until... - got_int || // interrupted by the user - proc->refcount == 1); // job exited + // Until... + got_int // interrupted by the user + || proc->refcount == 1); // job exited // we'll assume that a user frantically hitting interrupt doesn't like // the current job. Signal that it has to be killed. diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c index d344daed11..e8314e02e0 100644 --- a/src/nvim/ex_cmds.c +++ b/src/nvim/ex_cmds.c @@ -3,6 +3,7 @@ */ #include <assert.h> +#include <float.h> #include <stdbool.h> #include <string.h> #include <stdlib.h> @@ -50,7 +51,6 @@ #include "nvim/strings.h" #include "nvim/syntax.h" #include "nvim/tag.h" -#include "nvim/tempfile.h" #include "nvim/ui.h" #include "nvim/undo.h" #include "nvim/window.h" @@ -274,17 +274,26 @@ static int linelen(int *has_tab) static char_u *sortbuf1; static char_u *sortbuf2; -static int sort_ic; /* ignore case */ -static int sort_nr; /* sort on number */ -static int sort_rx; /* sort on regex instead of skipping it */ +static int sort_ic; ///< ignore case +static int sort_nr; ///< sort on number +static int sort_rx; ///< sort on regex instead of skipping it +static int sort_flt; ///< sort on floating number -static int sort_abort; /* flag to indicate if sorting has been interrupted */ +static int sort_abort; ///< flag to indicate if sorting has been interrupted -/* Struct to store info to be sorted. */ +/// Struct to store info to be sorted. typedef struct { - linenr_T lnum; /* line number */ - long start_col_nr; /* starting column number or number */ - long end_col_nr; /* ending column number */ + linenr_T lnum; ///< line number + long start_col_nr; ///< starting column number or number + long end_col_nr; ///< ending column number + union { + struct { + long start_col_nr; ///< starting column number + long end_col_nr; ///< ending column number + } line; + long value; ///< value if sorting by integer + float_T value_flt; ///< value if sorting by float + } st_u; } sorti_T; @@ -303,21 +312,26 @@ static int sort_compare(const void *s1, const void *s2) if (got_int) sort_abort = TRUE; - /* When sorting numbers "start_col_nr" is the number, not the column - * number. */ - if (sort_nr) - result = l1.start_col_nr == l2.start_col_nr ? 0 - : l1.start_col_nr > l2.start_col_nr ? 1 : -1; - else { - /* We need to copy one line into "sortbuf1", because there is no - * guarantee that the first pointer becomes invalid when obtaining the - * second one. */ - STRNCPY(sortbuf1, ml_get(l1.lnum) + l1.start_col_nr, - l1.end_col_nr - l1.start_col_nr + 1); - sortbuf1[l1.end_col_nr - l1.start_col_nr] = 0; - STRNCPY(sortbuf2, ml_get(l2.lnum) + l2.start_col_nr, - l2.end_col_nr - l2.start_col_nr + 1); - sortbuf2[l2.end_col_nr - l2.start_col_nr] = 0; + // When sorting numbers "start_col_nr" is the number, not the column + // number. + if (sort_nr) { + result = l1.st_u.value == l2.st_u.value + ? 0 : l1.st_u.value > l2.st_u.value + ? 1 : -1; + } else if (sort_flt) { + result = l1.st_u.value_flt == l2.st_u.value_flt + ? 0 : l1.st_u.value_flt > l2.st_u.value_flt + ? 1 : -1; + } else { + // We need to copy one line into "sortbuf1", because there is no + // guarantee that the first pointer becomes invalid when obtaining the + // second one. + STRNCPY(sortbuf1, ml_get(l1.lnum) + l1.st_u.line.start_col_nr, + l1.st_u.line.end_col_nr - l1.st_u.line.start_col_nr + 1); + sortbuf1[l1.st_u.line.end_col_nr - l1.st_u.line.start_col_nr] = 0; + STRNCPY(sortbuf2, ml_get(l2.lnum) + l2.st_u.line.start_col_nr, + l2.st_u.line.end_col_nr - l2.st_u.line.start_col_nr + 1); + sortbuf2[l2.st_u.line.end_col_nr - l2.st_u.line.start_col_nr] = 0; result = sort_ic ? STRICMP(sortbuf1, sortbuf2) : STRCMP(sortbuf1, sortbuf2); @@ -361,7 +375,7 @@ void ex_sort(exarg_T *eap) regmatch.regprog = NULL; sorti_T *nrs = xmalloc(count * sizeof(sorti_T)); - sort_abort = sort_ic = sort_rx = sort_nr = 0; + sort_abort = sort_ic = sort_rx = sort_nr = sort_flt = 0; size_t format_found = 0; for (p = eap->arg; *p != NUL; ++p) { @@ -371,7 +385,10 @@ void ex_sort(exarg_T *eap) } else if (*p == 'r') { sort_rx = true; } else if (*p == 'n') { - sort_nr = 2; + sort_nr = 1; + format_found++; + } else if (*p == 'f') { + sort_flt = 1; format_found++; } else if (*p == 'b') { sort_what = STR2NR_BIN + STR2NR_FORCE; @@ -424,7 +441,8 @@ void ex_sort(exarg_T *eap) goto sortend; } - // From here on "sort_nr" is used as a flag for any number sorting. + // From here on "sort_nr" is used as a flag for any integer number + // sorting. sort_nr += sort_what; // Make an array with all line numbers. This avoids having to copy all @@ -453,7 +471,7 @@ void ex_sort(exarg_T *eap) end_col = 0; } - if (sort_nr) { + if (sort_nr || sort_flt) { // Make sure vim_str2nr doesn't read any digits past the end // of the match, by temporarily terminating the string there s2 = s + end_col; @@ -461,29 +479,42 @@ void ex_sort(exarg_T *eap) *s2 = NUL; // Sorting on number: Store the number itself. p = s + start_col; - if (sort_what & STR2NR_HEX) { - s = skiptohex(p); - } else if (sort_what & STR2NR_BIN) { - s = (char_u*) skiptobin((char*) p); - } else { - s = skiptodigit(p); - } - if (s > p && s[-1] == '-') { - // include preceding negative sign - s--; - } - if (*s == NUL) { - // empty line should sort before any number - nrs[lnum - eap->line1].start_col_nr = -MAXLNUM; + if (sort_nr) { + if (sort_what & STR2NR_HEX) { + s = skiptohex(p); + } else if (sort_what & STR2NR_BIN) { + s = (char_u *)skiptobin((char *)p); + } else { + s = skiptodigit(p); + } + if (s > p && s[-1] == '-') { + s--; // include preceding negative sign + } + if (*s == NUL) { + // empty line should sort before any number + nrs[lnum - eap->line1].st_u.value = -MAXLNUM; + } else { + vim_str2nr(s, NULL, NULL, sort_what, + &nrs[lnum - eap->line1].st_u.value, NULL, 0); + } } else { - vim_str2nr(s, NULL, NULL, sort_what, - &nrs[lnum - eap->line1].start_col_nr, NULL, 0); + s = skipwhite(p); + if (*s == '+') { + s = skipwhite(s + 1); + } + + if (*s == NUL) { + // empty line should sort before any number + nrs[lnum - eap->line1].st_u.value_flt = -DBL_MAX; + } else { + nrs[lnum - eap->line1].st_u.value_flt = strtod((char *)s, NULL); + } } *s2 = c; } else { // Store the column to sort at. - nrs[lnum - eap->line1].start_col_nr = start_col; - nrs[lnum - eap->line1].end_col_nr = end_col; + nrs[lnum - eap->line1].st_u.line.start_col_nr = start_col; + nrs[lnum - eap->line1].st_u.line.end_col_nr = end_col; } nrs[lnum - eap->line1].lnum = lnum; @@ -619,13 +650,13 @@ void ex_retab(exarg_T *eap) num_tabs += num_spaces / new_ts; num_spaces -= (num_spaces / new_ts) * new_ts; } - if (curbuf->b_p_et || got_tab || - (num_spaces + num_tabs < len)) { - if (did_undo == FALSE) { - did_undo = TRUE; + if (curbuf->b_p_et || got_tab + || (num_spaces + num_tabs < len)) { + if (did_undo == false) { + did_undo = true; if (u_save((linenr_T)(lnum - 1), - (linenr_T)(lnum + 1)) == FAIL) { - new_line = NULL; /* flag out-of-memory */ + (linenr_T)(lnum + 1)) == FAIL) { + new_line = NULL; // flag out-of-memory break; } } @@ -1592,15 +1623,14 @@ int do_write(exarg_T *eap) } } - /* - * Writing to the current file is not allowed in readonly mode - * and a file name is required. - * "nofile" and "nowrite" buffers cannot be written implicitly either. - */ - if (!other && ( - bt_dontwrite_msg(curbuf) || - check_fname() == FAIL || check_readonly(&eap->forceit, curbuf))) + // Writing to the current file is not allowed in readonly mode + // and a file name is required. + // "nofile" and "nowrite" buffers cannot be written implicitly either. + if (!other && (bt_dontwrite_msg(curbuf) + || check_fname() == FAIL + || check_readonly(&eap->forceit, curbuf))) { goto theend; + } if (!other) { ffname = curbuf->b_ffname; @@ -2227,16 +2257,15 @@ do_ecmd ( delbuf_msg(new_name); /* frees new_name */ goto theend; } - if (buf == curbuf) /* already in new buffer */ - auto_buf = TRUE; - else { - /* - * <VN> We could instead free the synblock - * and re-attach to buffer, perhaps. - */ - if (curwin->w_buffer != NULL && - curwin->w_s == &(curwin->w_buffer->b_s)) + if (buf == curbuf) { // already in new buffer + auto_buf = true; + } else { + // <VN> We could instead free the synblock + // and re-attach to buffer, perhaps. + if (curwin->w_buffer != NULL + && curwin->w_s == &(curwin->w_buffer->b_s)) { curwin->w_s = &(buf->b_s); + } curwin->w_buffer = buf; curbuf = buf; @@ -2263,11 +2292,11 @@ do_ecmd ( curwin->w_pcmark.lnum = 1; curwin->w_pcmark.col = 0; - } else { /* !other_file */ - if ( - (flags & ECMD_ADDBUF) || - check_fname() == FAIL) + } else { // !other_file + if ((flags & ECMD_ADDBUF) + || check_fname() == FAIL) { goto theend; + } oldbuf = (flags & ECMD_OLDBUF); } @@ -5017,7 +5046,9 @@ helptags_one ( /* * Sort the tags. */ - sort_strings((char_u **)ga.ga_data, ga.ga_len); + if (ga.ga_data != NULL) { + sort_strings((char_u **)ga.ga_data, ga.ga_len); + } /* * Check for duplicates. @@ -5785,13 +5816,14 @@ void set_context_in_sign_cmd(expand_T *xp, char_u *arg) switch (cmd_idx) { case SIGNCMD_DEFINE: - if (STRNCMP(last, "texthl", p - last) == 0 || - STRNCMP(last, "linehl", p - last) == 0) + if (STRNCMP(last, "texthl", p - last) == 0 + || STRNCMP(last, "linehl", p - last) == 0) { xp->xp_context = EXPAND_HIGHLIGHT; - else if (STRNCMP(last, "icon", p - last) == 0) + } else if (STRNCMP(last, "icon", p - last) == 0) { xp->xp_context = EXPAND_FILES; - else + } else { xp->xp_context = EXPAND_NOTHING; + } break; case SIGNCMD_PLACE: if (STRNCMP(last, "name", p - last) == 0) diff --git a/src/nvim/ex_cmds.lua b/src/nvim/ex_cmds.lua index 6c8835b5c5..04fd88cc8d 100644 --- a/src/nvim/ex_cmds.lua +++ b/src/nvim/ex_cmds.lua @@ -2575,6 +2575,18 @@ return { func='ex_copymove', }, { + command='tcd', + flags=bit.bor(BANG, FILE1, TRLBAR, CMDWIN), + addr_type=ADDR_LINES, + func='ex_cd', + }, + { + command='tchdir', + flags=bit.bor(BANG, FILE1, TRLBAR, CMDWIN), + addr_type=ADDR_LINES, + func='ex_cd', + }, + { command='tNext', flags=bit.bor(RANGE, NOTADR, BANG, TRLBAR, ZEROR), addr_type=ADDR_LINES, diff --git a/src/nvim/ex_cmds2.c b/src/nvim/ex_cmds2.c index 2c8271c696..12efddc205 100644 --- a/src/nvim/ex_cmds2.c +++ b/src/nvim/ex_cmds2.c @@ -432,14 +432,12 @@ dbg_parsearg ( bp = &DEBUGGY(gap, gap->ga_len); - /* Find "func" or "file". */ - if (STRNCMP(p, "func", 4) == 0) + // Find "func" or "file". + if (STRNCMP(p, "func", 4) == 0) { bp->dbg_type = DBG_FUNC; - else if (STRNCMP(p, "file", 4) == 0) + } else if (STRNCMP(p, "file", 4) == 0) { bp->dbg_type = DBG_FILE; - else if ( - gap != &prof_ga && - STRNCMP(p, "here", 4) == 0) { + } else if (gap != &prof_ga && STRNCMP(p, "here", 4) == 0) { if (curbuf->b_ffname == NULL) { EMSG(_(e_noname)); return FAIL; @@ -452,16 +450,15 @@ dbg_parsearg ( } p = skipwhite(p + 4); - /* Find optional line number. */ - if (here) + // Find optional line number. + if (here) { bp->dbg_lnum = curwin->w_cursor.lnum; - else if ( - gap != &prof_ga && - ascii_isdigit(*p)) { + } else if (gap != &prof_ga && ascii_isdigit(*p)) { bp->dbg_lnum = getdigits_long(&p); p = skipwhite(p); - } else + } else { bp->dbg_lnum = 0; + } /* Find the function or file name. Don't accept a function name with (). */ if ((!here && *p == NUL) @@ -700,14 +697,13 @@ debuggy_find ( /* Skip entries that are not useful or are for a line that is beyond * an already found breakpoint. */ bp = &DEBUGGY(gap, i); - if (((bp->dbg_type == DBG_FILE) == file && ( - gap == &prof_ga || - (bp->dbg_lnum > after && (lnum == 0 || bp->dbg_lnum < lnum))))) { - /* - * Save the value of got_int and reset it. We don't want a - * previous interruption cancel matching, only hitting CTRL-C - * while matching should abort it. - */ + if (((bp->dbg_type == DBG_FILE) == file + && (gap == &prof_ga + || (bp->dbg_lnum > after + && (lnum == 0 || bp->dbg_lnum < lnum))))) { + // Save the value of got_int and reset it. We don't want a + // previous interruption cancel matching, only hitting CTRL-C + // while matching should abort it. prev_got_int = got_int; got_int = FALSE; if (vim_regexec_prog(&bp->dbg_prog, false, name, (colnr_T)0)) { @@ -1937,8 +1933,8 @@ void ex_listdo(exarg_T *eap) if (buf != NULL) { goto_buffer(eap, DOBUF_FIRST, FORWARD, buf->b_fnum); } - } else if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo || - eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo) { + } else if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo + || eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo) { qf_size = qf_get_size(eap); assert(eap->line1 >= 0); if (qf_size == 0 || (size_t)eap->line1 > qf_size) { @@ -2040,8 +2036,8 @@ void ex_listdo(exarg_T *eap) } } - if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo || - eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo) { + if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo + || eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo) { assert(i >= 0); if ((size_t)i >= qf_size || i >= eap->line2) { break; @@ -2373,8 +2369,9 @@ static FILE *fopen_noinh_readbin(char *filename) # ifdef HAVE_FD_CLOEXEC { int fdflags = fcntl(fd_tmp, F_GETFD); - if (fdflags >= 0 && (fdflags & FD_CLOEXEC) == 0) - fcntl(fd_tmp, F_SETFD, fdflags | FD_CLOEXEC); + if (fdflags >= 0 && (fdflags & FD_CLOEXEC) == 0) { + (void)fcntl(fd_tmp, F_SETFD, fdflags | FD_CLOEXEC); + } } # endif @@ -3182,8 +3179,11 @@ void set_lang_var(void) * back to LC_CTYPE if it's empty. */ # ifdef HAVE_WORKING_LIBINTL loc = (char *) get_mess_env(); -# else +# elif defined(LC_MESSAGES) loc = get_locale_val(LC_MESSAGES); +# else + // In Windows LC_MESSAGES is not defined fallback to LC_CTYPE + loc = get_locale_val(LC_CTYPE); # endif set_vim_var_string(VV_LANG, loc, -1); diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index 6391e023c3..89c35a3c45 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -1654,16 +1654,15 @@ static char_u * do_one_cmd(char_u **cmdlinep, * If we got a line, but no command, then go to the line. * If we find a '|' or '\n' we set ea.nextcmd. */ - if (*ea.cmd == NUL || *ea.cmd == '"' || - (ea.nextcmd = check_nextcmd(ea.cmd)) != NULL) { - /* - * strange vi behaviour: - * ":3" jumps to line 3 - * ":3|..." prints line 3 - * ":|" prints current line - */ - if (ea.skip) /* skip this if inside :if */ + if (*ea.cmd == NUL || *ea.cmd == '"' + || (ea.nextcmd = check_nextcmd(ea.cmd)) != NULL) { + // strange vi behaviour: + // ":3" jumps to line 3 + // ":3|..." prints line 3 + // ":|" prints current line + if (ea.skip) { // skip this if inside :if goto doend; + } if (*ea.cmd == '|' || (exmode_active && ea.line1 != ea.line2)) { ea.cmdidx = CMD_print; ea.argt = RANGE | COUNT | TRLBAR; @@ -1826,9 +1825,10 @@ static char_u * do_one_cmd(char_u **cmdlinep, correct_range(&ea); - if (((ea.argt & WHOLEFOLD) || ea.addr_count >= 2) && !global_busy) { - /* Put the first line at the start of a closed fold, put the last line - * at the end of a closed fold. */ + if (((ea.argt & WHOLEFOLD) || ea.addr_count >= 2) && !global_busy + && ea.addr_type == ADDR_LINES) { + // Put the first line at the start of a closed fold, put the last line + // at the end of a closed fold. (void)hasFolding(ea.line1, &ea.line1, NULL); (void)hasFolding(ea.line2, NULL, &ea.line2); } @@ -2823,10 +2823,11 @@ set_one_cmd_context ( } } - /* no arguments allowed */ - if (!(ea.argt & EXTRA) && *arg != NUL && - vim_strchr((char_u *)"|\"", *arg) == NULL) + // no arguments allowed + if (!(ea.argt & EXTRA) && *arg != NUL + && vim_strchr((char_u *)"|\"", *arg) == NULL) { return NULL; + } /* Find start of last argument (argument just before cursor): */ p = buff; @@ -2958,8 +2959,11 @@ set_one_cmd_context ( case CMD_chdir: case CMD_lcd: case CMD_lchdir: - if (xp->xp_context == EXPAND_FILES) + case CMD_tcd: + case CMD_tchdir: + if (xp->xp_context == EXPAND_FILES) { xp->xp_context = EXPAND_DIRECTORIES; + } break; case CMD_help: xp->xp_context = EXPAND_HELP; @@ -4553,7 +4557,8 @@ static int uc_add_command(char_u *name, size_t name_len, char_u *rep, char_u *rep_buf = NULL; garray_T *gap; - replace_termcodes(rep, &rep_buf, FALSE, FALSE, FALSE); + replace_termcodes(rep, STRLEN(rep), &rep_buf, false, false, false, + CPO_TO_CPO_FLAGS); if (rep_buf == NULL) { /* Can't replace termcodes - try using the string as is */ rep_buf = vim_strsave(rep); @@ -4767,14 +4772,15 @@ static void uc_list(char_u *name, size_t name_len) IObuff[len++] = ' '; } while (len < 11); - /* Address Type */ - for (j = 0; addr_type_complete[j].expand != -1; ++j) - if (addr_type_complete[j].expand != ADDR_LINES && - addr_type_complete[j].expand == cmd->uc_addr_type) { + // Address Type + for (j = 0; addr_type_complete[j].expand != -1; j++) { + if (addr_type_complete[j].expand != ADDR_LINES + && addr_type_complete[j].expand == cmd->uc_addr_type) { STRCPY(IObuff + len, addr_type_complete[j].name); len += (int)STRLEN(IObuff + len); break; } + } do { IObuff[len++] = ' '; @@ -5499,7 +5505,8 @@ int parse_addr_type_arg(char_u *value, int vallen, uint32_t *argt, int *addr_type_arg) { int i, a, b; - for (i = 0; addr_type_complete[i].expand != -1; ++i) { + + for (i = 0; addr_type_complete[i].expand != -1; i++) { a = (int)STRLEN(addr_type_complete[i].name) == vallen; b = STRNCMP(value, addr_type_complete[i].name, vallen) == 0; if (a && b) { @@ -5510,8 +5517,8 @@ int parse_addr_type_arg(char_u *value, int vallen, uint32_t *argt, if (addr_type_complete[i].expand == -1) { char_u *err = value; - for (i = 0; err[i] == NUL || !ascii_iswhite(err[i]); i++) - ; + + for (i = 0; err[i] != NUL && !ascii_iswhite(err[i]); i++) {} err[i] = NUL; EMSG2(_("E180: Invalid address type value: %s"), err); return FAIL; @@ -5648,12 +5655,13 @@ static void ex_quit(exarg_T *eap) wp = curwin; } - apply_autocmds(EVENT_QUITPRE, NULL, NULL, FALSE, curbuf); - /* Refuse to quit when locked or when the buffer in the last window is - * being closed (can only happen in autocommands). */ - if (curbuf_locked() || - (wp->w_buffer->b_nwindows == 1 && wp->w_buffer->b_closing)) + apply_autocmds(EVENT_QUITPRE, NULL, NULL, false, curbuf); + // Refuse to quit when locked or when the buffer in the last window is + // being closed (can only happen in autocommands). + if (curbuf_locked() + || (wp->w_buffer->b_nwindows == 1 && wp->w_buffer->b_closing)) { return; + } /* @@ -6814,36 +6822,55 @@ void free_cd_dir(void) #endif -/* - * Deal with the side effects of changing the current directory. - * When "local" is TRUE then this was after an ":lcd" command. - */ -void post_chdir(int local) +/// Deal with the side effects of changing the current directory. +/// +/// @param scope Scope of the function call (global, tab or window). +void post_chdir(CdScope scope) { + // The local directory of the current window is always overwritten. xfree(curwin->w_localdir); curwin->w_localdir = NULL; - if (local) { - /* If still in global directory, need to remember current - * directory as global directory. */ - if (globaldir == NULL && prev_dir != NULL) + + // Overwrite the local directory of the current tab page for `cd` and `tcd` + if (scope >= kCdScopeTab) { + xfree(curtab->localdir); + curtab->localdir = NULL; + } + + if (scope < kCdScopeGlobal) { + // If still in global directory, need to remember current directory as + // global directory. + if (globaldir == NULL && prev_dir != NULL) { globaldir = vim_strsave(prev_dir); - /* Remember this local directory for the window. */ - if (os_dirname(NameBuff, MAXPATHL) == OK) - curwin->w_localdir = vim_strsave(NameBuff); - } else { - /* We are now in the global directory, no need to remember its - * name. */ + } + } + + switch (scope) { + case kCdScopeGlobal: + // We are now in the global directory, no need to remember its name. xfree(globaldir); globaldir = NULL; + break; + case kCdScopeTab: + // Remember this local directory for the tab page. + if (os_dirname(NameBuff, MAXPATHL) == OK) { + curtab->localdir = vim_strsave(NameBuff); + } + break; + case kCdScopeWindow: + // Remember this local directory for the window. + if (os_dirname(NameBuff, MAXPATHL) == OK) { + curwin->w_localdir = vim_strsave(NameBuff); + } + break; } shorten_fnames(TRUE); } -/* - * ":cd", ":lcd", ":chdir" and ":lchdir". - */ + +/// `:cd`, `:tcd`, `:lcd`, `:chdir`, `:tchdir` and `:lchdir`. void ex_cd(exarg_T *eap) { char_u *new_dir; @@ -6884,10 +6911,25 @@ void ex_cd(exarg_T *eap) new_dir = NameBuff; } #endif - if (new_dir == NULL || vim_chdir(new_dir)) + if (vim_chdir(new_dir)) { EMSG(_(e_failed)); - else { - post_chdir(eap->cmdidx == CMD_lcd || eap->cmdidx == CMD_lchdir); + } else { + CdScope scope = kCdScopeGlobal; // Depends on command invoked + + switch (eap->cmdidx) { + case CMD_tcd: + case CMD_tchdir: + scope = kCdScopeTab; + break; + case CMD_lcd: + case CMD_lchdir: + scope = kCdScopeWindow; + break; + default: + break; + } + + post_chdir(scope); /* Echo the new current directory if the command was typed. */ if (KeyTyped || p_verbose >= 5) @@ -7031,9 +7073,9 @@ static void ex_operators(exarg_T *eap) oa.start.lnum = eap->line1; oa.end.lnum = eap->line2; oa.line_count = eap->line2 - eap->line1 + 1; - oa.motion_type = MLINE; - virtual_op = FALSE; - if (eap->cmdidx != CMD_yank) { /* position cursor for undo */ + oa.motion_type = kMTLineWise; + virtual_op = false; + if (eap->cmdidx != CMD_yank) { // position cursor for undo setpcmark(); curwin->w_cursor.lnum = eap->line1; beginline(BL_SOL | BL_FIX); @@ -9145,16 +9187,15 @@ static char *get_view_file(int c) */ int put_eol(FILE *fd) { - if ( -#ifdef USE_CRNL - ( -# ifdef MKSESSION_NL - !mksession_nl && -# endif - (putc('\r', fd) < 0)) || +#if defined(USE_CRNL) && defined(MKSESSION_NL) + if ((!mksession_nl && putc('\r', fd) < 0) || putc('\n', fd) < 0) { +#elif defined(USE_CRNL) + if (putc('\r', fd) < 0 || putc('\n', fd) < 0) { +#else + if (putc('\n', fd) < 0) { #endif - (putc('\n', fd) < 0)) return FAIL; + } return OK; } diff --git a/src/nvim/ex_docmd.h b/src/nvim/ex_docmd.h index a5a4edbbbf..dbfc64e2f1 100644 --- a/src/nvim/ex_docmd.h +++ b/src/nvim/ex_docmd.h @@ -19,6 +19,20 @@ #define EXMODE_NORMAL 1 #define EXMODE_VIM 2 +/// The scope of a working-directory command like `:cd`. +/// +/// Scopes are enumerated from lowest to highest. When adding a scope make sure +/// to update all functions using scopes as well, such as the implementation of +/// `getcwd()`. When using scopes as limits (e.g. in loops) don't use the scopes +/// directly, use `MIN_CD_SCOPE` and `MAX_CD_SCOPE` instead. +typedef enum { + kCdScopeWindow, ///< Affects one window. + kCdScopeTab, ///< Affects one tab page. + kCdScopeGlobal, ///< Affects the entire instance of Neovim. +} CdScope; +#define MIN_CD_SCOPE kCdScopeWindow +#define MAX_CD_SCOPE kCdScopeGlobal + #ifdef INCLUDE_GENERATED_DECLARATIONS # include "ex_docmd.h.generated.h" #endif diff --git a/src/nvim/ex_eval.c b/src/nvim/ex_eval.c index 41ad96a378..82d4c2b2d5 100644 --- a/src/nvim/ex_eval.c +++ b/src/nvim/ex_eval.c @@ -403,14 +403,15 @@ char_u *get_exception_string(void *value, int type, char_u *cmdname, int *should && (p[3] == ':' || (ascii_isdigit(p[3]) && p[4] == ':')))))) { - if (*p == NUL || p == mesg) - STRCAT(val, mesg); /* 'E123' missing or at beginning */ - else { - /* '"filename" E123: message text' */ - if (mesg[0] != '"' || p-2 < &mesg[1] || - p[-2] != '"' || p[-1] != ' ') - /* "E123:" is part of the file name. */ + if (*p == NUL || p == mesg) { + STRCAT(val, mesg); // 'E123' missing or at beginning + } else { + // '"filename" E123: message text' + if (mesg[0] != '"' || p-2 < &mesg[1] + || p[-2] != '"' || p[-1] != ' ') { + // "E123:" is part of the file name. continue; + } STRCAT(val, p); p[-2] = NUL; @@ -1565,22 +1566,21 @@ void ex_endtry(exarg_T *eap) void *rettv = NULL; struct condstack *cstack = eap->cstack; - if (cstack->cs_trylevel <= 0 || cstack->cs_idx < 0) + if (cstack->cs_trylevel <= 0 || cstack->cs_idx < 0) { eap->errmsg = (char_u *)N_("E602: :endtry without :try"); - else { - /* - * Don't do something after an error, interrupt or throw in the try - * block, catch clause, or finally clause preceding this ":endtry" or - * when an error or interrupt occurred after a ":continue", ":break", - * ":return", or ":finish" in a try block or catch clause preceding this - * ":endtry" or when the try block never got active (because of an - * inactive surrounding conditional or after an error or interrupt or - * throw) or when there is a surrounding conditional and it has been - * made inactive by a ":continue", ":break", ":return", or ":finish" in - * the finally clause. The latter case need not be tested since then - * anything pending has already been discarded. */ - skip = did_emsg || got_int || did_throw || - !(cstack->cs_flags[cstack->cs_idx] & CSF_TRUE); + } else { + // Don't do something after an error, interrupt or throw in the try + // block, catch clause, or finally clause preceding this ":endtry" or + // when an error or interrupt occurred after a ":continue", ":break", + // ":return", or ":finish" in a try block or catch clause preceding this + // ":endtry" or when the try block never got active (because of an + // inactive surrounding conditional or after an error or interrupt or + // throw) or when there is a surrounding conditional and it has been + // made inactive by a ":continue", ":break", ":return", or ":finish" in + // the finally clause. The latter case need not be tested since then + // anything pending has already been discarded. + skip = (did_emsg || got_int || did_throw + || !(cstack->cs_flags[cstack->cs_idx] & CSF_TRUE)); if (!(cstack->cs_flags[cstack->cs_idx] & CSF_TRY)) { eap->errmsg = get_end_emsg(cstack); diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index cffda1ca55..a4e5a4dcd7 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -289,7 +289,9 @@ static uint8_t *command_line_enter(int firstc, long count, int indent) if (ccline.cmdbuff != NULL) { // Put line in history buffer (":" and "=" only when it was typed). - if (ccline.cmdlen && s->firstc != NUL + if (s->histype != HIST_INVALID + && ccline.cmdlen + && s->firstc != NUL && (s->some_key_typed || s->histype == HIST_SEARCH)) { add_to_history(s->histype, ccline.cmdbuff, true, s->histype == HIST_SEARCH ? s->firstc : NUL); @@ -622,8 +624,8 @@ static int command_line_execute(VimState *state, int key) // CTRL-\ e doesn't work when obtaining an expression, unless it // is in a mapping. if (s->c != Ctrl_N && s->c != Ctrl_G && (s->c != 'e' - || (ccline.cmdfirstc == '=' && - KeyTyped))) { + || (ccline.cmdfirstc == '=' + && KeyTyped))) { vungetc(s->c); s->c = Ctrl_BSL; } else if (s->c == 'e') { @@ -1268,7 +1270,7 @@ static int command_line_handle_key(CommandLineState *s) case K_KPAGEUP: case K_PAGEDOWN: case K_KPAGEDOWN: - if (hislen == 0 || s->firstc == NUL) { + if (s->histype == HIST_INVALID || hislen == 0 || s->firstc == NUL) { // no history return command_line_not_changed(s); } @@ -3981,6 +3983,7 @@ static void expand_shellcmd(char_u *filepat, int *num_file, char_u ***file, char_u *s, *e; int flags = flagsarg; int ret; + bool did_curdir = false; /* for ":set path=" and ":set tags=" halve backslashes for escaped * space */ @@ -3989,7 +3992,7 @@ static void expand_shellcmd(char_u *filepat, int *num_file, char_u ***file, if (pat[i] == '\\' && pat[i + 1] == ' ') STRMOVE(pat + i, pat + i + 1); - flags |= EW_FILE | EW_EXEC; + flags |= EW_FILE | EW_EXEC | EW_SHELLCMD; bool mustfree = false; // Track memory allocation for *path. /* For an absolute name we don't use $PATH. */ @@ -4009,12 +4012,24 @@ static void expand_shellcmd(char_u *filepat, int *num_file, char_u ***file, /* * Go over all directories in $PATH. Expand matches in that directory and - * collect them in "ga". + * collect them in "ga". When "." is not in $PATH also expaned for the + * current directory, to find "subdir/cmd". */ ga_init(&ga, (int)sizeof(char *), 10); - for (s = path; *s != NUL; s = e) { - if (*s == ' ') - ++s; /* Skip space used for absolute path name. */ + for (s = path; ; s = e) { + if (*s == NUL) { + if (did_curdir) { + break; + } + // Find directories in the current directory, path is empty. + did_curdir = true; + } else if (*s == '.') { + did_curdir = true; + } + + if (*s == ' ') { + s++; // Skip space used for absolute path name. + } e = vim_strchr(s, ':'); if (e == NULL) @@ -4272,20 +4287,33 @@ void globpath(char_u *path, char_u *file, garray_T *ga, int expand_options) * Command line history stuff * *********************************/ -/* - * Translate a history character to the associated type number. - */ -static int hist_char2type(int c) +/// Translate a history character to the associated type number +static HistoryType hist_char2type(const int c) + FUNC_ATTR_CONST FUNC_ATTR_WARN_UNUSED_RESULT { - if (c == ':') - return HIST_CMD; - if (c == '=') - return HIST_EXPR; - if (c == '@') - return HIST_INPUT; - if (c == '>') - return HIST_DEBUG; - return HIST_SEARCH; /* must be '?' or '/' */ + switch (c) { + case ':': { + return HIST_CMD; + } + case '=': { + return HIST_EXPR; + } + case '@': { + return HIST_INPUT; + } + case '>': { + return HIST_DEBUG; + } + case '/': + case '?': { + return HIST_SEARCH; + } + default: { + return HIST_INVALID; + } + } + // Silence -Wreturn-type + return 0; } /* @@ -4454,28 +4482,38 @@ in_history ( return false; } -/* - * Convert history name (from table above) to its HIST_ equivalent. - * When "name" is empty, return "cmd" history. - * Returns -1 for unknown history name. - */ -int get_histtype(char_u *name) +/// Convert history name to its HIST_ equivalent +/// +/// Names are taken from the table above. When `name` is empty returns currently +/// active history or HIST_DEFAULT, depending on `return_default` argument. +/// +/// @param[in] name Converted name. +/// @param[in] len Name length. +/// @param[in] return_default Determines whether HIST_DEFAULT should be +/// returned or value based on `ccline.cmdfirstc`. +/// +/// @return Any value from HistoryType enum, including HIST_INVALID. May not +/// return HIST_DEFAULT unless return_default is true. +HistoryType get_histtype(const char_u *const name, const size_t len, + const bool return_default) + FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT { - int i; - int len = (int)STRLEN(name); - - /* No argument: use current history. */ - if (len == 0) - return hist_char2type(ccline.cmdfirstc); + // No argument: use current history. + if (len == 0) { + return return_default ? HIST_DEFAULT : hist_char2type(ccline.cmdfirstc); + } - for (i = 0; history_names[i] != NULL; ++i) - if (STRNICMP(name, history_names[i], len) == 0) + for (HistoryType i = 0; history_names[i] != NULL; i++) { + if (STRNICMP(name, history_names[i], len) == 0) { return i; + } + } - if (vim_strchr((char_u *)":=@>?/", name[0]) != NULL && name[1] == NUL) + if (vim_strchr((char_u *)":=@>?/", name[0]) != NULL && len == 1) { return hist_char2type(name[0]); + } - return -1; + return HIST_INVALID; } static int last_maptick = -1; /* last seen maptick */ @@ -4496,8 +4534,10 @@ add_to_history ( histentry_T *hisptr; int len; - if (hislen == 0) /* no history */ + if (hislen == 0 || histype == HIST_INVALID) { // no history return; + } + assert(histype != HIST_DEFAULT); if (cmdmod.keeppatterns && histype == HIST_SEARCH) return; @@ -4847,23 +4887,20 @@ void ex_history(exarg_T *eap) while (ASCII_ISALPHA(*end) || vim_strchr((char_u *)":=@>/?", *end) != NULL) end++; - i = *end; - *end = NUL; - histype1 = get_histtype(arg); - if (histype1 == -1) { - if (STRNICMP(arg, "all", STRLEN(arg)) == 0) { + histype1 = get_histtype(arg, end - arg, false); + if (histype1 == HIST_INVALID) { + if (STRNICMP(arg, "all", end - arg) == 0) { histype1 = 0; histype2 = HIST_COUNT-1; } else { - *end = i; EMSG(_(e_trailing)); return; } } else histype2 = histype1; - *end = i; - } else + } else { end = arg; + } if (!get_list_range(&end, &hisidx1, &hisidx2) || *end != NUL) { EMSG(_(e_trailing)); return; @@ -4971,7 +5008,6 @@ static int ex_window(void) win_T *wp; int i; linenr_T lnum; - int histtype; garray_T winsizes; char_u typestr[2]; int save_restart_edit = restart_edit; @@ -5020,7 +5056,7 @@ static int ex_window(void) /* Showing the prompt may have set need_wait_return, reset it. */ need_wait_return = FALSE; - histtype = hist_char2type(cmdwin_type); + const int histtype = hist_char2type(cmdwin_type); if (histtype == HIST_CMD || histtype == HIST_DEBUG) { if (p_wc == TAB) { add_map((char_u *)"<buffer> <Tab> <C-X><C-V>", INSERT); @@ -5035,7 +5071,7 @@ static int ex_window(void) /* Fill the buffer with the history. */ init_history(); - if (hislen > 0) { + if (hislen > 0 && histtype != HIST_INVALID) { i = hisidx[histtype]; if (i >= 0) { lnum = 0; diff --git a/src/nvim/ex_getln.h b/src/nvim/ex_getln.h index 21da8b9d42..24eebdc303 100644 --- a/src/nvim/ex_getln.h +++ b/src/nvim/ex_getln.h @@ -27,11 +27,13 @@ /// Present history tables typedef enum { - HIST_CMD, ///< Colon commands. - HIST_SEARCH, ///< Search commands. - HIST_EXPR, ///< Expressions (e.g. from entering = register). - HIST_INPUT, ///< input() lines. - HIST_DEBUG, ///< Debug commands. + HIST_DEFAULT = -2, ///< Default (current) history. + HIST_INVALID = -1, ///< Unknown history. + HIST_CMD = 0, ///< Colon commands. + HIST_SEARCH, ///< Search commands. + HIST_EXPR, ///< Expressions (e.g. from entering = register). + HIST_INPUT, ///< input() lines. + HIST_DEBUG, ///< Debug commands. } HistoryType; /// Number of history tables diff --git a/src/nvim/farsi.c b/src/nvim/farsi.c index 47a132c0d0..61e17128ea 100644 --- a/src/nvim/farsi.c +++ b/src/nvim/farsi.c @@ -100,8 +100,9 @@ static char_u toF_Xor_X_(int c) case F_HE : tempc = _HE; - if (p_ri && - (curwin->w_cursor.col + 1 < (colnr_T)STRLEN(get_cursor_line_ptr()))) { + if (p_ri + && (curwin->w_cursor.col + 1 + < (colnr_T)STRLEN(get_cursor_line_ptr()))) { inc_cursor(); if (F_is_TyB_TyC_TyD(SRC_EDT, AT_CURSOR)) { tempc = _HE_; @@ -526,8 +527,8 @@ static void chg_l_toXor_X(void) { char_u tempc; - if ((curwin->w_cursor.col != 0) && - (curwin->w_cursor.col + 1 == (colnr_T)STRLEN(get_cursor_line_ptr()))) { + if ((curwin->w_cursor.col != 0) + && (curwin->w_cursor.col + 1 == (colnr_T)STRLEN(get_cursor_line_ptr()))) { return; } @@ -680,17 +681,17 @@ int fkmap(int c) } } - if ((c < 0x100) && - (isalpha(c) || - (c == '&') || - (c == '^') || - (c == ';') || - (c == '\'') || - (c == ',') || - (c == '[') || - (c == ']') || - (c == '{') || - (c == '}'))) { + if ((c < 0x100) + && (isalpha(c) + || (c == '&') + || (c == '^') + || (c == ';') + || (c == '\'') + || (c == ',') + || (c == '[') + || (c == ']') + || (c == '{') + || (c == '}'))) { chg_r_to_Xor_X_(); } diff --git a/src/nvim/file_search.c b/src/nvim/file_search.c index 2929790ebf..beefc4238e 100644 --- a/src/nvim/file_search.c +++ b/src/nvim/file_search.c @@ -1400,8 +1400,14 @@ find_file_in_path_option ( && (ff_file_to_find[2] == NUL || vim_ispathsep(ff_file_to_find[2]))))); if (vim_isAbsName(ff_file_to_find) - /* "..", "../path", "." and "./path": don't use the path_option */ + // "..", "../path", "." and "./path": don't use the path_option || rel_to_curdir +#if defined(WIN32) + // handle "\tmp" as absolute path + || vim_ispathsep(ff_file_to_find[0]) + // handle "c:name" as absolute path + || (ff_file_to_find[0] != NUL && ff_file_to_find[1] == ':') +#endif ) { /* * Absolute path, no need to use "path_option". diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c index 32e1b645d0..6c0bc59d93 100644 --- a/src/nvim/fileio.c +++ b/src/nvim/fileio.c @@ -45,7 +45,6 @@ #include "nvim/search.h" #include "nvim/sha256.h" #include "nvim/strings.h" -#include "nvim/tempfile.h" #include "nvim/ui.h" #include "nvim/types.h" #include "nvim/undo.h" @@ -606,13 +605,14 @@ readfile ( * Don't do this for a "nofile" or "nowrite" buffer type. */ if (!bt_dontwrite(curbuf)) { check_need_swap(newfile); - if (!read_stdin && (curbuf != old_curbuf - || (using_b_ffname && (old_b_ffname != curbuf->b_ffname)) - || (using_b_fname && - (old_b_fname != curbuf->b_fname)))) { + if (!read_stdin + && (curbuf != old_curbuf + || (using_b_ffname && (old_b_ffname != curbuf->b_ffname)) + || (using_b_fname && (old_b_fname != curbuf->b_fname)))) { EMSG(_(e_auchangedbuf)); - if (!read_buffer) + if (!read_buffer) { close(fd); + } return FAIL; } #ifdef UNIX @@ -2577,7 +2577,7 @@ buf_write ( errmsg = (char_u *)_("is a directory"); goto fail; } - if (mch_nodetype(fname) != NODE_WRITABLE) { + if (os_nodetype((char *)fname) != NODE_WRITABLE) { errnum = (char_u *)"E503: "; errmsg = (char_u *)_("is not a file or writable device"); goto fail; @@ -2589,11 +2589,11 @@ buf_write ( perm = -1; } } -#else /* !UNIX */ +#else /* win32 */ /* * Check for a writable device name. */ - c = mch_nodetype(fname); + c = os_nodetype((char *)fname); if (c == NODE_OTHER) { errnum = (char_u *)"E503: "; errmsg = (char_u *)_("is not a file or writable device"); @@ -2689,7 +2689,6 @@ buf_write ( } else if ((bkc & BKC_AUTO)) { /* "auto" */ int i; -# ifdef UNIX /* * Don't rename the file when: * - it's a hard link @@ -2700,9 +2699,7 @@ buf_write ( || !os_fileinfo_link((char *)fname, &file_info) || !os_fileinfo_id_equal(&file_info, &file_info_old)) { backup_copy = TRUE; - } else -# endif - { + } else { /* * Check if we can create a file and set the owner/group to * the ones from the original file. @@ -4373,8 +4370,8 @@ char *modname(const char *fname, const char *ext, bool prepend_dot) // (we need the full path in case :cd is used). if (fname == NULL || *fname == NUL) { retval = xmalloc(MAXPATHL + extlen + 3); // +3 for PATHSEP, "_" (Win), NUL - if (os_dirname((char_u *)retval, MAXPATHL) == FAIL || - (fnamelen = strlen(retval)) == 0) { + if (os_dirname((char_u *)retval, MAXPATHL) == FAIL + || (fnamelen = strlen(retval)) == 0) { xfree(retval); return NULL; } @@ -5116,6 +5113,147 @@ void forward_slash(char_u *fname) } #endif +/// Name of Vim's own temp dir. Ends in a slash. +static char_u *vim_tempdir = NULL; + +/// Create a directory for private use by this instance of Neovim. +/// This is done once, and the same directory is used for all temp files. +/// This method avoids security problems because of symlink attacks et al. +/// It's also a bit faster, because we only need to check for an existing +/// file when creating the directory and not for each temp file. +static void vim_maketempdir(void) +{ + static const char *temp_dirs[] = TEMP_DIR_NAMES; + // Try the entries in `TEMP_DIR_NAMES` to create the temp directory. + char_u template[TEMP_FILE_PATH_MAXLEN]; + char_u path[TEMP_FILE_PATH_MAXLEN]; + for (size_t i = 0; i < ARRAY_SIZE(temp_dirs); i++) { + // Expand environment variables, leave room for "/nvimXXXXXX/999999999" + expand_env((char_u *)temp_dirs[i], template, TEMP_FILE_PATH_MAXLEN - 22); + if (!os_isdir(template)) { // directory doesn't exist + continue; + } + + add_pathsep((char *)template); + // Concatenate with temporary directory name pattern + STRCAT(template, "nvimXXXXXX"); + + if (os_mkdtemp((const char *)template, (char *)path) != 0) { + continue; + } + + if (vim_settempdir((char *)path)) { + // Successfully created and set temporary directory so stop trying. + break; + } else { + // Couldn't set `vim_tempdir` to `path` so remove created directory. + os_rmdir((char *)path); + } + } +} + +/// Delete "name" and everything in it, recursively. +/// @param name The path which should be deleted. +/// @return 0 for success, -1 if some file was not deleted. +int delete_recursive(char_u *name) +{ + int result = 0; + + if (os_isrealdir(name)) { + snprintf((char *)NameBuff, MAXPATHL, "%s/*", name); // NOLINT + + char_u **files; + int file_count; + char_u *exp = vim_strsave(NameBuff); + if (gen_expand_wildcards(1, &exp, &file_count, &files, + EW_DIR | EW_FILE | EW_SILENT | EW_ALLLINKS + | EW_DODOT | EW_EMPTYOK) == OK) { + for (int i = 0; i < file_count; i++) { + if (delete_recursive(files[i]) != 0) { + result = -1; + } + } + FreeWild(file_count, files); + } else { + result = -1; + } + + xfree(exp); + os_rmdir((char *)name); + } else { + result = os_remove((char *)name) == 0 ? 0 : -1; + } + + return result; +} + +/// Delete the temp directory and all files it contains. +void vim_deltempdir(void) +{ + if (vim_tempdir != NULL) { + // remove the trailing path separator + path_tail(vim_tempdir)[-1] = NUL; + delete_recursive(vim_tempdir); + xfree(vim_tempdir); + vim_tempdir = NULL; + } +} + +/// Get the name of temp directory. This directory would be created on the first +/// call to this function. +char_u *vim_gettempdir(void) +{ + if (vim_tempdir == NULL) { + vim_maketempdir(); + } + + return vim_tempdir; +} + +/// Set Neovim own temporary directory name to `tempdir`. This directory should +/// be already created. Expand this name to a full path and put it in +/// `vim_tempdir`. This avoids that using `:cd` would confuse us. +/// +/// @param tempdir must be no longer than MAXPATHL. +/// +/// @return false if we run out of memory. +static bool vim_settempdir(char *tempdir) +{ + char *buf = verbose_try_malloc(MAXPATHL + 2); + if (!buf) { + return false; + } + vim_FullName(tempdir, buf, MAXPATHL, false); + add_pathsep(buf); + vim_tempdir = (char_u *)xstrdup(buf); + xfree(buf); + return true; +} + +/// Return a unique name that can be used for a temp file. +/// +/// @note The temp file is NOT created. +/// +/// @return pointer to the temp file name or NULL if Neovim can't create +/// temporary directory for its own temporary files. +char_u *vim_tempname(void) +{ + // Temp filename counter. + static uint32_t temp_count; + + char_u *tempdir = vim_gettempdir(); + if (!tempdir) { + return NULL; + } + + // There is no need to check if the file exists, because we own the directory + // and nobody else creates a file in it. + char_u template[TEMP_FILE_PATH_MAXLEN]; + snprintf((char *)template, TEMP_FILE_PATH_MAXLEN, + "%s%" PRIu32, tempdir, temp_count++); + return vim_strsave(template); +} + /* * Code for automatic commands. diff --git a/src/nvim/fold.c b/src/nvim/fold.c index 7f46a37315..ac3cf959c8 100644 --- a/src/nvim/fold.c +++ b/src/nvim/fold.c @@ -2110,10 +2110,11 @@ static linenr_T foldUpdateIEMSRecurse(garray_T *gap, int level, */ if (getlevel == foldlevelMarker && flp->start <= flp->lvl - level && flp->lvl > 0) { - foldFind(gap, startlnum - 1, &fp); + (void)foldFind(gap, startlnum - 1, &fp); if (fp >= ((fold_T *)gap->ga_data) + gap->ga_len - || fp->fd_top >= startlnum) + || fp->fd_top >= startlnum) { fp = NULL; + } } /* @@ -2167,13 +2168,15 @@ static linenr_T foldUpdateIEMSRecurse(garray_T *gap, int level, } } if (lvl < level + i) { - foldFind(&fp->fd_nested, flp->lnum - fp->fd_top, &fp2); - if (fp2 != NULL) + (void)foldFind(&fp->fd_nested, flp->lnum - fp->fd_top, &fp2); + if (fp2 != NULL) { bot = fp2->fd_top + fp2->fd_len - 1 + fp->fd_top; - } else if (fp->fd_top + fp->fd_len <= flp->lnum && lvl >= level) - finish = TRUE; - else + } + } else if (fp->fd_top + fp->fd_len <= flp->lnum && lvl >= level) { + finish = true; + } else { break; + } } /* At the start of the first nested fold and at the end of the current diff --git a/src/nvim/getchar.c b/src/nvim/getchar.c index 437495faa4..dbf0322d78 100644 --- a/src/nvim/getchar.c +++ b/src/nvim/getchar.c @@ -144,7 +144,7 @@ static int KeyNoremap = 0; /* remapping flags */ static char_u typebuf_init[TYPELEN_INIT]; /* initial typebuf.tb_buf */ static char_u noremapbuf_init[TYPELEN_INIT]; /* initial typebuf.tb_noremap */ -static int last_recorded_len = 0; /* number of last recorded chars */ +static size_t last_recorded_len = 0; // number of last recorded chars static const uint8_t ui_toggle[] = { K_SPECIAL, KS_EXTRA, KE_PASTE, 0 }; #ifdef INCLUDE_GENERATED_DECLARATIONS @@ -211,7 +211,7 @@ char_u *get_recorded(void) * (possibly mapped) characters that stopped the recording. */ len = STRLEN(p); - if ((int)len >= last_recorded_len) { + if (len >= last_recorded_len) { len -= last_recorded_len; p[len] = NUL; } @@ -243,13 +243,15 @@ static void add_buff ( buffheader_T *buf, char_u *s, - long slen /* length of "s" or -1 */ + ssize_t slen // length of "s" or -1 ) { - if (slen < 0) - slen = (long)STRLEN(s); - if (slen == 0) /* don't add empty strings */ + if (slen < 0) { + slen = (ssize_t)STRLEN(s); + } + if (slen == 0) { // don't add empty strings return; + } if (buf->bh_first.b_next == NULL) { /* first add to list */ buf->bh_space = 0; @@ -263,18 +265,19 @@ add_buff ( STRLEN(buf->bh_first.b_next->b_str + buf->bh_index) + 1); buf->bh_index = 0; - ssize_t len; - if (buf->bh_space >= (int)slen) { + size_t len; + if (buf->bh_space >= (size_t)slen) { len = STRLEN(buf->bh_curr->b_str); STRLCPY(buf->bh_curr->b_str + len, s, slen + 1); - buf->bh_space -= slen; + buf->bh_space -= (size_t)slen; } else { - if (slen < MINIMAL_SIZE) + if (slen < MINIMAL_SIZE) { len = MINIMAL_SIZE; - else - len = slen; + } else { + len = (size_t)slen; + } buffblock_T *p = xmalloc(sizeof(buffblock_T) + len); - buf->bh_space = (int)(len - slen); + buf->bh_space = len - (size_t)slen; STRLCPY(p->b_str, s, slen + 1); p->b_next = buf->bh_curr->b_next; @@ -317,11 +320,11 @@ static void add_char_buff(buffheader_T *buf, int c) if (IS_SPECIAL(c) || c == K_SPECIAL || c == NUL) { /* translate special key code into three byte sequence */ temp[0] = K_SPECIAL; - temp[1] = K_SECOND(c); - temp[2] = K_THIRD(c); + temp[1] = (char_u)K_SECOND(c); + temp[2] = (char_u)K_THIRD(c); temp[3] = NUL; } else { - temp[0] = c; + temp[0] = (char_u)c; temp[1] = NUL; } add_buff(buf, temp, -1L); @@ -694,10 +697,11 @@ static int read_redo(int init, int old_redo) bp = bp->b_next; p = bp->b_str; } - buf[i] = c; - if (i == n - 1) { /* last byte of a character */ - if (n != 1) + buf[i] = (char_u)c; + if (i == n - 1) { // last byte of a character + if (n != 1) { c = (*mb_ptr2char)(buf); + } break; } c = *p; @@ -882,8 +886,8 @@ int ins_typebuf(char_u *str, int noremap, int offset, int nottyped, bool silent) setcursor(); return FAIL; } - s1 = xmalloc(newlen); - s2 = xmalloc(newlen); + s1 = xmalloc((size_t)newlen); + s2 = xmalloc((size_t)newlen); typebuf.tb_buflen = newlen; /* copy the old chars, before the insertion point */ @@ -937,7 +941,7 @@ int ins_typebuf(char_u *str, int noremap, int offset, int nottyped, bool silent) nrm = noremap; for (i = 0; i < addlen; ++i) typebuf.tb_noremap[typebuf.tb_off + i + offset] = - (--nrm >= 0) ? val : RM_YES; + (char_u)((--nrm >= 0) ? val : RM_YES); /* tb_maplen and tb_silent only remember the length of mapped and/or * silent mappings at the start of the buffer, assuming that a mapped @@ -965,8 +969,8 @@ void ins_char_typebuf(int c) char_u buf[MB_MAXBYTES + 1]; if (IS_SPECIAL(c)) { buf[0] = K_SPECIAL; - buf[1] = K_SECOND(c); - buf[2] = K_THIRD(c); + buf[1] = (char_u)K_SECOND(c); + buf[2] = (char_u)K_THIRD(c); buf[3] = NUL; } else { buf[(*mb_char2bytes)(c, buf)] = NUL; @@ -1083,25 +1087,25 @@ void del_typebuf(int len, int offset) * Write typed characters to script file. * If recording is on put the character in the recordbuffer. */ -static void gotchars(char_u *chars, int len) +static void gotchars(char_u *chars, size_t len) { char_u *s = chars; int c; char_u buf[2]; - int todo = len; - /* remember how many chars were last recorded */ - if (Recording) + // remember how many chars were last recorded + if (Recording) { last_recorded_len += len; + } buf[1] = NUL; - while (todo--) { - /* Handle one byte at a time; no translation to be done. */ + while (len--) { + // Handle one byte at a time; no translation to be done. c = *s++; updatescript(c); if (Recording) { - buf[0] = c; + buf[0] = (char_u)c; add_buff(&recordbuff, buf, 1L); } } @@ -1465,10 +1469,10 @@ int vgetc(void) * Note: This will loop until enough bytes are received! */ if (has_mbyte && (n = MB_BYTE2LEN_CHECK(c)) > 1) { - ++no_mapping; - buf[0] = c; - for (i = 1; i < n; ++i) { - buf[i] = vgetorpeek(TRUE); + no_mapping++; + buf[0] = (char_u)c; + for (i = 1; i < n; i++) { + buf[i] = (char_u)vgetorpeek(true); if (buf[i] == K_SPECIAL ) { /* Must be a K_SPECIAL - KS_SPECIAL - KE_FILLER sequence, @@ -1562,7 +1566,7 @@ int char_avail(void) { int retval; - ++no_mapping; + no_mapping++; retval = vpeekc(); --no_mapping; return retval != NUL; @@ -1711,7 +1715,7 @@ static int vgetorpeek(int advance) if (advance) { /* Also record this character, it might be needed to * get out of Insert mode. */ - *typebuf.tb_buf = c; + *typebuf.tb_buf = (char_u)c; gotchars(typebuf.tb_buf, 1); } cmd_silent = FALSE; @@ -1877,19 +1881,19 @@ static int vgetorpeek(int advance) match = typebuf_match_len(p_pt, &mlen); } if (match) { - /* write chars to script file(s) */ - if (mlen > typebuf.tb_maplen) - gotchars(typebuf.tb_buf + typebuf.tb_off - + typebuf.tb_maplen, - mlen - typebuf.tb_maplen); + // write chars to script file(s) + if (mlen > typebuf.tb_maplen) { + gotchars(typebuf.tb_buf + typebuf.tb_off + typebuf.tb_maplen, + (size_t)(mlen - typebuf.tb_maplen)); + } del_typebuf(mlen, 0); /* remove the chars */ set_option_value((char_u *)"paste", (long)!p_paste, NULL, 0); if (!(State & INSERT)) { msg_col = 0; - msg_row = Rows - 1; - msg_clr_eos(); /* clear ruler */ + msg_row = (int)Rows - 1; + msg_clr_eos(); // clear ruler } status_redraw_all(); redraw_statuslines(); @@ -1975,11 +1979,11 @@ static int vgetorpeek(int advance) char_u *save_m_keys; char_u *save_m_str; - /* write chars to script file(s) */ - if (keylen > typebuf.tb_maplen) - gotchars(typebuf.tb_buf + typebuf.tb_off - + typebuf.tb_maplen, - keylen - typebuf.tb_maplen); + // write chars to script file(s) + if (keylen > typebuf.tb_maplen) { + gotchars(typebuf.tb_buf + typebuf.tb_off + typebuf.tb_maplen, + (size_t)(keylen - typebuf.tb_maplen)); + } cmd_silent = (typebuf.tb_silent > 0); del_typebuf(keylen, 0); /* remove the mapped keys */ @@ -2417,7 +2421,7 @@ inchar ( else return -1; } else { - buf[0] = script_char; + buf[0] = (char_u)script_char; len = 1; } } @@ -2453,7 +2457,7 @@ inchar ( * Fill up to a third of the buffer, because each character may be * tripled below. */ - len = os_inchar(buf, maxlen / 3, wait_time, tb_change_cnt); + len = os_inchar(buf, maxlen / 3, (int)wait_time, tb_change_cnt); } if (typebuf_changed(tb_change_cnt)) @@ -2496,8 +2500,8 @@ fix_input_buffer ( && !script && (i < 2 || p[1] != KS_EXTRA))) { memmove(p + 3, p + 1, (size_t)i); - p[2] = K_THIRD(p[0]); - p[1] = K_SECOND(p[0]); + p[2] = (char_u)K_THIRD(p[0]); + p[1] = (char_u)K_SECOND(p[0]); p[0] = K_SPECIAL; p += 2; len += 2; @@ -2573,11 +2577,11 @@ do_map ( int new_hash; mapblock_T **abbr_table; mapblock_T **map_table; - int unique = FALSE; - int nowait = FALSE; - int silent = FALSE; - int special = FALSE; - int expr = FALSE; + bool unique = false; + bool nowait = false; + bool silent = false; + bool special = false; + bool expr = false; int noremap; char_u *orig_rhs; @@ -2609,7 +2613,7 @@ do_map ( */ if (STRNCMP(keys, "<nowait>", 8) == 0) { keys = skipwhite(keys + 8); - nowait = TRUE; + nowait = true; continue; } @@ -2618,7 +2622,7 @@ do_map ( */ if (STRNCMP(keys, "<silent>", 8) == 0) { keys = skipwhite(keys + 8); - silent = TRUE; + silent = true; continue; } @@ -2627,7 +2631,7 @@ do_map ( */ if (STRNCMP(keys, "<special>", 9) == 0) { keys = skipwhite(keys + 9); - special = TRUE; + special = true; continue; } @@ -2645,7 +2649,7 @@ do_map ( */ if (STRNCMP(keys, "<expr>", 6) == 0) { keys = skipwhite(keys + 6); - expr = TRUE; + expr = true; continue; } /* @@ -2653,7 +2657,7 @@ do_map ( */ if (STRNCMP(keys, "<unique>", 8) == 0) { keys = skipwhite(keys + 8); - unique = TRUE; + unique = true; continue; } break; @@ -2669,13 +2673,14 @@ do_map ( p = keys; do_backslash = (vim_strchr(p_cpo, CPO_BSLASH) == NULL); while (*p && (maptype == 1 || !ascii_iswhite(*p))) { - if ((p[0] == Ctrl_V || (do_backslash && p[0] == '\\')) && - p[1] != NUL) - ++p; /* skip CTRL-V or backslash */ - ++p; + if ((p[0] == Ctrl_V || (do_backslash && p[0] == '\\')) && p[1] != NUL) { + p++; // skip CTRL-V or backslash + } + p++; } - if (*p != NUL) + if (*p != NUL) { *p++ = NUL; + } p = skipwhite(p); rhs = p; @@ -2688,22 +2693,24 @@ do_map ( goto theend; } - /* - * If mapping has been given as ^V<C_UP> say, then replace the term codes - * with the appropriate two bytes. If it is a shifted special key, unshift - * it too, giving another two bytes. - * replace_termcodes() may move the result to allocated memory, which - * needs to be freed later (*keys_buf and *arg_buf). - * replace_termcodes() also removes CTRL-Vs and sometimes backslashes. - */ - if (haskey) - keys = replace_termcodes(keys, &keys_buf, TRUE, TRUE, special); + // If mapping has been given as ^V<C_UP> say, then replace the term codes + // with the appropriate two bytes. If it is a shifted special key, unshift + // it too, giving another two bytes. + // replace_termcodes() may move the result to allocated memory, which + // needs to be freed later (*keys_buf and *arg_buf). + // replace_termcodes() also removes CTRL-Vs and sometimes backslashes. + if (haskey) { + keys = replace_termcodes(keys, STRLEN(keys), &keys_buf, true, true, special, + CPO_TO_CPO_FLAGS); + } orig_rhs = rhs; if (hasarg) { - if (STRICMP(rhs, "<nop>") == 0) /* "<Nop>" means nothing */ + if (STRICMP(rhs, "<nop>") == 0) { // "<Nop>" means nothing rhs = (char_u *)""; - else - rhs = replace_termcodes(rhs, &arg_buf, FALSE, TRUE, special); + } else { + rhs = replace_termcodes(rhs, STRLEN(rhs), &arg_buf, false, true, special, + CPO_TO_CPO_FLAGS); + } } /* @@ -3270,7 +3277,8 @@ int map_to_exists(char_u *str, char_u *modechars, int abbr) char_u *buf; int retval; - rhs = replace_termcodes(str, &buf, FALSE, TRUE, FALSE); + rhs = replace_termcodes(str, STRLEN(str), &buf, false, true, false, + CPO_TO_CPO_FLAGS); if (vim_strchr(modechars, 'n') != NULL) mode |= NORMAL; @@ -3465,7 +3473,7 @@ int ExpandMappings(regmatch_T *regmatch, int *num_file, char_u ***file) mp = maphash[hash]; for (; mp; mp = mp->m_next) { if (mp->m_mode & expand_mapmodes) { - p = translate_mapping(mp->m_keys, TRUE); + p = translate_mapping(mp->m_keys, true, CPO_TO_CPO_FLAGS); if (p != NULL && vim_regexec(regmatch, p, (colnr_T)0)) { if (round == 1) ++count; @@ -3483,7 +3491,7 @@ int ExpandMappings(regmatch_T *regmatch, int *num_file, char_u ***file) break; /* for (round) */ if (round == 1) { - *file = (char_u **)xmalloc(count * sizeof(char_u *)); + *file = (char_u **)xmalloc((size_t)count * sizeof(char_u *)); } } /* for (round) */ @@ -3647,8 +3655,8 @@ int check_abbr(int c, char_u *ptr, int col, int mincol) /* special key code, split up */ if (IS_SPECIAL(c) || c == K_SPECIAL) { tb[j++] = K_SPECIAL; - tb[j++] = K_SECOND(c); - tb[j++] = K_THIRD(c); + tb[j++] = (char_u)K_SECOND(c); + tb[j++] = (char_u)K_THIRD(c); } else { if (c < ABBR_OFF && (c < ' ' || c > '~')) tb[j++] = Ctrl_V; /* special char needs CTRL-V */ @@ -3657,8 +3665,9 @@ int check_abbr(int c, char_u *ptr, int col, int mincol) if (c >= ABBR_OFF) c -= ABBR_OFF; j += (*mb_char2bytes)(c, tb + j); - } else - tb[j++] = c; + } else { + tb[j++] = (char_u)c; + } } tb[j] = NUL; /* insert the last typed char */ @@ -4190,14 +4199,15 @@ void add_map(char_u *map, int mode) // Returns NULL when there is a problem. static char_u * translate_mapping ( char_u *str, - int expmap // TRUE when expanding mappings on command-line + int expmap, // True when expanding mappings on command-line + int cpo_flags // Value of various flags present in &cpo ) { garray_T ga; ga_init(&ga, 1, 40); - int cpo_bslash = (vim_strchr(p_cpo, CPO_BSLASH) != NULL); - int cpo_special = (vim_strchr(p_cpo, CPO_SPECI) != NULL); + bool cpo_bslash = !(cpo_flags&FLAG_CPO_BSLASH); + bool cpo_special = !(cpo_flags&FLAG_CPO_SPECI); for (; *str; ++str) { int c = *str; diff --git a/src/nvim/hardcopy.c b/src/nvim/hardcopy.c index cc49bcd074..916d27a964 100644 --- a/src/nvim/hardcopy.c +++ b/src/nvim/hardcopy.c @@ -32,7 +32,6 @@ #include "nvim/syntax.h" #include "nvim/ui.h" #include "nvim/version.h" -#include "nvim/tempfile.h" #include "nvim/os/os.h" #include "nvim/os/input.h" @@ -2191,18 +2190,19 @@ int mch_print_init(prt_settings_T *psettings, char_u *jobname, int forceit) mbfont_opts[OPT_MBFONT_BOLDOBLIQUE].strlen); } - /* Check if need to use Courier for ASCII code range, and if so pick up - * the encoding to use */ - prt_use_courier = mbfont_opts[OPT_MBFONT_USECOURIER].present && - (TOLOWER_ASC(mbfont_opts[OPT_MBFONT_USECOURIER].string[0]) - == 'y'); + // Check if need to use Courier for ASCII code range, and if so pick up + // the encoding to use + prt_use_courier = ( + mbfont_opts[OPT_MBFONT_USECOURIER].present + && (TOLOWER_ASC(mbfont_opts[OPT_MBFONT_USECOURIER].string[0]) == 'y')); if (prt_use_courier) { - /* Use national ASCII variant unless ASCII wanted */ - if (mbfont_opts[OPT_MBFONT_ASCII].present && - (TOLOWER_ASC(mbfont_opts[OPT_MBFONT_ASCII].string[0]) == 'y')) + // Use national ASCII variant unless ASCII wanted + if (mbfont_opts[OPT_MBFONT_ASCII].present + && (TOLOWER_ASC(mbfont_opts[OPT_MBFONT_ASCII].string[0]) == 'y')) { prt_ascii_encoding = "ascii"; - else + } else { prt_ascii_encoding = prt_ps_mbfonts[cmap].ascii_enc; + } } prt_ps_font = &prt_ps_mb_font; @@ -3030,10 +3030,10 @@ int mch_print_text_out(char_u *p, size_t len) prt_text_run += char_width; prt_pos_x += char_width; - /* The downside of fp - use relative error on right margin check */ + // The downside of fp - use relative error on right margin check next_pos = prt_pos_x + prt_char_width; - need_break = (next_pos > prt_right_margin) && - ((next_pos - prt_right_margin) > (prt_right_margin*1e-5)); + need_break = ((next_pos > prt_right_margin) + && ((next_pos - prt_right_margin) > (prt_right_margin * 1e-5))); if (need_break) prt_flush_buffer(); diff --git a/src/nvim/if_cscope.c b/src/nvim/if_cscope.c index a143490356..2f9ec0b3ff 100644 --- a/src/nvim/if_cscope.c +++ b/src/nvim/if_cscope.c @@ -27,7 +27,6 @@ #include "nvim/quickfix.h" #include "nvim/strings.h" #include "nvim/tag.h" -#include "nvim/tempfile.h" #include "nvim/window.h" #include "nvim/os/os.h" #include "nvim/os/input.h" @@ -1063,8 +1062,8 @@ static int cs_find_common(char *opt, char *pat, int forceit, int verbose, if (qf_init(wp, tmp, (char_u *)"%f%*\\t%l%*\\t%m", *qfpos == '-', cmdline) > 0) { if (postponed_split != 0) { - win_split(postponed_split > 0 ? postponed_split : 0, - postponed_split_flags); + (void)win_split(postponed_split > 0 ? postponed_split : 0, + postponed_split_flags); RESET_BINDING(curwin); postponed_split = 0; } diff --git a/src/nvim/indent_c.c b/src/nvim/indent_c.c index 17fadc4bfd..efe8e73a3c 100644 --- a/src/nvim/indent_c.c +++ b/src/nvim/indent_c.c @@ -2282,15 +2282,14 @@ int get_c_indent(void) * location for b_ind_open_extra. */ - if (start_brace == BRACE_IN_COL0) { /* '{' is in column 0 */ + if (start_brace == BRACE_IN_COL0) { // '{' is in column 0 amount = curbuf->b_ind_open_left_imag; - lookfor_cpp_namespace = TRUE; - } else if (start_brace == BRACE_AT_START && - lookfor_cpp_namespace) { /* '{' is at start */ - - lookfor_cpp_namespace = TRUE; + lookfor_cpp_namespace = true; + } else if (start_brace == BRACE_AT_START + && lookfor_cpp_namespace) { // '{' is at start + lookfor_cpp_namespace = true; } else { - if (start_brace == BRACE_AT_END) { /* '{' is at end of line */ + if (start_brace == BRACE_AT_END) { // '{' is at end of line amount += curbuf->b_ind_open_imag; l = skipwhite(get_cursor_line_ptr()); diff --git a/src/nvim/keymap.c b/src/nvim/keymap.c index 6c75d8bdf4..99e94fc60f 100644 --- a/src/nvim/keymap.c +++ b/src/nvim/keymap.c @@ -482,26 +482,28 @@ char_u *get_special_key_name(int c, int modifiers) return string; } -/* - * Try translating a <> name at (*srcp)[] to dst[]. - * Return the number of characters added to dst[], zero for no match. - * If there is a match, srcp is advanced to after the <> name. - * dst[] must be big enough to hold the result (up to six characters)! - */ -unsigned int -trans_special ( - char_u **srcp, - char_u *dst, - int keycode /* prefer key code, e.g. K_DEL instead of DEL */ -) +/// Try translating a <> name +/// +/// @param[in,out] srcp Source from which <> are translated. Is advanced to +/// after the <> name if there is a match. +/// @param[in] src_len Length of the srcp. +/// @param[out] dst Location where translation result will be kept. Must have +/// at least six bytes. +/// @param[in] keycode Prefer key code, e.g. K_DEL in place of DEL. +/// +/// @return Number of characters added to dst, zero for no match. +unsigned int trans_special(const char_u **srcp, const size_t src_len, + char_u *const dst, const bool keycode) + FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT { int modifiers = 0; int key; unsigned int dlen = 0; - key = find_special_key(srcp, &modifiers, keycode, FALSE); - if (key == 0) + key = find_special_key(srcp, src_len, &modifiers, keycode, false); + if (key == 0) { return 0; + } /* Put the appropriate modifier in a string */ if (modifiers != 0) { @@ -514,69 +516,78 @@ trans_special ( dst[dlen++] = K_SPECIAL; dst[dlen++] = (char_u)KEY2TERMCAP0(key); dst[dlen++] = KEY2TERMCAP1(key); - } else if (has_mbyte && !keycode) + } else if (has_mbyte && !keycode) { dlen += (unsigned int)(*mb_char2bytes)(key, dst + dlen); - else if (keycode) { + } else if (keycode) { char_u *after = add_char2buf(key, dst + dlen); assert(after >= dst && (uintmax_t)(after - dst) <= UINT_MAX); dlen = (unsigned int)(after - dst); - } - else + } else { dst[dlen++] = (char_u)key; + } return dlen; } -// Try translating a <> name at (*srcp)[], return the key and modifiers. -// srcp is advanced to after the <> name. -// returns 0 if there is no match. -int find_special_key( - char_u **srcp, - int *modp, - int keycode, // prefer key code, e.g. K_DEL instead of DEL - int keep_x_key // don't translate xHome to Home key -) +/// Try translating a <> name +/// +/// @param[in,out] srcp Translated <> name. Is advanced to after the <> name. +/// @param[in] src_len srcp length. +/// @param[out] modp Location where information about modifiers is saved. +/// @param[in] keycode Prefer key code, e.g. K_DEL in place of DEL. +/// @param[in] keep_x_key Don’t translate xHome to Home key. +/// +/// @return Key and modifiers or 0 if there is no match. +int find_special_key(const char_u **srcp, const size_t src_len, int *const modp, + const bool keycode, const bool keep_x_key) + FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL { - char_u *last_dash; - char_u *end_of_name; - char_u *src; - char_u *bp; + const char_u *last_dash; + const char_u *end_of_name; + const char_u *src; + const char_u *bp; + const char_u *const end = *srcp + src_len - 1; int modifiers; int bit; int key; unsigned long n; int l; + if (src_len == 0) { + return 0; + } + src = *srcp; - if (src[0] != '<') + if (src[0] != '<') { return 0; + } // Find end of modifier list last_dash = src; - for (bp = src + 1; *bp == '-' || vim_isIDc(*bp); bp++) { + for (bp = src + 1; bp <= end && (*bp == '-' || vim_isIDc(*bp)); bp++) { if (*bp == '-') { last_dash = bp; - if (bp[1] != NUL) { + if (bp + 1 <= end) { if (has_mbyte) { - l = mb_ptr2len(bp + 1); + l = mb_ptr2len_len(bp + 1, (int) (end - bp) + 1); } else { l = 1; } - if (bp[l + 1] == '>') { - bp += l; // anything accepted, like <C-?> + if (end - bp > l && bp[l + 1] == '>') { + bp += l; // anything accepted, like <C-?> } } } - if (bp[0] == 't' && bp[1] == '_' && bp[2] && bp[3]) { - bp += 3; // skip t_xx, xx may be '-' or '>' - } else if (STRNICMP(bp, "char-", 5) == 0) { + if (end - bp > 3 && bp[0] == 't' && bp[1] == '_') { + bp += 3; // skip t_xx, xx may be '-' or '>' + } else if (end - bp > 4 && STRNICMP(bp, "char-", 5) == 0) { vim_str2nr(bp + 5, NULL, &l, STR2NR_ALL, NULL, NULL, 0); bp += l + 5; break; } } - if (*bp == '>') { /* found matching '>' */ + if (bp <= end && *bp == '>') { // found matching '>' end_of_name = bp + 1; /* Which modifiers are given? */ @@ -696,7 +707,7 @@ int find_special_key_in_table(int c) * termcap name. * Return the key code, or 0 if not found. */ -int get_special_key_code(char_u *name) +int get_special_key_code(const char_u *name) { char_u *table_name; int i, j; @@ -730,50 +741,58 @@ int get_mouse_button(int code, bool *is_click, bool *is_drag) return 0; /* Shouldn't get here */ } -// Replace any terminal code strings in from[] with the equivalent internal -// vim representation. This is used for the "from" and "to" part of a -// mapping, and the "to" part of a menu command. -// Any strings like "<C-UP>" are also replaced, unless 'cpoptions' contains -// '<'. -// K_SPECIAL by itself is replaced by K_SPECIAL KS_SPECIAL KE_FILLER. -// -// The replacement is done in result[] and finally copied into allocated -// memory. If this all works well *bufp is set to the allocated memory and a -// pointer to it is returned. If something fails *bufp is set to NULL and from -// is returned. -// -// CTRL-V characters are removed. When "from_part" is TRUE, a trailing CTRL-V -// is included, otherwise it is removed (for ":map xx ^V", maps xx to -// nothing). When 'cpoptions' does not contain 'B', a backslash can be used -// instead of a CTRL-V. -char_u * replace_termcodes ( - char_u *from, - char_u **bufp, - int from_part, - int do_lt, // also translate <lt> - int special // always accept <key> notation -) +/// Replace any terminal code strings with the equivalent internal +/// representation +/// +/// This is used for the "from" and "to" part of a mapping, and the "to" part of +/// a menu command. Any strings like "<C-UP>" are also replaced, unless +/// 'cpoptions' contains '<'. K_SPECIAL by itself is replaced by K_SPECIAL +/// KS_SPECIAL KE_FILLER. +/// +/// @param[in] from What characters to replace. +/// @param[in] from_len Length of the "from" argument. +/// @param[out] bufp Location where results were saved in case of success +/// (allocated). Will be set to NULL in case of failure. +/// @param[in] do_lt If true, also translate <lt>. +/// @param[in] from_part If true, trailing <C-v> is included, otherwise it is +/// removed (to make ":map xx ^V" map xx to nothing). +/// When cpo_flags contains #FLAG_CPO_BSLASH, a backslash +/// can be used in place of <C-v>. All other <C-v> +/// characters are removed. +/// @param[in] special If true, always accept <key> notation. +/// @param[in] cpo_flags Relevant flags derived from p_cpo, see +/// #CPO_TO_CPO_FLAGS. +/// +/// @return Pointer to an allocated memory in case of success, "from" in case of +/// failure. In case of success returned pointer is also saved to +/// "bufp". +char_u *replace_termcodes(const char_u *from, const size_t from_len, + char_u **bufp, const bool from_part, const bool do_lt, + const bool special, int cpo_flags) + FUNC_ATTR_NONNULL_ALL { ssize_t i; size_t slen; char_u key; size_t dlen = 0; - char_u *src; + const char_u *src; + const char_u *const end = from + from_len - 1; int do_backslash; // backslash is a special character int do_special; // recognize <> key codes char_u *result; // buffer for resulting string - do_backslash = (vim_strchr(p_cpo, CPO_BSLASH) == NULL); - do_special = (vim_strchr(p_cpo, CPO_SPECI) == NULL) || special; + do_backslash = !(cpo_flags&FLAG_CPO_BSLASH); + do_special = !(cpo_flags&FLAG_CPO_SPECI) || special; // Allocate space for the translation. Worst case a single character is // replaced by 6 bytes (shifted special key), plus a NUL at the end. - result = xmalloc(STRLEN(from) * 6 + 1); + result = xmalloc(from_len * 6 + 1); src = from; // Check for #n at start only: function key n - if (from_part && src[0] == '#' && ascii_isdigit(src[1])) { // function key + if (from_part && from_len > 1 && src[0] == '#' + && ascii_isdigit(src[1])) { // function key result[dlen++] = K_SPECIAL; result[dlen++] = 'k'; if (src[1] == '0') { @@ -785,13 +804,14 @@ char_u * replace_termcodes ( } // Copy each byte from *from to result[dlen] - while (*src != NUL) { + while (src <= end) { // If 'cpoptions' does not contain '<', check for special key codes, // like "<C-S-LeftMouse>" - if (do_special && (do_lt || STRNCMP(src, "<lt>", 4) != 0)) { + if (do_special && (do_lt || ((end - src) >= 3 + && STRNCMP(src, "<lt>", 4) != 0))) { // Replace <SID> by K_SNR <script-nr> _. // (room: 5 * 6 = 30 bytes; needed: 3 + <nr> + 1 <= 14) - if (STRNICMP(src, "<SID>", 5) == 0) { + if (end - src >= 4 && STRNICMP(src, "<SID>", 5) == 0) { if (current_SID <= 0) { EMSG(_(e_usingsid)); } else { @@ -806,7 +826,7 @@ char_u * replace_termcodes ( } } - slen = trans_special(&src, result + dlen, TRUE); + slen = trans_special(&src, (size_t) (end - src) + 1, result + dlen, true); if (slen) { dlen += slen; continue; @@ -819,10 +839,10 @@ char_u * replace_termcodes ( // Replace <Leader> by the value of "mapleader". // Replace <LocalLeader> by the value of "maplocalleader". // If "mapleader" or "maplocalleader" isn't set use a backslash. - if (STRNICMP(src, "<Leader>", 8) == 0) { + if (end - src >= 7 && STRNICMP(src, "<Leader>", 8) == 0) { len = 8; p = get_var_value((char_u *)"g:mapleader"); - } else if (STRNICMP(src, "<LocalLeader>", 13) == 0) { + } else if (end - src >= 12 && STRNICMP(src, "<LocalLeader>", 13) == 0) { len = 13; p = get_var_value((char_u *)"g:maplocalleader"); } else { @@ -851,8 +871,8 @@ char_u * replace_termcodes ( // If 'cpoptions' does not contain 'B', also accept a backslash. key = *src; if (key == Ctrl_V || (do_backslash && key == '\\')) { - ++src; // skip CTRL-V or backslash - if (*src == NUL) { + src++; // skip CTRL-V or backslash + if (src > end) { if (from_part) { result[dlen++] = key; } @@ -861,7 +881,7 @@ char_u * replace_termcodes ( } // skip multibyte char correctly - for (i = (*mb_ptr2len)(src); i > 0; --i) { + for (i = (*mb_ptr2len_len)(src, (int) (end - src) + 1); i > 0; i--) { // If the character is K_SPECIAL, replace it with K_SPECIAL // KS_SPECIAL KE_FILLER. // If compiled with the GUI replace CSI with K_CSI. diff --git a/src/nvim/keymap.h b/src/nvim/keymap.h index 8f9980c6b4..bb8ba84a6a 100644 --- a/src/nvim/keymap.h +++ b/src/nvim/keymap.h @@ -1,6 +1,8 @@ #ifndef NVIM_KEYMAP_H #define NVIM_KEYMAP_H +#include "nvim/strings.h" + /* * Keycode definitions for special keys. * @@ -461,6 +463,14 @@ enum key_extra { // This is a total of 6 tokens, and is currently the longest one possible. #define MAX_KEY_CODE_LEN 6 +#define FLAG_CPO_BSLASH 0x01 +#define FLAG_CPO_SPECI 0x02 +#define CPO_TO_CPO_FLAGS (((vim_strchr(p_cpo, CPO_BSLASH) == NULL) \ + ? 0 \ + : FLAG_CPO_BSLASH)| \ + (vim_strchr(p_cpo, CPO_SPECI) == NULL \ + ? 0 \ + : FLAG_CPO_SPECI)) #ifdef INCLUDE_GENERATED_DECLARATIONS # include "keymap.h.generated.h" diff --git a/src/nvim/memline.c b/src/nvim/memline.c index 10176752d5..4e35dd481f 100644 --- a/src/nvim/memline.c +++ b/src/nvim/memline.c @@ -65,7 +65,6 @@ #include "nvim/strings.h" #include "nvim/ui.h" #include "nvim/version.h" -#include "nvim/tempfile.h" #include "nvim/undo.h" #include "nvim/window.h" #include "nvim/os/os.h" @@ -787,9 +786,8 @@ void ml_recover(void) if (fname == NULL) /* When there is no file name */ fname = (char_u *)""; len = (int)STRLEN(fname); - if (len >= 4 && - STRNICMP(fname + len - 4, ".s", 2) - == 0 + if (len >= 4 + && STRNICMP(fname + len - 4, ".s", 2) == 0 && vim_strchr((char_u *)"UVWuvw", fname[len - 2]) != NULL && ASCII_ISALPHA(fname[len - 1])) { directly = TRUE; diff --git a/src/nvim/menu.c b/src/nvim/menu.c index 91a72abfc5..3c2394d579 100644 --- a/src/nvim/menu.c +++ b/src/nvim/menu.c @@ -215,10 +215,12 @@ ex_menu ( if (STRICMP(map_to, "<nop>") == 0) { /* "<Nop>" means nothing */ map_to = (char_u *)""; map_buf = NULL; - } else if (modes & MENU_TIP_MODE) - map_buf = NULL; /* Menu tips are plain text. */ - else - map_to = replace_termcodes(map_to, &map_buf, FALSE, TRUE, special); + } else if (modes & MENU_TIP_MODE) { + map_buf = NULL; // Menu tips are plain text. + } else { + map_to = replace_termcodes(map_to, STRLEN(map_to), &map_buf, false, true, + special, CPO_TO_CPO_FLAGS); + } menuarg.modes = modes; menuarg.noremap[0] = noremap; menuarg.silent[0] = silent; diff --git a/src/nvim/message.c b/src/nvim/message.c index 97b098c6d2..f60b128712 100644 --- a/src/nvim/message.c +++ b/src/nvim/message.c @@ -1570,39 +1570,31 @@ static void msg_puts_display(char_u *str, int maxlen, int attr, int recurse) int wrap; int did_last_char; - did_wait_return = FALSE; + did_wait_return = false; while ((maxlen < 0 || (int)(s - str) < maxlen) && *s != NUL) { - /* - * We are at the end of the screen line when: - * - When outputting a newline. - * - When outputting a character in the last column. - */ - if (!recurse && msg_row >= Rows - 1 && (*s == '\n' || ( - cmdmsg_rl - ? ( - msg_col <= 1 - || (*s == TAB && msg_col <= 7) - || (has_mbyte && - (*mb_ptr2cells)(s) > 1 && - msg_col <= 2) - ) - : - (msg_col + t_col >= Columns - 1 - || (*s == TAB && msg_col + - t_col >= ((Columns - 1) & ~7)) - || (has_mbyte && - (*mb_ptr2cells)(s) > 1 - && msg_col + t_col >= - Columns - 2) - )))) { - /* - * The screen is scrolled up when at the last row (some terminals - * scroll automatically, some don't. To avoid problems we scroll - * ourselves). - */ - if (t_col > 0) - /* output postponed text */ + // We are at the end of the screen line when: + // - When outputting a newline. + // - When outputting a character in the last column. + if (!recurse && msg_row >= Rows - 1 + && (*s == '\n' || (cmdmsg_rl + ? (msg_col <= 1 + || (*s == TAB && msg_col <= 7) + || (has_mbyte + && (*mb_ptr2cells)(s) > 1 + && msg_col <= 2)) + : (msg_col + t_col >= Columns - 1 + || (*s == TAB + && msg_col + t_col >= ((Columns - 1) & ~7)) + || (has_mbyte + && (*mb_ptr2cells)(s) > 1 + && msg_col + t_col >= Columns - 2))))) { + // The screen is scrolled up when at the last row (some terminals + // scroll automatically, some don't. To avoid problems we scroll + // ourselves). + if (t_col > 0) { + // output postponed text t_puts(&t_col, t_s, s, attr); + } /* When no more prompt and no more room, truncate here */ if (msg_no_more && lines_left == 0) @@ -1709,18 +1701,15 @@ static void msg_puts_display(char_u *str, int maxlen, int attr, int recurse) cw = 1; l = 1; } - /* When drawing from right to left or when a double-wide character - * doesn't fit, draw a single character here. Otherwise collect - * characters and draw them all at once later. */ - if ( - cmdmsg_rl - || - (cw > 1 && msg_col + t_col >= Columns - 1) - ) { - if (l > 1) + // When drawing from right to left or when a double-wide character + // doesn't fit, draw a single character here. Otherwise collect + // characters and draw them all at once later. + if (cmdmsg_rl || (cw > 1 && msg_col + t_col >= Columns - 1)) { + if (l > 1) { s = screen_puts_mbyte(s, l, attr) - 1; - else + } else { msg_screen_putchar(*s, attr); + } } else { /* postpone this character until later */ if (t_col == 0) @@ -3382,8 +3371,8 @@ int vim_vsnprintf(char *str, size_t str_m, const char *fmt, va_list ap, // leave negative numbers for sprintf to handle, to // avoid handling tricky cases like (short int)-32768 } else if (alternate_form) { - if (arg_sign != 0 && (fmt_spec == 'x' || fmt_spec == 'X' || - fmt_spec == 'b' || fmt_spec == 'B')) { + if (arg_sign != 0 && (fmt_spec == 'x' || fmt_spec == 'X' + || fmt_spec == 'b' || fmt_spec == 'B')) { tmp[str_arg_l++] = '0'; tmp[str_arg_l++] = fmt_spec; } diff --git a/src/nvim/misc1.c b/src/nvim/misc1.c index a20ee562fa..53eceaa4ef 100644 --- a/src/nvim/misc1.c +++ b/src/nvim/misc1.c @@ -43,7 +43,6 @@ #include "nvim/search.h" #include "nvim/strings.h" #include "nvim/tag.h" -#include "nvim/tempfile.h" #include "nvim/ui.h" #include "nvim/undo.h" #include "nvim/window.h" @@ -205,15 +204,12 @@ open_line ( else lead_len = 0; if (dir == FORWARD) { - /* - * Skip preprocessor directives, unless they are - * recognised as comments. - */ - if ( - lead_len == 0 && - ptr[0] == '#') { - while (ptr[0] == '#' && curwin->w_cursor.lnum > 1) + // Skip preprocessor directives, unless they are + // recognised as comments. + if (lead_len == 0 && ptr[0] == '#') { + while (ptr[0] == '#' && curwin->w_cursor.lnum > 1) { ptr = ml_get(--curwin->w_cursor.lnum); + } newindent = get_indent(); } if (flags & OPENLINE_DO_COM) @@ -297,28 +293,26 @@ open_line ( && cin_is_cinword(ptr)) did_si = TRUE; } - } else { /* dir == BACKWARD */ - /* - * Skip preprocessor directives, unless they are - * recognised as comments. - */ - if ( - lead_len == 0 && - ptr[0] == '#') { - int was_backslashed = FALSE; - - while ((ptr[0] == '#' || was_backslashed) && - curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count) { - if (*ptr && ptr[STRLEN(ptr) - 1] == '\\') - was_backslashed = TRUE; - else - was_backslashed = FALSE; + } else { // dir == BACKWARD + // Skip preprocessor directives, unless they are + // recognised as comments. + if (lead_len == 0 && ptr[0] == '#') { + bool was_backslashed = false; + + while ((ptr[0] == '#' || was_backslashed) + && curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count) { + if (*ptr && ptr[STRLEN(ptr) - 1] == '\\') { + was_backslashed = true; + } else { + was_backslashed = false; + } ptr = ml_get(++curwin->w_cursor.lnum); } - if (was_backslashed) - newindent = 0; /* Got to end of file */ - else + if (was_backslashed) { + newindent = 0; // Got to end of file + } else { newindent = get_indent(); + } } p = skipwhite(ptr); if (*p == '}') /* if line starts with '}': do indent */ @@ -668,16 +662,12 @@ open_line ( did_si = can_si = FALSE; } else if (comment_end != NULL) { - /* - * We have finished a comment, so we don't use the leader. - * If this was a C-comment and 'ai' or 'si' is set do a normal - * indent to align with the line containing the start of the - * comment. - */ - if (comment_end[0] == '*' && comment_end[1] == '/' && - (curbuf->b_p_ai - || do_si - )) { + // We have finished a comment, so we don't use the leader. + // If this was a C-comment and 'ai' or 'si' is set do a normal + // indent to align with the line containing the start of the + // comment. + if (comment_end[0] == '*' && comment_end[1] == '/' + && (curbuf->b_p_ai || do_si)) { old_cursor = curwin->w_cursor; curwin->w_cursor.col = (colnr_T)(comment_end - saved_line); if ((pos = findmatch(NULL, NUL)) != NULL) { diff --git a/src/nvim/mouse.c b/src/nvim/mouse.c index 3ae1a6a890..2f499e477c 100644 --- a/src/nvim/mouse.c +++ b/src/nvim/mouse.c @@ -14,6 +14,8 @@ #include "nvim/misc1.h" #include "nvim/cursor.h" #include "nvim/buffer_defs.h" +#include "nvim/memline.h" +#include "nvim/charset.h" #ifdef INCLUDE_GENERATED_DECLARATIONS # include "mouse.c.generated.h" @@ -503,3 +505,95 @@ void set_mouse_topline(win_T *wp) orig_topfill = wp->w_topfill; } +/// +/// Return length of line "lnum" for horizontal scrolling. +/// +static colnr_T scroll_line_len(linenr_T lnum) +{ + colnr_T col = 0; + char_u *line = ml_get(lnum); + if (*line != NUL) { + for (;;) { + int numchar = chartabsize(line, col); + mb_ptr_adv(line); + if (*line == NUL) { // don't count the last character + break; + } + col += numchar; + } + } + return col; +} + +/// +/// Find longest visible line number. +/// +static linenr_T find_longest_lnum(void) +{ + linenr_T ret = 0; + + // Calculate maximum for horizontal scrollbar. Check for reasonable + // line numbers, topline and botline can be invalid when displaying is + // postponed. + if (curwin->w_topline <= curwin->w_cursor.lnum + && curwin->w_botline > curwin->w_cursor.lnum + && curwin->w_botline <= curbuf->b_ml.ml_line_count + 1) { + long max = 0; + + // Use maximum of all visible lines. Remember the lnum of the + // longest line, closest to the cursor line. Used when scrolling + // below. + for (linenr_T lnum = curwin->w_topline; lnum < curwin->w_botline; lnum++) { + colnr_T len = scroll_line_len(lnum); + if (len > (colnr_T)max) { + max = len; + ret = lnum; + } else if (len == (colnr_T)max + && abs((int)(lnum - curwin->w_cursor.lnum)) + < abs((int)(ret - curwin->w_cursor.lnum))) { + ret = lnum; + } + } + } else { + // Use cursor line only. + ret = curwin->w_cursor.lnum; + } + + return ret; +} + +/// +/// Do a horizontal scroll. Return TRUE if the cursor moved, FALSE otherwise. +/// +bool mouse_scroll_horiz(int dir) +{ + if (curwin->w_p_wrap) { + return false; + } + + int step = 6; + if (mod_mask & (MOD_MASK_SHIFT | MOD_MASK_CTRL)) { + step = curwin->w_width; + } + + int leftcol = curwin->w_leftcol + (dir == MSCR_RIGHT ? -step : +step); + if (leftcol < 0) { + leftcol = 0; + } + + if (curwin->w_leftcol == leftcol) { + return false; + } + + curwin->w_leftcol = (colnr_T)leftcol; + + // When the line of the cursor is too short, move the cursor to the + // longest visible line. + if (!virtual_active() + && (colnr_T)leftcol > scroll_line_len(curwin->w_cursor.lnum)) { + curwin->w_cursor.lnum = find_longest_lnum(); + curwin->w_cursor.col = 0; + } + + return leftcol_changed(); +} diff --git a/src/nvim/mouse.h b/src/nvim/mouse.h index c824bcc8f0..0149f7c7c0 100644 --- a/src/nvim/mouse.h +++ b/src/nvim/mouse.h @@ -34,6 +34,12 @@ #define MOUSE_X1 0x300 // Mouse-button X1 (6th) #define MOUSE_X2 0x400 // Mouse-button X2 +// Direction for nv_mousescroll() and ins_mousescroll() +#define MSCR_DOWN 0 // DOWN must be FALSE +#define MSCR_UP 1 +#define MSCR_LEFT -1 +#define MSCR_RIGHT -2 + #ifdef INCLUDE_GENERATED_DECLARATIONS # include "mouse.h.generated.h" diff --git a/src/nvim/move.c b/src/nvim/move.c index ba79c0411a..b129c5cb7a 100644 --- a/src/nvim/move.c +++ b/src/nvim/move.c @@ -1010,12 +1010,9 @@ scrollup ( int byfold /* true: count a closed fold as one line */ ) { - if ( - (byfold && hasAnyFolding(curwin)) - || - curwin->w_p_diff - ) { - /* count each sequence of folded lines as one logical line */ + if ((byfold && hasAnyFolding(curwin)) + || curwin->w_p_diff) { + // count each sequence of folded lines as one logical line linenr_T lnum = curwin->w_topline; while (line_count--) { if (curwin->w_topfill > 0) diff --git a/src/nvim/msgpack_rpc/helpers.c b/src/nvim/msgpack_rpc/helpers.c index 5ef81721d4..0049ae6b95 100644 --- a/src/nvim/msgpack_rpc/helpers.c +++ b/src/nvim/msgpack_rpc/helpers.c @@ -419,8 +419,8 @@ void msgpack_rpc_validate(uint64_t *response_id, return; } - if ((type == kMessageTypeRequest && req->via.array.size != 4) || - (type == kMessageTypeNotification && req->via.array.size != 3)) { + if ((type == kMessageTypeRequest && req->via.array.size != 4) + || (type == kMessageTypeNotification && req->via.array.size != 3)) { api_set_error(err, Validation, _("Request array size should be 4 (request) " "or 3 (notification)")); return; diff --git a/src/nvim/msgpack_rpc/server.c b/src/nvim/msgpack_rpc/server.c index bf384e3379..6cc56ba3dd 100644 --- a/src/nvim/msgpack_rpc/server.c +++ b/src/nvim/msgpack_rpc/server.c @@ -14,7 +14,7 @@ #include "nvim/vim.h" #include "nvim/memory.h" #include "nvim/log.h" -#include "nvim/tempfile.h" +#include "nvim/fileio.h" #include "nvim/path.h" #include "nvim/strings.h" diff --git a/src/nvim/normal.c b/src/nvim/normal.c index 5b7c4b68b1..57638ee388 100644 --- a/src/nvim/normal.c +++ b/src/nvim/normal.c @@ -569,36 +569,33 @@ static bool normal_need_aditional_char(NormalState *s) static bool normal_need_redraw_mode_message(NormalState *s) { return ( - ( // 'showmode' is set and messages can be printed - p_smd && msg_silent == 0 - // must restart insert mode(ctrl+o or ctrl+l) or we just entered visual - // mode - && (restart_edit != 0 || (VIsual_active - && s->old_pos.lnum == curwin->w_cursor.lnum - && s->old_pos.col == curwin->w_cursor.col)) - // command-line must be cleared or redrawn - && (clear_cmdline || redraw_cmdline) - // some message was printed or scrolled - && (msg_didout || (msg_didany && msg_scroll)) - // it is fine to remove the current message - && !msg_nowait - // the command was the result of direct user input and not a mapping - && KeyTyped - ) - || - // must restart insert mode, not in visual mode and error message is - // being shown - (restart_edit != 0 && !VIsual_active && (msg_scroll && emsg_on_display)) - ) - // no register was used - && s->oa.regname == 0 - && !(s->ca.retval & CA_COMMAND_BUSY) - && stuff_empty() - && typebuf_typed() - && emsg_silent == 0 - && !did_wait_return - && s->oa.op_type == OP_NOP; + ((p_smd && msg_silent == 0 + // must restart insert mode(ctrl+o or ctrl+l) or we just entered visual + // mode + && (restart_edit != 0 || (VIsual_active + && s->old_pos.lnum == curwin->w_cursor.lnum + && s->old_pos.col == curwin->w_cursor.col)) + // command-line must be cleared or redrawn + && (clear_cmdline || redraw_cmdline) + // some message was printed or scrolled + && (msg_didout || (msg_didany && msg_scroll)) + // it is fine to remove the current message + && !msg_nowait + // the command was the result of direct user input and not a mapping + && KeyTyped) + // must restart insert mode, not in visual mode and error message is + // being shown + || (restart_edit != 0 && !VIsual_active && msg_scroll + && emsg_on_display)) + // no register was used + && s->oa.regname == 0 + && !(s->ca.retval & CA_COMMAND_BUSY) + && stuff_empty() + && typebuf_typed() + && emsg_silent == 0 + && !did_wait_return + && s->oa.op_type == OP_NOP); } static void normal_redraw_mode_message(NormalState *s) @@ -1436,19 +1433,20 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank) } curwin->w_p_lbr = false; oap->is_VIsual = VIsual_active; - if (oap->motion_force == 'V') - oap->motion_type = MLINE; - else if (oap->motion_force == 'v') { - /* If the motion was linewise, "inclusive" will not have been set. - * Use "exclusive" to be consistent. Makes "dvj" work nice. */ - if (oap->motion_type == MLINE) + if (oap->motion_force == 'V') { + oap->motion_type = kMTLineWise; + } else if (oap->motion_force == 'v') { + // If the motion was linewise, "inclusive" will not have been set. + // Use "exclusive" to be consistent. Makes "dvj" work nice. + if (oap->motion_type == kMTLineWise) { oap->inclusive = false; - /* If the motion already was characterwise, toggle "inclusive" */ - else if (oap->motion_type == MCHAR) + } else if (oap->motion_type == kMTCharWise) { + // If the motion already was characterwise, toggle "inclusive" oap->inclusive = !oap->inclusive; - oap->motion_type = MCHAR; + } + oap->motion_type = kMTCharWise; } else if (oap->motion_force == Ctrl_V) { - /* Change line- or characterwise motion into Visual block mode. */ + // Change line- or characterwise motion into Visual block mode. VIsual_active = true; VIsual = oap->start; VIsual_mode = Ctrl_V; @@ -1586,13 +1584,15 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank) * automatically. */ curwin->w_valid &= ~VALID_VIRTCOL; } else { - /* Include folded lines completely. */ - if (!VIsual_active && oap->motion_type == MLINE) { + // Include folded lines completely. + if (!VIsual_active && oap->motion_type == kMTLineWise) { if (hasFolding(curwin->w_cursor.lnum, &curwin->w_cursor.lnum, - NULL)) + NULL)) { curwin->w_cursor.col = 0; - if (hasFolding(oap->start.lnum, NULL, &oap->start.lnum)) + } + if (hasFolding(oap->start.lnum, NULL, &oap->start.lnum)) { oap->start.col = (colnr_T)STRLEN(ml_get(oap->start.lnum)); + } } oap->end = oap->start; oap->start = curwin->w_cursor; @@ -1663,17 +1663,16 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank) } } - /* - * oap->inclusive defaults to true. - * If oap->end is on a NUL (empty line) oap->inclusive becomes - * false. This makes "d}P" and "v}dP" work the same. - */ - if (oap->motion_force == NUL || oap->motion_type == MLINE) + // oap->inclusive defaults to true. + // If oap->end is on a NUL (empty line) oap->inclusive becomes + // false. This makes "d}P" and "v}dP" work the same. + if (oap->motion_force == NUL || oap->motion_type == kMTLineWise) { oap->inclusive = true; + } if (VIsual_mode == 'V') { - oap->motion_type = MLINE; + oap->motion_type = kMTLineWise; } else if (VIsual_mode == 'v') { - oap->motion_type = MCHAR; + oap->motion_type = kMTCharWise; if (*ml_get_pos(&(oap->end)) == NUL && (include_line_break || !virtual_op) ) { @@ -1731,7 +1730,7 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank) * oap->empty is set when start and end are the same. The inclusive * flag affects this too, unless yanking and the end is on a NUL. */ - oap->empty = (oap->motion_type != MLINE + oap->empty = (oap->motion_type != kMTLineWise && (!oap->inclusive || (oap->op_type == OP_YANK && gchar_pos(&oap->end) == NUL)) @@ -1756,23 +1755,23 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank) /* * If the end of an operator is in column one while oap->motion_type - * is MCHAR and oap->inclusive is false, we put op_end after the last + * is kMTCharWise and oap->inclusive is false, we put op_end after the last * character in the previous line. If op_start is on or before the * first non-blank in the line, the operator becomes linewise * (strange, but that's the way vi does it). */ - if (oap->motion_type == MCHAR + if (oap->motion_type == kMTCharWise && oap->inclusive == false && !(cap->retval & CA_NO_ADJ_OP_END) && oap->end.col == 0 && (!oap->is_VIsual || *p_sel == 'o') && oap->line_count > 1) { oap->end_adjusted = true; // remember that we did this - --oap->line_count; - --oap->end.lnum; - if (inindent(0)) - oap->motion_type = MLINE; - else { + oap->line_count--; + oap->end.lnum--; + if (inindent(0)) { + oap->motion_type = kMTLineWise; + } else { oap->end.col = (colnr_T)STRLEN(ml_get(oap->end.lnum)); if (oap->end.col) { --oap->end.col; @@ -1811,8 +1810,9 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank) CancelRedo(); } else { (void)op_delete(oap); - if (oap->motion_type == MLINE && has_format_option(FO_AUTO)) - u_save_cursor(); /* cursor line wasn't saved yet */ + if (oap->motion_type == kMTLineWise && has_format_option(FO_AUTO)) { + u_save_cursor(); // cursor line wasn't saved yet + } auto_format(false, true); } break; @@ -2011,7 +2011,7 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank) /* * if 'sol' not set, go back to old column for some commands */ - if (!p_sol && oap->motion_type == MLINE && !oap->end_adjusted + if (!p_sol && oap->motion_type == kMTLineWise && !oap->end_adjusted && (oap->op_type == OP_LSHIFT || oap->op_type == OP_RSHIFT || oap->op_type == OP_DELETE)) { curwin->w_p_lbr = false; @@ -2086,13 +2086,14 @@ static void op_function(oparg_T *oap) /* Set '[ and '] marks to text to be operated on. */ curbuf->b_op_start = oap->start; curbuf->b_op_end = oap->end; - if (oap->motion_type != MLINE && !oap->inclusive) - /* Exclude the end position. */ + if (oap->motion_type != kMTLineWise && !oap->inclusive) { + // Exclude the end position. decl(&curbuf->b_op_end); + } - if (oap->motion_type == MBLOCK) { + if (oap->motion_type == kMTBlockWise) { argv[0] = (char_u *)"block"; - } else if (oap->motion_type == MLINE) { + } else if (oap->motion_type == kMTLineWise) { argv[0] = (char_u *)"line"; } else { argv[0] = (char_u *)"char"; @@ -2530,7 +2531,7 @@ do_mouse ( */ if (!is_drag && oap != NULL && oap->op_type != OP_NOP) { got_click = false; - oap->motion_type = MCHAR; + oap->motion_type = kMTCharWise; } /* When releasing the button let jump_to_mouse() know. */ @@ -2598,11 +2599,10 @@ do_mouse ( end_visual.col = leftcol; else end_visual.col = rightcol; - if (curwin->w_cursor.lnum < - (start_visual.lnum + end_visual.lnum) / 2) - end_visual.lnum = end_visual.lnum; - else + if (curwin->w_cursor.lnum >= + (start_visual.lnum + end_visual.lnum) / 2) { end_visual.lnum = start_visual.lnum; + } /* move VIsual to the right column */ start_visual = curwin->w_cursor; /* save the cursor pos */ @@ -2770,21 +2770,23 @@ do_mouse ( end_visual = curwin->w_cursor; while (gc = gchar_pos(&end_visual), ascii_iswhite(gc)) inc(&end_visual); - if (oap != NULL) - oap->motion_type = MCHAR; + if (oap != NULL) { + oap->motion_type = kMTCharWise; + } if (oap != NULL && VIsual_mode == 'v' && !vim_iswordc(gchar_pos(&end_visual)) && equalpos(curwin->w_cursor, VIsual) && (pos = findmatch(oap, NUL)) != NULL) { curwin->w_cursor = *pos; - if (oap->motion_type == MLINE) + if (oap->motion_type == kMTLineWise) { VIsual_mode = 'V'; - else if (*p_sel == 'e') { - if (lt(curwin->w_cursor, VIsual)) - ++VIsual.col; - else - ++curwin->w_cursor.col; + } else if (*p_sel == 'e') { + if (lt(curwin->w_cursor, VIsual)) { + VIsual.col++; + } else { + curwin->w_cursor.col++; + } } } } @@ -3244,9 +3246,9 @@ void clear_showcmd(void) top = curwin->w_cursor.lnum; bot = VIsual.lnum; } - /* Include closed folds as a whole. */ - hasFolding(top, &top, NULL); - hasFolding(bot, NULL, &bot); + // Include closed folds as a whole. + (void)hasFolding(top, &top, NULL); + (void)hasFolding(bot, NULL, &bot); lines = bot - top + 1; if (VIsual_mode == Ctrl_V) { @@ -3782,7 +3784,7 @@ static bool nv_screengo(oparg_T *oap, int dir, long dist) int width1; /* text width for first screen line */ int width2; /* test width for wrapped screen line */ - oap->motion_type = MCHAR; + oap->motion_type = kMTCharWise; oap->inclusive = (curwin->w_curswant == MAXCOL); col_off1 = curwin_col_off(); @@ -3927,6 +3929,8 @@ static void nv_mousescroll(cmdarg_T *cap) cap->count0 = 3; nv_scroll_line(cap); } + } else { + mouse_scroll_horiz(cap->arg); } curwin->w_redr_status = true; @@ -4053,16 +4057,15 @@ static void nv_zet(cmdarg_T *cap) } dozet: - if ( - /* "zf" and "zF" are always an operator, "zd", "zo", "zO", "zc" - * and "zC" only in Visual mode. "zj" and "zk" are motion - * commands. */ - cap->nchar != 'f' && cap->nchar != 'F' - && !(VIsual_active && vim_strchr((char_u *)"dcCoO", cap->nchar)) - && cap->nchar != 'j' && cap->nchar != 'k' - && - checkclearop(cap->oap)) + // "zf" and "zF" are always an operator, "zd", "zo", "zO", "zc" + // and "zC" only in Visual mode. "zj" and "zk" are motion + // commands. */ + if (cap->nchar != 'f' && cap->nchar != 'F' + && !(VIsual_active && vim_strchr((char_u *)"dcCoO", cap->nchar)) + && cap->nchar != 'j' && cap->nchar != 'k' + && checkclearop(cap->oap)) { return; + } /* * For "z+", "z<CR>", "zt", "z.", "zz", "z^", "z-", "zb": @@ -4463,8 +4466,8 @@ static void nv_colon(cmdarg_T *cap) nv_operator(cap); else { if (cap->oap->op_type != OP_NOP) { - /* Using ":" as a movement is characterwise exclusive. */ - cap->oap->motion_type = MCHAR; + // Using ":" as a movement is characterwise exclusive. + cap->oap->motion_type = kMTCharWise; cap->oap->inclusive = false; } else if (cap->count0) { /* translate "count:" into ":.,.+(count - 1)" */ @@ -4863,7 +4866,7 @@ static void nv_scroll(cmdarg_T *cap) linenr_T lnum; int half; - cap->oap->motion_type = MLINE; + cap->oap->motion_type = kMTLineWise; setpcmark(); if (cap->cmdchar == 'L') { @@ -4943,7 +4946,7 @@ static void nv_right(cmdarg_T *cap) return; } - cap->oap->motion_type = MCHAR; + cap->oap->motion_type = kMTCharWise; cap->oap->inclusive = false; PAST_LINE = (VIsual_active && *p_sel != 'o'); @@ -5030,7 +5033,7 @@ static void nv_left(cmdarg_T *cap) return; } - cap->oap->motion_type = MCHAR; + cap->oap->motion_type = kMTCharWise; cap->oap->inclusive = false; for (n = cap->count1; n > 0; --n) { if (oneleft() == false) { @@ -5092,11 +5095,12 @@ static void nv_up(cmdarg_T *cap) cap->arg = BACKWARD; nv_page(cap); } else { - cap->oap->motion_type = MLINE; - if (cursor_up(cap->count1, cap->oap->op_type == OP_NOP) == false) + cap->oap->motion_type = kMTLineWise; + if (cursor_up(cap->count1, cap->oap->op_type == OP_NOP) == false) { clearopbeep(cap->oap); - else if (cap->arg) + } else if (cap->arg) { beginline(BL_WHITE | BL_FIX); + } } } @@ -5110,23 +5114,24 @@ static void nv_down(cmdarg_T *cap) /* <S-Down> is page down */ cap->arg = FORWARD; nv_page(cap); - } else - /* In a quickfix window a <CR> jumps to the error under the cursor. */ - if (bt_quickfix(curbuf) && cap->cmdchar == CAR) - if (curwin->w_llist_ref == NULL) - do_cmdline_cmd(".cc"); /* quickfix window */ - else - do_cmdline_cmd(".ll"); /* location list window */ - else { - /* In the cmdline window a <CR> executes the command. */ - if (cmdwin_type != 0 && cap->cmdchar == CAR) + } else if (bt_quickfix(curbuf) && cap->cmdchar == CAR) { + // In a quickfix window a <CR> jumps to the error under the cursor. + if (curwin->w_llist_ref == NULL) { + do_cmdline_cmd(".cc"); // quickfix window + } else { + do_cmdline_cmd(".ll"); // location list window + } + } else { + // In the cmdline window a <CR> executes the command. + if (cmdwin_type != 0 && cap->cmdchar == CAR) { cmdwin_result = CAR; - else { - cap->oap->motion_type = MLINE; - if (cursor_down(cap->count1, cap->oap->op_type == OP_NOP) == false) + } else { + cap->oap->motion_type = kMTLineWise; + if (cursor_down(cap->count1, cap->oap->op_type == OP_NOP) == false) { clearopbeep(cap->oap); - else if (cap->arg) + } else if (cap->arg) { beginline(BL_WHITE | BL_FIX); + } } } } @@ -5152,9 +5157,10 @@ static void nv_gotofile(cmdarg_T *cap) ptr = grab_file_name(cap->count1, &lnum); if (ptr != NULL) { - /* do autowrite if necessary */ - if (curbufIsChanged() && curbuf->b_nwindows <= 1 && !P_HID(curbuf)) - autowrite(curbuf, false); + // do autowrite if necessary + if (curbufIsChanged() && curbuf->b_nwindows <= 1 && !P_HID(curbuf)) { + (void)autowrite(curbuf, false); + } setpcmark(); (void)do_ecmd(0, ptr, NULL, NULL, ECMD_LAST, P_HID(curbuf) ? ECMD_HIDE : 0, curwin); @@ -5186,7 +5192,7 @@ static void nv_end(cmdarg_T *cap) */ static void nv_dollar(cmdarg_T *cap) { - cap->oap->motion_type = MCHAR; + cap->oap->motion_type = kMTCharWise; cap->oap->inclusive = true; /* In virtual mode when off the edge of a line and an operator * is pending (whew!) keep the cursor where it is. @@ -5261,18 +5267,19 @@ static int normal_search( { int i; - cap->oap->motion_type = MCHAR; + cap->oap->motion_type = kMTCharWise; cap->oap->inclusive = false; cap->oap->use_reg_one = true; curwin->w_set_curswant = true; i = do_search(cap->oap, dir, pat, cap->count1, - opt | SEARCH_OPT | SEARCH_ECHO | SEARCH_MSG, NULL); - if (i == 0) + opt | SEARCH_OPT | SEARCH_ECHO | SEARCH_MSG, NULL); + if (i == 0) { clearop(cap->oap); - else { - if (i == 2) - cap->oap->motion_type = MLINE; + } else { + if (i == 2) { + cap->oap->motion_type = kMTLineWise; + } curwin->w_cursor.coladd = 0; if (cap->oap->op_type == OP_NOP && (fdo_flags & FDO_SEARCH) && KeyTyped) foldOpenCursor(); @@ -5299,10 +5306,10 @@ static void nv_csearch(cmdarg_T *cap) else t_cmd = false; - cap->oap->motion_type = MCHAR; - if (IS_SPECIAL(cap->nchar) || searchc(cap, t_cmd) == false) + cap->oap->motion_type = kMTCharWise; + if (IS_SPECIAL(cap->nchar) || searchc(cap, t_cmd) == false) { clearopbeep(cap->oap); - else { + } else { curwin->w_set_curswant = true; /* Include a Tab for "tx" and for "dfx". */ if (gchar_cursor() == TAB && virtual_active() && cap->arg == FORWARD @@ -5334,7 +5341,7 @@ static void nv_brackets(cmdarg_T *cap) int findc; int c; - cap->oap->motion_type = MCHAR; + cap->oap->motion_type = kMTCharWise; cap->oap->inclusive = false; old_pos = curwin->w_cursor; curwin->w_cursor.coladd = 0; /* TODO: don't do this for an error. */ @@ -5624,11 +5631,11 @@ static void nv_percent(cmdarg_T *cap) linenr_T lnum = curwin->w_cursor.lnum; cap->oap->inclusive = true; - if (cap->count0) { /* {cnt}% : goto {cnt} percentage in file */ - if (cap->count0 > 100) + if (cap->count0) { // {cnt}% : goto {cnt} percentage in file + if (cap->count0 > 100) { clearopbeep(cap->oap); - else { - cap->oap->motion_type = MLINE; + } else { + cap->oap->motion_type = kMTLineWise; setpcmark(); /* Round up, so CTRL-G will give same value. Watch out for a * large line count, the line number must not go negative! */ @@ -5642,8 +5649,8 @@ static void nv_percent(cmdarg_T *cap) curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count; beginline(BL_SOL | BL_FIX); } - } else { /* "%" : go to matching paren */ - cap->oap->motion_type = MCHAR; + } else { // "%" : go to matching paren + cap->oap->motion_type = kMTCharWise; cap->oap->use_reg_one = true; if ((pos = findmatch(cap->oap, NUL)) == NULL) clearopbeep(cap->oap); @@ -5668,7 +5675,7 @@ static void nv_percent(cmdarg_T *cap) */ static void nv_brace(cmdarg_T *cap) { - cap->oap->motion_type = MCHAR; + cap->oap->motion_type = kMTCharWise; cap->oap->use_reg_one = true; /* The motion used to be inclusive for "(", but that is not what Vi does. */ cap->oap->inclusive = false; @@ -5702,7 +5709,7 @@ static void nv_mark(cmdarg_T *cap) */ static void nv_findpar(cmdarg_T *cap) { - cap->oap->motion_type = MCHAR; + cap->oap->motion_type = kMTCharWise; cap->oap->inclusive = false; cap->oap->use_reg_one = true; curwin->w_set_curswant = true; @@ -5806,14 +5813,11 @@ static void nv_replace(cmdarg_T *cap) return; } - /* - * Replacing with a TAB is done by edit() when it is complicated because - * 'expandtab' or 'smarttab' is set. CTRL-V TAB inserts a literal TAB. - * Other characters are done below to avoid problems with things like - * CTRL-V 048 (for edit() this would be R CTRL-V 0 ESC). - */ - if (had_ctrl_v != Ctrl_V && cap->nchar == '\t' && - (curbuf->b_p_et || p_sta)) { + // Replacing with a TAB is done by edit() when it is complicated because + // 'expandtab' or 'smarttab' is set. CTRL-V TAB inserts a literal TAB. + // Other characters are done below to avoid problems with things like + // CTRL-V 048 (for edit() this would be R CTRL-V 0 ESC). + if (had_ctrl_v != Ctrl_V && cap->nchar == '\t' && (curbuf->b_p_et || p_sta)) { stuffnumReadbuff(cap->count1); stuffcharReadbuff('R'); stuffcharReadbuff('\t'); @@ -6080,10 +6084,11 @@ static void nv_cursormark(cmdarg_T *cap, int flag, pos_T *pos) else check_cursor(); } - cap->oap->motion_type = flag ? MLINE : MCHAR; - if (cap->cmdchar == '`') + cap->oap->motion_type = flag ? kMTLineWise : kMTCharWise; + if (cap->cmdchar == '`') { cap->oap->use_reg_one = true; - cap->oap->inclusive = false; /* ignored if not MCHAR */ + } + cap->oap->inclusive = false; // ignored if not kMTCharWise curwin->w_set_curswant = true; } @@ -6560,7 +6565,7 @@ static void nv_g_cmd(cmdarg_T *cap) if (!curwin->w_p_wrap || hasFolding(curwin->w_cursor.lnum, NULL, NULL) ) { - oap->motion_type = MLINE; + oap->motion_type = kMTLineWise; i = cursor_down(cap->count1, oap->op_type == OP_NOP); } else i = nv_screengo(oap, FORWARD, cap->count1); @@ -6575,7 +6580,7 @@ static void nv_g_cmd(cmdarg_T *cap) if (!curwin->w_p_wrap || hasFolding(curwin->w_cursor.lnum, NULL, NULL) ) { - oap->motion_type = MLINE; + oap->motion_type = kMTLineWise; i = cursor_up(cap->count1, oap->op_type == OP_NOP); } else i = nv_screengo(oap, BACKWARD, cap->count1); @@ -6602,7 +6607,7 @@ static void nv_g_cmd(cmdarg_T *cap) case 'm': case K_HOME: case K_KHOME: - oap->motion_type = MCHAR; + oap->motion_type = kMTCharWise; oap->inclusive = false; if (curwin->w_p_wrap && curwin->w_width != 0 @@ -6635,7 +6640,7 @@ static void nv_g_cmd(cmdarg_T *cap) case '_': /* "g_": to the last non-blank character in the line or <count> lines * downward. */ - cap->oap->motion_type = MCHAR; + cap->oap->motion_type = kMTCharWise; cap->oap->inclusive = true; curwin->w_curswant = MAXCOL; if (cursor_down(cap->count1 - 1, @@ -6663,7 +6668,7 @@ static void nv_g_cmd(cmdarg_T *cap) { int col_off = curwin_col_off(); - oap->motion_type = MCHAR; + oap->motion_type = kMTCharWise; oap->inclusive = true; if (curwin->w_p_wrap && curwin->w_width != 0 @@ -6725,7 +6730,7 @@ static void nv_g_cmd(cmdarg_T *cap) */ case 'e': case 'E': - oap->motion_type = MCHAR; + oap->motion_type = kMTCharWise; curwin->w_set_curswant = true; oap->inclusive = true; if (bckend_word(cap->count1, cap->nchar == 'E', false) == false) @@ -7085,17 +7090,19 @@ static void set_op_var(int optype) */ static void nv_lineop(cmdarg_T *cap) { - cap->oap->motion_type = MLINE; - if (cursor_down(cap->count1 - 1L, cap->oap->op_type == OP_NOP) == false) + cap->oap->motion_type = kMTLineWise; + if (cursor_down(cap->count1 - 1L, cap->oap->op_type == OP_NOP) == false) { clearopbeep(cap->oap); - else if ( (cap->oap->op_type == OP_DELETE /* only with linewise motions */ + } else if ((cap->oap->op_type == OP_DELETE + // only with linewise motions && cap->oap->motion_force != 'v' && cap->oap->motion_force != Ctrl_V) || cap->oap->op_type == OP_LSHIFT - || cap->oap->op_type == OP_RSHIFT) + || cap->oap->op_type == OP_RSHIFT) { beginline(BL_SOL | BL_FIX); - else if (cap->oap->op_type != OP_YANK) /* 'Y' does not move cursor */ + } else if (cap->oap->op_type != OP_YANK) { // 'Y' does not move cursor beginline(BL_WHITE | BL_FIX); + } } /* @@ -7119,7 +7126,7 @@ static void nv_home(cmdarg_T *cap) */ static void nv_pipe(cmdarg_T *cap) { - cap->oap->motion_type = MCHAR; + cap->oap->motion_type = kMTCharWise; cap->oap->inclusive = false; beginline(0); if (cap->count0 > 0) { @@ -7138,7 +7145,7 @@ static void nv_pipe(cmdarg_T *cap) */ static void nv_bck_word(cmdarg_T *cap) { - cap->oap->motion_type = MCHAR; + cap->oap->motion_type = kMTCharWise; cap->oap->inclusive = false; curwin->w_set_curswant = true; if (bck_word(cap->count1, cap->arg, false) == false) @@ -7187,7 +7194,7 @@ static void nv_wordcmd(cmdarg_T *cap) } } - cap->oap->motion_type = MCHAR; + cap->oap->motion_type = kMTCharWise; curwin->w_set_curswant = true; if (word_end) n = end_word(cap->count1, cap->arg, flag, false); @@ -7238,7 +7245,7 @@ static void adjust_cursor(oparg_T *oap) */ static void nv_beginline(cmdarg_T *cap) { - cap->oap->motion_type = MCHAR; + cap->oap->motion_type = kMTCharWise; cap->oap->inclusive = false; beginline(cap->arg); if ((fdo_flags & FDO_HOR) && KeyTyped && cap->oap->op_type == OP_NOP) @@ -7317,7 +7324,7 @@ static void nv_goto(cmdarg_T *cap) lnum = curbuf->b_ml.ml_line_count; else lnum = 1L; - cap->oap->motion_type = MLINE; + cap->oap->motion_type = kMTLineWise; setpcmark(); /* When a count is given, use it instead of the default lnum */ @@ -7803,7 +7810,7 @@ static void get_op_vcol( return; } - oap->motion_type = MBLOCK; + oap->motion_type = kMTBlockWise; // prevent from moving onto a trail byte if (has_mbyte) { diff --git a/src/nvim/normal.h b/src/nvim/normal.h index 95619c7ef6..51170105ed 100644 --- a/src/nvim/normal.h +++ b/src/nvim/normal.h @@ -10,18 +10,29 @@ #define FIND_STRING 2 /* find any string (WORD) */ #define FIND_EVAL 4 /* include "->", "[]" and "." */ +/// Motion types, used for operators and for yank/delete registers. +/// +/// The three valid numerical values must not be changed, as they +/// are used in external communication and serialization. +typedef enum { + kMTCharWise = 0, ///< character-wise movement/register + kMTLineWise = 1, ///< line-wise movement/register + kMTBlockWise = 2, ///< block-wise movement/register + kMTUnknown = -1 ///< Unknown or invalid motion type +} MotionType; + /* * Arguments for operators. */ typedef struct oparg_S { int op_type; // current pending operator type int regname; // register to use for the operator - int motion_type; // type of the current cursor motion + MotionType motion_type; // type of the current cursor motion int motion_force; // force motion type: 'v', 'V' or CTRL-V bool use_reg_one; // true if delete uses reg 1 even when not // linewise bool inclusive; // true if char motion is inclusive (only - // valid when motion_type is MCHAR) + // valid when motion_type is kMTCharWise) bool end_adjusted; // backuped b_op_end one char (only used by // do_format()) pos_T start; // start of the operator diff --git a/src/nvim/ops.c b/src/nvim/ops.c index 601890d133..a6ff68a8f8 100644 --- a/src/nvim/ops.c +++ b/src/nvim/ops.c @@ -191,7 +191,7 @@ void op_shift(oparg_T *oap, int curs_top, int amount) (linenr_T)(oap->end.lnum + 1)) == FAIL) return; - if (oap->motion_type == MBLOCK) { + if (oap->motion_type == kMTBlockWise) { block_col = curwin->w_cursor.col; } @@ -199,7 +199,7 @@ void op_shift(oparg_T *oap, int curs_top, int amount) first_char = *get_cursor_line_ptr(); if (first_char == NUL) { // empty line curwin->w_cursor.col = 0; - } else if (oap->motion_type == MBLOCK) { + } else if (oap->motion_type == kMTBlockWise) { shift_block(oap, amount); } else if (first_char != '#' || !preprocs_left()) { // Move the line right if it doesn't start with '#', 'smartindent' @@ -213,7 +213,7 @@ void op_shift(oparg_T *oap, int curs_top, int amount) /* The cursor line is not in a closed fold */ foldOpenCursor(); - if (oap->motion_type == MBLOCK) { + if (oap->motion_type == kMTBlockWise) { curwin->w_cursor.lnum = oap->start.lnum; curwin->w_cursor.col = block_col; } else if (curs_top) { /* put cursor on first line, for ">>" */ @@ -811,17 +811,17 @@ yankreg_T *copy_register(int name) return copy; } -/* - * return TRUE if the current yank register has type MLINE - */ -int yank_register_mline(int regname) +/// check if the current yank register has kMTLineWise register type +bool yank_register_mline(int regname) { - if (regname != 0 && !valid_yank_reg(regname, false)) - return FALSE; - if (regname == '_') /* black hole is always empty */ - return FALSE; + if (regname != 0 && !valid_yank_reg(regname, false)) { + return false; + } + if (regname == '_') { // black hole is always empty + return false; + } yankreg_T *reg = get_yank_register(regname, YREG_PASTE); - return reg->y_type == MLINE; + return reg->y_type == kMTLineWise; } /* @@ -919,7 +919,7 @@ static int stuff_yank(int regname, char_u *p) reg->y_array = (char_u **)xmalloc(sizeof(char_u *)); reg->y_array[0] = p; reg->y_size = 1; - reg->y_type = MCHAR; /* used to be MLINE, why? */ + reg->y_type = kMTCharWise; } reg->timestamp = os_time(); return OK; @@ -1011,8 +1011,8 @@ do_execreg ( for (i = reg->y_size - 1; i >= 0; i--) { char_u *escaped; - /* insert NL between lines and after last line if type is MLINE */ - if (reg->y_type == MLINE || i < reg->y_size - 1 + // insert NL between lines and after last line if type is kMTLineWise + if (reg->y_type == kMTLineWise || i < reg->y_size - 1 || addcr) { if (ins_typebuf((char_u *)"\n", remap, 0, TRUE, silent) == FAIL) return FAIL; @@ -1137,12 +1137,11 @@ insert_reg ( else { for (i = 0; i < reg->y_size; i++) { stuffescaped(reg->y_array[i], literally); - /* - * Insert a newline between lines and after last line if - * y_type is MLINE. - */ - if (reg->y_type == MLINE || i < reg->y_size - 1) + // Insert a newline between lines and after last line if + // y_type is kMTLineWise. + if (reg->y_type == kMTLineWise || i < reg->y_size - 1) { stuffcharReadbuff('\n'); + } } } } @@ -1283,9 +1282,9 @@ bool cmdline_paste_reg(int regname, bool literally, bool remcr) for (i = 0; i < reg->y_size; i++) { cmdline_paste_str(reg->y_array[i], literally); - // Insert ^M between lines and after last line if type is MLINE. + // Insert ^M between lines and after last line if type is kMTLineWise. // Don't do this when "remcr" is true. - if ((reg->y_type == MLINE || i < reg->y_size - 1) && !remcr) { + if ((reg->y_type == kMTLineWise || i < reg->y_size - 1) && !remcr) { cmdline_paste_str((char_u *)"\r", literally); } @@ -1329,10 +1328,10 @@ int op_delete(oparg_T *oap) /* * Imitate the strange Vi behaviour: If the delete spans more than one - * line and motion_type == MCHAR and the result is a blank line, make the + * line and motion_type == kMTCharWise and the result is a blank line, make the * delete linewise. Don't do this for the change command or Visual mode. */ - if (oap->motion_type == MCHAR + if (oap->motion_type == kMTCharWise && !oap->is_VIsual && oap->line_count > 1 && oap->motion_force == NUL @@ -1341,15 +1340,16 @@ int op_delete(oparg_T *oap) if (*ptr != NUL) ptr += oap->inclusive; ptr = skipwhite(ptr); - if (*ptr == NUL && inindent(0)) - oap->motion_type = MLINE; + if (*ptr == NUL && inindent(0)) { + oap->motion_type = kMTLineWise; + } } /* * Check for trying to delete (e.g. "D") in an empty line. * Note: For the change operator it is ok. */ - if (oap->motion_type != MLINE + if (oap->motion_type != kMTLineWise && oap->line_count == 1 && oap->op_type == OP_DELETE && *ml_get(oap->start.lnum) == NUL) { @@ -1385,7 +1385,7 @@ int op_delete(oparg_T *oap) * Put deleted text into register 1 and shift number registers if the * delete contains a line break, or when a regname has been specified. */ - if (oap->regname != 0 || oap->motion_type == MLINE + if (oap->regname != 0 || oap->motion_type == kMTLineWise || oap->line_count > 1 || oap->use_reg_one) { free_register(&y_regs[9]); /* free register "9 */ for (n = 9; n > 1; n--) @@ -1398,7 +1398,7 @@ int op_delete(oparg_T *oap) /* Yank into small delete register when no named register specified * and the delete is within one line. */ - if (oap->regname == 0 && oap->motion_type != MLINE + if (oap->regname == 0 && oap->motion_type != kMTLineWise && oap->line_count == 1) { reg = get_yank_register('-', YREG_YANK); op_yank_reg(oap, false, reg, false); @@ -1414,7 +1414,7 @@ int op_delete(oparg_T *oap) /* * block mode delete */ - if (oap->motion_type == MBLOCK) { + if (oap->motion_type == kMTBlockWise) { if (u_save((linenr_T)(oap->start.lnum - 1), (linenr_T)(oap->end.lnum + 1)) == FAIL) { return FAIL; @@ -1452,9 +1452,9 @@ int op_delete(oparg_T *oap) check_cursor_col(); changed_lines(curwin->w_cursor.lnum, curwin->w_cursor.col, - oap->end.lnum + 1, 0L); - oap->line_count = 0; /* no lines deleted */ - } else if (oap->motion_type == MLINE) { + oap->end.lnum + 1, 0L); + 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 @@ -1582,7 +1582,7 @@ int op_delete(oparg_T *oap) msgmore(curbuf->b_ml.ml_line_count - old_lcount); setmarks: - if (oap->motion_type == MBLOCK) { + if (oap->motion_type == kMTBlockWise) { curbuf->b_op_end.lnum = oap->end.lnum; curbuf->b_op_end.col = oap->start.col; } else @@ -1643,7 +1643,7 @@ int op_replace(oparg_T *oap, int c) /* * block mode replace */ - if (oap->motion_type == MBLOCK) { + if (oap->motion_type == kMTBlockWise) { bd.is_MAX = (curwin->w_curswant == MAXCOL); for (; curwin->w_cursor.lnum <= oap->end.lnum; ++curwin->w_cursor.lnum) { curwin->w_cursor.col = 0; /* make sure cursor position is valid */ @@ -1732,10 +1732,8 @@ int op_replace(oparg_T *oap, int c) } } } else { - /* - * MCHAR and MLINE motion replace. - */ - if (oap->motion_type == MLINE) { + // Characterwise or linewise motion replace. + if (oap->motion_type == kMTLineWise) { oap->start.col = 0; curwin->w_cursor.col = 0; oap->end.col = (colnr_T)STRLEN(ml_get(oap->end.lnum)); @@ -1825,8 +1823,8 @@ void op_tilde(oparg_T *oap) return; pos = oap->start; - if (oap->motion_type == MBLOCK) { // Visual block mode - for (; pos.lnum <= oap->end.lnum; ++pos.lnum) { + if (oap->motion_type == kMTBlockWise) { // Visual block mode + for (; pos.lnum <= oap->end.lnum; pos.lnum++) { int one_change; block_prep(oap, &bd, pos.lnum, FALSE); @@ -1837,8 +1835,8 @@ void op_tilde(oparg_T *oap) } if (did_change) changed_lines(oap->start.lnum, 0, oap->end.lnum + 1, 0L); - } else { /* not block mode */ - if (oap->motion_type == MLINE) { + } else { // not block mode + if (oap->motion_type == kMTLineWise) { oap->start.col = 0; pos.col = 0; oap->end.col = (colnr_T)STRLEN(ml_get(oap->end.lnum)); @@ -1988,7 +1986,7 @@ void op_insert(oparg_T *oap, long count1) curwin->w_cursor.lnum = oap->start.lnum; update_screen(INVERTED); - if (oap->motion_type == MBLOCK) { + if (oap->motion_type == kMTBlockWise) { // When 'virtualedit' is used, need to insert the extra spaces before // doing block_prep(). When only "block" is used, virtual edit is // already disabled, but still need it when calling @@ -2014,7 +2012,7 @@ void op_insert(oparg_T *oap, long count1) } if (oap->op_type == OP_APPEND) { - if (oap->motion_type == MBLOCK + if (oap->motion_type == kMTBlockWise && curwin->w_cursor.coladd == 0 ) { /* Move the cursor to the character right of the block. */ @@ -2048,8 +2046,8 @@ void op_insert(oparg_T *oap, long count1) // When a tab was inserted, and the characters in front of the tab // have been converted to a tab as well, the column of the cursor // might have actually been reduced, so need to adjust here. */ - if (t1.lnum == curbuf->b_op_start_orig.lnum && - lt(curbuf->b_op_start_orig, t1)) { + if (t1.lnum == curbuf->b_op_start_orig.lnum + && lt(curbuf->b_op_start_orig, t1)) { oap->start = curbuf->b_op_start_orig; } @@ -2059,7 +2057,7 @@ void op_insert(oparg_T *oap, long count1) if (curwin->w_cursor.lnum != oap->start.lnum || got_int) return; - if (oap->motion_type == MBLOCK) { + if (oap->motion_type == kMTBlockWise) { struct block_def bd2; /* The user may have moved the cursor before inserting something, try @@ -2146,7 +2144,7 @@ int op_change(oparg_T *oap) struct block_def bd; l = oap->start.col; - if (oap->motion_type == MLINE) { + if (oap->motion_type == kMTLineWise) { l = 0; if (!p_paste && curbuf->b_p_si && !curbuf->b_p_cin @@ -2168,7 +2166,7 @@ int op_change(oparg_T *oap) // check for still on same line (<CR> in inserted text meaningless) // skip blank lines too - if (oap->motion_type == MBLOCK) { + if (oap->motion_type == kMTBlockWise) { // Add spaces before getting the current line length. if (virtual_op && (curwin->w_cursor.coladd > 0 || gchar_cursor() == NUL)) { @@ -2180,8 +2178,9 @@ int op_change(oparg_T *oap) bd.textcol = curwin->w_cursor.col; } - if (oap->motion_type == MLINE) + if (oap->motion_type == kMTLineWise) { fix_indent(); + } retval = edit(NUL, FALSE, (linenr_T)1); @@ -2190,7 +2189,7 @@ int op_change(oparg_T *oap) * block. * Don't repeat the insert when Insert mode ended with CTRL-C. */ - if (oap->motion_type == MBLOCK + if (oap->motion_type == kMTBlockWise && oap->start.lnum != oap->end.lnum && !got_int) { // Auto-indenting may have changed the indent. If the cursor was past // the indent, exclude that indent change from the inserted text. @@ -2318,7 +2317,7 @@ static void op_yank_reg(oparg_T *oap, bool message, yankreg_T *reg, bool append) char_u **new_ptr; linenr_T lnum; /* current line number */ long j; - int yanktype = oap->motion_type; + MotionType yank_type = oap->motion_type; long yanklines = oap->line_count; linenr_T yankendlnum = oap->end.lnum; char_u *p; @@ -2336,19 +2335,19 @@ static void op_yank_reg(oparg_T *oap, bool message, yankreg_T *reg, bool append) * If the cursor was in column 1 before and after the movement, and the * operator is not inclusive, the yank is always linewise. */ - if (oap->motion_type == MCHAR + if (oap->motion_type == kMTCharWise && oap->start.col == 0 && !oap->inclusive && (!oap->is_VIsual || *p_sel == 'o') && oap->end.col == 0 && yanklines > 1) { - yanktype = MLINE; - --yankendlnum; - --yanklines; + yank_type = kMTLineWise; + yankendlnum--; + yanklines--; } reg->y_size = yanklines; - reg->y_type = yanktype; /* set the yank register type */ + reg->y_type = yank_type; // set the yank register type reg->y_width = 0; reg->y_array = xcalloc(yanklines, sizeof(char_u *)); reg->additional_data = NULL; @@ -2357,7 +2356,7 @@ static void op_yank_reg(oparg_T *oap, bool message, yankreg_T *reg, bool append) y_idx = 0; lnum = oap->start.lnum; - if (yanktype == MBLOCK) { + if (yank_type == kMTBlockWise) { // Visual block mode reg->y_width = oap->end_vcol - oap->start_vcol; @@ -2367,16 +2366,16 @@ static void op_yank_reg(oparg_T *oap, bool message, yankreg_T *reg, bool append) for (; lnum <= yankendlnum; lnum++, y_idx++) { switch (reg->y_type) { - case MBLOCK: - block_prep(oap, &bd, lnum, FALSE); + case kMTBlockWise: + block_prep(oap, &bd, lnum, false); yank_copy_line(reg, &bd, y_idx); break; - case MLINE: + case kMTLineWise: reg->y_array[y_idx] = vim_strsave(ml_get(lnum)); break; - case MCHAR: + case kMTCharWise: { colnr_T startcol = 0, endcol = MAXCOL; int is_oneChar = FALSE; @@ -2437,7 +2436,9 @@ static void op_yank_reg(oparg_T *oap, bool message, yankreg_T *reg, bool append) yank_copy_line(reg, &bd, y_idx); break; } - /* NOTREACHED */ + // NOTREACHED + case kMTUnknown: + assert(false); } } @@ -2448,12 +2449,15 @@ static void op_yank_reg(oparg_T *oap, bool message, yankreg_T *reg, bool append) xfree(curr->y_array); curr->y_array = new_ptr; - if (yanktype == MLINE) /* MLINE overrides MCHAR and MBLOCK */ - curr->y_type = MLINE; + if (yank_type == kMTLineWise) { + // kMTLineWise overrides kMTCharWise and kMTBlockWise + curr->y_type = kMTLineWise; + } - /* Concatenate the last line of the old block with the first line of - * the new block, unless being Vi compatible. */ - if (curr->y_type == MCHAR && vim_strchr(p_cpo, CPO_REGAPPEND) == NULL) { + // Concatenate the last line of the old block with the first line of + // the new block, unless being Vi compatible. + if (curr->y_type == kMTCharWise + && vim_strchr(p_cpo, CPO_REGAPPEND) == NULL) { pnew = xmalloc(STRLEN(curr->y_array[curr->y_size - 1]) + STRLEN(reg->y_array[0]) + 1); STRCPY(pnew, curr->y_array[--j]); @@ -2473,7 +2477,7 @@ static void op_yank_reg(oparg_T *oap, bool message, yankreg_T *reg, bool append) redraw_later(SOME_VALID); // cursor moved to start } if (message) { // Display message about yank? - if (yanktype == MCHAR && yanklines == 1) { + if (yank_type == kMTCharWise && yanklines == 1) { yanklines = 0; } // Some versions of Vi use ">=" here, some don't... @@ -2481,12 +2485,12 @@ static void op_yank_reg(oparg_T *oap, bool message, yankreg_T *reg, bool append) // redisplay now, so message is not deleted update_topline_redraw(); if (yanklines == 1) { - if (yanktype == MBLOCK) { + if (yank_type == kMTBlockWise) { MSG(_("block of 1 line yanked")); } else { MSG(_("1 line yanked")); } - } else if (yanktype == MBLOCK) { + } else if (yank_type == kMTBlockWise) { smsg(_("block of %" PRId64 " lines yanked"), (int64_t)yanklines); } else { @@ -2500,7 +2504,7 @@ static void op_yank_reg(oparg_T *oap, bool message, yankreg_T *reg, bool append) */ curbuf->b_op_start = oap->start; curbuf->b_op_end = oap->end; - if (yanktype == MLINE) { + if (yank_type == kMTLineWise) { curbuf->b_op_start.col = 0; curbuf->b_op_end.col = MAXCOL; } @@ -2590,8 +2594,8 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags) int totlen = 0; /* init for gcc */ linenr_T lnum; colnr_T col; - long i; /* index in y_array[] */ - int y_type; + long i; // index in y_array[] + MotionType y_type; long y_size; int oldlen; long y_width = 0; @@ -2652,7 +2656,7 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags) } if (insert_string != NULL) { - y_type = MCHAR; + y_type = kMTCharWise; if (regname == '=') { /* For the = register we need to split the string at NL * characters. @@ -2671,7 +2675,7 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags) ++ptr; /* A trailing '\n' makes the register linewise. */ if (*ptr == NUL) { - y_type = MLINE; + y_type = kMTLineWise; break; } } @@ -2712,7 +2716,7 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags) return; } - if (y_type == MLINE) { + if (y_type == kMTLineWise) { if (flags & PUT_LINE_SPLIT) { // "p" or "P" in Visual mode: split the lines to put the text in // between. @@ -2746,8 +2750,9 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags) curbuf->b_op_end = curwin->w_cursor; /* default for '] mark */ } - if (flags & PUT_LINE) /* :put command or "p" in Visual line mode. */ - y_type = MLINE; + if (flags & PUT_LINE) { // :put command or "p" in Visual line mode. + y_type = kMTLineWise; + } if (y_size == 0 || y_array == NULL) { EMSG2(_("E353: Nothing in register %s"), @@ -2755,13 +2760,13 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags) goto end; } - if (y_type == MBLOCK) { + if (y_type == kMTBlockWise) { lnum = curwin->w_cursor.lnum + y_size + 1; if (lnum > curbuf->b_ml.ml_line_count) lnum = curbuf->b_ml.ml_line_count + 1; if (u_save(curwin->w_cursor.lnum - 1, lnum) == FAIL) goto end; - } else if (y_type == MLINE) { + } else if (y_type == kMTLineWise) { lnum = curwin->w_cursor.lnum; /* Correct line number for closed fold. Don't move the cursor yet, * u_save() uses it. */ @@ -2785,7 +2790,7 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags) yanklen = (int)STRLEN(y_array[0]); - if (ve_flags == VE_ALL && y_type == MCHAR) { + if (ve_flags == VE_ALL && y_type == kMTCharWise) { if (gchar_cursor() == TAB) { /* Don't need to insert spaces when "p" on the last position of a * tab or "P" on the first position. */ @@ -2805,7 +2810,7 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags) /* * Block mode */ - if (y_type == MBLOCK) { + if (y_type == kMTBlockWise) { char c = gchar_cursor(); colnr_T endcol2 = 0; @@ -2953,12 +2958,10 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags) } else curwin->w_cursor.lnum = lnum; } else { - /* - * Character or Line mode - */ - if (y_type == MCHAR) { - /* if type is MCHAR, FORWARD is the same as BACKWARD on the next - * char */ + // Character or Line mode + if (y_type == kMTCharWise) { + // if type is kMTCharWise, FORWARD is the same as BACKWARD on the next + // char if (dir == FORWARD && gchar_cursor() != NUL) { if (has_mbyte) { int bytelen = (*mb_ptr2len)(get_cursor_pos_ptr()); @@ -2989,7 +2992,7 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags) /* * simple case: insert into current line */ - if (y_type == MCHAR && y_size == 1) { + if (y_type == kMTCharWise && y_size == 1) { do { totlen = count * yanklen; if (totlen > 0) { @@ -3024,18 +3027,14 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags) ++curwin->w_cursor.col; changed_bytes(lnum, col); } else { - /* - * Insert at least one line. When y_type is MCHAR, break the first - * line in two. - */ - for (cnt = 1; cnt <= count; ++cnt) { + // Insert at least one line. When y_type is kMTCharWise, break the first + // line in two. + for (cnt = 1; cnt <= count; cnt++) { i = 0; - if (y_type == MCHAR) { - /* - * Split the current line in two at the insert position. - * First insert y_array[size - 1] in front of second line. - * Then append y_array[0] to first line. - */ + if (y_type == kMTCharWise) { + // Split the current line in two at the insert position. + // First insert y_array[size - 1] in front of second line. + // Then append y_array[0] to first line. lnum = new_cursor.lnum; ptr = ml_get(lnum) + col; totlen = (int)STRLEN(y_array[y_size - 1]); @@ -3059,10 +3058,11 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags) } for (; i < y_size; i++) { - if ((y_type != MCHAR || i < y_size - 1) - && ml_append(lnum, y_array[i], (colnr_T)0, FALSE) - == FAIL) + if ((y_type != kMTCharWise || i < y_size - 1) + && ml_append(lnum, y_array[i], (colnr_T)0, false) + == FAIL) { goto error; + } lnum++; ++nr_lines; if (flags & PUT_FIXINDENT) { @@ -3091,22 +3091,23 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags) } error: - /* Adjust marks. */ - if (y_type == MLINE) { + // Adjust marks. + if (y_type == kMTLineWise) { curbuf->b_op_start.col = 0; if (dir == FORWARD) curbuf->b_op_start.lnum++; } - mark_adjust(curbuf->b_op_start.lnum + (y_type == MCHAR), - (linenr_T)MAXLNUM, nr_lines, 0L); + mark_adjust(curbuf->b_op_start.lnum + (y_type == kMTCharWise), + (linenr_T)MAXLNUM, nr_lines, 0L); - /* note changed text for displaying and folding */ - if (y_type == MCHAR) + // note changed text for displaying and folding + if (y_type == kMTCharWise) { changed_lines(curwin->w_cursor.lnum, col, - curwin->w_cursor.lnum + 1, nr_lines); - else + curwin->w_cursor.lnum + 1, nr_lines); + } else { changed_lines(curbuf->b_op_start.lnum, 0, - curbuf->b_op_start.lnum, nr_lines); + curbuf->b_op_start.lnum, nr_lines); + } /* put '] mark at last inserted character */ curbuf->b_op_end.lnum = lnum; @@ -3122,19 +3123,20 @@ error: curwin->w_cursor.lnum = lnum; beginline(BL_WHITE | BL_FIX); } else if (flags & PUT_CURSEND) { - /* put cursor after inserted text */ - if (y_type == MLINE) { - if (lnum >= curbuf->b_ml.ml_line_count) + // put cursor after inserted text + if (y_type == kMTLineWise) { + if (lnum >= curbuf->b_ml.ml_line_count) { curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count; - else + } else { curwin->w_cursor.lnum = lnum + 1; + } curwin->w_cursor.col = 0; } else { curwin->w_cursor.lnum = lnum; curwin->w_cursor.col = col; } - } else if (y_type == MLINE) { - /* put cursor on first non-blank in first inserted line */ + } else if (y_type == kMTLineWise) { + // put cursor on first non-blank in first inserted line curwin->w_cursor.col = 0; if (dir == FORWARD) ++curwin->w_cursor.lnum; @@ -3187,11 +3189,9 @@ void adjust_cursor_eol(void) */ int preprocs_left(void) { - return - (curbuf->b_p_si && !curbuf->b_p_cin) || - (curbuf->b_p_cin && in_cinkeys('#', ' ', TRUE) - && curbuf->b_ind_hash_comment == 0) - ; + return ((curbuf->b_p_si && !curbuf->b_p_cin) + || (curbuf->b_p_cin && in_cinkeys('#', ' ', true) + && curbuf->b_ind_hash_comment == 0)); } /* Return the character name of the register with the given number */ @@ -3273,9 +3273,10 @@ void ex_display(exarg_T *eap) p += clen - 1; } } - if (n > 1 && yb->y_type == MLINE) + if (n > 1 && yb->y_type == kMTLineWise) { MSG_PUTS_ATTR("^J", attr); - ui_flush(); /* show one line at a time */ + } + ui_flush(); // show one line at a time } os_breakcheck(); } @@ -4265,18 +4266,18 @@ void op_addsub(oparg_T *oap, linenr_T Prenum1, bool g_cmd) } pos = oap->start; - for (; pos.lnum <= oap->end.lnum; ++pos.lnum) { - if (oap->motion_type == MBLOCK) { + for (; pos.lnum <= oap->end.lnum; pos.lnum++) { + if (oap->motion_type == kMTBlockWise) { // Visual block mode block_prep(oap, &bd, pos.lnum, false); pos.col = bd.textcol; length = bd.textlen; - } else if (oap->motion_type == MLINE) { + } else if (oap->motion_type == kMTLineWise) { curwin->w_cursor.col = 0; pos.col = 0; length = (colnr_T)STRLEN(ml_get(pos.lnum)); } else { - // oap->motion_type == MCHAR + // oap->motion_type == kMTCharWise if (!oap->inclusive) { dec(&(oap->end)); } @@ -4396,8 +4397,7 @@ int do_addsub(int op_type, pos_T *pos, int length, linenr_T Prenum1) if (dobin && dohex && !((col > 0 - && (ptr[col] == 'X' || - ptr[col] == 'x') + && (ptr[col] == 'X' || ptr[col] == 'x') && ptr[col - 1] == '0' && ascii_isxdigit(ptr[col + 1])))) { // In case of binary/hexadecimal pattern overlap match, rescan @@ -4411,17 +4411,15 @@ int do_addsub(int op_type, pos_T *pos, int length, linenr_T Prenum1) if ((dohex && col > 0 - && (ptr[col] == 'X' - || ptr[col] == 'x') + && (ptr[col] == 'X' || ptr[col] == 'x') && ptr[col - 1] == '0' - && ascii_isxdigit(ptr[col + 1])) || - (dobin - && col > 0 - && (ptr[col] == 'B' - || ptr[col] == 'b') - && ptr[col - 1] == '0' - && ascii_isbdigit(ptr[col + 1]))) { - // Found hexadecimal or binary number, move to its start. + && ascii_isxdigit(ptr[col + 1])) + || (dobin + && col > 0 + && (ptr[col] == 'B' || ptr[col] == 'b') + && ptr[col - 1] == '0' + && ascii_isbdigit(ptr[col + 1]))) { + // Found hexadecimal or binary number, move to its start. col--; } else { // Search forward and then backward to find the start of number. @@ -4442,8 +4440,8 @@ int do_addsub(int op_type, pos_T *pos, int length, linenr_T Prenum1) } if (visual) { - while (ptr[col] != NUL && length > 0 && !ascii_isdigit(ptr[col]) && - !(doalp && ASCII_ISALPHA(ptr[col]))) { + while (ptr[col] != NUL && length > 0 && !ascii_isdigit(ptr[col]) + && !(doalp && ASCII_ISALPHA(ptr[col]))) { col++; length--; } @@ -4605,8 +4603,7 @@ int do_addsub(int op_type, pos_T *pos, int length, linenr_T Prenum1) *ptr++ = '0'; length--; } - if (pre == 'b' || pre == 'B' || - pre == 'x' || pre == 'X') { + if (pre == 'b' || pre == 'B' || pre == 'x' || pre == 'X') { *ptr++ = pre; length--; } @@ -4679,64 +4676,65 @@ theend: /* * Return the type of a register. * Used for getregtype() - * Returns MAUTO for error. + * Returns kMTUnknown for error. */ -char_u get_reg_type(int regname, colnr_T *reg_width) +MotionType get_reg_type(int regname, colnr_T *reg_width) { switch (regname) { - case '%': /* file name */ - case '#': /* alternate file name */ - case '=': /* expression */ - case ':': /* last command line */ - case '/': /* last search-pattern */ - case '.': /* last inserted text */ - case Ctrl_F: /* Filename under cursor */ - case Ctrl_P: /* Path under cursor, expand via "path" */ - case Ctrl_W: /* word under cursor */ - case Ctrl_A: /* WORD (mnemonic All) under cursor */ - case '_': /* black hole: always empty */ - return MCHAR; + case '%': // file name + case '#': // alternate file name + case '=': // expression + case ':': // last command line + case '/': // last search-pattern + case '.': // last inserted text + case Ctrl_F: // Filename under cursor + case Ctrl_P: // Path under cursor, expand via "path" + case Ctrl_W: // word under cursor + case Ctrl_A: // WORD (mnemonic All) under cursor + case '_': // black hole: always empty + return kMTCharWise; } - if (regname != NUL && !valid_yank_reg(regname, false)) - return MAUTO; + if (regname != NUL && !valid_yank_reg(regname, false)) { + return kMTUnknown; + } yankreg_T *reg = get_yank_register(regname, YREG_PASTE); if (reg->y_array != NULL) { - if (reg_width != NULL && reg->y_type == MBLOCK) { + if (reg_width != NULL && reg->y_type == kMTBlockWise) { *reg_width = reg->y_width; } return reg->y_type; } - return MAUTO; + return kMTUnknown; } /// Format the register type as a string. /// /// @param reg_type The register type. -/// @param reg_width The width, only used if "reg_type" is MBLOCK. +/// @param reg_width The width, only used if "reg_type" is kMTBlockWise. /// @param[out] buf Buffer to store formatted string. The allocated size should /// be at least NUMBUFLEN+2 to always fit the value. /// @param buf_len The allocated size of the buffer. -void format_reg_type(char_u reg_type, colnr_T reg_width, - char* buf, size_t buf_len) +void format_reg_type(MotionType reg_type, colnr_T reg_width, + char *buf, size_t buf_len) FUNC_ATTR_NONNULL_ALL { assert(buf_len > 1); switch (reg_type) { - case MLINE: + case kMTLineWise: buf[0] = 'V'; buf[1] = NUL; break; - case MCHAR: + case kMTCharWise: buf[0] = 'v'; buf[1] = NUL; break; - case MBLOCK: + case kMTBlockWise: snprintf(buf, buf_len, CTRL_V_STR "%" PRIdCOLNR, reg_width + 1); break; - case MAUTO: + case kMTUnknown: buf[0] = NUL; break; } @@ -4821,10 +4819,11 @@ void *get_reg_contents(int regname, int flags) len += STRLEN(reg->y_array[i]); /* * Insert a newline between lines and after last line if - * y_type is MLINE. + * y_type is kMTLineWise. */ - if (reg->y_type == MLINE || i < reg->y_size - 1) - ++len; + if (reg->y_type == kMTLineWise || i < reg->y_size - 1) { + len++; + } } retval = xmalloc(len + 1); @@ -4839,10 +4838,11 @@ void *get_reg_contents(int regname, int flags) /* * Insert a NL between lines and after the last line if y_type is - * MLINE. + * kMTLineWise. */ - if (reg->y_type == MLINE || i < reg->y_size - 1) + if (reg->y_type == kMTLineWise || i < reg->y_size - 1) { retval[len++] = '\n'; + } } retval[len] = NUL; @@ -4883,11 +4883,12 @@ static void finish_write_reg(int name, yankreg_T *reg, yankreg_T *old_y_previous void write_reg_contents(int name, const char_u *str, ssize_t len, int must_append) { - write_reg_contents_ex(name, str, len, must_append, MAUTO, 0L); + write_reg_contents_ex(name, str, len, must_append, kMTUnknown, 0L); } void write_reg_contents_lst(int name, char_u **strings, int maxlen, - bool must_append, int yank_type, long block_len) + bool must_append, MotionType yank_type, + long block_len) { if (name == '/' || name == '=') { char_u *s = strings[0]; @@ -4933,13 +4934,13 @@ void write_reg_contents_lst(int name, char_u **strings, int maxlen, /// contents of the register. Note that regardless of /// `must_append`, this function will append when `name` /// is an uppercase letter. -/// @param yank_type MCHAR, MLINE, MBLOCK or MAUTO +/// @param yank_type The motion type (kMTUnknown to auto detect) /// @param block_len width of visual block void write_reg_contents_ex(int name, const char_u *str, ssize_t len, bool must_append, - int yank_type, + MotionType yank_type, long block_len) { if (len < 0) { @@ -5013,24 +5014,24 @@ void write_reg_contents_ex(int name, /// When the register is not empty, the string is appended. /// /// @param y_ptr pointer to yank register -/// @param yank_type MCHAR, MLINE, MBLOCK or MAUTO +/// @param yank_type The motion type (kMTUnknown to auto detect) /// @param str string or list of strings to put in register /// @param len length of the string (Ignored when str_list=true.) /// @param blocklen width of visual block, or -1 for "I don't know." /// @param str_list True if str is `char_u **`. -static void str_to_reg(yankreg_T *y_ptr, int yank_type, const char_u *str, - size_t len, colnr_T blocklen, bool str_list) +static void str_to_reg(yankreg_T *y_ptr, MotionType yank_type, + const char_u *str, size_t len, colnr_T blocklen, + bool str_list) FUNC_ATTR_NONNULL_ALL { if (y_ptr->y_array == NULL) { // NULL means empty register y_ptr->y_size = 0; } - int type = yank_type; // MCHAR, MLINE or MBLOCK - if (yank_type == MAUTO) { - type = ((str_list || - (len > 0 && (str[len - 1] == NL || str[len - 1] == CAR))) - ? MLINE : MCHAR); + if (yank_type == kMTUnknown) { + yank_type = ((str_list + || (len > 0 && (str[len - 1] == NL || str[len - 1] == CAR))) + ? kMTLineWise : kMTCharWise); } size_t newlines = 0; @@ -5044,11 +5045,11 @@ static void str_to_reg(yankreg_T *y_ptr, int yank_type, const char_u *str, } } else { newlines = memcnt(str, '\n', len); - if (type == MCHAR || len == 0 || str[len - 1] != '\n') { + if (yank_type == kMTCharWise || len == 0 || str[len - 1] != '\n') { extraline = 1; ++newlines; // count extra newline at the end } - if (y_ptr->y_size > 0 && y_ptr->y_type == MCHAR) { + if (y_ptr->y_size > 0 && y_ptr->y_type == kMTCharWise) { append = true; --newlines; // uncount newline when appending first line } @@ -5101,11 +5102,11 @@ static void str_to_reg(yankreg_T *y_ptr, int yank_type, const char_u *str, memchrsub(pp[lnum], NUL, '\n', s_len); } } - y_ptr->y_type = type; + y_ptr->y_type = yank_type; y_ptr->y_size = lnum; set_yreg_additional_data(y_ptr, NULL); y_ptr->timestamp = os_time(); - if (type == MBLOCK) { + if (yank_type == kMTBlockWise) { y_ptr->y_width = (blocklen == -1 ? (colnr_T) maxlen - 1 : blocklen); } else { y_ptr->y_width = 0; @@ -5218,7 +5219,7 @@ void cursor_pos_info(void) /* Make 'sbr' empty for a moment to get the correct size. */ p_sbr = empty_option; oparg.is_VIsual = true; - oparg.motion_type = MBLOCK; + oparg.motion_type = kMTBlockWise; oparg.op_type = OP_NOP; getvcols(curwin, &min_pos, &max_pos, &oparg.start_vcol, &oparg.end_vcol); @@ -5473,16 +5474,16 @@ static bool get_clipboard(int name, yankreg_T **target, bool quiet) } switch (regtype[0]) { case 0: - reg->y_type = MAUTO; + reg->y_type = kMTUnknown; break; case 'v': case 'c': - reg->y_type = MCHAR; + reg->y_type = kMTCharWise; break; case 'V': case 'l': - reg->y_type = MLINE; + reg->y_type = kMTLineWise; break; case 'b': case Ctrl_V: - reg->y_type = MBLOCK; + reg->y_type = kMTBlockWise; break; default: goto err; @@ -5490,7 +5491,7 @@ static bool get_clipboard(int name, yankreg_T **target, bool quiet) } else { lines = res; // provider did not specify regtype, calculate it below - reg->y_type = MAUTO; + reg->y_type = kMTUnknown; } reg->y_array = xcalloc(lines->lv_len, sizeof(uint8_t *)); @@ -5511,20 +5512,20 @@ static bool get_clipboard(int name, yankreg_T **target, bool quiet) if (reg->y_size > 0 && strlen((char*)reg->y_array[reg->y_size-1]) == 0) { // a known-to-be charwise yank might have a final linebreak // but otherwise there is no line after the final newline - if (reg->y_type != MCHAR) { + if (reg->y_type != kMTCharWise) { xfree(reg->y_array[reg->y_size-1]); reg->y_size--; - if (reg->y_type == MAUTO) { - reg->y_type = MLINE; + if (reg->y_type == kMTUnknown) { + reg->y_type = kMTLineWise; } } } else { - if (reg->y_type == MAUTO) { - reg->y_type = MCHAR; + if (reg->y_type == kMTUnknown) { + reg->y_type = kMTCharWise; } } - if (reg->y_type == MBLOCK) { + if (reg->y_type == kMTBlockWise) { int maxlen = 0; for (int i = 0; i < reg->y_size; i++) { int rowlen = STRLEN(reg->y_array[i]); @@ -5573,17 +5574,19 @@ static void set_clipboard(int name, yankreg_T *reg) char_u regtype; switch (reg->y_type) { - case MLINE: + case kMTLineWise: regtype = 'V'; list_append_string(lines, (char_u*)"", 0); break; - case MCHAR: + case kMTCharWise: regtype = 'v'; break; - case MBLOCK: + case kMTBlockWise: regtype = 'b'; list_append_string(lines, (char_u*)"", 0); break; + case kMTUnknown: + assert(false); } list_append_string(args, ®type, 1); @@ -5624,7 +5627,7 @@ static inline bool reg_empty(const yankreg_T *const reg) return (reg->y_array == NULL || reg->y_size == 0 || (reg->y_size == 1 - && reg->y_type == MCHAR + && reg->y_type == kMTCharWise && *(reg->y_array[0]) == NUL)); } diff --git a/src/nvim/ops.h b/src/nvim/ops.h index f33e87572f..8c8a586957 100644 --- a/src/nvim/ops.h +++ b/src/nvim/ops.h @@ -78,10 +78,10 @@ enum GRegFlags { /// Definition of one register typedef struct yankreg { - char_u **y_array; ///< Pointer to an array of line pointers. - linenr_T y_size; ///< Number of lines in y_array. - char_u y_type; ///< Register type: MLINE, MCHAR or MBLOCK. - colnr_T y_width; ///< Register width (only valid for y_type == MBLOCK). + char_u **y_array; ///< Pointer to an array of line pointers. + linenr_T y_size; ///< Number of lines in y_array. + MotionType y_type; ///< Register type + colnr_T y_width; ///< Register width (only valid for y_type == kBlockWise). Timestamp timestamp; ///< Time when register was last modified. dict_T *additional_data; ///< Additional data from ShaDa file. } yankreg_T; diff --git a/src/nvim/option.c b/src/nvim/option.c index f9d1cdbaec..2f22c245dd 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -32,6 +32,7 @@ #include "nvim/vim.h" #include "nvim/ascii.h" +#include "nvim/edit.h" #include "nvim/option.h" #include "nvim/buffer.h" #include "nvim/charset.h" @@ -1177,28 +1178,27 @@ do_set ( errmsg = e_invarg; goto skip; } - arg[len] = NUL; /* put NUL after name */ - if (arg[1] == 't' && arg[2] == '_') /* could be term code */ - opt_idx = findoption(arg + 1); - arg[len++] = '>'; /* restore '>' */ - if (opt_idx == -1) + if (arg[1] == 't' && arg[2] == '_') { // could be term code + opt_idx = findoption_len(arg + 1, (size_t) (len - 1)); + } + len++; + if (opt_idx == -1) { key = find_key_option(arg + 1); + } } else { len = 0; - /* - * The two characters after "t_" may not be alphanumeric. - */ - if (arg[0] == 't' && arg[1] == '_' && arg[2] && arg[3]) + // The two characters after "t_" may not be alphanumeric. + if (arg[0] == 't' && arg[1] == '_' && arg[2] && arg[3]) { len = 4; - else - while (ASCII_ISALNUM(arg[len]) || arg[len] == '_') - ++len; - nextchar = arg[len]; - arg[len] = NUL; /* put NUL after name */ - opt_idx = findoption(arg); - arg[len] = nextchar; /* restore nextchar */ - if (opt_idx == -1) + } else { + while (ASCII_ISALNUM(arg[len]) || arg[len] == '_') { + len++; + } + } + opt_idx = findoption_len(arg, (size_t) len); + if (opt_idx == -1) { key = find_key_option(arg); + } } /* remember character after option name */ @@ -2057,6 +2057,7 @@ static void didset_options(void) (void)opt_strings_flags(p_vop, p_ssop_values, &vop_flags, true); (void)opt_strings_flags(p_fdo, p_fdo_values, &fdo_flags, true); (void)opt_strings_flags(p_dy, p_dy_values, &dy_flags, true); + (void)opt_strings_flags(p_tc, p_tc_values, &tc_flags, false); (void)opt_strings_flags(p_ve, p_ve_values, &ve_flags, true); (void)spell_check_msm(); (void)spell_check_sps(); @@ -2144,6 +2145,7 @@ void check_buf_options(buf_T *buf) check_string_option(&buf->b_p_ep); check_string_option(&buf->b_p_path); check_string_option(&buf->b_p_tags); + check_string_option(&buf->b_p_tc); check_string_option(&buf->b_p_dict); check_string_option(&buf->b_p_tsr); check_string_option(&buf->b_p_lw); @@ -2957,13 +2959,17 @@ did_set_string_option ( } /* 'completeopt' */ else if (varp == &p_cot) { - if (check_opt_strings(p_cot, p_cot_values, TRUE) != OK) + if (check_opt_strings(p_cot, p_cot_values, true) != OK) { errmsg = e_invarg; + } else { + completeopt_was_set(); + } } /* 'pastetoggle': translate key codes like in a mapping */ else if (varp == &p_pt) { if (*p_pt) { - (void)replace_termcodes(p_pt, &p, TRUE, TRUE, FALSE); + (void)replace_termcodes(p_pt, STRLEN(p_pt), &p, true, true, false, + CPO_TO_CPO_FLAGS); if (p != NULL) { if (new_value_alloced) free_string_option(p_pt); @@ -2983,6 +2989,24 @@ did_set_string_option ( if (opt_strings_flags(p_bo, p_bo_values, &bo_flags, true) != OK) { errmsg = e_invarg; } + } else if (gvarp == &p_tc) { // 'tagcase' + unsigned int *flags; + + if (opt_flags & OPT_LOCAL) { + p = curbuf->b_p_tc; + flags = &curbuf->b_tc_flags; + } else { + p = p_tc; + flags = &tc_flags; + } + + if ((opt_flags & OPT_LOCAL) && *p == NUL) { + // make the local value empty: use the global value + *flags = 0; + } else if (*p == NUL + || opt_strings_flags(p, p_tc_values, flags, false) != OK) { + errmsg = e_invarg; + } } else if (varp == &p_cmp) { // 'casemap' if (opt_strings_flags(p_cmp, p_cmp_values, &cmp_flags, true) != OK) errmsg = e_invarg; @@ -4283,14 +4307,16 @@ static void check_redraw(uint32_t flags) redraw_all_later(NOT_VALID); } -/* - * Find index for option 'arg'. - * Return -1 if not found. - */ -static int findoption(char_u *arg) +/// Find index for named option +/// +/// @param[in] arg Option to find index for. +/// @param[in] len Length of the option. +/// +/// @return Index of the option or -1 if option was not found. +int findoption_len(const char_u *const arg, const size_t len) { - char *s, *p; - static short quick_tab[27] = {0, 0}; /* quick access table */ + char *s, *p; + static int quick_tab[27] = { 0, 0 }; // quick access table int is_term_opt; /* @@ -4314,25 +4340,31 @@ static int findoption(char_u *arg) /* * Check for name starting with an illegal character. */ - if (arg[0] < 'a' || arg[0] > 'z') + if (len == 0 || arg[0] < 'a' || arg[0] > 'z') { return -1; + } int opt_idx; - is_term_opt = (arg[0] == 't' && arg[1] == '_'); - if (is_term_opt) + is_term_opt = (len > 2 && arg[0] == 't' && arg[1] == '_'); + if (is_term_opt) { opt_idx = quick_tab[26]; - else + } else { opt_idx = quick_tab[CharOrdLow(arg[0])]; + } + // Match full name for (; (s = options[opt_idx].fullname) != NULL; opt_idx++) { - if (STRCMP(arg, s) == 0) /* match full name */ + if (STRNCMP(arg, s, len) == 0 && s[len] == NUL) { break; + } } if (s == NULL && !is_term_opt) { opt_idx = quick_tab[CharOrdLow(arg[0])]; + // Match short name for (; options[opt_idx].fullname != NULL; opt_idx++) { s = options[opt_idx].shortname; - if (s != NULL && STRCMP(arg, s) == 0) /* match short name */ + if (s != NULL && STRNCMP(arg, s, len) == 0 && s[len] == NUL) { break; + } s = NULL; } } @@ -4400,6 +4432,15 @@ bool set_tty_option(char *name, char *value) } /* + * Find index for option 'arg'. + * Return -1 if not found. + */ +static int findoption(char_u *arg) +{ + return findoption_len(arg, STRLEN(arg)); +} + +/* * Get the value for an option. * * Returns: @@ -4655,27 +4696,32 @@ char_u *get_highlight_default(void) /* * Translate a string like "t_xx", "<t_xx>" or "<S-Tab>" to a key number. */ -static int find_key_option(char_u *arg) +int find_key_option_len(const char_u *arg, size_t len) { int key; int modifiers; - /* - * Don't use get_special_key_code() for t_xx, we don't want it to call - * add_termcap_entry(). - */ - if (arg[0] == 't' && arg[1] == '_' && arg[2] && arg[3]) + // Don't use get_special_key_code() for t_xx, we don't want it to call + // add_termcap_entry(). + if (len >= 4 && arg[0] == 't' && arg[1] == '_') { key = TERMCAP2KEY(arg[2], arg[3]); - else { - --arg; /* put arg at the '<' */ + } else { + arg--; // put arg at the '<' modifiers = 0; - key = find_special_key(&arg, &modifiers, TRUE, TRUE); - if (modifiers) /* can't handle modifiers here */ + key = find_special_key(&arg, len + 1, &modifiers, true, true); + if (modifiers) { // can't handle modifiers here key = 0; + } } return key; } +static int find_key_option(const char_u *arg) +{ + return find_key_option_len(arg, STRLEN(arg)); +} + + /* * if 'all' == 0: show changed options * if 'all' == 1: show all normal options @@ -4736,9 +4782,10 @@ showoptions ( option_value2string(p, opt_flags); len = (int)STRLEN(p->fullname) + vim_strsize(NameBuff) + 1; } - if ((len <= INC - GAP && run == 1) || - (len > INC - GAP && run == 2)) + if ((len <= INC - GAP && run == 1) + || (len > INC - GAP && run == 2)) { items[item_count++] = p; + } } } @@ -4927,18 +4974,15 @@ int makeset(FILE *fd, int opt_flags, int local_only) } else { /* P_STRING */ int do_endif = FALSE; - /* Don't set 'syntax' and 'filetype' again if the value is - * already right, avoids reloading the syntax file. */ - if ( - p->indir == PV_SYN - || - p->indir == PV_FT - ) { + // Don't set 'syntax' and 'filetype' again if the value is + // already right, avoids reloading the syntax file. + if (p->indir == PV_SYN || p->indir == PV_FT) { if (fprintf(fd, "if &%s != '%s'", p->fullname, - *(char_u **)(varp)) < 0 - || put_eol(fd) < 0) + *(char_u **)(varp)) < 0 + || put_eol(fd) < 0) { return FAIL; - do_endif = TRUE; + } + do_endif = true; } if (put_setstring(fd, cmd, p->fullname, (char_u **)varp, (p->flags & P_EXPAND) != 0) == FAIL) @@ -5111,6 +5155,10 @@ void unset_global_local_option(char *name, void *from) case PV_TAGS: clear_string_option(&buf->b_p_tags); break; + case PV_TC: + clear_string_option(&buf->b_p_tc); + buf->b_tc_flags = 0; + break; case PV_DEF: clear_string_option(&buf->b_p_def); break; @@ -5164,6 +5212,7 @@ static char_u *get_varp_scope(vimoption_T *p, int opt_flags) case PV_PATH: return (char_u *)&(curbuf->b_p_path); case PV_AR: return (char_u *)&(curbuf->b_p_ar); case PV_TAGS: return (char_u *)&(curbuf->b_p_tags); + case PV_TC: return (char_u *)&(curbuf->b_p_tc); case PV_DEF: return (char_u *)&(curbuf->b_p_def); case PV_INC: return (char_u *)&(curbuf->b_p_inc); case PV_DICT: return (char_u *)&(curbuf->b_p_dict); @@ -5201,6 +5250,8 @@ static char_u *get_varp(vimoption_T *p) ? (char_u *)&(curbuf->b_p_ar) : p->var; case PV_TAGS: return *curbuf->b_p_tags != NUL ? (char_u *)&(curbuf->b_p_tags) : p->var; + case PV_TC: return *curbuf->b_p_tc != NUL + ? (char_u *)&(curbuf->b_p_tc) : p->var; case PV_BKC: return *curbuf->b_p_bkc != NUL ? (char_u *)&(curbuf->b_p_bkc) : p->var; case PV_DEF: return *curbuf->b_p_def != NUL @@ -5580,6 +5631,8 @@ void buf_copy_options(buf_T *buf, int flags) buf->b_p_kp = empty_option; buf->b_p_path = empty_option; buf->b_p_tags = empty_option; + buf->b_p_tc = empty_option; + buf->b_tc_flags = 0; buf->b_p_def = empty_option; buf->b_p_inc = empty_option; buf->b_p_inex = vim_strsave(p_inex); @@ -6170,10 +6223,10 @@ int has_format_option(int x) /// 'shortmess' contains 'a' and "x" is present in SHM_ALL_ABBREVIATIONS. bool shortmess(int x) { - return p_shm != NULL && - (vim_strchr(p_shm, x) != NULL - || (vim_strchr(p_shm, 'a') != NULL - && vim_strchr((char_u *)SHM_ALL_ABBREVIATIONS, x) != NULL)); + return (p_shm != NULL + && (vim_strchr(p_shm, x) != NULL + || (vim_strchr(p_shm, 'a') != NULL + && vim_strchr((char_u *)SHM_ALL_ABBREVIATIONS, x) != NULL))); } /* diff --git a/src/nvim/option_defs.h b/src/nvim/option_defs.h index bbe40873ec..87a9a7398c 100644 --- a/src/nvim/option_defs.h +++ b/src/nvim/option_defs.h @@ -597,6 +597,14 @@ static char *(p_swb_values[]) = #define SWB_NEWTAB 0x008 #define SWB_VSPLIT 0x010 EXTERN int p_tbs; ///< 'tagbsearch' +EXTERN char_u *p_tc; ///< 'tagcase' +EXTERN unsigned tc_flags; ///< flags from 'tagcase' +#ifdef IN_OPTION_C +static char *(p_tc_values[]) = { "followic", "ignore", "match", NULL }; +#endif +#define TC_FOLLOWIC 0x01 +#define TC_IGNORE 0x02 +#define TC_MATCH 0x04 EXTERN long p_tl; ///< 'taglength' EXTERN int p_tr; ///< 'tagrelative' EXTERN char_u *p_tags; ///< 'tags' @@ -737,6 +745,7 @@ enum { , BV_SW , BV_SWF , BV_TAGS + , BV_TC , BV_TS , BV_TW , BV_TX diff --git a/src/nvim/options.lua b/src/nvim/options.lua index df77c374ec..a743e8c605 100644 --- a/src/nvim/options.lua +++ b/src/nvim/options.lua @@ -2332,6 +2332,13 @@ return { defaults={if_true={vi=true}} }, { + full_name='tagcase', abbreviation='tc', + type='string', scope={'global', 'buffer'}, + vim=true, + varname='p_tc', + defaults={if_true={vi="followic", vim="followic"}} + }, + { full_name='taglength', abbreviation='tl', type='number', scope={'global'}, vi_def=true, diff --git a/src/nvim/os/fs.c b/src/nvim/os/fs.c index 34d8fde4f1..49a74cf0d1 100644 --- a/src/nvim/os/fs.c +++ b/src/nvim/os/fs.c @@ -2,6 +2,7 @@ #include <stdbool.h> #include <assert.h> +#include <fcntl.h> #include "nvim/os/os.h" #include "nvim/os/os_defs.h" @@ -59,6 +60,23 @@ int os_dirname(char_u *buf, size_t len) return OK; } +/// Check if the given path is a directory and not a symlink to a directory. +/// @return `true` if `name` is a directory and NOT a symlink to a directory. +/// `false` if `name` is not a directory or if an error occurred. +bool os_isrealdir(const char_u *name) + FUNC_ATTR_NONNULL_ALL +{ + uv_fs_t request; + if (uv_fs_lstat(&fs_loop, &request, (char *)name, NULL) != kLibuvSuccess) { + return false; + } + if (S_ISLNK(request.statbuf.st_mode)) { + return false; + } else { + return S_ISDIR(request.statbuf.st_mode); + } +} + /// Check if the given path is a directory or not. /// /// @return `true` if `fname` is a directory. @@ -77,10 +95,76 @@ bool os_isdir(const char_u *name) return true; } +/// Check what `name` is: +/// @return NODE_NORMAL: file or directory (or doesn't exist) +/// NODE_WRITABLE: writable device, socket, fifo, etc. +/// NODE_OTHER: non-writable things +int os_nodetype(const char *name) +{ +#ifdef WIN32 + // Edge case from Vim os_win32.c: + // We can't open a file with a name "\\.\con" or "\\.\prn", trying to read + // from it later will cause Vim to hang. Thus return NODE_WRITABLE here. + if (STRNCMP(name, "\\\\.\\", 4) == 0) { + return NODE_WRITABLE; + } +#endif + + uv_stat_t statbuf; + if (os_stat(name, &statbuf) == 0) { + return NODE_NORMAL; + } + +#ifndef WIN32 + // libuv does not handle BLK and DIR in uv_handle_type. + // Related: https://github.com/joyent/libuv/pull/1421 + if (S_ISREG(statbuf.st_mode) || S_ISDIR(statbuf.st_mode)) { + return NODE_NORMAL; + } + if (S_ISBLK(statbuf.st_mode)) { // block device isn't writable + return NODE_OTHER; + } +#endif + + // Vim os_win32.c:mch_nodetype does this (since patch 7.4.015): + // if (enc_codepage >= 0 && (int)GetACP() != enc_codepage) { + // wn = enc_to_utf16(name, NULL); + // hFile = CreatFile(wn, ...) + // to get a HANDLE. But libuv just calls win32's _get_osfhandle() on the fd we + // give it. uv_fs_open calls fs__capture_path which does a similar dance and + // saves us the hassle. + + int nodetype = NODE_WRITABLE; + int fd = os_open(name, O_RDONLY, 0); + switch(uv_guess_handle(fd)) { + case UV_TTY: // FILE_TYPE_CHAR + nodetype = NODE_WRITABLE; + break; + case UV_FILE: // FILE_TYPE_DISK + nodetype = NODE_NORMAL; + break; + case UV_NAMED_PIPE: // not handled explicitly in Vim os_win32.c + case UV_UDP: // unix only + case UV_TCP: // unix only + case UV_UNKNOWN_HANDLE: + default: +#ifdef WIN32 + nodetype = NODE_NORMAL; +#else + nodetype = NODE_WRITABLE; // Everything else is writable? +#endif + break; + } + + close(fd); + return nodetype; +} + /// Checks if the given path represents an executable file. /// -/// @param[in] name The name of the executable. +/// @param[in] name Name of the executable. /// @param[out] abspath Path of the executable, if found and not `NULL`. +/// @param[in] use_path If 'false', only check if "name" is executable /// /// @return `true` if `name` is executable and /// - can be found in $PATH, @@ -88,14 +172,18 @@ bool os_isdir(const char_u *name) /// - is absolute. /// /// @return `false` otherwise. -bool os_can_exe(const char_u *name, char_u **abspath) +bool os_can_exe(const char_u *name, char_u **abspath, bool use_path) FUNC_ATTR_NONNULL_ARG(1) { - // If it's an absolute or relative path don't need to use $PATH. - if (path_is_absolute_path(name) || - (name[0] == '.' && (name[1] == '/' || - (name[1] == '.' && name[2] == '/')))) { - if (is_executable(name)) { + // when use_path is false or if it's an absolute or relative path don't + // need to use $PATH. + if (!use_path || path_is_absolute_path(name) + || (name[0] == '.' + && (name[1] == '/' + || (name[1] == '.' && name[2] == '/')))) { + // There must be a path separator, files in the current directory + // can't be executed + if (gettail_dir(name) != name && is_executable(name)) { if (abspath != NULL) { *abspath = save_absolute_path(name); } diff --git a/src/nvim/os/fs_defs.h b/src/nvim/os/fs_defs.h index 52b2841514..0bd9c37750 100644 --- a/src/nvim/os/fs_defs.h +++ b/src/nvim/os/fs_defs.h @@ -26,4 +26,10 @@ typedef struct { /// negative libuv error codes are returned by a number of os functions. #define os_strerror uv_strerror +// Values returned by os_nodetype() +#define NODE_NORMAL 0 // file or directory, check with os_isdir() +#define NODE_WRITABLE 1 // something we can write to (character + // device, fifo, socket, ..) +#define NODE_OTHER 2 // non-writable thing (e.g., block device) + #endif // NVIM_OS_FS_DEFS_H diff --git a/src/nvim/os/input.c b/src/nvim/os/input.c index f317fd6b5a..7687b14f02 100644 --- a/src/nvim/os/input.c +++ b/src/nvim/os/input.c @@ -175,8 +175,9 @@ size_t input_enqueue(String keys) char *ptr = keys.data, *end = ptr + keys.size; while (rbuffer_space(input_buffer) >= 6 && ptr < end) { - uint8_t buf[6] = {0}; - unsigned int new_size = trans_special((uint8_t **)&ptr, buf, true); + uint8_t buf[6] = { 0 }; + unsigned int new_size = trans_special((const uint8_t **)&ptr, keys.size, + buf, true); if (new_size) { new_size = handle_mouse_event(&ptr, buf, new_size); @@ -402,9 +403,9 @@ static int push_event_key(uint8_t *buf, int maxlen) // Check if there's pending input static bool input_ready(void) { - return typebuf_was_filled || // API call filled typeahead - rbuffer_size(input_buffer) || // Input buffer filled - pending_events(); // Events must be processed + return (typebuf_was_filled // API call filled typeahead + || rbuffer_size(input_buffer) // Input buffer filled + || pending_events()); // Events must be processed } // Exit because of an input read error. diff --git a/src/nvim/os/mem.c b/src/nvim/os/mem.c index 5e483c0c3d..871ece7a0e 100644 --- a/src/nvim/os/mem.c +++ b/src/nvim/os/mem.c @@ -8,5 +8,5 @@ uint64_t os_get_total_mem_kib(void) { // Convert bytes to KiB. - return uv_get_total_memory() >> 10; + return uv_get_total_memory() / 1024; } diff --git a/src/nvim/os/win_defs.h b/src/nvim/os/win_defs.h index 242d355f77..55894e4d12 100644 --- a/src/nvim/os/win_defs.h +++ b/src/nvim/os/win_defs.h @@ -1,6 +1,9 @@ #ifndef NVIM_OS_WIN_DEFS_H #define NVIM_OS_WIN_DEFS_H +// winsock2.h must be first to avoid incompatibilities +// with winsock.h (included by windows.h) +#include <winsock2.h> #include <windows.h> #include <sys/stat.h> #include <io.h> diff --git a/src/nvim/os_unix.c b/src/nvim/os_unix.c index cb9a58cc77..2ed0c2c856 100644 --- a/src/nvim/os_unix.c +++ b/src/nvim/os_unix.c @@ -34,7 +34,6 @@ #include "nvim/screen.h" #include "nvim/strings.h" #include "nvim/syntax.h" -#include "nvim/tempfile.h" #include "nvim/ui.h" #include "nvim/types.h" #include "nvim/os/os.h" @@ -137,26 +136,6 @@ void mch_free_acl(vim_acl_T aclent) } #endif -/* - * Check what "name" is: - * NODE_NORMAL: file or directory (or doesn't exist) - * NODE_WRITABLE: writable device, socket, fifo, etc. - * NODE_OTHER: non-writable things - */ -int mch_nodetype(char_u *name) -{ - struct stat st; - - if (stat((char *)name, &st)) - return NODE_NORMAL; - if (S_ISREG(st.st_mode) || S_ISDIR(st.st_mode)) - return NODE_NORMAL; - if (S_ISBLK(st.st_mode)) /* block device isn't writable */ - return NODE_OTHER; - /* Everything else is writable? */ - return NODE_WRITABLE; -} - void mch_exit(int r) { exiting = true; @@ -597,9 +576,11 @@ int mch_expand_wildcards(int num_pat, char_u **pat, int *num_file, if ((dir && !(flags & EW_DIR)) || (!dir && !(flags & EW_FILE))) continue; - /* Skip files that are not executable if we check for that. */ - if (!dir && (flags & EW_EXEC) && !os_can_exe((*file)[i], NULL)) + // Skip files that are not executable if we check for that. + if (!dir && (flags & EW_EXEC) + && !os_can_exe((*file)[i], NULL, !(flags & EW_SHELLCMD))) { continue; + } p = xmalloc(STRLEN((*file)[i]) + 1 + dir); STRCPY(p, (*file)[i]); diff --git a/src/nvim/os_unix.h b/src/nvim/os_unix.h index 5a3eb84ba4..d627b16ec0 100644 --- a/src/nvim/os_unix.h +++ b/src/nvim/os_unix.h @@ -4,12 +4,6 @@ #include "nvim/types.h" // for vim_acl_T #include "nvim/os/shell.h" -/* Values returned by mch_nodetype() */ -#define NODE_NORMAL 0 /* file or directory, check with os_isdir()*/ -#define NODE_WRITABLE 1 /* something we can write to (character - device, fifo, socket, ..) */ -#define NODE_OTHER 2 /* non-writable thing (e.g., block device) */ - #ifdef INCLUDE_GENERATED_DECLARATIONS # include "os_unix.h.generated.h" #endif diff --git a/src/nvim/path.c b/src/nvim/path.c index aaf54bc5b4..aff0ee2d48 100644 --- a/src/nvim/path.c +++ b/src/nvim/path.c @@ -604,7 +604,7 @@ static size_t do_path_expand(garray_T *gap, const char_u *path, starstar = true; // convert the file pattern to a regexp pattern - int starts_with_dot = (*s == '.'); + int starts_with_dot = *s == '.'; char_u *pat = file_pat_to_reg_pat(s, e, NULL, false); if (pat == NULL) { xfree(buf); @@ -647,9 +647,12 @@ static size_t do_path_expand(garray_T *gap, const char_u *path, if (os_file_is_readable(dirpath) && os_scandir(&dir, dirpath)) { // Find all matching entries. char_u *name; - scandir_next_with_dots(NULL /* initialize */); - while((name = (char_u *) scandir_next_with_dots(&dir)) && name != NULL) { - if ((name[0] != '.' || starts_with_dot) + scandir_next_with_dots(NULL); // initialize + while ((name = (char_u *) scandir_next_with_dots(&dir)) && name != NULL) { + if ((name[0] != '.' + || starts_with_dot + || ((flags & EW_DODOT) + && name[1] != NUL && (name[1] != '.' || name[2] != NUL))) && ((regmatch.regprog != NULL && vim_regexec(®match, name, 0)) || ((flags & EW_NOTWILD) && fnamencmp(path + (s - buf), name, e - s) == 0))) { @@ -978,12 +981,12 @@ static void uniquefy_paths(garray_T *gap, char_u *pattern) * "/path/file", "/path/dir/", "/path//dir", "/file" * ^ ^ ^ ^ */ -static char_u *gettail_dir(char_u *fname) +char_u *gettail_dir(const char_u *fname) { - char_u *dir_end = fname; - char_u *next_dir_end = fname; + const char_u *dir_end = fname; + const char_u *next_dir_end = fname; bool look_for_sep = true; - char_u *p; + const char_u *p; for (p = fname; *p != NUL; ) { if (vim_ispathsep(*p)) { @@ -998,7 +1001,7 @@ static char_u *gettail_dir(char_u *fname) } mb_ptr_adv(p); } - return dir_end; + return (char_u *)dir_end; } @@ -1220,7 +1223,7 @@ int gen_expand_wildcards(int num_pat, char_u **pat, int *num_file, recursive = false; - return (ga.ga_data != NULL) ? OK : FAIL; + return ((flags & EW_EMPTYOK) || ga.ga_data != NULL) ? OK : FAIL; } @@ -1298,9 +1301,10 @@ void addfile( FileInfo file_info; // if the file/dir/link doesn't exist, may not add it - if (!(flags & EW_NOTFOUND) && - ((flags & EW_ALLLINKS) ? - !os_fileinfo_link((char *)f, &file_info) : !os_file_exists(f))) { + if (!(flags & EW_NOTFOUND) + && ((flags & EW_ALLLINKS) + ? !os_fileinfo_link((char *)f, &file_info) + : !os_file_exists(f))) { return; } @@ -1314,9 +1318,12 @@ void addfile( if ((isdir && !(flags & EW_DIR)) || (!isdir && !(flags & EW_FILE))) return; - /* If the file isn't executable, may not add it. Do accept directories. */ - if (!isdir && (flags & EW_EXEC) && !os_can_exe(f, NULL)) + // If the file isn't executable, may not add it. Do accept directories. + // When invoked from expand_shellcmd() do not use $PATH. + if (!isdir && (flags & EW_EXEC) + && !os_can_exe(f, NULL, !(flags & EW_SHELLCMD))) { return; + } char_u *p = xmalloc(STRLEN(f) + 1 + isdir); @@ -1380,9 +1387,9 @@ void simplify_filename(char_u *filename) --p; /* strip preceding path separator */ STRMOVE(p, tail); } - } else if (p[0] == '.' && p[1] == '.' && - (vim_ispathsep(p[2]) || p[2] == NUL)) { - /* Skip to after ".." or "../" or "..///". */ + } else if (p[0] == '.' && p[1] == '.' + && (vim_ispathsep(p[2]) || p[2] == NUL)) { + // Skip to after ".." or "../" or "..///". tail = p + 2; while (vim_ispathsep(*tail)) mb_ptr_adv(tail); @@ -1923,7 +1930,7 @@ int expand_wildcards_eval(char_u **pat, int *num_file, char_u ***file, /// If FAIL is returned, *num_file and *file are either /// unchanged or *num_file is set to 0 and *file is set to /// NULL or points to "". -int expand_wildcards(int num_pat, char_u **pat, int *num_file, char_u ***file, +int expand_wildcards(int num_pat, char_u **pat, int *num_files, char_u ***files, int flags) { int retval; @@ -1931,7 +1938,7 @@ int expand_wildcards(int num_pat, char_u **pat, int *num_file, char_u ***file, char_u *p; int non_suf_match; /* number without matching suffix */ - retval = gen_expand_wildcards(num_pat, pat, num_file, file, flags); + retval = gen_expand_wildcards(num_pat, pat, num_files, files, flags); /* When keeping all matches, return here */ if ((flags & EW_KEEPALL) || retval == FAIL) @@ -1943,18 +1950,20 @@ int expand_wildcards(int num_pat, char_u **pat, int *num_file, char_u ***file, if (*p_wig) { char_u *ffname; - /* check all files in (*file)[] */ - for (i = 0; i < *num_file; ++i) { - ffname = (char_u *)FullName_save((char *)(*file)[i], FALSE); - if (ffname == NULL) /* out of memory */ + // check all filess in (*files)[] + for (i = 0; i < *num_files; i++) { + ffname = (char_u *)FullName_save((char *)(*files)[i], false); + if (ffname == NULL) { // out of memory break; - if (match_file_list(p_wig, (*file)[i], ffname)) { - /* remove this matching file from the list */ - xfree((*file)[i]); - for (j = i; j + 1 < *num_file; ++j) - (*file)[j] = (*file)[j + 1]; - --*num_file; - --i; + } + if (match_file_list(p_wig, (*files)[i], ffname)) { + // remove this matching files from the list + xfree((*files)[i]); + for (j = i; j + 1 < *num_files; j++) { + (*files)[j] = (*files)[j + 1]; + } + (*num_files)--; + i--; } xfree(ffname); } @@ -1963,26 +1972,28 @@ int expand_wildcards(int num_pat, char_u **pat, int *num_file, char_u ***file, /* * Move the names where 'suffixes' match to the end. */ - if (*num_file > 1) { + if (*num_files > 1) { non_suf_match = 0; - for (i = 0; i < *num_file; ++i) { - if (!match_suffix((*file)[i])) { - /* - * Move the name without matching suffix to the front - * of the list. - */ - p = (*file)[i]; - for (j = i; j > non_suf_match; --j) - (*file)[j] = (*file)[j - 1]; - (*file)[non_suf_match++] = p; + for (i = 0; i < *num_files; i++) { + if (!match_suffix((*files)[i])) { + // + // Move the name without matching suffix to the front + // of the list. + // + p = (*files)[i]; + for (j = i; j > non_suf_match; j--) { + (*files)[j] = (*files)[j - 1]; + } + (*files)[non_suf_match++] = p; } } } // Free empty array of matches - if (*num_file == 0) { - xfree(*file); - *file = NULL; + if (*num_files == 0) { + xfree(*files); + *files = NULL; + return FAIL; } return retval; @@ -2009,8 +2020,8 @@ int match_suffix(char_u *fname) break; } } else { - if (fnamelen >= setsuflen && - fnamencmp(suf_buf, fname + fnamelen - setsuflen, setsuflen) == 0) { + if (fnamelen >= setsuflen + && fnamencmp(suf_buf, fname + fnamelen - setsuflen, setsuflen) == 0) { break; } setsuflen = 0; diff --git a/src/nvim/path.h b/src/nvim/path.h index eac367d0ac..4e466d1b71 100644 --- a/src/nvim/path.h +++ b/src/nvim/path.h @@ -21,6 +21,10 @@ /* Note: mostly EW_NOTFOUND and EW_SILENT are mutually exclusive: EW_NOTFOUND * is used when executing commands and EW_SILENT for interactive expanding. */ #define EW_ALLLINKS 0x1000 // also links not pointing to existing file +#define EW_SHELLCMD 0x2000 // called from expand_shellcmd(), don't check + // if executable is in $PATH +#define EW_DODOT 0x4000 // also files starting with a dot +#define EW_EMPTYOK 0x8000 // no matches is not an error /// Return value for the comparison of two files. Also @see path_full_compare. typedef enum file_comparison { diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c index 28c0425e2c..17cb8a86aa 100644 --- a/src/nvim/quickfix.c +++ b/src/nvim/quickfix.c @@ -39,7 +39,6 @@ #include "nvim/search.h" #include "nvim/strings.h" #include "nvim/ui.h" -#include "nvim/tempfile.h" #include "nvim/window.h" #include "nvim/os/os.h" #include "nvim/os/input.h" @@ -2758,8 +2757,8 @@ void ex_cc(exarg_T *eap) // For cdo and ldo commands, jump to the nth valid error. // For cfdo and lfdo commands, jump to the nth valid file entry. - if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo || - eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo) { + if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo + || eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo) { size_t n; if (eap->addr_count > 0) { assert(eap->line1 >= 0); @@ -2802,9 +2801,9 @@ void ex_cnext(exarg_T *eap) } int errornr; - if (eap->addr_count > 0 && - (eap->cmdidx != CMD_cdo && eap->cmdidx != CMD_ldo && - eap->cmdidx != CMD_cfdo && eap->cmdidx != CMD_lfdo)) { + if (eap->addr_count > 0 + && (eap->cmdidx != CMD_cdo && eap->cmdidx != CMD_ldo + && eap->cmdidx != CMD_cfdo && eap->cmdidx != CMD_lfdo)) { errornr = (int)eap->line2; } else { errornr = 1; @@ -2973,16 +2972,18 @@ void ex_vimgrep(exarg_T *eap) goto theend; } - if ((eap->cmdidx != CMD_grepadd && eap->cmdidx != CMD_lgrepadd && - eap->cmdidx != CMD_vimgrepadd && eap->cmdidx != CMD_lvimgrepadd) - || qi->qf_curlist == qi->qf_listcount) - /* make place for a new list */ + if ((eap->cmdidx != CMD_grepadd && eap->cmdidx != CMD_lgrepadd + && eap->cmdidx != CMD_vimgrepadd && eap->cmdidx != CMD_lvimgrepadd) + || qi->qf_curlist == qi->qf_listcount) { + // make place for a new list qf_new_list(qi, *eap->cmdlinep); - else if (qi->qf_lists[qi->qf_curlist].qf_count > 0) - /* Adding to existing list, find last entry. */ + } else if (qi->qf_lists[qi->qf_curlist].qf_count > 0) { + // Adding to existing list, find last entry. for (prevp = qi->qf_lists[qi->qf_curlist].qf_start; - prevp->qf_next != prevp; prevp = prevp->qf_next) - ; + prevp->qf_next != prevp; + prevp = prevp->qf_next) { + } + } /* parse the list of arguments */ if (get_arglist_exp(p, &fcount, &fnames, true) == FAIL) diff --git a/src/nvim/regexp.c b/src/nvim/regexp.c index 608aa38466..886a48e7c5 100644 --- a/src/nvim/regexp.c +++ b/src/nvim/regexp.c @@ -3445,13 +3445,14 @@ static long bt_regexec_both(char_u *line, c = regline[col]; if (prog->regstart == NUL || prog->regstart == c - || (ireg_ic && (( - (enc_utf8 && utf_fold(prog->regstart) == utf_fold(c))) - || (c < 255 && prog->regstart < 255 && - vim_tolower(prog->regstart) == vim_tolower(c))))) + || (ireg_ic + && (((enc_utf8 && utf_fold(prog->regstart) == utf_fold(c))) + || (c < 255 && prog->regstart < 255 + && vim_tolower(prog->regstart) == vim_tolower(c))))) { retval = regtry(prog, col); - else + } else { retval = 0; + } } else { int tm_count = 0; /* Messy cases: unanchored match. */ @@ -4121,15 +4122,15 @@ regmatch ( char_u *opnd; opnd = OPERAND(scan); - /* Inline the first byte, for speed. */ + // Inline the first byte, for speed. if (*opnd != *reginput - && (!ireg_ic || ( - !enc_utf8 && - vim_tolower(*opnd) != vim_tolower(*reginput)))) + && (!ireg_ic + || (!enc_utf8 + && vim_tolower(*opnd) != vim_tolower(*reginput)))) { status = RA_NOMATCH; - else if (*opnd == NUL) { - /* match empty string always works; happens when "~" is - * empty. */ + } else if (*opnd == NUL) { + // match empty string always works; happens when "~" is + // empty. } else { if (opnd[1] == NUL && !(enc_utf8 && ireg_ic)) { len = 1; /* matched a single byte above */ diff --git a/src/nvim/regexp_nfa.c b/src/nvim/regexp_nfa.c index e2849fb17a..7e53b2ccd1 100644 --- a/src/nvim/regexp_nfa.c +++ b/src/nvim/regexp_nfa.c @@ -3464,13 +3464,12 @@ static char *pim_info(nfa_pim_T *pim) #endif -/* Used during execution: whether a match has been found. */ +// Used during execution: whether a match has been found. static int nfa_match; +static proftime_T *nfa_time_limit; +static int nfa_time_count; - -/* - * Copy postponed invisible match info from "from" to "to". - */ +// Copy postponed invisible match info from "from" to "to". static void copy_pim(nfa_pim_T *to, nfa_pim_T *from) { to->result = from->result; @@ -4566,7 +4565,7 @@ static int recursive_regmatch(nfa_state_T *state, nfa_pim_T *pim, nfa_regprog_T if (log_fd != NULL) { fprintf(log_fd, "****************************\n"); fprintf(log_fd, "FINISHED RUNNING nfa_regmatch() recursively\n"); - fprintf(log_fd, "MATCH = %s\n", result == TRUE ? "OK" : "FALSE"); + fprintf(log_fd, "MATCH = %s\n", !result ? "FALSE" : "OK"); fprintf(log_fd, "****************************\n"); } else { EMSG(_( @@ -4778,8 +4777,8 @@ static long find_match_text(colnr_T startcol, int regstart, char_u *match_text) int c2_len = PTR2LEN(s2); int c2 = PTR2CHAR(s2); - if ((c1 != c2 && (!ireg_ic || vim_tolower(c1) != vim_tolower(c2))) || - c1_len != c2_len) { + if ((c1 != c2 && (!ireg_ic || vim_tolower(c1) != vim_tolower(c2))) + || c1_len != c2_len) { match = false; break; } @@ -4813,22 +4812,21 @@ static long find_match_text(colnr_T startcol, int regstart, char_u *match_text) #undef PTR2LEN } -/* - * Main matching routine. - * - * Run NFA to determine whether it matches reginput. - * - * When "nfa_endp" is not NULL it is a required end-of-match position. - * - * Return TRUE if there is a match, FALSE otherwise. - * When there is a match "submatch" contains the positions. - * Note: Caller must ensure that: start != NULL. - */ -static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start, regsubs_T *submatch, regsubs_T *m) +/// Main matching routine. +/// +/// Run NFA to determine whether it matches reginput. +/// +/// When "nfa_endp" is not NULL it is a required end-of-match position. +/// +/// Return TRUE if there is a match, FALSE otherwise. +/// When there is a match "submatch" contains the positions. +/// Note: Caller must ensure that: start != NULL. +static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start, + regsubs_T *submatch, regsubs_T *m) { int result; int flag = 0; - int go_to_nextline = FALSE; + bool go_to_nextline = false; nfa_thread_T *t; nfa_list_T list[2]; int listidx; @@ -4845,18 +4843,22 @@ static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start, regsubs_T *subm if (debug == NULL) { EMSG2(_("(NFA) COULD NOT OPEN %s !"), NFA_REGEXP_DEBUG_LOG); - return FALSE; + return false; } #endif - /* Some patterns may take a long time to match, especially when using - * recursive_regmatch(). Allow interrupting them with CTRL-C. */ + // Some patterns may take a long time to match, especially when using + // recursive_regmatch(). Allow interrupting them with CTRL-C. fast_breakcheck(); - if (got_int) - return FALSE; + if (got_int) { + return false; + } + if (nfa_time_limit != NULL && profile_passed_limit(*nfa_time_limit)) { + return false; + } - nfa_match = FALSE; + nfa_match = false; - /* Allocate memory for the lists of nodes. */ + // Allocate memory for the lists of nodes. size_t size = (nstate + 1) * sizeof(nfa_thread_T); list[0].t = xmalloc(size); list[0].len = nstate + 1; @@ -4924,7 +4926,7 @@ static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start, regsubs_T *subm } if (curc == NUL) { clen = 0; - go_to_nextline = FALSE; + go_to_nextline = false; } /* swap lists */ @@ -5007,7 +5009,7 @@ static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start, regsubs_T *subm if (enc_utf8 && !ireg_icombine && utf_iscomposing(curc)) { break; } - nfa_match = TRUE; + nfa_match = true; copy_sub(&submatch->norm, &t->subs.norm); if (nfa_has_zsubexpr) copy_sub(&submatch->synt, &t->subs.synt); @@ -5072,10 +5074,11 @@ static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start, regsubs_T *subm fprintf(log_fd, "Match found:\n"); log_subsexpr(m); #endif - nfa_match = TRUE; - /* See comment above at "goto nextchar". */ - if (nextlist->n == 0) + nfa_match = true; + // See comment above at "goto nextchar". + if (nextlist->n == 0) { clen = 0; + } goto nextchar; case NFA_START_INVISIBLE: @@ -5092,8 +5095,8 @@ static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start, regsubs_T *subm failure_chance(t->state->out, 0), failure_chance(t->state->out1->out, 0)); #endif - /* Do it directly if there already is a PIM or when - * nfa_postprocess() detected it will work better. */ + // Do it directly if there already is a PIM or when + // nfa_postprocess() detected it will work better. if (t->pim.result != NFA_PIM_UNUSED || t->state->c == NFA_START_INVISIBLE_FIRST || t->state->c == NFA_START_INVISIBLE_NEG_FIRST @@ -5101,42 +5104,40 @@ static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start, regsubs_T *subm || t->state->c == NFA_START_INVISIBLE_BEFORE_NEG_FIRST) { int in_use = m->norm.in_use; - /* Copy submatch info for the recursive call, opposite - * of what happens on success below. */ + // Copy submatch info for the recursive call, opposite + // of what happens on success below. copy_sub_off(&m->norm, &t->subs.norm); if (nfa_has_zsubexpr) copy_sub_off(&m->synt, &t->subs.synt); - /* - * First try matching the invisible match, then what - * follows. - */ - result = recursive_regmatch(t->state, NULL, prog, - submatch, m, &listids); + // First try matching the invisible match, then what + // follows. + result = recursive_regmatch(t->state, NULL, prog, submatch, m, + &listids); if (result == NFA_TOO_EXPENSIVE) { nfa_match = result; goto theend; } - /* for \@! and \@<! it is a match when the result is - * FALSE */ + // for \@! and \@<! it is a match when the result is + // FALSE if (result != (t->state->c == NFA_START_INVISIBLE_NEG || t->state->c == NFA_START_INVISIBLE_NEG_FIRST || t->state->c == NFA_START_INVISIBLE_BEFORE_NEG || t->state->c == NFA_START_INVISIBLE_BEFORE_NEG_FIRST)) { - /* Copy submatch info from the recursive call */ + // Copy submatch info from the recursive call copy_sub_off(&t->subs.norm, &m->norm); if (nfa_has_zsubexpr) copy_sub_off(&t->subs.synt, &m->synt); - /* If the pattern has \ze and it matched in the - * sub pattern, use it. */ + // If the pattern has \ze and it matched in the + // sub pattern, use it. copy_ze_off(&t->subs.norm, &m->norm); - /* t->state->out1 is the corresponding - * END_INVISIBLE node; Add its out to the current - * list (zero-width match). */ + // t->state->out1 is the corresponding + // END_INVISIBLE node; Add its out to the current + // list (zero-width match). add_here = true; add_state = t->state->out1->out; } @@ -5144,12 +5145,10 @@ static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start, regsubs_T *subm } else { nfa_pim_T pim; - /* - * First try matching what follows. Only if a match - * is found verify the invisible match matches. Add a - * nfa_pim_T to the following states, it contains info - * about the invisible match. - */ + // First try matching what follows. Only if a match + // is found verify the invisible match matches. Add a + // nfa_pim_T to the following states, it contains info + // about the invisible match. pim.state = t->state; pim.result = NFA_PIM_TODO; pim.subs.norm.in_use = 0; @@ -5160,9 +5159,9 @@ static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start, regsubs_T *subm } else pim.end.ptr = reginput; - /* t->state->out1 is the corresponding END_INVISIBLE - * node; Add its out to the current list (zero-width - * match). */ + // t->state->out1 is the corresponding END_INVISIBLE + // node; Add its out to the current list (zero-width + // match). addstate_here(thislist, t->state->out1->out, &t->subs, &pim, &listidx); } @@ -5176,8 +5175,8 @@ static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start, regsubs_T *subm int skip_lid = 0; #endif - /* There is no point in trying to match the pattern if the - * output state is not going to be added to the list. */ + // There is no point in trying to match the pattern if the + // output state is not going to be added to the list. if (state_in_list(nextlist, t->state->out1->out, &t->subs)) { skip = t->state->out1->out; #ifdef REGEXP_DEBUG @@ -5206,15 +5205,16 @@ static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start, regsubs_T *subm #endif break; } - /* Copy submatch info to the recursive call, opposite of what - * happens afterwards. */ + // Copy submatch info to the recursive call, opposite of what + // happens afterwards. copy_sub_off(&m->norm, &t->subs.norm); - if (nfa_has_zsubexpr) + if (nfa_has_zsubexpr) { copy_sub_off(&m->synt, &t->subs.synt); + } - /* First try matching the pattern. */ - result = recursive_regmatch(t->state, NULL, prog, - submatch, m, &listids); + // First try matching the pattern. + result = recursive_regmatch(t->state, NULL, prog, submatch, m, + &listids); if (result == NFA_TOO_EXPENSIVE) { nfa_match = result; goto theend; @@ -5226,36 +5226,38 @@ static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start, regsubs_T *subm fprintf(log_fd, "NFA_START_PATTERN matches:\n"); log_subsexpr(m); #endif - /* Copy submatch info from the recursive call */ + // Copy submatch info from the recursive call copy_sub_off(&t->subs.norm, &m->norm); - if (nfa_has_zsubexpr) + if (nfa_has_zsubexpr) { copy_sub_off(&t->subs.synt, &m->synt); - /* Now we need to skip over the matched text and then - * continue with what follows. */ - if (REG_MULTI) - /* TODO: multi-line match */ + } + // Now we need to skip over the matched text and then + // continue with what follows. + if (REG_MULTI) { + // TODO(RE): multi-line match bytelen = m->norm.list.multi[0].end_col - (int)(reginput - regline); - else + } else { bytelen = (int)(m->norm.list.line[0].end - reginput); + } #ifdef REGEXP_DEBUG fprintf(log_fd, "NFA_START_PATTERN length: %d\n", bytelen); #endif if (bytelen == 0) { - /* empty match, output of corresponding - * NFA_END_PATTERN/NFA_SKIP to be used at current - * position */ + // empty match, output of corresponding + // NFA_END_PATTERN/NFA_SKIP to be used at current + // position add_here = true; add_state = t->state->out1->out->out; } else if (bytelen <= clen) { - /* match current character, output of corresponding - * NFA_END_PATTERN to be used at next position. */ + // match current character, output of corresponding + // NFA_END_PATTERN to be used at next position. add_state = t->state->out1->out->out; add_off = clen; } else { - /* skip over the matched characters, set character - * count in NFA_SKIP */ + // skip over the matched characters, set character + // count in NFA_SKIP add_state = t->state->out1->out; add_off = bytelen; add_count = bytelen - clen; @@ -5279,23 +5281,25 @@ static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start, regsubs_T *subm break; case NFA_BOW: - result = TRUE; + result = true; - if (curc == NUL) - result = FALSE; - else if (has_mbyte) { + if (curc == NUL) { + result = false; + } else if (has_mbyte) { int this_class; - /* Get class of current and previous char (if it exists). */ + // Get class of current and previous char (if it exists). this_class = mb_get_class_buf(reginput, reg_buf); - if (this_class <= 1) - result = FALSE; - else if (reg_prev_class() == this_class) - result = FALSE; + if (this_class <= 1) { + result = false; + } else if (reg_prev_class() == this_class) { + result = false; + } } else if (!vim_iswordc_buf(curc, reg_buf) || (reginput > regline - && vim_iswordc_buf(reginput[-1], reg_buf))) - result = FALSE; + && vim_iswordc_buf(reginput[-1], reg_buf))) { + result = false; + } if (result) { add_here = true; add_state = t->state->out; @@ -5303,22 +5307,24 @@ static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start, regsubs_T *subm break; case NFA_EOW: - result = TRUE; - if (reginput == regline) - result = FALSE; - else if (has_mbyte) { + result = true; + if (reginput == regline) { + result = false; + } else if (has_mbyte) { int this_class, prev_class; - /* Get class of current and previous char (if it exists). */ + // Get class of current and previous char (if it exists). this_class = mb_get_class_buf(reginput, reg_buf); prev_class = reg_prev_class(); if (this_class == prev_class - || prev_class == 0 || prev_class == 1) - result = FALSE; + || prev_class == 0 || prev_class == 1) { + result = false; + } } else if (!vim_iswordc_buf(reginput[-1], reg_buf) || (reginput[0] != NUL - && vim_iswordc_buf(curc, reg_buf))) - result = FALSE; + && vim_iswordc_buf(curc, reg_buf))) { + result = false; + } if (result) { add_here = true; add_state = t->state->out; @@ -5353,30 +5359,31 @@ static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start, regsubs_T *subm sta = t->state->out; len = 0; if (utf_iscomposing(sta->c)) { - /* Only match composing character(s), ignore base - * character. Used for ".{composing}" and "{composing}" - * (no preceding character). */ + // Only match composing character(s), ignore base + // character. Used for ".{composing}" and "{composing}" + // (no preceding character). len += mb_char2len(mc); } if (ireg_icombine && len == 0) { - /* If \Z was present, then ignore composing characters. - * When ignoring the base character this always matches. */ - if (sta->c != curc) + // If \Z was present, then ignore composing characters. + // When ignoring the base character this always matches. + if (sta->c != curc) { result = FAIL; - else + } else { result = OK; - while (sta->c != NFA_END_COMPOSING) + } + while (sta->c != NFA_END_COMPOSING) { sta = sta->out; - } - /* Check base character matches first, unless ignored. */ - else if (len > 0 || mc == sta->c) { + } + } else if (len > 0 || mc == sta->c) { + // Check base character matches first, unless ignored. if (len == 0) { len += mb_char2len(mc); sta = sta->out; } - /* We don't care about the order of composing characters. - * Get them into cchars[] first. */ + // We don't care about the order of composing characters. + // Get them into cchars[] first. while (len < clen) { mc = mb_ptr2char(reginput + len); cchars[ccount++] = mc; @@ -5385,9 +5392,9 @@ static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start, regsubs_T *subm break; } - /* Check that each composing char in the pattern matches a - * composing char in the text. We do not check if all - * composing chars are matched. */ + // Check that each composing char in the pattern matches a + // composing char in the text. We do not check if all + // composing chars are matched. result = OK; while (sta->c != NFA_END_COMPOSING) { for (j = 0; j < ccount; ++j) @@ -5402,7 +5409,7 @@ static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start, regsubs_T *subm } else result = FAIL; - end = t->state->out1; /* NFA_END_COMPOSING */ + end = t->state->out1; // NFA_END_COMPOSING ADD_STATE_IF_MATCH(end); break; } @@ -5410,13 +5417,13 @@ static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start, regsubs_T *subm case NFA_NEWL: if (curc == NUL && !reg_line_lbr && REG_MULTI && reglnum <= reg_maxline) { - go_to_nextline = TRUE; - /* Pass -1 for the offset, which means taking the position - * at the start of the next line. */ + go_to_nextline = true; + // Pass -1 for the offset, which means taking the position + // at the start of the next line. add_state = t->state->out; add_off = -1; } else if (curc == '\n' && reg_line_lbr) { - /* match \n as if it is an ordinary character */ + // match \n as if it is an ordinary character add_state = t->state->out; add_off = 1; } @@ -5425,16 +5432,17 @@ static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start, regsubs_T *subm case NFA_START_COLL: case NFA_START_NEG_COLL: { - /* What follows is a list of characters, until NFA_END_COLL. - * One of them must match or none of them must match. */ + // What follows is a list of characters, until NFA_END_COLL. + // One of them must match or none of them must match. nfa_state_T *state; int result_if_matched; int c1, c2; - /* Never match EOL. If it's part of the collection it is added - * as a separate state with an OR. */ - if (curc == NUL) + // Never match EOL. If it's part of the collection it is added + // as a separate state with an OR. + if (curc == NUL) { break; + } state = t->state->out; result_if_matched = (t->state->c == NFA_START_COLL); @@ -5445,7 +5453,7 @@ static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start, regsubs_T *subm } if (state->c == NFA_RANGE_MIN) { c1 = state->val; - state = state->out; /* advance to NFA_RANGE_MAX */ + state = state->out; // advance to NFA_RANGE_MAX c2 = state->val; #ifdef REGEXP_DEBUG fprintf(log_fd, "NFA_RANGE_MIN curc=%d c1=%d c2=%d\n", @@ -5478,8 +5486,8 @@ static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start, regsubs_T *subm state = state->out; } if (result) { - /* next state is in out of the NFA_END_COLL, out1 of - * START points to the END state */ + // next state is in out of the NFA_END_COLL, out1 of + // START points to the END state add_state = t->state->out1->out; add_off = clen; } @@ -5487,7 +5495,7 @@ static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start, regsubs_T *subm } case NFA_ANY: - /* Any char except '\0', (end of input) does not match. */ + // Any char except '\0', (end of input) does not match. if (curc > 0) { add_state = t->state->out; add_off = clen; @@ -5506,157 +5514,155 @@ static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start, regsubs_T *subm add_state = t->state->out; break; - /* - * Character classes like \a for alpha, \d for digit etc. - */ - case NFA_IDENT: /* \i */ + // Character classes like \a for alpha, \d for digit etc. + case NFA_IDENT: // \i result = vim_isIDc(curc); ADD_STATE_IF_MATCH(t->state); break; - case NFA_SIDENT: /* \I */ + case NFA_SIDENT: // \I result = !ascii_isdigit(curc) && vim_isIDc(curc); ADD_STATE_IF_MATCH(t->state); break; - case NFA_KWORD: /* \k */ + case NFA_KWORD: // \k result = vim_iswordp_buf(reginput, reg_buf); ADD_STATE_IF_MATCH(t->state); break; - case NFA_SKWORD: /* \K */ + case NFA_SKWORD: // \K result = !ascii_isdigit(curc) && vim_iswordp_buf(reginput, reg_buf); ADD_STATE_IF_MATCH(t->state); break; - case NFA_FNAME: /* \f */ + case NFA_FNAME: // \f result = vim_isfilec(curc); ADD_STATE_IF_MATCH(t->state); break; - case NFA_SFNAME: /* \F */ + case NFA_SFNAME: // \F result = !ascii_isdigit(curc) && vim_isfilec(curc); ADD_STATE_IF_MATCH(t->state); break; - case NFA_PRINT: /* \p */ + case NFA_PRINT: // \p result = vim_isprintc(PTR2CHAR(reginput)); ADD_STATE_IF_MATCH(t->state); break; - case NFA_SPRINT: /* \P */ + case NFA_SPRINT: // \P result = !ascii_isdigit(curc) && vim_isprintc(PTR2CHAR(reginput)); ADD_STATE_IF_MATCH(t->state); break; - case NFA_WHITE: /* \s */ + case NFA_WHITE: // \s result = ascii_iswhite(curc); ADD_STATE_IF_MATCH(t->state); break; - case NFA_NWHITE: /* \S */ + case NFA_NWHITE: // \S result = curc != NUL && !ascii_iswhite(curc); ADD_STATE_IF_MATCH(t->state); break; - case NFA_DIGIT: /* \d */ + case NFA_DIGIT: // \d result = ri_digit(curc); ADD_STATE_IF_MATCH(t->state); break; - case NFA_NDIGIT: /* \D */ + case NFA_NDIGIT: // \D result = curc != NUL && !ri_digit(curc); ADD_STATE_IF_MATCH(t->state); break; - case NFA_HEX: /* \x */ + case NFA_HEX: // \x result = ri_hex(curc); ADD_STATE_IF_MATCH(t->state); break; - case NFA_NHEX: /* \X */ + case NFA_NHEX: // \X result = curc != NUL && !ri_hex(curc); ADD_STATE_IF_MATCH(t->state); break; - case NFA_OCTAL: /* \o */ + case NFA_OCTAL: // \o result = ri_octal(curc); ADD_STATE_IF_MATCH(t->state); break; - case NFA_NOCTAL: /* \O */ + case NFA_NOCTAL: // \O result = curc != NUL && !ri_octal(curc); ADD_STATE_IF_MATCH(t->state); break; - case NFA_WORD: /* \w */ + case NFA_WORD: // \w result = ri_word(curc); ADD_STATE_IF_MATCH(t->state); break; - case NFA_NWORD: /* \W */ + case NFA_NWORD: // \W result = curc != NUL && !ri_word(curc); ADD_STATE_IF_MATCH(t->state); break; - case NFA_HEAD: /* \h */ + case NFA_HEAD: // \h result = ri_head(curc); ADD_STATE_IF_MATCH(t->state); break; - case NFA_NHEAD: /* \H */ + case NFA_NHEAD: // \H result = curc != NUL && !ri_head(curc); ADD_STATE_IF_MATCH(t->state); break; - case NFA_ALPHA: /* \a */ + case NFA_ALPHA: // \a result = ri_alpha(curc); ADD_STATE_IF_MATCH(t->state); break; - case NFA_NALPHA: /* \A */ + case NFA_NALPHA: // \A result = curc != NUL && !ri_alpha(curc); ADD_STATE_IF_MATCH(t->state); break; - case NFA_LOWER: /* \l */ + case NFA_LOWER: // \l result = ri_lower(curc); ADD_STATE_IF_MATCH(t->state); break; - case NFA_NLOWER: /* \L */ + case NFA_NLOWER: // \L result = curc != NUL && !ri_lower(curc); ADD_STATE_IF_MATCH(t->state); break; - case NFA_UPPER: /* \u */ + case NFA_UPPER: // \u result = ri_upper(curc); ADD_STATE_IF_MATCH(t->state); break; - case NFA_NUPPER: /* \U */ + case NFA_NUPPER: // \U result = curc != NUL && !ri_upper(curc); ADD_STATE_IF_MATCH(t->state); break; - case NFA_LOWER_IC: /* [a-z] */ + case NFA_LOWER_IC: // [a-z] result = ri_lower(curc) || (ireg_ic && ri_upper(curc)); ADD_STATE_IF_MATCH(t->state); break; - case NFA_NLOWER_IC: /* [^a-z] */ + case NFA_NLOWER_IC: // [^a-z] result = curc != NUL && !(ri_lower(curc) || (ireg_ic && ri_upper(curc))); ADD_STATE_IF_MATCH(t->state); break; - case NFA_UPPER_IC: /* [A-Z] */ + case NFA_UPPER_IC: // [A-Z] result = ri_upper(curc) || (ireg_ic && ri_lower(curc)); ADD_STATE_IF_MATCH(t->state); break; - case NFA_NUPPER_IC: /* ^[A-Z] */ + case NFA_NUPPER_IC: // [^A-Z] result = curc != NUL && !(ri_upper(curc) || (ireg_ic && ri_lower(curc))); ADD_STATE_IF_MATCH(t->state); @@ -5680,7 +5686,7 @@ static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start, regsubs_T *subm case NFA_ZREF7: case NFA_ZREF8: case NFA_ZREF9: - /* \1 .. \9 \z1 .. \z9 */ + // \1 .. \9 \z1 .. \z9 { int subidx; int bytelen; @@ -5695,18 +5701,18 @@ static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start, regsubs_T *subm if (result) { if (bytelen == 0) { - /* empty match always works, output of NFA_SKIP to be - * used next */ + // empty match always works, output of NFA_SKIP to be + // used next add_here = true; add_state = t->state->out->out; } else if (bytelen <= clen) { - /* match current character, jump ahead to out of - * NFA_SKIP */ + // match current character, jump ahead to out of + // NFA_SKIP add_state = t->state->out->out; add_off = clen; } else { - /* skip over the matched characters, set character - * count in NFA_SKIP */ + // skip over the matched characters, set character + // count in NFA_SKIP add_state = t->state->out; add_off = bytelen; add_count = bytelen - clen; @@ -5715,13 +5721,13 @@ static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start, regsubs_T *subm break; } case NFA_SKIP: - /* character of previous matching \1 .. \9 or \@> */ + // character of previous matching \1 .. \9 or \@> if (t->count - clen <= 0) { - /* end of match, go to what follows */ + // end of match, go to what follows add_state = t->state->out; add_off = clen; } else { - /* add state again with decremented count */ + // add state again with decremented count add_state = t->state; add_off = 0; add_count = t->count - clen; @@ -5773,7 +5779,7 @@ static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start, regsubs_T *subm break; } - result = FALSE; + result = false; win_T *wp = reg_win == NULL ? curwin : reg_win; if (op == 1 && col - 1 > t->state->val && col > 100) { long ts = wp->w_buffer->b_p_ts; @@ -5803,9 +5809,9 @@ static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start, regsubs_T *subm { pos_T *pos = getmark_buf(reg_buf, t->state->val, FALSE); - /* Compare the mark position to the match position. */ - result = (pos != NULL /* mark doesn't exist */ - && pos->lnum > 0 /* mark isn't set in reg_buf */ + // Compare the mark position to the match position. + result = (pos != NULL // mark doesn't exist + && pos->lnum > 0 // mark isn't set in reg_buf && (pos->lnum == reglnum + reg_firstlnum ? (pos->col == (colnr_T)(reginput - regline) ? t->state->c == NFA_MARK @@ -5862,11 +5868,11 @@ static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start, regsubs_T *subm case NFA_ZOPEN9: case NFA_NOPEN: case NFA_ZSTART: - /* These states are only added to be able to bail out when - * they are added again, nothing is to be done. */ + // These states are only added to be able to bail out when + // they are added again, nothing is to be done. break; - default: /* regular character */ + default: // regular character { int c = t->state->c; @@ -5888,8 +5894,7 @@ static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start, regsubs_T *subm ADD_STATE_IF_MATCH(t->state); break; } - - } /* switch (t->state->c) */ + } // switch (t->state->c) if (add_state != NULL) { nfa_pim_T *pim; @@ -5900,8 +5905,8 @@ static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start, regsubs_T *subm else pim = &t->pim; - /* Handle the postponed invisible match if the match might end - * without advancing and before the end of the line. */ + // Handle the postponed invisible match if the match might end + // without advancing and before the end of the line. if (pim != NULL && (clen == 0 || match_follows(add_state, 0))) { if (pim->result == NFA_PIM_TODO) { #ifdef REGEXP_DEBUG @@ -5913,15 +5918,15 @@ static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start, regsubs_T *subm result = recursive_regmatch(pim->state, pim, prog, submatch, m, &listids); pim->result = result ? NFA_PIM_MATCH : NFA_PIM_NOMATCH; - /* for \@! and \@<! it is a match when the result is - * FALSE */ + // for \@! and \@<! it is a match when the result is + // FALSE if (result != (pim->state->c == NFA_START_INVISIBLE_NEG || pim->state->c == NFA_START_INVISIBLE_NEG_FIRST || pim->state->c == NFA_START_INVISIBLE_BEFORE_NEG || pim->state->c == NFA_START_INVISIBLE_BEFORE_NEG_FIRST)) { - /* Copy submatch info from the recursive call */ + // Copy submatch info from the recursive call copy_sub_off(&pim->subs.norm, &m->norm); if (nfa_has_zsubexpr) copy_sub_off(&pim->subs.synt, &m->synt); @@ -5934,34 +5939,35 @@ static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start, regsubs_T *subm log_fd, "Using previous recursive nfa_regmatch() result, result == %d\n", pim->result); - fprintf(log_fd, "MATCH = %s\n", result == TRUE ? "OK" : "FALSE"); + fprintf(log_fd, "MATCH = %s\n", result ? "OK" : "FALSE"); fprintf(log_fd, "\n"); #endif } - /* for \@! and \@<! it is a match when result is FALSE */ + // for \@! and \@<! it is a match when result is FALSE if (result != (pim->state->c == NFA_START_INVISIBLE_NEG || pim->state->c == NFA_START_INVISIBLE_NEG_FIRST || pim->state->c == NFA_START_INVISIBLE_BEFORE_NEG || pim->state->c == NFA_START_INVISIBLE_BEFORE_NEG_FIRST)) { - /* Copy submatch info from the recursive call */ + // Copy submatch info from the recursive call copy_sub_off(&t->subs.norm, &pim->subs.norm); if (nfa_has_zsubexpr) copy_sub_off(&t->subs.synt, &pim->subs.synt); - } else - /* look-behind match failed, don't add the state */ + } else { + // look-behind match failed, don't add the state continue; + } - /* Postponed invisible match was handled, don't add it to - * following states. */ + // Postponed invisible match was handled, don't add it to + // following states. pim = NULL; } - /* If "pim" points into l->t it will become invalid when - * adding the state causes the list to be reallocated. Make a - * local copy to avoid that. */ + // If "pim" points into l->t it will become invalid when + // adding the state causes the list to be reallocated. Make a + // local copy to avoid that. if (pim == &t->pim) { copy_pim(&pim_copy, pim); pim = &pim_copy; @@ -5975,18 +5981,17 @@ static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start, regsubs_T *subm nextlist->t[nextlist->n - 1].count = add_count; } } - - } /* for (thislist = thislist; thislist->state; thislist++) */ - - /* Look for the start of a match in the current position by adding the - * start state to the list of states. - * The first found match is the leftmost one, thus the order of states - * matters! - * Do not add the start state in recursive calls of nfa_regmatch(), - * because recursive calls should only start in the first position. - * Unless "nfa_endp" is not NULL, then we match the end position. - * Also don't start a match past the first line. */ - if (nfa_match == FALSE + } // for (thislist = thislist; thislist->state; thislist++) + + // Look for the start of a match in the current position by adding the + // start state to the list of states. + // The first found match is the leftmost one, thus the order of states + // matters! + // Do not add the start state in recursive calls of nfa_regmatch(), + // because recursive calls should only start in the first position. + // Unless "nfa_endp" is not NULL, then we match the end position. + // Also don't start a match past the first line. + if (!nfa_match && ((toplevel && reglnum == 0 && clen != 0 @@ -6002,8 +6007,8 @@ static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start, regsubs_T *subm #ifdef REGEXP_DEBUG fprintf(log_fd, "(---) STARTSTATE\n"); #endif - /* Inline optimized code for addstate() if we know the state is - * the first MOPEN. */ + // Inline optimized code for addstate() if we know the state is + // the first MOPEN. if (toplevel) { int add = TRUE; int c; @@ -6012,18 +6017,19 @@ static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start, regsubs_T *subm if (nextlist->n == 0) { colnr_T col = (colnr_T)(reginput - regline) + clen; - /* Nextlist is empty, we can skip ahead to the - * character that must appear at the start. */ - if (skip_to_start(prog->regstart, &col) == FAIL) + // Nextlist is empty, we can skip ahead to the + // character that must appear at the start. + if (skip_to_start(prog->regstart, &col) == FAIL) { break; + } #ifdef REGEXP_DEBUG fprintf(log_fd, " Skipping ahead %d bytes to regstart\n", col - ((colnr_T)(reginput - regline) + clen)); #endif reginput = regline + col - clen; } else { - /* Checking if the required start character matches is - * cheaper than adding a state that won't match. */ + // Checking if the required start character matches is + // cheaper than adding a state that won't match. c = PTR2CHAR(reginput + clen); if (c != prog->regstart && (!ireg_ic || vim_tolower(c) != vim_tolower(prog->regstart))) { @@ -6060,21 +6066,29 @@ static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start, regsubs_T *subm #endif nextchar: - /* Advance to the next character, or advance to the next line, or - * finish. */ - if (clen != 0) + // Advance to the next character, or advance to the next line, or + // finish. + if (clen != 0) { reginput += clen; - else if (go_to_nextline || (nfa_endp != NULL && REG_MULTI - && reglnum < nfa_endp->se_u.pos.lnum)) + } else if (go_to_nextline || (nfa_endp != NULL && REG_MULTI + && reglnum < nfa_endp->se_u.pos.lnum)) { reg_nextline(); - else + } else { break; + } // Allow interrupting with CTRL-C. - fast_breakcheck(); + line_breakcheck(); if (got_int) { break; } + // Check for timeout once every twenty times to avoid overhead. + if (nfa_time_limit != NULL && ++nfa_time_count == 20) { + nfa_time_count = 0; + if (profile_passed_limit(*nfa_time_limit)) { + break; + } + } } #ifdef REGEXP_DEBUG @@ -6084,7 +6098,7 @@ nextchar: #endif theend: - /* Free memory */ + // Free memory xfree(list[0].t); xfree(list[1].t); xfree(listids); @@ -6096,11 +6110,9 @@ theend: return nfa_match; } -/* - * Try match of "prog" with at regline["col"]. - * Returns <= 0 for failure, number of lines contained in the match otherwise. - */ -static long nfa_regtry(nfa_regprog_T *prog, colnr_T col) +// Try match of "prog" with at regline["col"]. +// Returns <= 0 for failure, number of lines contained in the match otherwise. +static long nfa_regtry(nfa_regprog_T *prog, colnr_T col, proftime_T *tm) { int i; regsubs_T subs, m; @@ -6110,6 +6122,8 @@ static long nfa_regtry(nfa_regprog_T *prog, colnr_T col) #endif reginput = regline + col; + nfa_time_limit = tm; + nfa_time_count = 0; #ifdef REGEXP_DEBUG f = fopen(NFA_REGEXP_RUN_LOG, "a"); @@ -6134,7 +6148,7 @@ static long nfa_regtry(nfa_regprog_T *prog, colnr_T col) clear_sub(&m.synt); int result = nfa_regmatch(prog, start, &subs, &m); - if (result == FALSE) { + if (!result) { return 0; } else if (result == NFA_TOO_EXPENSIVE) { return result; @@ -6207,17 +6221,16 @@ static long nfa_regtry(nfa_regprog_T *prog, colnr_T col) return 1 + reglnum; } -/* - * Match a regexp against a string ("line" points to the string) or multiple - * lines ("line" is NULL, use reg_getline()). - * - * Returns <= 0 for failure, number of lines contained in the match otherwise. - */ -static long -nfa_regexec_both ( - char_u *line, - colnr_T startcol /* column to start looking for match */ -) +/// Match a regexp against a string ("line" points to the string) or multiple +/// lines ("line" is NULL, use reg_getline()). +/// +/// @param line String in which to search or NULL +/// @param startcol Column to start looking for match +/// @param tm Timeout limit or NULL +/// +/// @return <= 0 if there is no match and number of lines contained in the +/// match otherwise. +static long nfa_regexec_both(char_u *line, colnr_T startcol, proftime_T *tm) { nfa_regprog_T *prog; long retval = 0L; @@ -6297,7 +6310,7 @@ nfa_regexec_both ( prog->state[i].lastlist[1] = 0; } - retval = nfa_regtry(prog, col); + retval = nfa_regtry(prog, col, tm); nfa_regengine.expr = NULL; @@ -6449,7 +6462,7 @@ nfa_regexec_nl ( ireg_ic = rmp->rm_ic; ireg_icombine = FALSE; ireg_maxcol = 0; - return nfa_regexec_both(line, col); + return nfa_regexec_both(line, col, NULL); } /// Matches a regexp against multiple lines. @@ -6500,5 +6513,5 @@ static long nfa_regexec_multi(regmmatch_T *rmp, win_T *win, buf_T *buf, ireg_icombine = FALSE; ireg_maxcol = rmp->rmm_maxcol; - return nfa_regexec_both(NULL, col); + return nfa_regexec_both(NULL, col, tm); } diff --git a/src/nvim/screen.c b/src/nvim/screen.c index d650d56bc0..10b5b6bba4 100644 --- a/src/nvim/screen.c +++ b/src/nvim/screen.c @@ -387,14 +387,15 @@ void update_screen(int type) if (wp->w_buffer->b_mod_set) { win_T *wwp; - /* Check if we already did this buffer. */ - for (wwp = firstwin; wwp != wp; wwp = wwp->w_next) - if (wwp->w_buffer == wp->w_buffer) + // Check if we already did this buffer. + for (wwp = firstwin; wwp != wp; wwp = wwp->w_next) { + if (wwp->w_buffer == wp->w_buffer) { break; - if ( - wwp == wp && - syntax_present(wp)) + } + } + if (wwp == wp && syntax_present(wp)) { syn_stack_apply_changes(wp->w_buffer); + } } } @@ -1231,16 +1232,16 @@ static void win_update(win_T *wp) || did_update == DID_FOLD || (did_update == DID_LINE && syntax_present(wp) - && ( - (foldmethodIsSyntax(wp) - && hasAnyFolding(wp)) || - syntax_check_changed(lnum))) + && ((foldmethodIsSyntax(wp) + && hasAnyFolding(wp)) + || syntax_check_changed(lnum))) // match in fixed position might need redraw // if lines were inserted or deleted - || (wp->w_match_head != NULL && buf->b_mod_xlines != 0) - ))))) { - if (lnum == mod_top) - top_to_mod = FALSE; + || (wp->w_match_head != NULL + && buf->b_mod_xlines != 0)))))) { + if (lnum == mod_top) { + top_to_mod = false; + } /* * When at start of changed lines: May scroll following lines @@ -2472,21 +2473,16 @@ win_line ( mb_ptr_adv(ptr); } - /* When: - * - 'cuc' is set, or - * - 'colorcolumn' is set, or - * - 'virtualedit' is set, or - * - the visual mode is active, - * the end of the line may be before the start of the displayed part. - */ - if (vcol < v && ( - wp->w_p_cuc - || draw_color_col - || - virtual_active() - || - (VIsual_active && wp->w_buffer == curwin->w_buffer) - )) { + // When: + // - 'cuc' is set, or + // - 'colorcolumn' is set, or + // - 'virtualedit' is set, or + // - the visual mode is active, + // the end of the line may be before the start of the displayed part. + if (vcol < v && (wp->w_p_cuc + || draw_color_col + || virtual_active() + || (VIsual_active && wp->w_buffer == curwin->w_buffer))) { vcol = v; } @@ -3273,12 +3269,12 @@ win_line ( * contains the @Spell cluster. */ if (has_spell && v >= word_end && v > cur_checked_col) { spell_attr = 0; - if (!attr_pri) + if (!attr_pri) { char_attr = syntax_attr; - if (c != 0 && ( - !has_syntax || - can_spell)) { - char_u *prev_ptr, *p; + } + if (c != 0 && (!has_syntax || can_spell)) { + char_u *prev_ptr; + char_u *p; int len; hlf_T spell_hlf = HLF_COUNT; if (has_mbyte) { @@ -3607,25 +3603,22 @@ win_line ( wp->w_p_rl ? (col >= 0) : (col < wp->w_width))) { c = ' '; - --ptr; /* put it back at the NUL */ - } else if (( - diff_hlf != (hlf_T)0 || - line_attr != 0 - ) && ( - wp->w_p_rl ? (col >= 0) : - (col - - boguscols - < wp->w_width))) { - /* Highlight until the right side of the window */ + ptr--; // put it back at the NUL + } else if ((diff_hlf != (hlf_T)0 || line_attr != 0) + && (wp->w_p_rl + ? (col >= 0) + : (col - boguscols < wp->w_width))) { + // Highlight until the right side of the window c = ' '; - --ptr; /* put it back at the NUL */ + ptr--; // put it back at the NUL - /* Remember we do the char for line highlighting. */ - ++did_line_attr; + // Remember we do the char for line highlighting. + did_line_attr++; - /* don't do search HL for the rest of the line */ - if (line_attr != 0 && char_attr == search_attr && col > 0) + // don't do search HL for the rest of the line + if (line_attr != 0 && char_attr == search_attr && col > 0) { char_attr = line_attr; + } if (diff_hlf == HLF_TXD) { diff_hlf = HLF_CHD; if (attr == 0 || char_attr != attr) { @@ -3639,8 +3632,8 @@ win_line ( } if (wp->w_p_cole > 0 - && (wp != curwin || lnum != wp->w_cursor.lnum || - conceal_cursor_line(wp)) + && (wp != curwin || lnum != wp->w_cursor.lnum + || conceal_cursor_line(wp)) && ((syntax_flags & HL_CONCEAL) != 0 || has_match_conc) && !(lnum_in_visual_area && vim_strchr(wp->w_p_cocu, 'v') == NULL)) { diff --git a/src/nvim/search.c b/src/nvim/search.c index fffae1ecb2..6e2b69fff7 100644 --- a/src/nvim/search.c +++ b/src/nvim/search.c @@ -453,25 +453,24 @@ void last_pat_prog(regmmatch_T *regmatch) --emsg_off; } -/* - * lowest level search function. - * Search for 'count'th occurrence of pattern 'pat' in direction 'dir'. - * Start at position 'pos' and return the found position in 'pos'. - * - * if (options & SEARCH_MSG) == 0 don't give any messages - * if (options & SEARCH_MSG) == SEARCH_NFMSG don't give 'notfound' messages - * if (options & SEARCH_MSG) == SEARCH_MSG give all messages - * if (options & SEARCH_HIS) put search pattern in history - * if (options & SEARCH_END) return position at end of match - * if (options & SEARCH_START) accept match at pos itself - * if (options & SEARCH_KEEP) keep previous search pattern - * if (options & SEARCH_FOLD) match only once in a closed fold - * if (options & SEARCH_PEEK) check for typed char, cancel search - * - * Return FAIL (zero) for failure, non-zero for success. - * Returns the index of the first matching - * subpattern plus one; one if there was none. - */ +/// lowest level search function. +/// Search for 'count'th occurrence of pattern 'pat' in direction 'dir'. +/// Start at position 'pos' and return the found position in 'pos'. +/// +/// if (options & SEARCH_MSG) == 0 don't give any messages +/// if (options & SEARCH_MSG) == SEARCH_NFMSG don't give 'notfound' messages +/// if (options & SEARCH_MSG) == SEARCH_MSG give all messages +/// if (options & SEARCH_HIS) put search pattern in history +/// if (options & SEARCH_END) return position at end of match +/// if (options & SEARCH_START) accept match at pos itself +/// if (options & SEARCH_KEEP) keep previous search pattern +/// if (options & SEARCH_FOLD) match only once in a closed fold +/// if (options & SEARCH_PEEK) check for typed char, cancel search +/// if (options & SEARCH_COL) start at pos->col instead of zero +/// +/// @returns FAIL (zero) for failure, non-zero for success. +/// the index of the first matching +/// subpattern plus one; one if there was none. int searchit( win_T *win, /* window to search in, can be NULL for a buffer without a window! */ @@ -571,16 +570,14 @@ int searchit( if (tm != NULL && profile_passed_limit(*tm)) break; - /* - * Look for a match somewhere in line "lnum". - */ + // Look for a match somewhere in line "lnum". + colnr_T col = at_first_line && (options & SEARCH_COL) ? pos->col : 0; nmatched = vim_regexec_multi(®match, win, buf, - lnum, (colnr_T)0, - tm - ); - /* Abort searching on an error (e.g., out of stack). */ - if (called_emsg) + lnum, col, tm); + // Abort searching on an error (e.g., out of stack). + if (called_emsg) { break; + } if (nmatched > 0) { /* match may actually be in another line when using \zs */ matchpos = regmatch.startpos[0]; @@ -641,9 +638,9 @@ int searchit( break; } - if (ptr[matchcol] == NUL || - (nmatched = vim_regexec_multi(®match, win, buf, lnum, - matchcol, tm)) == 0) { + if (ptr[matchcol] == NUL + || (nmatched = vim_regexec_multi(®match, win, buf, lnum, + matchcol, tm)) == 0) { match_ok = false; break; } @@ -881,9 +878,8 @@ static void set_vv_searchforward(void) set_vim_var_nr(VV_SEARCHFORWARD, (long)(spats[0].off.dir == '/')); } -/* - * Return the number of the first subpat that matched. - */ +// Return the number of the first subpat that matched. +// Return zero if none of them matched. static int first_submatch(regmmatch_T *rp) { int submatch; @@ -1031,19 +1027,18 @@ int do_search( spats[0].off.line = FALSE; spats[0].off.end = FALSE; spats[0].off.off = 0; - /* - * Check for a line offset or a character offset. - * For get_address (echo off) we don't check for a character - * offset, because it is meaningless and the 's' could be a - * substitute command. - */ - if (*p == '+' || *p == '-' || ascii_isdigit(*p)) - spats[0].off.line = TRUE; - else if ((options & SEARCH_OPT) && - (*p == 'e' || *p == 's' || *p == 'b')) { - if (*p == 'e') /* end */ + // Check for a line offset or a character offset. + // For get_address (echo off) we don't check for a character + // offset, because it is meaningless and the 's' could be a + // substitute command. + if (*p == '+' || *p == '-' || ascii_isdigit(*p)) { + spats[0].off.line = true; + } else if ((options & SEARCH_OPT) + && (*p == 'e' || *p == 's' || *p == 'b')) { + if (*p == 'e') { // end spats[0].off.end = true; - ++p; + } + p++; } if (ascii_isdigit(*p) || *p == '+' || *p == '-') { /* got an offset */ /* 'nr' or '+nr' or '-nr' */ @@ -1651,8 +1646,9 @@ pos_T *findmatchlimit(oparg_T *oap, int initc, int flags, int64_t maxtravel) /* * Look for matching #if, #else, #elif, or #endif */ - if (oap != NULL) - oap->motion_type = MLINE; /* Linewise for this case only */ + if (oap != NULL) { + oap->motion_type = kMTLineWise; // Linewise for this case only + } if (initc != '#') { ptr = skipwhite(skipwhite(linep) + 1); if (STRNCMP(ptr, "if", 2) == 0 || STRNCMP(ptr, "el", 2) == 0) @@ -1787,14 +1783,13 @@ pos_T *findmatchlimit(oparg_T *oap, int initc, int flags, int64_t maxtravel) } } - /* - * If FM_BLOCKSTOP given, stop at a '{' or '}' in column 0. - */ - if (pos.col == 0 && (flags & FM_BLOCKSTOP) && - (linep[0] == '{' || linep[0] == '}')) { - if (linep[0] == findc && count == 0) /* match! */ + // If FM_BLOCKSTOP given, stop at a '{' or '}' in column 0. + if (pos.col == 0 && (flags & FM_BLOCKSTOP) + && (linep[0] == '{' || linep[0] == '}')) { + if (linep[0] == findc && count == 0) { // match! return &pos; - break; /* out of scope */ + } + break; // out of scope } if (comment_dir) { @@ -1963,15 +1958,15 @@ pos_T *findmatchlimit(oparg_T *oap, int initc, int flags, int64_t maxtravel) if (linep[pos.col - 2] == '\'') { pos.col -= 2; break; - } else if (linep[pos.col - 2] == '\\' && - pos.col > 2 && linep[pos.col - 3] == '\'') { + } else if (linep[pos.col - 2] == '\\' + && pos.col > 2 && linep[pos.col - 3] == '\'') { pos.col -= 3; break; } } - } else if (linep[pos.col + 1]) { /* forward search */ - if (linep[pos.col + 1] == '\\' && - linep[pos.col + 2] && linep[pos.col + 3] == '\'') { + } else if (linep[pos.col + 1]) { // forward search + if (linep[pos.col + 1] == '\\' + && linep[pos.col + 2] && linep[pos.col + 3] == '\'') { pos.col += 3; break; } else if (linep[pos.col + 2] == '\'') { @@ -2188,30 +2183,32 @@ int findsent(int dir, long count) * if on an empty line, skip up to a non-empty line */ if (gchar_pos(&pos) == NUL) { - do - if ((*func)(&pos) == -1) + do { + if ((*func)(&pos) == -1) { break; - while (gchar_pos(&pos) == NUL); - if (dir == FORWARD) + } + } while (gchar_pos(&pos) == NUL); + if (dir == FORWARD) { goto found; - } - /* - * if on the start of a paragraph or a section and searching forward, - * go to the next line - */ - else if (dir == FORWARD && pos.col == 0 && - startPS(pos.lnum, NUL, FALSE)) { - if (pos.lnum == curbuf->b_ml.ml_line_count) + } + // if on the start of a paragraph or a section and searching forward, + // go to the next line + } else if (dir == FORWARD && pos.col == 0 + && startPS(pos.lnum, NUL, false)) { + if (pos.lnum == curbuf->b_ml.ml_line_count) { return FAIL; - ++pos.lnum; + } + pos.lnum++; goto found; - } else if (dir == BACKWARD) + } else if (dir == BACKWARD) { decl(&pos); + } - /* go back to the previous non-blank char */ - found_dot = FALSE; - while ((c = gchar_pos(&pos)) == ' ' || c == '\t' || - (dir == BACKWARD && vim_strchr((char_u *)".!?)]\"'", c) != NULL)) { + // go back to the previous non-blank char + found_dot = false; + while ((c = gchar_pos(&pos)) == ' ' || c == '\t' + || (dir == BACKWARD + && vim_strchr((char_u *)".!?)]\"'", c) != NULL)) { if (vim_strchr((char_u *)".!?", c) != NULL) { /* Only skip over a '.', '!' and '?' once. */ if (found_dot) @@ -2375,12 +2372,14 @@ int startPS(linenr_T lnum, int para, int both) char_u *s; s = ml_get(lnum); - if (*s == para || *s == '\f' || (both && *s == '}')) - return TRUE; - if (*s == '.' && (inmacro(p_sections, s + 1) || - (!para && inmacro(p_para, s + 1)))) - return TRUE; - return FALSE; + if (*s == para || *s == '\f' || (both && *s == '}')) { + return true; + } + if (*s == '.' && (inmacro(p_sections, s + 1) + || (!para && inmacro(p_para, s + 1)))) { + return true; + } + return false; } /* @@ -2797,7 +2796,7 @@ current_word ( redraw_curbuf_later(INVERTED); /* update the inversion */ } else { oap->start = start_pos; - oap->motion_type = MCHAR; + oap->motion_type = kMTCharWise; } --count; } @@ -3032,7 +3031,7 @@ extend: else oap->inclusive = false; oap->start = start_pos; - oap->motion_type = MCHAR; + oap->motion_type = kMTCharWise; } return OK; } @@ -3156,7 +3155,7 @@ current_block ( showmode(); } else { oap->start = start_pos; - oap->motion_type = MCHAR; + oap->motion_type = kMTCharWise; oap->inclusive = false; if (sol) incl(&curwin->w_cursor); @@ -3403,7 +3402,7 @@ again: showmode(); } else { oap->start = start_pos; - oap->motion_type = MCHAR; + oap->motion_type = kMTCharWise; if (lt(end_pos, start_pos)) { /* End is before the start: there is no text between tags; operate * on an empty area. */ @@ -3568,7 +3567,7 @@ extend: } else { oap->start.lnum = start_lnum; oap->start.col = 0; - oap->motion_type = MLINE; + oap->motion_type = kMTLineWise; } curwin->w_cursor.lnum = end_lnum; curwin->w_cursor.col = 0; @@ -3810,7 +3809,7 @@ current_quote ( } } else { oap->start = curwin->w_cursor; - oap->motion_type = MCHAR; + oap->motion_type = kMTCharWise; } /* Set end position. */ @@ -4154,19 +4153,20 @@ find_pattern_in_path ( FNAME_EXP|FNAME_INCL|FNAME_REL, 1L, p_fname, NULL); already_searched = FALSE; if (new_fname != NULL) { - /* Check whether we have already searched in this file */ + // Check whether we have already searched in this file for (i = 0;; i++) { - if (i == depth + 1) + if (i == depth + 1) { i = old_files; - if (i == max_path_depth) + } + if (i == max_path_depth) { break; - if (path_full_compare(new_fname, files[i].name, TRUE) & kEqualFiles) { - if (type != CHECK_PATH && - action == ACTION_SHOW_ALL && files[i].matched) { - msg_putchar('\n'); /* cursor below last one */ - if (!got_int) { /* don't display if 'q' - typed at "--more--" - message */ + } + if (path_full_compare(new_fname, files[i].name, true) & kEqualFiles) { + if (type != CHECK_PATH + && action == ACTION_SHOW_ALL && files[i].matched) { + msg_putchar('\n'); // cursor below last one */ + if (!got_int) { // don't display if 'q' typed at "--more--" + // message msg_home_replace_hl(new_fname); MSG_PUTS(_(" (includes previously listed match)")); prev_fname = NULL; @@ -4181,15 +4181,15 @@ find_pattern_in_path ( } if (type == CHECK_PATH && (action == ACTION_SHOW_ALL - || (new_fname == NULL && - !already_searched))) { - if (did_show) - msg_putchar('\n'); /* cursor below last one */ - else { - gotocmdline(TRUE); /* cursor at status line */ + || (new_fname == NULL && !already_searched))) { + if (did_show) { + msg_putchar('\n'); // cursor below last one + } else { + gotocmdline(true); // cursor at status line MSG_PUTS_TITLE(_("--- Included files ")); - if (action != ACTION_SHOW_ALL) + if (action != ACTION_SHOW_ALL) { MSG_PUTS_TITLE(_("not found ")); + } MSG_PUTS_TITLE(_("in path ---\n")); } did_show = TRUE; @@ -4348,16 +4348,15 @@ search_line: && vim_regexec(®match, line, (colnr_T)(p - line))) { matched = TRUE; startp = regmatch.startp[0]; - /* - * Check if the line is not a comment line (unless we are - * looking for a define). A line starting with "# define" - * is not considered to be a comment line. - */ + // Check if the line is not a comment line (unless we are + // looking for a define). A line starting with "# define" + // is not considered to be a comment line. if (skip_comments) { - if ((*line != '#' || - STRNCMP(skipwhite(line + 1), "define", 6) != 0) - && get_leader_len(line, NULL, FALSE, TRUE)) - matched = FALSE; + if ((*line != '#' + || STRNCMP(skipwhite(line + 1), "define", 6) != 0) + && get_leader_len(line, NULL, false, true)) { + matched = false; + } /* * Also check for a "/ *" or "/ /" before the match. diff --git a/src/nvim/search.h b/src/nvim/search.h index 6947f79d49..d4e40cb287 100644 --- a/src/nvim/search.h +++ b/src/nvim/search.h @@ -15,19 +15,20 @@ #define ACTION_SHOW_ALL 4 #define ACTION_EXPAND 5 -/* Values for 'options' argument in do_search() and searchit() */ -#define SEARCH_REV 0x01 /* go in reverse of previous dir. */ -#define SEARCH_ECHO 0x02 /* echo the search command and handle options */ -#define SEARCH_MSG 0x0c /* give messages (yes, it's not 0x04) */ -#define SEARCH_NFMSG 0x08 /* give all messages except not found */ -#define SEARCH_OPT 0x10 /* interpret optional flags */ -#define SEARCH_HIS 0x20 /* put search pattern in history */ -#define SEARCH_END 0x40 /* put cursor at end of match */ -#define SEARCH_NOOF 0x80 /* don't add offset to position */ -#define SEARCH_START 0x100 /* start search without col offset */ -#define SEARCH_MARK 0x200 /* set previous context mark */ -#define SEARCH_KEEP 0x400 /* keep previous search pattern */ -#define SEARCH_PEEK 0x800 /* peek for typed char, cancel search */ +// Values for 'options' argument in do_search() and searchit() +#define SEARCH_REV 0x01 ///< go in reverse of previous dir. +#define SEARCH_ECHO 0x02 ///< echo the search command and handle options +#define SEARCH_MSG 0x0c ///< give messages (yes, it's not 0x04) +#define SEARCH_NFMSG 0x08 ///< give all messages except not found +#define SEARCH_OPT 0x10 ///< interpret optional flags +#define SEARCH_HIS 0x20 ///< put search pattern in history +#define SEARCH_END 0x40 ///< put cursor at end of match +#define SEARCH_NOOF 0x80 ///< don't add offset to position +#define SEARCH_START 0x100 ///< start search without col offset +#define SEARCH_MARK 0x200 ///< set previous context mark +#define SEARCH_KEEP 0x400 ///< keep previous search pattern +#define SEARCH_PEEK 0x800 ///< peek for typed char, cancel search +#define SEARCH_COL 0x1000 ///< start at specified column instead of zero /* Values for flags argument for findmatchlimit() */ #define FM_BACKWARD 0x01 /* search backwards */ diff --git a/src/nvim/shada.c b/src/nvim/shada.c index 32a02b0fb7..3192be1b3c 100644 --- a/src/nvim/shada.c +++ b/src/nvim/shada.c @@ -283,7 +283,7 @@ typedef struct { } history_item; struct reg { char name; - uint8_t type; + MotionType type; char **contents; size_t contents_size; size_t width; @@ -475,7 +475,7 @@ static const ShadaEntry sd_default_values[] = { .additional_elements = NULL), DEF_SDE(Register, reg, .name = NUL, - .type = MCHAR, + .type = kMTCharWise, .contents = NULL, .contents_size = 0, .width = 0, @@ -1407,9 +1407,9 @@ static void shada_read(ShaDaReadDef *const sd_reader, const int flags) break; } case kSDItemRegister: { - if (cur_entry.data.reg.type != MCHAR - && cur_entry.data.reg.type != MLINE - && cur_entry.data.reg.type != MBLOCK) { + if (cur_entry.data.reg.type != kMTCharWise + && cur_entry.data.reg.type != kMTLineWise + && cur_entry.data.reg.type != kMTBlockWise) { shada_free_shada_entry(&cur_entry); break; } @@ -1882,7 +1882,7 @@ static ShaDaWriteResult shada_pack_entry(msgpack_packer *const packer, msgpack_pack_char(spacker, entry.data.reg.name); if (!CHECK_DEFAULT(entry, reg.type)) { PACK_STATIC_STR(REG_KEY_TYPE); - msgpack_pack_uint8(spacker, entry.data.reg.type); + msgpack_pack_uint8(spacker, (uint8_t)entry.data.reg.type); } if (!CHECK_DEFAULT(entry, reg.width)) { PACK_STATIC_STR(REG_KEY_WIDTH); @@ -2757,8 +2757,8 @@ static ShaDaWriteResult shada_write(ShaDaWriteDef *const sd_writer, .reg = { .contents = (char **) reg.y_array, .contents_size = (size_t) reg.y_size, - .type = (uint8_t) reg.y_type, - .width = (size_t) (reg.y_type == MBLOCK ? reg.y_width : 0), + .type = reg.y_type, + .width = (size_t) (reg.y_type == kMTBlockWise ? reg.y_width : 0), .additional_data = reg.additional_data, .name = name, } diff --git a/src/nvim/spell.c b/src/nvim/spell.c index fdae89b84c..0acaa9ae2b 100644 --- a/src/nvim/spell.c +++ b/src/nvim/spell.c @@ -319,7 +319,6 @@ #include "nvim/strings.h" #include "nvim/syntax.h" #include "nvim/ui.h" -#include "nvim/tempfile.h" #include "nvim/undo.h" #include "nvim/os/os.h" #include "nvim/os/input.h" diff --git a/src/nvim/syntax.c b/src/nvim/syntax.c index 26f0a6c94b..41af7af55c 100644 --- a/src/nvim/syntax.c +++ b/src/nvim/syntax.c @@ -4478,12 +4478,10 @@ syn_cmd_region ( if (illegal || not_enough) rest = NULL; - /* - * Must have a "start" and "end" pattern. - */ - if (rest != NULL && (pat_ptrs[ITEM_START] == NULL || - pat_ptrs[ITEM_END] == NULL)) { - not_enough = TRUE; + // Must have a "start" and "end" pattern. + if (rest != NULL && (pat_ptrs[ITEM_START] == NULL + || pat_ptrs[ITEM_END] == NULL)) { + not_enough = true; rest = NULL; } diff --git a/src/nvim/tag.c b/src/nvim/tag.c index 26a89094aa..7885d467d8 100644 --- a/src/nvim/tag.c +++ b/src/nvim/tag.c @@ -526,19 +526,17 @@ do_tag ( taglen_advance(taglen); MSG_PUTS_ATTR(_("file\n"), hl_attr(HLF_T)); - for (i = 0; i < num_matches && !got_int; ++i) { + for (i = 0; i < num_matches && !got_int; i++) { parse_match(matches[i], &tagp); - if (!new_tag && ( - (g_do_tagpreview != 0 - && i == ptag_entry.cur_match) || - (use_tagstack - && i == tagstack[tagstackidx].cur_match))) + if (!new_tag && ((g_do_tagpreview != 0 && i == ptag_entry.cur_match) + || (use_tagstack + && i == tagstack[tagstackidx].cur_match))) { *IObuff = '>'; - else + } else { *IObuff = ' '; - vim_snprintf((char *)IObuff + 1, IOSIZE - 1, - "%2d %s ", i + 1, - mt_names[matches[i][0] & MT_MASK]); + } + vim_snprintf((char *)IObuff + 1, IOSIZE - 1, "%2d %s ", i + 1, + mt_names[matches[i][0] & MT_MASK]); msg_puts(IObuff); if (tagp.tagkind != NULL) msg_outtrans_len(tagp.tagkind, @@ -1147,6 +1145,22 @@ find_tags ( int get_it_again = FALSE; int use_cscope = (flags & TAG_CSCOPE); int verbose = (flags & TAG_VERBOSE); + int save_p_ic = p_ic; + + // Change the value of 'ignorecase' according to 'tagcase' for the + // duration of this function. + switch (curbuf->b_tc_flags ? curbuf->b_tc_flags : tc_flags) { + case TC_FOLLOWIC: + break; + case TC_IGNORE: + p_ic = true; + break; + case TC_MATCH: + p_ic = false; + break; + default: + assert(false); + } help_save = curbuf->b_help; orgpat.pat = pat; @@ -1210,20 +1224,15 @@ find_tags ( for (round = 1; round <= 2; ++round) { linear = (orgpat.headlen == 0 || !p_tbs || round == 2); - /* - * Try tag file names from tags option one by one. - */ - for (first_file = TRUE; - use_cscope || - get_tagfname(&tn, first_file, tag_fname) == OK; - first_file = FALSE) { - /* - * A file that doesn't exist is silently ignored. Only when not a - * single file is found, an error message is given (further on). - */ - if (use_cscope) - fp = NULL; /* avoid GCC warning */ - else { + // Try tag file names from tags option one by one. + for (first_file = true; + use_cscope || get_tagfname(&tn, first_file, tag_fname) == OK; + first_file = false) { + // A file that doesn't exist is silently ignored. Only when not a + // single file is found, an error message is given (further on). + if (use_cscope) { + fp = NULL; // avoid GCC warning + } else { if (curbuf->b_help) { /* Prefer help tags according to 'helplang'. Put the * two-letter language name in help_lang[]. */ @@ -1955,6 +1964,8 @@ findtag_end: curbuf->b_help = help_save; xfree(saved_pat); + p_ic = save_p_ic; + return retval; } diff --git a/src/nvim/tempfile.c b/src/nvim/tempfile.c deleted file mode 100644 index afe926b2ef..0000000000 --- a/src/nvim/tempfile.c +++ /dev/null @@ -1,139 +0,0 @@ -#include <inttypes.h> -#include <stdbool.h> -#include <stdlib.h> -#include <stdio.h> - -#include "nvim/ascii.h" -#include "nvim/memory.h" -#include "nvim/misc1.h" -#include "nvim/os/os.h" -#include "nvim/os/os_defs.h" -#include "nvim/path.h" -#include "nvim/strings.h" -#include "nvim/tempfile.h" - -#ifdef INCLUDE_GENERATED_DECLARATIONS -# include "tempfile.c.generated.h" -#endif - -/// Name of Vim's own temp dir. Ends in a slash. -static char_u *vim_tempdir = NULL; - -/// Create a directory for private use by this instance of Neovim. -/// This is done once, and the same directory is used for all temp files. -/// This method avoids security problems because of symlink attacks et al. -/// It's also a bit faster, because we only need to check for an existing -/// file when creating the directory and not for each temp file. -static void vim_maketempdir(void) -{ - static const char *temp_dirs[] = TEMP_DIR_NAMES; - // Try the entries in `TEMP_DIR_NAMES` to create the temp directory. - char_u template[TEMP_FILE_PATH_MAXLEN]; - char_u path[TEMP_FILE_PATH_MAXLEN]; - for (size_t i = 0; i < ARRAY_SIZE(temp_dirs); ++i) { - // Expand environment variables, leave room for "/nvimXXXXXX/999999999" - // Skip the directory check if the expansion fails. - expand_env((char_u *)temp_dirs[i], template, TEMP_FILE_PATH_MAXLEN - 22); - if (template[0] == '$' || !os_isdir(template)) { - continue; - } - - add_pathsep((char *)template); - // Concatenate with temporary directory name pattern - STRCAT(template, "nvimXXXXXX"); - - if (os_mkdtemp((const char *)template, (char *)path) != 0) { - continue; - } - - if (vim_settempdir((char *)path)) { - // Successfully created and set temporary directory so stop trying. - break; - } else { - // Couldn't set `vim_tempdir` to `path` so remove created directory. - os_rmdir((char *)path); - } - } -} - -/// Delete the temp directory and all files it contains. -void vim_deltempdir(void) -{ - if (vim_tempdir != NULL) { - snprintf((char *)NameBuff, MAXPATHL, "%s*", vim_tempdir); - - char_u **files; - int file_count; - - // Note: We cannot just do `&NameBuff` because it is a statically - // sized array so `NameBuff == &NameBuff` according to C semantics. - char_u *buff_list[1] = {NameBuff}; - if (gen_expand_wildcards(1, buff_list, &file_count, &files, - EW_DIR|EW_FILE|EW_SILENT) == OK) { - for (int i = 0; i < file_count; ++i) { - os_remove((char *)files[i]); - } - FreeWild(file_count, files); - } - path_tail(NameBuff)[-1] = NUL; - os_rmdir((char *)NameBuff); - - xfree(vim_tempdir); - vim_tempdir = NULL; - } -} - -/// Get the name of temp directory. This directory would be created on the first -/// call to this function. -char_u *vim_gettempdir(void) -{ - if (vim_tempdir == NULL) { - vim_maketempdir(); - } - - return vim_tempdir; -} - -/// Set Neovim own temporary directory name to `tempdir`. This directory should -/// be already created. Expand this name to a full path and put it in -/// `vim_tempdir`. This avoids that using `:cd` would confuse us. -/// -/// @param tempdir must be no longer than MAXPATHL. -/// -/// @return false if we run out of memory. -static bool vim_settempdir(char *tempdir) -{ - char *buf = verbose_try_malloc(MAXPATHL + 2); - if (!buf) { - return false; - } - vim_FullName(tempdir, buf, MAXPATHL, false); - add_pathsep(buf); - vim_tempdir = (char_u *)xstrdup(buf); - xfree(buf); - return true; -} - -/// Return a unique name that can be used for a temp file. -/// -/// @note The temp file is NOT created. -/// -/// @return pointer to the temp file name or NULL if Neovim can't create -/// temporary directory for its own temporary files. -char_u *vim_tempname(void) -{ - // Temp filename counter. - static uint32_t temp_count; - - char_u *tempdir = vim_gettempdir(); - if (!tempdir) { - return NULL; - } - - // There is no need to check if the file exists, because we own the directory - // and nobody else creates a file in it. - char_u template[TEMP_FILE_PATH_MAXLEN]; - snprintf((char *)template, TEMP_FILE_PATH_MAXLEN, - "%s%" PRIu32, tempdir, temp_count++); - return vim_strsave(template); -} diff --git a/src/nvim/tempfile.h b/src/nvim/tempfile.h deleted file mode 100644 index c030a70eeb..0000000000 --- a/src/nvim/tempfile.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef NVIM_TEMPFILE_H -#define NVIM_TEMPFILE_H - -#ifdef INCLUDE_GENERATED_DECLARATIONS -# include "tempfile.h.generated.h" -#endif - -#endif // NVIM_TEMPFILE_H diff --git a/src/nvim/terminal.c b/src/nvim/terminal.c index 0440272eb9..104cc47cda 100644 --- a/src/nvim/terminal.c +++ b/src/nvim/terminal.c @@ -175,7 +175,16 @@ void terminal_init(void) for (int color_index = 0; color_index < 256; color_index++) { VTermColor color; - vterm_state_get_palette_color(state, color_index, &color); + // Some of the default 16 colors has the same color as the later + // 240 colors. To avoid collisions, we will use the custom colors + // below in non true color mode. + if (color_index < 16) { + color.red = 0; + color.green = 0; + color.blue = (uint8_t)(color_index + 1); + } else { + vterm_state_get_palette_color(state, color_index, &color); + } map_put(int, int)(color_indexes, RGB(color.red, color.green, color.blue), color_index + 1); } @@ -248,6 +257,15 @@ Terminal *terminal_open(TerminalOptions opts) rv->sb_buffer = xmalloc(sizeof(ScrollbackLine *) * rv->sb_size); if (!true_color) { + // Change the first 16 colors so we can easily get the correct color + // index from them. + for (int i = 0; i < 16; i++) { + VTermColor color; + color.red = 0; + color.green = 0; + color.blue = (uint8_t)(i + 1); + vterm_state_set_palette_color(state, i, &color); + } return rv; } @@ -548,9 +566,9 @@ void terminal_get_line_attributes(Terminal *term, win_T *wp, int linenr, // Since libvterm does not expose the color index used by the program, we // use the rgb value to find the appropriate index in the cache computed by // `terminal_init`. - int vt_fg_idx = vt_fg != default_vt_fg ? + int vt_fg_idx = vt_fg != -1 ? map_get(int, int)(color_indexes, vt_fg) : 0; - int vt_bg_idx = vt_bg != default_vt_bg ? + int vt_bg_idx = vt_bg != -1 ? map_get(int, int)(color_indexes, vt_bg) : 0; int hl_attrs = (cell.attrs.bold ? HL_BOLD : 0) diff --git a/src/nvim/testdir/Makefile b/src/nvim/testdir/Makefile index 55a49122d5..82c7cd4de9 100644 --- a/src/nvim/testdir/Makefile +++ b/src/nvim/testdir/Makefile @@ -36,9 +36,13 @@ SCRIPTS := \ test_breakindent.out \ test_close_count.out \ test_marks.out \ - test_match_conceal.out \ -NEW_TESTS = test_viml.res +# Tests using runtest.vim.vim. +# Keep test_alot*.res as the last one, sort the others. +NEW_TESTS = \ + test_viml.res \ + test_cursor_func.res \ + test_alot.res SCRIPTS_GUI := test16.out diff --git a/src/nvim/testdir/runtest.vim b/src/nvim/testdir/runtest.vim index 1c610eab51..6601dcf52f 100644 --- a/src/nvim/testdir/runtest.vim +++ b/src/nvim/testdir/runtest.vim @@ -62,6 +62,7 @@ else endif " Locate Test_ functions and execute them. +set nomore redir @q function /^Test_ redir END diff --git a/src/nvim/testdir/test49.in b/src/nvim/testdir/test49.in index 1ce57246ee..d95052e14c 100644 --- a/src/nvim/testdir/test49.in +++ b/src/nvim/testdir/test49.in @@ -8,7 +8,9 @@ STARTTEST :se nomore :lang mess C :so test49.vim -GGGGGGGGGGGGGG"rp:.-,$w! test.out +:" Go back to this file and append the results from register r. +:buf test49.in +G"rp:/^Results/,$w! test.out :" :" make valgrind happy :redir => funclist diff --git a/src/nvim/testdir/test_alot.vim b/src/nvim/testdir/test_alot.vim new file mode 100644 index 0000000000..1d1da94bac --- /dev/null +++ b/src/nvim/testdir/test_alot.vim @@ -0,0 +1,3 @@ +" A series of tests that can run in one Vim invocation. +" This makes testing go faster, since Vim doesn't need to restart. + diff --git a/src/nvim/testdir/test_cursor_func.vim b/src/nvim/testdir/test_cursor_func.vim new file mode 100644 index 0000000000..d819b7b092 --- /dev/null +++ b/src/nvim/testdir/test_cursor_func.vim @@ -0,0 +1,52 @@ +" Tests for cursor(). + +func Test_wrong_arguments() + try + call cursor(1. 3) + " not reached + call assert_false(1) + catch + call assert_exception('E474:') + endtry +endfunc + +func Test_move_cursor() + new + call setline(1, ['aaa', 'bbb', 'ccc', 'ddd']) + + call cursor([1, 1, 0, 1]) + call assert_equal([1, 1, 0, 1], getcurpos()[1:]) + call cursor([4, 3, 0, 3]) + call assert_equal([4, 3, 0, 3], getcurpos()[1:]) + + call cursor(2, 2) + call assert_equal([2, 2, 0, 2], getcurpos()[1:]) + " line number zero keeps the line number + call cursor(0, 1) + call assert_equal([2, 1, 0, 1], getcurpos()[1:]) + " col number zero keeps the column + call cursor(3, 0) + call assert_equal([3, 1, 0, 1], getcurpos()[1:]) + " below last line goes to last line + call cursor(9, 1) + call assert_equal([4, 1, 0, 1], getcurpos()[1:]) + + quit! +endfunc + +" Very short version of what matchparen does. +function s:Highlight_Matching_Pair() + let save_cursor = getcurpos() + call setpos('.', save_cursor) +endfunc + +func Test_curswant_with_autocommand() + new + call setline(1, ['func()', '{', '}', '----']) + autocmd! CursorMovedI * call s:Highlight_Matching_Pair() + exe "normal! 3Ga\<Down>X\<Esc>" + call assert_equal('-X---', getline(4)) + autocmd! CursorMovedI * + quit! +endfunc + diff --git a/src/nvim/tui/input.c b/src/nvim/tui/input.c index b41e4d2fba..99eb230a88 100644 --- a/src/nvim/tui/input.c +++ b/src/nvim/tui/input.c @@ -224,9 +224,9 @@ static void tk_getkeys(TermInput *input, bool force) while ((result = tk_getkey(input->tk, &key, force)) == TERMKEY_RES_KEY) { if (key.type == TERMKEY_TYPE_UNICODE && !key.modifiers) { forward_simple_utf8(input, &key); - } else if (key.type == TERMKEY_TYPE_UNICODE || - key.type == TERMKEY_TYPE_FUNCTION || - key.type == TERMKEY_TYPE_KEYSYM) { + } else if (key.type == TERMKEY_TYPE_UNICODE + || key.type == TERMKEY_TYPE_FUNCTION + || key.type == TERMKEY_TYPE_KEYSYM) { forward_modified_utf8(input, &key); } else if (key.type == TERMKEY_TYPE_MOUSE) { forward_mouse_event(input, &key); @@ -282,9 +282,9 @@ static bool handle_focus_event(TermInput *input) static bool handle_bracketed_paste(TermInput *input) { - if (rbuffer_size(input->read_stream.buffer) > 5 && - (!rbuffer_cmp(input->read_stream.buffer, "\x1b[200~", 6) || - !rbuffer_cmp(input->read_stream.buffer, "\x1b[201~", 6))) { + if (rbuffer_size(input->read_stream.buffer) > 5 + && (!rbuffer_cmp(input->read_stream.buffer, "\x1b[200~", 6) + || !rbuffer_cmp(input->read_stream.buffer, "\x1b[201~", 6))) { bool enable = *rbuffer_get(input->read_stream.buffer, 4) == '0'; // Advance past the sequence rbuffer_consumed(input->read_stream.buffer, 6); diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c index 00e2821075..e1c0407b27 100644 --- a/src/nvim/tui/tui.c +++ b/src/nvim/tui/tui.c @@ -628,8 +628,8 @@ static void tui_suspend(UI *ui) static void tui_set_title(UI *ui, char *title) { TUIData *data = ui->data; - if (!(title && unibi_get_str(data->ut, unibi_to_status_line) && - unibi_get_str(data->ut, unibi_from_status_line))) { + if (!(title && unibi_get_str(data->ut, unibi_to_status_line) + && unibi_get_str(data->ut, unibi_from_status_line))) { return; } unibi_out(ui, unibi_to_status_line); @@ -694,8 +694,8 @@ static void update_size(UI *ui) } // 2 - try from a system call(ioctl/TIOCGWINSZ on unix) - if (data->out_isatty && - !uv_tty_get_winsize(&data->output_handle.tty, &width, &height)) { + if (data->out_isatty + && !uv_tty_get_winsize(&data->output_handle.tty, &width, &height)) { goto end; } diff --git a/src/nvim/undo.c b/src/nvim/undo.c index 7d9b2c7c3b..f16b4264d7 100644 --- a/src/nvim/undo.c +++ b/src/nvim/undo.c @@ -2876,9 +2876,7 @@ static char_u *u_save_line(linenr_T lnum) /// @return true if the buffer has changed bool bufIsChanged(buf_T *buf) { - return - !bt_dontwrite(buf) && - (buf->b_changed || file_ff_differs(buf, true)); + return !bt_dontwrite(buf) && (buf->b_changed || file_ff_differs(buf, true)); } /// Check if the 'modified' flag is set, or 'ff' has changed (only need to @@ -2888,9 +2886,8 @@ bool bufIsChanged(buf_T *buf) /// @return true if the current buffer has changed bool curbufIsChanged(void) { - return - !bt_dontwrite(curbuf) && - (curbuf->b_changed || file_ff_differs(curbuf, true)); + return (!bt_dontwrite(curbuf) + && (curbuf->b_changed || file_ff_differs(curbuf, true))); } /* diff --git a/src/nvim/version.c b/src/nvim/version.c index d7051647dd..b2dbfe87c8 100644 --- a/src/nvim/version.c +++ b/src/nvim/version.c @@ -69,83 +69,396 @@ static char *features[] = { // clang-format off static int included_patches[] = { + 1757, 1755, + 1753, 1654, 1652, 1643, 1641, + + // 1600 NA + // 1599 NA + // 1598 NA + // 1597 NA + // 1596, + // 1595 NA + // 1594 NA + // 1593 NA + // 1592, + // 1591, + // 1590, + // 1589, + // 1588, + // 1587 NA + // 1586, + // 1585, + // 1584 NA + // 1583 NA + // 1582, + + // 1581, + // 1580, + // 1579, + // 1578, + // 1577, + 1576, + // 1575 NA 1574, + // 1573, + // 1572 NA + // 1571, 1570, + 1569, + // 1568, + // 1567, + // 1566 NA + // 1565, + // 1564, + // 1563, + // 1562, + // 1561 NA + // 1560, + // 1559, + // 1558, + // 1557, + // 1556, + // 1555, + // 1554, + // 1553, + // 1552, + // 1551, + // 1550, + // 1549, + // 1548, + // 1547, + // 1546, + // 1545 NA + // 1544 NA + // 1543 NA + // 1542 NA + // 1541 NA + // 1540 NA + // 1539 NA + // 1538 NA + // 1537 NA + // 1536 NA + // 1535, + // 1534 NA + // 1533, + // 1532 NA + // 1531 NA + // 1530 NA + // 1529 NA + // 1528, + // 1527 NA + // 1526 NA + // 1525 NA + // 1524 NA + // 1523 NA + // 1522 NA + // 1521, + // 1520 NA + // 1519 NA + // 1518 NA + // 1517 NA + // 1516, + // 1515 NA + // 1514 NA + // 1513, + // 1512 NA 1511, + // 1510 NA + // 1509 NA + // 1508 NA + // 1507 NA + // 1506 NA + // 1505 NA + // 1504 NA + // 1503 NA + // 1502 NA + // 1501 NA + 1500, + // 1499, + // 1498 NA + // 1497 NA + // 1496 NA + // 1495 NA + // 1494, + // 1493 NA + // 1492, + // 1491, + // 1490 NA + // 1489 NA + // 1488 NA + // 1487 NA + // 1486, + // 1485 NA + // 1484 NA + // 1483 NA + // 1482 NA + // 1481 NA + // 1480, + // 1479, + // 1478, + // 1477, + // 1476 NA + // 1475 NA + // 1474 NA + // 1473 NA + // 1472 NA + // 1471 NA + // 1470 NA + // 1469 NA + // 1468, + // 1467 NA + // 1466 NA + // 1465 NA + // 1464, + // 1463 NA + // 1462 NA + // 1461 NA + // 1460 NA + // 1459 NA + // 1458 NA + // 1457 NA + // 1456, + // 1455 NA + // 1454 NA + // 1453 NA + // 1452 NA + // 1451 NA + // 1450 NA + // 1449 NA + // 1448 NA + // 1447 NA + // 1446 NA + // 1445 NA + // 1444 NA + // 1443 NA + // 1442 NA + // 1441 NA + // 1440 NA + // 1439 NA + // 1438 NA + // 1437 NA + // 1436 NA + // 1435 NA + // 1434 NA + // 1433 NA + // 1432 NA + // 1431 NA + // 1430 NA + // 1429 NA + // 1428 NA + // 1427 NA + // 1426 NA 1425, + // 1424 NA + // 1423 NA + // 1422 NA + // 1421 NA + // 1420 NA + // 1419 NA + // 1418 NA + // 1417 NA + // 1416 NA + // 1415 NA + // 1414 NA + // 1413 NA + // 1412 NA + // 1411 NA + 1410, + // 1409 NA + // 1408 NA + // 1407 NA + 1406, + 1405, + // 1404 NA + // 1403 NA + // 1402 NA + 1401, + // 1400 NA + // 1399 NA + // 1398 NA + // 1397, + // 1396, + // 1395 NA + // 1394, + // 1393 NA + // 1392 NA + // 1391 NA + // 1390 NA + // 1389 NA + // 1388, + // 1387 NA + // 1386 NA + // 1385 NA + // 1384, + // 1383 NA + // 1382 NA + // 1381 NA + // 1380 NA + // 1379 NA + // 1378 NA + // 1377 NA + // 1376 NA + // 1375 NA + // 1374 NA + // 1373 NA + // 1372 NA + // 1371 NA + // 1370 NA + // 1369 NA + // 1368 NA + // 1367 NA 1366, + // 1365, + // 1364 NA + // 1363 NA + // 1362 NA + // 1361 NA + // 1360 NA + // 1359 NA + // 1358 NA + // 1357 NA + // 1356 NA + // 1355 NA + // 1354 NA + // 1353 NA + // 1352, + // 1351 NA + // 1350 NA + // 1349 NA + // 1348 NA + // 1347, + 1346, + // 1345 NA + // 1344 NA + // 1343 NA + // 1342 NA + // 1341 NA + // 1340 NA + // 1339 NA + // 1338 NA + // 1337 NA + // 1336 NA + // 1335 NA + // 1334 NA + // 1333 NA + // 1332 NA + // 1331 NA + // 1330 NA + // 1329 NA + // 1328 NA + // 1327 NA + // 1326 NA + // 1325 NA + // 1324 NA + // 1323 NA + // 1322 NA + // 1321 NA + // 1320 NA + // 1319 NA + // 1318 NA + // 1317 NA + // 1316 NA + // 1315 NA + // 1314 NA + // 1313 NA + // 1312 NA + // 1311 NA + // 1310 NA + 1309, + // 1308 NA + // 1307 NA + // 1306 NA + // 1305, 1304, + // 1303 NA + // 1302 NA + // 1301 NA + // 1300 NA + // 1299 NA + // 1298 NA + // 1297 NA + 1296, + // 1295 NA + // 1294 NA + // 1293 NA 1292, + // 1291 NA + // 1290 NA + // 1289 NA + // 1288 NA + // 1287 NA + // 1286 NA + // 1285, 1284, - // 1283 + // 1283 NA 1282, - // 1281 - // 1280 + // 1281, + // 1280 NA // 1279 NA // 1278 NA - // 1277 - // 1276 - // 1275 - // 1274 - // 1273 - // 1272 + // 1277 NA + // 1276, + // 1275 NA + // 1274 NA + // 1273, + // 1272 NA 1271, - // 1270 + // 1270 NA 1269, - // 1268 + // 1268 NA 1267, // 1266 - // 1265 - // 1264 - // 1263 - // 1262 - // 1261 - // 1260 - // 1259 - // 1258 - // 1257 - // 1256 - // 1255 - // 1254 - // 1253 - // 1252 - // 1251 - // 1250 - // 1249 - // 1248 - // 1247 - // 1246 - // 1245 - // 1244 + // 1265 NA + // 1264 NA + // 1263 NA + // 1262 NA + // 1261 NA + // 1260 NA + // 1259, + // 1258 NA + // 1257 NA + // 1256 NA + // 1255 NA + // 1254 NA + // 1253 NA + // 1252 NA + // 1251 NA + // 1250 NA + // 1249 NA + // 1248 NA + // 1247 NA + // 1246 NA + // 1245 NA + // 1244 NA // 1243 NA - // 1242 - // 1241 - // 1240 - // 1239 - // 1238 - // 1237 - // 1236 - // 1235 - // 1234 - // 1233 - // 1232 + // 1242 NA + // 1241 NA + // 1240 NA + // 1239 NA + // 1238 NA + // 1237, + 1236, + // 1235 NA + // 1234 NA + // 1233 NA + // 1232 NA // 1231 NA - // 1230 - // 1229 + // 1230 NA + // 1229 NA 1228, - // 1227 - // 1226 - // 1225 - // 1224 - // 1223 - // 1223 - // 1221 - // 1220 + // 1227 NA + // 1226 NA + // 1225 NA + // 1224 NA + // 1223, + // 1222 NA + // 1221 NA + // 1220 NA // 1219 NA // 1218 NA // 1217 NA @@ -177,7 +490,7 @@ static int included_patches[] = { // 1191 NA // 1190 NA // 1189 NA - // 1188, + // 1188 NA // 1187 NA // 1186, // 1185 NA @@ -211,7 +524,7 @@ static int included_patches[] = { 1157, // 1156 NA // 1155 NA - // 1154, + // 1154 NA // 1153, // 1152 NA // 1151, @@ -221,8 +534,8 @@ static int included_patches[] = { // 1147, // 1146 NA // 1145 NA - // 1144 NA - // 1143, + 1144, + 1143, // 1142, 1141, // 1140, @@ -230,8 +543,8 @@ static int included_patches[] = { // 1138 NA 1137, // 1136, - // 1135 NA, - // 1134 NA, + // 1135 NA + // 1134 NA // 1133 NA // 1132, // 1131 NA @@ -245,20 +558,20 @@ static int included_patches[] = { // 1123, // 1122 NA // 1121, - // 1120, + 1120, // 1119, - // 1118, - // 1117, - // 1116, + 1118, + 1117, + 1116, // 1115 NA - // 1114, + 1114, 1113, 1112, // 1111, // 1110, // 1109 NA // 1108, - // 1107, + 1107, // 1106 NA 1105, // 1104 NA @@ -272,40 +585,40 @@ static int included_patches[] = { // 1096, // 1095 NA // 1094, - // 1093, - // 1092, + 1093, + 1092, // 1091, // 1090, 1089, 1088, 1087, - // 1086, + 1086, 1085, 1084, - // 1083 NA, - // 1082 NA, + // 1083 NA + // 1082 NA 1081, - // 1080 NA, + // 1080 NA // 1079, - // 1078 NA, - // 1077 NA, + // 1078 NA + // 1077 NA 1076, - // 1075, + 1075, // 1074 NA, // 1073, 1072, // 1071, - // 1070 NA, - // 1069 NA, + // 1070 NA + // 1069 NA // 1068, - // 1067 NA, - // 1066 NA, + // 1067 NA + // 1066 NA 1065, // 1064, - // 1063 NA, - // 1062 NA, + // 1063 NA + // 1062 NA // 1061, - // 1060 NA, + // 1060 NA // 1059, // 1058, // 1057, @@ -320,54 +633,54 @@ static int included_patches[] = { // 1048, // 1047, // 1046, - // 1045 NA, - // 1044 NA, - // 1043 NA, + // 1045 NA + // 1044 NA + // 1043 NA // 1042, 1041, - // 1040 NA, + // 1040 NA // 1039, - // 1038 NA, + // 1038 NA // 1037, // 1036, - // 1035, + 1035, // 1034, - // 1033 NA, + // 1033 NA 1032, // 1031 NA, 1030, 1029, - // 1028 NA, + // 1028 NA 1027, - // 1026 NA, - // 1025 NA, - // 1024 NA, - // 1023 NA, - // 1022 NA, - // 1021 NA, - // 1020 NA, - // 1019 NA, + // 1026 NA + // 1025 NA + // 1024 NA + // 1023 NA + // 1022 NA + // 1021 NA + // 1020 NA + // 1019 NA // 1018, // 1017, - // 1016 NA, + // 1016 NA // 1015, - // 1014 NA, + // 1014 NA 1013, - // 1012 NA, - // 1011 NA, - // 1010, - // 1009 NA, - // 1008 NA, - // 1007, - // 1006, - // 1005, + // 1012 NA + // 1011 NA + // 1010 NA, + // 1009 NA + // 1008 NA + 1007, + 1006, + // 1005 NA, // 1004 NA, // 1003 NA, // 1002 NA, 1001, 1000, // 999 NA - // 998, + 998, // 997 NA // 996 NA // 995 NA @@ -381,8 +694,8 @@ static int included_patches[] = { // 987 NA // 986 NA // 985 NA - // 984, - // 983, + 984, + // 983 NA // 982 NA 981, 980, @@ -408,13 +721,13 @@ static int included_patches[] = { // 960 NA // 959 NA 958, - // 957, + 957, // 956 NA 955, // 954 NA 953, 952, - // 951, + 951, 950, 949, // 948 NA @@ -423,8 +736,8 @@ static int included_patches[] = { 945, 944, // 943 NA - // 942, - // 941, + 942, + 941, // 940 NA 939, // 938 NA @@ -476,14 +789,14 @@ static int included_patches[] = { // 892 NA 891, // 890 NA - // 889, + 889, 888, 887, // 886 NA 885, // 884 NA 883, - // 882, + 882, 881, // 880 NA 879, @@ -543,7 +856,7 @@ static int included_patches[] = { 825, // 824 NA 823, - // 822, + 822, // 821 NA 820, 819, @@ -568,7 +881,7 @@ static int included_patches[] = { 800, 799, 798, - // 797, + // 797 NA // 796 NA 795, // 794 NA @@ -632,7 +945,7 @@ static int included_patches[] = { 736, // 735 NA 734, - // 733, + // 733 NA 732, // 731 NA // 730 NA @@ -693,7 +1006,7 @@ static int included_patches[] = { 675, // 674 NA 673, - // 672, + 672, 671, 670, // 669 NA @@ -752,7 +1065,7 @@ static int included_patches[] = { 616, 615, 614, - // 613, + 613, 612, // 611 NA // 610 NA @@ -1121,13 +1434,13 @@ static int included_patches[] = { 247, // 246 NA 245, - // 244, + // 244 NA 243, 242, 241, 240, 239, - // 238, + // 238 NA 237, 236, 235, diff --git a/src/nvim/vim.h b/src/nvim/vim.h index 623ea19e36..165a44a148 100644 --- a/src/nvim/vim.h +++ b/src/nvim/vim.h @@ -201,15 +201,6 @@ enum { #define MAYBE 2 /* sometimes used for a variant on TRUE */ -/* - * Motion types, used for operators and for yank/delete registers. - */ -#define MCHAR 0 /* character-wise movement/register */ -#define MLINE 1 /* line-wise movement/register */ -#define MBLOCK 2 /* block-wise register */ - -#define MAUTO 0xff /* Decide between MLINE/MCHAR */ - #define STATUS_HEIGHT 1 /* height of a status line under a window */ #define QF_WINHEIGHT 10 /* default height for quickfix window */ diff --git a/src/nvim/window.c b/src/nvim/window.c index 1b8c953596..bea55c465f 100644 --- a/src/nvim/window.c +++ b/src/nvim/window.c @@ -97,7 +97,7 @@ do_window ( * don't replicate the quickfix buffer. */ if (bt_quickfix(curbuf)) goto newwindow; - win_split((int)Prenum, 0); + (void)win_split((int)Prenum, 0); break; /* split current window in two parts, vertically */ @@ -108,7 +108,7 @@ do_window ( * don't replicate the quickfix buffer. */ if (bt_quickfix(curbuf)) goto newwindow; - win_split((int)Prenum, WSP_VERT); + (void)win_split((int)Prenum, WSP_VERT); break; /* split current window and edit alternate file */ @@ -2948,7 +2948,7 @@ void free_tabpage(tabpage_T *tp) unref_var_dict(tp->tp_vars); - + xfree(tp->localdir); // Free tab-local working directory xfree(tp); } @@ -3560,18 +3560,24 @@ static void win_enter_ext(win_T *wp, bool undo_sync, int curwin_invalid, int tri curwin->w_cursor.coladd = 0; changed_line_abv_curs(); /* assume cursor position needs updating */ - if (curwin->w_localdir != NULL) { - /* Window has a local directory: Save current directory as global - * directory (unless that was done already) and change to the local - * directory. */ + // The new directory is either the local directory of the window, of the tab + // or NULL. + char_u *new_dir = curwin->w_localdir ? curwin->w_localdir : curtab->localdir; + + if (new_dir) { + // Window/tab has a local directory: Save current directory as global + // directory (unless that was done already) and change to the local + // directory. if (globaldir == NULL) { char_u cwd[MAXPATHL]; - if (os_dirname(cwd, MAXPATHL) == OK) + if (os_dirname(cwd, MAXPATHL) == OK) { globaldir = vim_strsave(cwd); + } + } + if (os_chdir((char *)new_dir) == 0) { + shorten_fnames(true); } - if (os_chdir((char *)curwin->w_localdir) == 0) - shorten_fnames(TRUE); } else if (globaldir != NULL) { /* Window doesn't have a local directory and we are not in the global * directory: Change to the global directory. */ |