diff options
Diffstat (limited to 'src')
76 files changed, 2946 insertions, 2416 deletions
diff --git a/src/nvim/CMakeLists.txt b/src/nvim/CMakeLists.txt index ea5125e4e7..ef9e11fbef 100644 --- a/src/nvim/CMakeLists.txt +++ b/src/nvim/CMakeLists.txt @@ -76,7 +76,6 @@ set(CONV_SOURCES diff.c edit.c eval.c - ex_cmds2.c ex_cmds.c ex_docmd.c ex_getln.c diff --git a/src/nvim/README.md b/src/nvim/README.md index e4939d94fd..f16c6de12f 100644 --- a/src/nvim/README.md +++ b/src/nvim/README.md @@ -11,7 +11,7 @@ that are constantly changing. As the code becomes more organized and stable, this document will be updated to reflect the changes. If you are looking for module-specific details, it is best to read the source -code. Some files are extensively commented at the top(eg: terminal.c, +code. Some files are extensively commented at the top (e.g. terminal.c, screen.c). ### Top-level program loops @@ -43,13 +43,13 @@ a typical editing session: Note that we have split user actions into sequences of inputs that change the state of the editor. While there's no documentation about a "g command -mode"(step 16), internally it is implemented similarly to "operator-pending +mode" (step 16), internally it is implemented similarly to "operator-pending mode". From this we can see that Vim has the behavior of a input-driven state -machine(more specifically, a pushdown automaton since it requires a stack for +machine (more specifically, a pushdown automaton since it requires a stack for transitioning back from states). Assuming each state has a callback responsible -for handling keys, this pseudocode(a python-like language) shows a good +for handling keys, this pseudocode (a python-like language) shows a good representation of the main program loop: ```py @@ -129,20 +129,20 @@ def insert_state(data, key): While the actual code is much more complicated, the above gives an idea of how Neovim is organized internally. Some states like the `g_command_state` or `get_operator_count_state` do not have a dedicated `state_enter` callback, but -are implicitly embedded into other states(this will change later as we continue +are implicitly embedded into other states (this will change later as we continue the refactoring effort). To start reading the actual code, here's the recommended order: -1. `state_enter()` function(state.c). This is the actual program loop, +1. `state_enter()` function (state.c). This is the actual program loop, note that a `VimState` structure is used, which contains function pointers for the callback and state data. -2. `main()` function(main.c). After all startup, `normal_enter` is called +2. `main()` function (main.c). After all startup, `normal_enter` is called at the end of function to enter normal mode. -3. `normal_enter()` function(normal.c) is a small wrapper for setting +3. `normal_enter()` function (normal.c) is a small wrapper for setting up the NormalState structure and calling `state_enter`. -4. `normal_check()` function(normal.c) is called before each iteration of +4. `normal_check()` function (normal.c) is called before each iteration of normal mode. -5. `normal_execute()` function(normal.c) is called when a key is read in normal +5. `normal_execute()` function (normal.c) is called when a key is read in normal mode. The basic structure described for normal mode in 3, 4 and 5 is used for other @@ -159,7 +159,7 @@ asynchronous events, which can include: - msgpack-rpc requests - job control callbacks -- timers(not implemented yet but the support code is already there) +- timers (not implemented yet but the support code is already there) Neovim implements this functionality by entering another event loop while waiting for characters, so instead of: @@ -180,11 +180,11 @@ def state_enter(state_callback, data): while state_callback(data, event) # invoke the callback for the current state ``` -where `event` is something the operating system delivers to us, including(but +where `event` is something the operating system delivers to us, including (but not limited to) user input. The `read_next_event()` part is internally implemented by libuv, the platform layer used by Neovim. Since Neovim inherited its code from Vim, the states are not prepared to receive -"arbitrary events", so we use a special key to represent those(When a state +"arbitrary events", so we use a special key to represent those (When a state receives an "arbitrary event", it normally doesn't do anything other update the screen). diff --git a/src/nvim/api/buffer.c b/src/nvim/api/buffer.c index b7a86af134..fa4b8e5f7d 100644 --- a/src/nvim/api/buffer.c +++ b/src/nvim/api/buffer.c @@ -19,6 +19,7 @@ #include "nvim/mark.h" #include "nvim/fileio.h" #include "nvim/move.h" +#include "nvim/syntax.h" #include "nvim/window.h" #include "nvim/undo.h" @@ -514,6 +515,99 @@ ArrayOf(Integer, 2) buffer_get_mark(Buffer buffer, String name, Error *err) return rv; } +/// Adds a highlight to buffer. +/// +/// This can be used for plugins which dynamically generate highlights to a +/// buffer (like a semantic highlighter or linter). The function adds a single +/// highlight to a buffer. Unlike matchaddpos() highlights follow changes to +/// line numbering (as lines are inserted/removed above the highlighted line), +/// like signs and marks do. +/// +/// "src_id" is useful for batch deletion/updating of a set of highlights. When +/// called with src_id = 0, an unique source id is generated and returned. +/// Succesive calls can pass in it as "src_id" to add new highlights to the same +/// source group. All highlights in the same group can then be cleared with +/// buffer_clear_highlight. If the highlight never will be manually deleted +/// pass in -1 for "src_id". +/// +/// If "hl_group" is the empty string no highlight is added, but a new src_id +/// is still returned. This is useful for an external plugin to synchrounously +/// request an unique src_id at initialization, and later asynchronously add and +/// clear highlights in response to buffer changes. +/// +/// @param buffer The buffer handle +/// @param src_id Source group to use or 0 to use a new group, +/// or -1 for ungrouped highlight +/// @param hl_group Name of the highlight group to use +/// @param line The line to highlight +/// @param col_start Start of range of columns to highlight +/// @param col_end End of range of columns to highlight, +/// or -1 to highlight to end of line +/// @param[out] err Details of an error that may have occurred +/// @return The src_id that was used +Integer buffer_add_highlight(Buffer buffer, + Integer src_id, + String hl_group, + Integer line, + Integer col_start, + Integer col_end, + Error *err) +{ + buf_T *buf = find_buffer_by_handle(buffer, err); + if (!buf) { + return 0; + } + + if (line < 0 || line >= MAXLNUM) { + api_set_error(err, Validation, _("Line number outside range")); + return 0; + } + if (col_start < 0 || col_start > MAXCOL) { + api_set_error(err, Validation, _("Column value outside range")); + return 0; + } + if (col_end < 0 || col_end > MAXCOL) { + col_end = MAXCOL; + } + + int hlg_id = syn_name2id((char_u*)hl_group.data); + src_id = bufhl_add_hl(buf, (int)src_id, hlg_id, (linenr_T)line+1, + (colnr_T)col_start+1, (colnr_T)col_end); + return src_id; +} + +/// Clears highlights from a given source group and a range of lines +/// +/// To clear a source group in the entire buffer, pass in 1 and -1 to +/// line_start and line_end respectively. +/// +/// @param buffer The buffer handle +/// @param src_id Highlight source group to clear, or -1 to clear all groups. +/// @param line_start Start of range of lines to clear +/// @param line_end End of range of lines to clear (exclusive) +/// or -1 to clear to end of file. +/// @param[out] err Details of an error that may have occurred +void buffer_clear_highlight(Buffer buffer, + Integer src_id, + Integer line_start, + Integer line_end, + Error *err) +{ + buf_T *buf = find_buffer_by_handle(buffer, err); + if (!buf) { + return; + } + + if (line_start < 0 || line_start >= MAXLNUM) { + api_set_error(err, Validation, _("Line number outside range")); + return; + } + if (line_end < 0 || line_end > MAXLNUM) { + line_end = MAXLNUM; + } + + bufhl_clear_line_range(buf, (int)src_id, (int)line_start+1, (int)line_end); +} // Check if deleting lines made the cursor position invalid. // Changed the lines from "lo" to "hi" and added "extra" lines (negative if diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c index a6e3fedd3f..62ab7495da 100644 --- a/src/nvim/buffer.c +++ b/src/nvim/buffer.c @@ -22,6 +22,7 @@ #include "nvim/api/private/handle.h" #include "nvim/ascii.h" +#include "nvim/assert.h" #include "nvim/vim.h" #include "nvim/buffer.h" #include "nvim/charset.h" @@ -579,16 +580,17 @@ free_buffer_stuff ( ) { if (free_options) { - clear_wininfo(buf); /* including window-local options */ - free_buf_options(buf, TRUE); + clear_wininfo(buf); // including window-local options + free_buf_options(buf, true); ga_clear(&buf->b_s.b_langp); } - vars_clear(&buf->b_vars->dv_hashtab); /* free all internal variables */ + vars_clear(&buf->b_vars->dv_hashtab); // free all internal variables hash_init(&buf->b_vars->dv_hashtab); - uc_clear(&buf->b_ucmds); /* clear local user commands */ - buf_delete_signs(buf); /* delete any signs */ - map_clear_int(buf, MAP_ALL_MODES, TRUE, FALSE); /* clear local mappings */ - map_clear_int(buf, MAP_ALL_MODES, TRUE, TRUE); /* clear local abbrevs */ + uc_clear(&buf->b_ucmds); // clear local user commands + buf_delete_signs(buf); // delete any signs + bufhl_clear_all(buf); // delete any highligts + map_clear_int(buf, MAP_ALL_MODES, true, false); // clear local mappings + map_clear_int(buf, MAP_ALL_MODES, true, true); // clear local abbrevs xfree(buf->b_start_fenc); buf->b_start_fenc = NULL; } @@ -1600,21 +1602,28 @@ int buflist_getfile(int n, linenr_T lnum, int options, int forceit) col = 0; if (options & GETF_SWITCH) { - /* If 'switchbuf' contains "useopen": jump to first window containing - * "buf" if one exists */ - if (swb_flags & SWB_USEOPEN) + // If 'switchbuf' contains "useopen": jump to first window containing + // "buf" if one exists + if (swb_flags & SWB_USEOPEN) { wp = buf_jump_open_win(buf); - /* If 'switchbuf' contains "usetab": jump to first window in any tab - * page containing "buf" if one exists */ - if (wp == NULL && (swb_flags & SWB_USETAB)) + } + + // If 'switchbuf' contains "usetab": jump to first window in any tab + // page containing "buf" if one exists + if (wp == NULL && (swb_flags & SWB_USETAB)) { wp = buf_jump_open_tab(buf); - /* If 'switchbuf' contains "split" or "newtab" and the current buffer - * isn't empty: open new window */ - if (wp == NULL && (swb_flags & (SWB_SPLIT | SWB_NEWTAB)) && !bufempty()) { - if (swb_flags & SWB_NEWTAB) /* Open in a new tab */ + } + + // If 'switchbuf' contains "split", "vsplit" or "newtab" and the + // current buffer isn't empty: open new tab or window + if (wp == NULL && (swb_flags & (SWB_VSPLIT | SWB_SPLIT | SWB_NEWTAB)) + && !bufempty()) { + if (swb_flags & SWB_NEWTAB) { tabpage_new(); - else if (win_split(0, 0) == FAIL) /* Open in a new window */ + } else if (win_split(0, (swb_flags & SWB_VSPLIT) ? WSP_VERT : 0) + == FAIL) { return FAIL; + } RESET_BINDING(curwin); } } @@ -1733,12 +1742,15 @@ int buflist_findpat( int toggledollar; if (pattern_end == pattern + 1 && (*pattern == '%' || *pattern == '#')) { - if (*pattern == '%') + if (*pattern == '%') { match = curbuf->b_fnum; - else + } else { match = curwin->w_alt_fnum; - if (diffmode && !diff_mode_buf(buflist_findnr(match))) + } + buf_T *found_buf = buflist_findnr(match); + if (diffmode && !(found_buf && diff_mode_buf(found_buf))) { match = -1; + } } /* * Try four ways of matching a listed buffer: @@ -2826,7 +2838,7 @@ typedef enum { /// @param fillchar Character to use when filling empty space in the statusline /// @param maxwidth The maximum width to make the statusline /// @param hltab HL attributes (can be NULL) -/// @param tabtab tab page nrs (can be NULL) +/// @param tabtab Tab clicks definition (can be NULL). /// /// @return The final width of the statusline int build_stl_str_hl( @@ -2838,13 +2850,15 @@ int build_stl_str_hl( int fillchar, int maxwidth, struct stl_hlrec *hltab, - struct stl_hlrec *tabtab + StlClickRecord *tabtab ) { int groupitem[STL_MAX_ITEM]; struct stl_item { // Where the item starts in the status line output buffer - char_u *start; + char_u *start; + // Function to run for ClickFunc items. + char *cmd; // The minimum width of the item int minwid; // The maximum width of the item @@ -2856,10 +2870,10 @@ int build_stl_str_hl( Middle, Highlight, TabPage, + ClickFunc, Trunc - } type; - } item[STL_MAX_ITEM]; - + } type; + } item[STL_MAX_ITEM]; #define TMPLEN 70 char_u tmp[TMPLEN]; char_u *usefmt = fmt; @@ -3164,6 +3178,24 @@ int build_stl_str_hl( continue; } + if (*fmt_p == STL_CLICK_FUNC) { + fmt_p++; + char *t = (char *) fmt_p; + while (*fmt_p != STL_CLICK_FUNC && *fmt_p) { + fmt_p++; + } + if (*fmt_p != STL_CLICK_FUNC) { + break; + } + item[curitem].type = ClickFunc; + item[curitem].start = out_p; + item[curitem].cmd = xmemdupz(t, (size_t) (((char *) fmt_p - t))); + item[curitem].minwid = minwid; + fmt_p++; + curitem++; + continue; + } + // Denotes the end of the minwid // the maxwid may follow immediately after if (*fmt_p == '.') { @@ -3281,6 +3313,7 @@ int build_stl_str_hl( } break; } + case STL_LINE: num = (wp->w_buffer->b_ml.ml_flags & ML_EMPTY) ? 0L : (long)(wp->w_cursor.lnum); @@ -3821,16 +3854,37 @@ int build_stl_str_hl( // Store the info about tab pages labels. if (tabtab != NULL) { - struct stl_hlrec *sp = tabtab; + StlClickRecord *cur_tab_rec = tabtab; for (long l = 0; l < itemcnt; l++) { if (item[l].type == TabPage) { - sp->start = item[l].start; - sp->userhl = item[l].minwid; - sp++; + cur_tab_rec->start = (char *) item[l].start; + if (item[l].minwid == 0) { + cur_tab_rec->def.type = kStlClickDisabled; + cur_tab_rec->def.tabnr = 0; + } else { + int tabnr = item[l].minwid; + if (item[l].minwid > 0) { + cur_tab_rec->def.type = kStlClickTabSwitch; + } else { + cur_tab_rec->def.type = kStlClickTabClose; + tabnr = -tabnr; + } + cur_tab_rec->def.tabnr = tabnr; + } + cur_tab_rec->def.func = NULL; + cur_tab_rec++; + } else if (item[l].type == ClickFunc) { + cur_tab_rec->start = (char *) item[l].start; + cur_tab_rec->def.type = kStlClickFuncRun; + cur_tab_rec->def.tabnr = item[l].minwid; + cur_tab_rec->def.func = item[l].cmd; + cur_tab_rec++; } } - sp->start = NULL; - sp->userhl = 0; + cur_tab_rec->start = NULL; + cur_tab_rec->def.type = kStlClickDisabled; + cur_tab_rec->def.tabnr = 0; + cur_tab_rec->def.func = NULL; } return width; @@ -3852,6 +3906,11 @@ void get_rel_pos(win_T *wp, char_u *buf, int buflen) above = wp->w_topline - 1; above += diff_check_fill(wp, wp->w_topline) - wp->w_topfill; + if (wp->w_topline == 1 && wp->w_topfill >= 1) { + // All buffer lines are displayed and there is an indication + // of filler lines, that can be considered seeing all lines. + above = 0; + } below = wp->w_buffer->b_ml.ml_line_count - wp->w_botline + 1; if (below <= 0) STRLCPY(buf, (above == 0 ? _("All") : _("Bot")), buflen); @@ -4812,6 +4871,224 @@ void sign_mark_adjust(linenr_T line1, linenr_T line2, long amount, long amount_a } } +// bufhl: plugin highlights associated with a buffer + +/// Adds a highlight to buffer. +/// +/// Unlike matchaddpos() highlights follow changes to line numbering (as lines +/// are inserted/removed above the highlighted line), like signs and marks do. +/// +/// When called with "src_id" set to 0, a unique source id is generated and +/// returned. Succesive calls can pass it in as "src_id" to add new highlights +/// to the same source group. All highlights in the same group can be cleared +/// at once. If the highlight never will be manually deleted pass in -1 for +/// "src_id" +/// +/// if "hl_id" or "lnum" is invalid no highlight is added, but a new src_id +/// is still returned. +/// +/// @param buf The buffer to add highlights to +/// @param src_id src_id to use or 0 to use a new src_id group, +/// or -1 for ungrouped highlight. +/// @param hl_id Id of the highlight group to use +/// @param lnum The line to highlight +/// @param col_start First column to highlight +/// @param col_end The last column to highlight, +/// or -1 to highlight to end of line +/// @return The src_id that was used +int bufhl_add_hl(buf_T *buf, + int src_id, + int hl_id, + linenr_T lnum, + colnr_T col_start, + colnr_T col_end) { + static int next_src_id = 1; + if (src_id == 0) { + src_id = next_src_id++; + } + if (hl_id <= 0) { + // no highlight group or invalid line, just return src_id + return src_id; + } + if (!buf->b_bufhl_info) { + buf->b_bufhl_info = map_new(linenr_T, bufhl_vec_T)(); + } + bufhl_vec_T* lineinfo = map_ref(linenr_T, bufhl_vec_T)(buf->b_bufhl_info, + lnum, true); + + bufhl_hl_item_T *hlentry = kv_pushp(bufhl_hl_item_T, *lineinfo); + hlentry->src_id = src_id; + hlentry->hl_id = hl_id; + hlentry->start = col_start; + hlentry->stop = col_end; + + if (0 < lnum && lnum <= buf->b_ml.ml_line_count) { + changed_lines_buf(buf, lnum, lnum+1, 0); + redraw_buf_later(buf, VALID); + } + return src_id; +} + +/// Clear bufhl highlights from a given source group and range of lines. +/// +/// @param buf The buffer to remove highlights from +/// @param src_id highlight source group to clear, or -1 to clear all groups. +/// @param line_start first line to clear +/// @param line_end last line to clear or MAXLNUM to clear to end of file. +void bufhl_clear_line_range(buf_T *buf, + int src_id, + linenr_T line_start, + linenr_T line_end) { + if (!buf->b_bufhl_info) { + return; + } + linenr_T line; + linenr_T first_changed = MAXLNUM, last_changed = -1; + // In the case line_start - line_end << bufhl_info->size + // it might be better to reverse this, i e loop over the lines + // to clear on. + bufhl_vec_T unused; + map_foreach(buf->b_bufhl_info, line, unused, { + (void)unused; + if (line_start <= line && line <= line_end) { + if (bufhl_clear_line(buf->b_bufhl_info, src_id, line)) { + if (line > last_changed) { + last_changed = line; + } + if (line < first_changed) { + first_changed = line; + } + } + } + }) + + if (last_changed != -1) { + changed_lines_buf(buf, first_changed, last_changed+1, 0); + redraw_buf_later(buf, VALID); + } +} + +/// Clear bufhl highlights from a given source group and given line +/// +/// @param bufhl_info The highlight info for the buffer +/// @param src_id Highlight source group to clear, or -1 to clear all groups. +/// @param lnum Linenr where the highlight should be cleared +static bool bufhl_clear_line(bufhl_info_T *bufhl_info, int src_id, int lnum) { + bufhl_vec_T* lineinfo = map_ref(linenr_T, bufhl_vec_T)(bufhl_info, + lnum, false); + size_t oldsize = kv_size(*lineinfo); + if (src_id < 0) { + kv_size(*lineinfo) = 0; + } else { + size_t newind = 0; + for (size_t i = 0; i < kv_size(*lineinfo); i++) { + if (kv_A(*lineinfo, i).src_id != src_id) { + if (i != newind) { + kv_A(*lineinfo, newind) = kv_A(*lineinfo, i); + } + newind++; + } + } + kv_size(*lineinfo) = newind; + } + + if (kv_size(*lineinfo) == 0) { + kv_destroy(*lineinfo); + map_del(linenr_T, bufhl_vec_T)(bufhl_info, lnum); + } + return kv_size(*lineinfo) != oldsize; +} + +/// Remove all highlights and free the highlight data +void bufhl_clear_all(buf_T* buf) { + if (!buf->b_bufhl_info) { + return; + } + bufhl_clear_line_range(buf, -1, 1, MAXLNUM); + map_free(linenr_T, bufhl_vec_T)(buf->b_bufhl_info); + buf->b_bufhl_info = NULL; +} + +/// Adjust a placed highlight for inserted/deleted lines. +void bufhl_mark_adjust(buf_T* buf, + linenr_T line1, + linenr_T line2, + long amount, + long amount_after) { + if (!buf->b_bufhl_info) { + return; + } + + bufhl_info_T *newmap = map_new(linenr_T, bufhl_vec_T)(); + linenr_T line; + bufhl_vec_T lineinfo; + map_foreach(buf->b_bufhl_info, line, lineinfo, { + if (line >= line1 && line <= line2) { + if (amount == MAXLNUM) { + bufhl_clear_line(buf->b_bufhl_info, -1, line); + continue; + } else { + line += amount; + } + } else if (line > line2) { + line += amount_after; + } + map_put(linenr_T, bufhl_vec_T)(newmap, line, lineinfo); + }); + map_free(linenr_T, bufhl_vec_T)(buf->b_bufhl_info); + buf->b_bufhl_info = newmap; +} + + +/// Get highlights to display at a specific line +/// +/// @param buf The buffer handle +/// @param lnum The line number +/// @param[out] info The highligts for the line +/// @return true if there was highlights to display +bool bufhl_start_line(buf_T *buf, linenr_T lnum, bufhl_lineinfo_T *info) { + if (!buf->b_bufhl_info) { + return false; + } + + info->valid_to = -1; + info->entries = map_get(linenr_T, bufhl_vec_T)(buf->b_bufhl_info, lnum); + return kv_size(info->entries) > 0; +} + +/// get highlighting at column col +/// +/// It is is assumed this will be called with +/// non-decreasing column nrs, so that it is +/// possible to only recalculate highlights +/// at endpoints. +/// +/// @param info The info returned by bufhl_start_line +/// @param col The column to get the attr for +/// @return The highilight attr to display at the column +int bufhl_get_attr(bufhl_lineinfo_T *info, colnr_T col) { + if (col <= info->valid_to) { + return info->current; + } + int attr = 0; + info->valid_to = MAXCOL; + for (size_t i = 0; i < kv_size(info->entries); i++) { + bufhl_hl_item_T entry = kv_A(info->entries, i); + if (entry.start <= col && col <= entry.stop) { + int entry_attr = syn_id2attr(entry.hl_id); + attr = hl_combine_attr(attr, entry_attr); + if (entry.stop < info->valid_to) { + info->valid_to = entry.stop; + } + } else if (col < entry.start && entry.start-1 < info->valid_to) { + info->valid_to = entry.start-1; + } + } + info->current = attr; + return attr; +} + + /* * Set 'buflisted' for curbuf to "on" and trigger autocommands if it changed. */ diff --git a/src/nvim/buffer.h b/src/nvim/buffer.h index 49025d3925..d51a2f7dae 100644 --- a/src/nvim/buffer.h +++ b/src/nvim/buffer.h @@ -4,6 +4,7 @@ #include "nvim/window.h" #include "nvim/pos.h" // for linenr_T #include "nvim/ex_cmds_defs.h" // for exarg_T +#include "nvim/screen.h" // for StlClickRecord // Values for buflist_getfile() enum getf_values { diff --git a/src/nvim/buffer_defs.h b/src/nvim/buffer_defs.h index 78d9a9484e..936a14b903 100644 --- a/src/nvim/buffer_defs.h +++ b/src/nvim/buffer_defs.h @@ -28,6 +28,8 @@ typedef struct file_buffer buf_T; // Forward declaration #include "nvim/profile.h" // for String #include "nvim/api/private/defs.h" +// for Map(K, V) +#include "nvim/map.h" #define MODIFIABLE(buf) (!buf->terminal && buf->b_p_ma) @@ -59,21 +61,21 @@ typedef struct file_buffer buf_T; // Forward declaration #define VALID_BOTLINE_AP 0x40 /* w_botine is approximated */ #define VALID_TOPLINE 0x80 /* w_topline is valid (for cursor position) */ -/* flags for b_flags */ -#define BF_RECOVERED 0x01 /* buffer has been recovered */ -#define BF_CHECK_RO 0x02 /* need to check readonly when loading file - into buffer (set by ":e", may be reset by - ":buf" */ -#define BF_NEVERLOADED 0x04 /* file has never been loaded into buffer, - many variables still need to be set */ -#define BF_NOTEDITED 0x08 /* Set when file name is changed after - starting to edit, reset when file is - written out. */ -#define BF_NEW 0x10 /* file didn't exist when editing started */ -#define BF_NEW_W 0x20 /* Warned for BF_NEW and file created */ -#define BF_READERR 0x40 /* got errors while reading the file */ -#define BF_DUMMY 0x80 /* dummy buffer, only used internally */ -#define BF_PRESERVED 0x100 /* ":preserve" was used */ +// flags for b_flags +#define BF_RECOVERED 0x01 // buffer has been recovered +#define BF_CHECK_RO 0x02 // need to check readonly when loading file + // into buffer (set by ":e", may be reset by + // ":buf") +#define BF_NEVERLOADED 0x04 // file has never been loaded into buffer, + // many variables still need to be set +#define BF_NOTEDITED 0x08 // Set when file name is changed after + // starting to edit, reset when file is + // written out. +#define BF_NEW 0x10 // file didn't exist when editing started +#define BF_NEW_W 0x20 // Warned for BF_NEW and file created +#define BF_READERR 0x40 // got errors while reading the file +#define BF_DUMMY 0x80 // dummy buffer, only used internally +#define BF_PRESERVED 0x100 // ":preserve" was used /* Mask to check for flags that prevent normal writing */ #define BF_WRITE_MASK (BF_NOTEDITED + BF_NEW + BF_READERR) @@ -101,6 +103,11 @@ typedef int scid_T; /* script ID */ // for signlist_T #include "nvim/sign_defs.h" +// for bufhl_*_T +#include "nvim/bufhl_defs.h" + +typedef Map(linenr_T, bufhl_vec_T) bufhl_info_T; + // for FileID #include "nvim/os/fs_defs.h" @@ -592,71 +599,72 @@ struct file_buffer { int b_p_scriptID[BV_COUNT]; /* SIDs for buffer-local options */ - int b_p_ai; /* 'autoindent' */ - int b_p_ai_nopaste; /* b_p_ai saved for paste mode */ - char_u *b_p_bkc; ///< 'backupcopy' - unsigned int b_bkc_flags; ///< flags for 'backupcopy' - int b_p_ci; /* 'copyindent' */ - int b_p_bin; /* 'binary' */ - int b_p_bomb; /* 'bomb' */ - char_u *b_p_bh; /* 'bufhidden' */ - char_u *b_p_bt; /* 'buftype' */ - int b_p_bl; /* 'buflisted' */ - int b_p_cin; /* 'cindent' */ - char_u *b_p_cino; /* 'cinoptions' */ - char_u *b_p_cink; /* 'cinkeys' */ - char_u *b_p_cinw; /* 'cinwords' */ - char_u *b_p_com; /* 'comments' */ - char_u *b_p_cms; /* 'commentstring' */ - char_u *b_p_cpt; /* 'complete' */ - char_u *b_p_cfu; /* 'completefunc' */ - char_u *b_p_ofu; /* 'omnifunc' */ - int b_p_eol; /* 'endofline' */ - int b_p_fixeol; /* 'fixendofline' */ - int b_p_et; /* 'expandtab' */ - int b_p_et_nobin; /* b_p_et saved for binary mode */ - char_u *b_p_fenc; /* 'fileencoding' */ - char_u *b_p_ff; /* 'fileformat' */ - char_u *b_p_ft; /* 'filetype' */ - char_u *b_p_fo; /* 'formatoptions' */ - char_u *b_p_flp; /* 'formatlistpat' */ - int b_p_inf; /* 'infercase' */ - char_u *b_p_isk; /* 'iskeyword' */ - char_u *b_p_def; /* 'define' local value */ - char_u *b_p_inc; /* 'include' */ - char_u *b_p_inex; /* 'includeexpr' */ - uint32_t b_p_inex_flags; /* flags for 'includeexpr' */ - char_u *b_p_inde; /* 'indentexpr' */ - uint32_t b_p_inde_flags; /* flags for 'indentexpr' */ - char_u *b_p_indk; /* 'indentkeys' */ - char_u *b_p_fex; /* 'formatexpr' */ - uint32_t b_p_fex_flags; /* flags for 'formatexpr' */ - char_u *b_p_kp; /* 'keywordprg' */ - int b_p_lisp; /* 'lisp' */ - char_u *b_p_mps; /* 'matchpairs' */ - int b_p_ml; /* 'modeline' */ - int b_p_ml_nobin; /* b_p_ml saved for binary mode */ - int b_p_ma; /* 'modifiable' */ - char_u *b_p_nf; /* 'nrformats' */ - int b_p_pi; /* 'preserveindent' */ - char_u *b_p_qe; /* 'quoteescape' */ - int b_p_ro; /* 'readonly' */ - long b_p_sw; /* 'shiftwidth' */ - int b_p_si; /* 'smartindent' */ - long b_p_sts; /* 'softtabstop' */ - long b_p_sts_nopaste; /* b_p_sts saved for paste mode */ - char_u *b_p_sua; /* 'suffixesadd' */ - bool b_p_swf; /* 'swapfile' */ - long b_p_smc; /* 'synmaxcol' */ - char_u *b_p_syn; /* 'syntax' */ - long b_p_ts; /* 'tabstop' */ - long b_p_tw; /* 'textwidth' */ - long b_p_tw_nobin; /* b_p_tw saved for binary mode */ - long b_p_tw_nopaste; /* b_p_tw saved for paste mode */ - long b_p_wm; /* 'wrapmargin' */ - long b_p_wm_nobin; /* b_p_wm saved for binary mode */ - long b_p_wm_nopaste; /* b_p_wm saved for paste mode */ - char_u *b_p_keymap; /* 'keymap' */ + int b_p_ai; ///< 'autoindent' + int b_p_ai_nopaste; ///< b_p_ai saved for paste mode + char_u *b_p_bkc; ///< 'backupco + unsigned int b_bkc_flags; ///< flags for 'backupco + int b_p_ci; ///< 'copyindent' + int b_p_bin; ///< 'binary' + int b_p_bomb; ///< 'bomb' + char_u *b_p_bh; ///< 'bufhidden' + char_u *b_p_bt; ///< 'buftype' + int b_p_bl; ///< 'buflisted' + int b_p_cin; ///< 'cindent' + char_u *b_p_cino; ///< 'cinoptions' + char_u *b_p_cink; ///< 'cinkeys' + char_u *b_p_cinw; ///< 'cinwords' + char_u *b_p_com; ///< 'comments' + char_u *b_p_cms; ///< 'commentstring' + char_u *b_p_cpt; ///< 'complete' + char_u *b_p_cfu; ///< 'completefunc' + char_u *b_p_ofu; ///< 'omnifunc' + int b_p_eol; ///< 'endofline' + int b_p_fixeol; ///< 'fixendofline' + int b_p_et; ///< 'expandtab' + int b_p_et_nobin; ///< b_p_et saved for binary mode + int b_p_et_nopaste; ///< b_p_et saved for paste mode + char_u *b_p_fenc; ///< 'fileencoding' + char_u *b_p_ff; ///< 'fileformat' + char_u *b_p_ft; ///< 'filetype' + char_u *b_p_fo; ///< 'formatoptions' + char_u *b_p_flp; ///< 'formatlistpat' + int b_p_inf; ///< 'infercase' + char_u *b_p_isk; ///< 'iskeyword' + char_u *b_p_def; ///< 'define' local value + char_u *b_p_inc; ///< 'include' + char_u *b_p_inex; ///< 'includeexpr' + uint32_t b_p_inex_flags; ///< flags for 'includeexpr' + char_u *b_p_inde; ///< 'indentexpr' + uint32_t b_p_inde_flags; ///< flags for 'indentexpr' + char_u *b_p_indk; ///< 'indentkeys' + char_u *b_p_fex; ///< 'formatexpr' + uint32_t b_p_fex_flags; ///< flags for 'formatexpr' + char_u *b_p_kp; ///< 'keywordprg' + int b_p_lisp; ///< 'lisp' + char_u *b_p_mps; ///< 'matchpairs' + int b_p_ml; ///< 'modeline' + int b_p_ml_nobin; ///< b_p_ml saved for binary mode + int b_p_ma; ///< 'modifiable' + char_u *b_p_nf; ///< 'nrformats' + int b_p_pi; ///< 'preserveindent' + char_u *b_p_qe; ///< 'quoteescape' + int b_p_ro; ///< 'readonly' + long b_p_sw; ///< 'shiftwidth' + int b_p_si; ///< 'smartindent' + long b_p_sts; ///< 'softtabstop' + long b_p_sts_nopaste; ///< b_p_sts saved for paste mode + char_u *b_p_sua; ///< 'suffixesadd' + bool b_p_swf; ///< 'swapfile' + long b_p_smc; ///< 'synmaxcol' + char_u *b_p_syn; ///< 'syntax' + long b_p_ts; ///< 'tabstop' + long b_p_tw; ///< 'textwidth' + long b_p_tw_nobin; ///< b_p_tw saved for binary mode + long b_p_tw_nopaste; ///< b_p_tw saved for paste mode + long b_p_wm; ///< 'wrapmargin' + long b_p_wm_nobin; ///< b_p_wm saved for binary mode + 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 */ @@ -753,6 +761,8 @@ struct file_buffer { dict_T *additional_data; // Additional data from shada file if any. int b_mapped_ctrl_c; // modes where CTRL-C is mapped + + bufhl_info_T *b_bufhl_info; // buffer stored highlights }; /* @@ -904,13 +914,14 @@ struct posmatch typedef struct matchitem matchitem_T; struct matchitem { matchitem_T *next; - int id; /* match ID */ - int priority; /* match priority */ - char_u *pattern; /* pattern to highlight */ - int hlg_id; /* highlight group ID */ - regmmatch_T match; /* regexp program for pattern */ - posmatch_T pos; // position matches - match_T hl; /* struct for doing the actual highlighting */ + int id; ///< match ID + int priority; ///< match priority + char_u *pattern; ///< pattern to highlight + int hlg_id; ///< highlight group ID + regmmatch_T match; ///< regexp program for pattern + posmatch_T pos; ///< position matches + match_T hl; ///< struct for doing the actual highlighting + int conceal_char; ///< cchar for Conceal highlighting }; /* diff --git a/src/nvim/bufhl_defs.h b/src/nvim/bufhl_defs.h new file mode 100644 index 0000000000..e47bb2a238 --- /dev/null +++ b/src/nvim/bufhl_defs.h @@ -0,0 +1,25 @@ +#ifndef NVIM_BUFHL_DEFS_H +#define NVIM_BUFHL_DEFS_H + +#include "nvim/pos.h" +#include "nvim/lib/kvec.h" +// bufhl: buffer specific highlighting + +struct bufhl_hl_item +{ + int src_id; + int hl_id; // highlight group + colnr_T start; // first column to highlight + colnr_T stop; // last column to highlight +}; +typedef struct bufhl_hl_item bufhl_hl_item_T; + +typedef kvec_t(struct bufhl_hl_item) bufhl_vec_T; + +typedef struct { + bufhl_vec_T entries; + int current; + colnr_T valid_to; +} bufhl_lineinfo_T; + +#endif // NVIM_BUFHL_DEFS_H diff --git a/src/nvim/charset.c b/src/nvim/charset.c index 9a0e1440cc..4e329b5cd8 100644 --- a/src/nvim/charset.c +++ b/src/nvim/charset.c @@ -799,32 +799,35 @@ unsigned int win_linetabsize(win_T *wp, char_u *line, colnr_T len) return (unsigned int)col; } -/// Return TRUE if 'c' is a normal identifier character: -/// +/// Check that "c" is a normal identifier character: /// Letters and characters from the 'isident' option. /// -/// @param c -/// -/// @return TRUE if 'c' is a normal identifier character. -int vim_isIDc(int c) +/// @param c character to check +bool vim_isIDc(int c) + FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT { return c > 0 && c < 0x100 && (chartab[c] & CT_ID_CHAR); } -/// return TRUE if 'c' is a keyword character: Letters and characters from -/// 'iskeyword' option for current buffer. -/// +/// Check that "c" is a keyword character: +/// Letters and characters from 'iskeyword' option for current buffer. /// For multi-byte characters mb_get_class() is used (builtin rules). /// -/// @param c -/// -/// @return TRUE if 'c' is a keyword character. -int vim_iswordc(int c) +/// @param c character to check +bool vim_iswordc(int c) + FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT { return vim_iswordc_buf(c, curbuf); } -int vim_iswordc_buf(int c, buf_T *buf) +/// Check that "c" is a keyword character: +/// Letters and characters from 'iskeyword' option for given buffer. +/// For multi-byte characters mb_get_class() is used (builtin rules). +/// +/// @param c character to check +/// @param buf buffer whose keywords to use +bool vim_iswordc_buf(int c, buf_T *buf) + FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ARG(2) { if (c >= 0x100) { if (enc_dbcs != 0) { @@ -840,10 +843,11 @@ int vim_iswordc_buf(int c, buf_T *buf) /// Just like vim_iswordc() but uses a pointer to the (multi-byte) character. /// -/// @param p +/// @param p pointer to the multi-byte character /// -/// @return TRUE if 'p' points to a keyword character. -int vim_iswordp(char_u *p) +/// @return true if "p" points to a keyword character. +bool vim_iswordp(char_u *p) + FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL { if (has_mbyte && (MB_BYTE2LEN(*p) > 1)) { return mb_get_class(p) >= 2; @@ -851,7 +855,15 @@ int vim_iswordp(char_u *p) return GET_CHARTAB(curbuf, *p) != 0; } -int vim_iswordp_buf(char_u *p, buf_T *buf) +/// Just like vim_iswordc_buf() but uses a pointer to the (multi-byte) +/// character. +/// +/// @param p pointer to the multi-byte character +/// @param buf buffer whose keywords to use +/// +/// @return true if "p" points to a keyword character. +bool vim_iswordp_buf(char_u *p, buf_T *buf) + FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL { if (has_mbyte && (MB_BYTE2LEN(*p) > 1)) { return mb_get_class(p) >= 2; @@ -859,26 +871,24 @@ int vim_iswordp_buf(char_u *p, buf_T *buf) return GET_CHARTAB(buf, *p) != 0; } -/// return TRUE if 'c' is a valid file-name character +/// Check that "c" is a valid file-name character. /// Assume characters above 0x100 are valid (multi-byte). /// -/// @param c -/// -/// @return TRUE if 'c' is a valid file name character. -int vim_isfilec(int c) +/// @param c character to check +bool vim_isfilec(int c) + FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT { return c >= 0x100 || (c > 0 && (chartab[c] & CT_FNAME_CHAR)); } -/// return TRUE if 'c' is a valid file-name character or a wildcard character +/// Check that "c" is a valid file-name character or a wildcard character /// Assume characters above 0x100 are valid (multi-byte). /// Explicitly interpret ']' as a wildcard character as path_has_wildcard("]") /// returns false. /// -/// @param c -/// -/// @return TRUE if 'c' is a valid file-name character or wildcard character. -int vim_isfilec_or_wc(int c) +/// @param c character to check +bool vim_isfilec_or_wc(int c) + FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT { char_u buf[2]; buf[0] = (char_u)c; @@ -886,14 +896,12 @@ int vim_isfilec_or_wc(int c) return vim_isfilec(c) || c == ']' || path_has_wildcard(buf); } -/// return TRUE if 'c' is a printable character -/// Assume characters above 0x100 are printable (multi-byte), except for -/// Unicode. -/// -/// @param c +/// Check that "c" is a printable character. +/// Assume characters above 0x100 are printable for double-byte encodings. /// -/// @return TRUE if 'c' a printable character. -int vim_isprintc(int c) +/// @param c character to check +bool vim_isprintc(int c) + FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT { if (enc_utf8 && (c >= 0x100)) { return utf_printable(c); @@ -901,16 +909,17 @@ int vim_isprintc(int c) return c >= 0x100 || (c > 0 && (chartab[c] & CT_PRINT_CHAR)); } -/// Strict version of vim_isprintc(c), don't return TRUE if "c" is the head +/// Strict version of vim_isprintc(c), don't return true if "c" is the head /// byte of a double-byte character. /// -/// @param c +/// @param c character to check /// -/// @return TRUE if 'c' is a printable character. -int vim_isprintc_strict(int c) +/// @return true if "c" is a printable character. +bool vim_isprintc_strict(int c) + FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT { if ((enc_dbcs != 0) && (c < 0x100) && (MB_BYTE2LEN(c) > 1)) { - return FALSE; + return false; } if (enc_utf8 && (c >= 0x100)) { @@ -921,7 +930,7 @@ int vim_isprintc_strict(int c) /// like chartabsize(), but also check for line breaks on the screen /// -/// @param line +/// @param line /// @param s /// @param col /// @@ -1144,35 +1153,33 @@ static int win_nolbr_chartabsize(win_T *wp, char_u *s, colnr_T col, int *headp) return n; } -/// Return TRUE if virtual column "vcol" is in the rightmost column of window -/// "wp". +/// Check that virtual column "vcol" is in the rightmost column of window "wp". /// -/// @param wp -/// @param vcol -/// -/// @return TRUE if the virtual column is in the rightmost column. -int in_win_border(win_T *wp, colnr_T vcol) +/// @param wp window +/// @param vcol column number +bool in_win_border(win_T *wp, colnr_T vcol) + FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ARG(1) { int width1; // width of first line (after line number) int width2; // width of further lines if (wp->w_width == 0) { // there is no border - return FALSE; + return false; } width1 = wp->w_width - win_col_off(wp); if ((int)vcol < width1 - 1) { - return FALSE; + return false; } if ((int)vcol == width1 - 1) { - return TRUE; + return true; } width2 = width1 + win_col_off2(wp); if (width2 <= 0) { - return FALSE; + return false; } return (vcol - width1) % width2 == width2 - 1; } @@ -1571,10 +1578,14 @@ static char_u latin1lower[257] = "\xdf\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee" "\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff"; -int vim_islower(int c) +/// Check that the character is lower-case +/// +/// @param c character to check +bool vim_islower(int c) + FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL { if (c <= '@') { - return FALSE; + return false; } if (c >= 0x80) { @@ -1588,7 +1599,7 @@ int vim_islower(int c) } // islower() can't handle these chars and may crash - return FALSE; + return false; } if (enc_latin1like) { @@ -1598,10 +1609,14 @@ int vim_islower(int c) return islower(c); } -int vim_isupper(int c) +/// Check that the character is upper-case +/// +/// @param c character to check +bool vim_isupper(int c) + FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL { if (c <= '@') { - return FALSE; + return false; } if (c >= 0x80) { @@ -1614,8 +1629,8 @@ int vim_isupper(int c) return iswupper(c); } - // islower() can't handle these chars and may crash - return FALSE; + // isupper() can't handle these chars and may crash + return false; } if (enc_latin1like) { @@ -1744,12 +1759,10 @@ long getdigits_long(char_u **pp) return (long)number; } -/// Return TRUE if "lbuf" is empty or only contains blanks. -/// -/// @param lbuf +/// Check that "lbuf" is empty or only contains blanks. /// -/// @return TRUE if `lbuf` is empty or only contains blanks. -int vim_isblankline(char_u *lbuf) +/// @param lbuf line buffer to check +bool vim_isblankline(char_u *lbuf) { char_u *p = skipwhite(lbuf); return *p == NUL || *p == '\r' || *p == '\n'; @@ -1922,8 +1935,8 @@ int hex2nr(int c) return c - '0'; } -/// Return true if "str" starts with a backslash that should be removed. -/// For WIN32 this is only done when the character after the +/// Check that "str" starts with a backslash that should be removed. +/// For Windows this is only done when the character after the /// backslash is not a normal file name character. /// '$' is a valid file name character, we don't remove the backslash before /// it. This means it is not possible to use an environment variable after a @@ -1934,10 +1947,9 @@ int hex2nr(int c) /// character, assume that all multi-byte characters are valid file name /// characters. /// -/// @param str -/// -/// @return true if `str` starts with a backslash that should be removed. +/// @param str file path string to check bool rem_backslash(const char_u *str) + FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL { #ifdef BACKSLASH_IN_FILENAME return str[0] == '\\' diff --git a/src/nvim/diff.c b/src/nvim/diff.c index ce79158050..0be8b3c514 100644 --- a/src/nvim/diff.c +++ b/src/nvim/diff.c @@ -763,8 +763,8 @@ void ex_diffupdate(exarg_T *eap) // Make a difference between the first buffer and every other. for (idx_new = idx_orig + 1; idx_new < DB_COUNT; ++idx_new) { buf_T *buf = curtab->tp_diffbuf[idx_new]; - if (buf == NULL) { - continue; + if (buf == NULL || buf->b_ml.ml_mfp == NULL) { + continue; // skip buffer that isn't loaded } if (diff_write(buf, tmp_new) == FAIL) { @@ -1057,27 +1057,28 @@ void diff_win_options(win_T *wp, int addbuf) newFoldLevel(); curwin = old_curwin; - wp->w_p_diff = TRUE; - // Use 'scrollbind' and 'cursorbind' when available - if (!wp->w_p_diff_saved) { + if (!wp->w_p_diff) { wp->w_p_scb_save = wp->w_p_scb; } wp->w_p_scb = TRUE; - if (!wp->w_p_diff_saved) { + if (!wp->w_p_diff) { wp->w_p_crb_save = wp->w_p_crb; } wp->w_p_crb = TRUE; - if (!wp->w_p_diff_saved) { + if (!wp->w_p_diff) { wp->w_p_wrap_save = wp->w_p_wrap; } wp->w_p_wrap = FALSE; curwin = wp; curbuf = curwin->w_buffer; - if (!wp->w_p_diff_saved) { + if (!wp->w_p_diff) { + if (wp->w_p_diff_saved) { + free_string_option(wp->w_p_fdm_save); + } wp->w_p_fdm_save = vim_strsave(wp->w_p_fdm); } set_string_option_direct((char_u *)"fdm", -1, (char_u *)"diff", @@ -1085,7 +1086,7 @@ void diff_win_options(win_T *wp, int addbuf) curwin = old_curwin; curbuf = curwin->w_buffer; - if (!wp->w_p_diff_saved) { + if (!wp->w_p_diff) { wp->w_p_fdc_save = wp->w_p_fdc; wp->w_p_fen_save = wp->w_p_fen; wp->w_p_fdl_save = wp->w_p_fdl; @@ -1104,6 +1105,8 @@ void diff_win_options(win_T *wp, int addbuf) // Saved the current values, to be restored in ex_diffoff(). wp->w_p_diff_saved = TRUE; + wp->w_p_diff = true; + if (addbuf) { diff_buf_add(wp->w_buffer); } @@ -1116,68 +1119,50 @@ void diff_win_options(win_T *wp, int addbuf) /// @param eap void ex_diffoff(exarg_T *eap) { - win_T *old_curwin = curwin; - int diffwin = FALSE; + int diffwin = false; FOR_ALL_WINDOWS_IN_TAB(wp, curtab) { if (eap->forceit ? wp->w_p_diff : (wp == curwin)) { - // Set 'diff', 'scrollbind' off and 'wrap' on. If option values - // were saved in diff_win_options() restore them. - wp->w_p_diff = FALSE; - - if (wp->w_p_scb) { - wp->w_p_scb = wp->w_p_diff_saved ? wp->w_p_scb_save : FALSE; - } - - if (wp->w_p_crb) { - wp->w_p_crb = wp->w_p_diff_saved ? wp->w_p_crb_save : FALSE; - } - - if (!wp->w_p_wrap) { - wp->w_p_wrap = wp->w_p_diff_saved ? wp->w_p_wrap_save : TRUE; - } - curwin = wp; - curbuf = curwin->w_buffer; + // Set 'diff' off. If option values were saved in + // diff_win_options(), restore the ones whose settings seem to have + // been left over from diff mode. + wp->w_p_diff = false; if (wp->w_p_diff_saved) { - free_string_option(wp->w_p_fdm); - wp->w_p_fdm = wp->w_p_fdm_save; - wp->w_p_fdm_save = empty_option; - } else { - set_string_option_direct((char_u *)"fdm", -1, - (char_u *)"manual", OPT_LOCAL | OPT_FREE, 0); - } - curwin = old_curwin; - curbuf = curwin->w_buffer; + if (wp->w_p_scb) { + wp->w_p_scb = wp->w_p_scb_save; + } - if (wp->w_p_fdc == diff_foldcolumn) { - wp->w_p_fdc = wp->w_p_diff_saved ? wp->w_p_fdc_save : 0; - } + if (wp->w_p_crb) { + wp->w_p_crb = wp->w_p_crb_save; + } - if ((wp->w_p_fdl == 0) - && wp->w_p_diff_saved) { - wp->w_p_fdl = wp->w_p_fdl_save; - } + if (!wp->w_p_wrap) { + wp->w_p_wrap = wp->w_p_wrap_save; + } - if (wp->w_p_fen) { + free_string_option(wp->w_p_fdm); + wp->w_p_fdm = vim_strsave(wp->w_p_fdm_save); + if (wp->w_p_fdc == diff_foldcolumn) { + wp->w_p_fdc = wp->w_p_fdc_save; + } + if (wp->w_p_fdl == 0) { + wp->w_p_fdl = wp->w_p_fdl_save; + } // Only restore 'foldenable' when 'foldmethod' is not // "manual", otherwise we continue to show the diff folds. - if (foldmethodIsManual(wp) || !wp->w_p_diff_saved) { - wp->w_p_fen = FALSE; - } else { - wp->w_p_fen = wp->w_p_fen_save; + if (wp->w_p_fen) { + wp->w_p_fen = foldmethodIsManual(wp) ? false : wp->w_p_fen_save; } - } - foldUpdateAll(wp); + foldUpdateAll(wp); - // make sure topline is not halfway through a fold - changed_window_setting_win(wp); + // make sure topline is not halfway through a fold + changed_window_setting_win(wp); + } // Note: 'sbo' is not restored, it's a global option. diff_buf_adjust(wp); - - wp->w_p_diff_saved = FALSE; } diffwin |= wp->w_p_diff; } @@ -1546,37 +1531,37 @@ int diff_check(win_T *wp, linenr_T lnum) return maxcount - dp->df_count[idx]; } -/// Compare two entries in diff "*dp" and return TRUE if they are equal. +/// Compare two entries in diff "dp" and return true if they are equal. /// -/// @param dp -/// @param idx1 First entry in diff "*dp" -/// @param idx2 Second entry in diff "*dp" +/// @param dp diff +/// @param idx1 first entry in diff "dp" +/// @param idx2 second entry in diff "dp" /// -/// @return return TRUE if two entires are equal. -static int diff_equal_entry(diff_T *dp, int idx1, int idx2) +/// @return true if two entires are equal. +static bool diff_equal_entry(diff_T *dp, int idx1, int idx2) + FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ARG(1) { if (dp->df_count[idx1] != dp->df_count[idx2]) { - return FALSE; + return false; } if (diff_check_sanity(curtab, dp) == FAIL) { - return FALSE; + return false; } - int i; - for (i = 0; i < dp->df_count[idx1]; ++i) { + for (int i = 0; i < dp->df_count[idx1]; i++) { char_u *line = vim_strsave(ml_get_buf(curtab->tp_diffbuf[idx1], - dp->df_lnum[idx1] + i, FALSE)); + dp->df_lnum[idx1] + i, false)); int cmp = diff_cmp(line, ml_get_buf(curtab->tp_diffbuf[idx2], - dp->df_lnum[idx2] + i, FALSE)); + dp->df_lnum[idx2] + i, false)); xfree(line); if (cmp != 0) { - return FALSE; + return false; } } - return TRUE; + return true; } /// Compare strings "s1" and "s2" according to 'diffopt'. @@ -1845,28 +1830,30 @@ int diffopt_changed(void) return OK; } -/// Return TRUE if 'diffopt' contains "horizontal". -/// -/// @return TRUE if 'diffopt' contains "horizontal" -int diffopt_horizontal(void) +/// Check that "diffopt" contains "horizontal". +bool diffopt_horizontal(void) + FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT { return (diff_flags & DIFF_HORIZONTAL) != 0; } /// Find the difference within a changed line. /// -/// @param startp first char of the change -/// @param endp last char of the change +/// @param wp window whose current buffer to check +/// @param lnum line number to check within the buffer +/// @param startp first char of the change +/// @param endp last char of the change /// -/// @returns TRUE if the line was added, no other buffer has it. -int diff_find_change(win_T *wp, linenr_T lnum, int *startp, int *endp) +/// @return true if the line was added, no other buffer has it. +bool diff_find_change(win_T *wp, linenr_T lnum, int *startp, int *endp) + FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL { char_u *line_new; int si_org; int si_new; int ei_org; int ei_new; - int added = TRUE; + bool added = true; // Make a copy of the line, the next ml_get() will invalidate it. char_u *line_org = vim_strsave(ml_get_buf(wp->w_buffer, lnum, FALSE)); @@ -1875,7 +1862,7 @@ int diff_find_change(win_T *wp, linenr_T lnum, int *startp, int *endp) if (idx == DB_COUNT) { // cannot happen xfree(line_org); - return FALSE; + return false; } // search for a change that includes "lnum" in the list of diffblocks. @@ -1888,7 +1875,7 @@ int diff_find_change(win_T *wp, linenr_T lnum, int *startp, int *endp) if ((dp == NULL) || (diff_check_sanity(curtab, dp) == FAIL)) { xfree(line_org); - return FALSE; + return false; } int off = lnum - dp->df_lnum[idx]; @@ -1899,7 +1886,7 @@ int diff_find_change(win_T *wp, linenr_T lnum, int *startp, int *endp) if (off >= dp->df_count[i]) { continue; } - added = FALSE; + added = false; line_new = ml_get_buf(curtab->tp_diffbuf[i], dp->df_lnum[i] + off, FALSE); @@ -1971,21 +1958,22 @@ int diff_find_change(win_T *wp, linenr_T lnum, int *startp, int *endp) return added; } -/// Return TRUE if line "lnum" is not close to a diff block, this line should +/// Check that line "lnum" is not close to a diff block, this line should /// be in a fold. /// -/// @param wp -/// @param lnum +/// @param wp window containing the buffer to check +/// @param lnum line number to check within the buffer /// -/// @return FALSE if there are no diff blocks at all in this window. -int diff_infold(win_T *wp, linenr_T lnum) +/// @return false if there are no diff blocks at all in this window. +bool diff_infold(win_T *wp, linenr_T lnum) + FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ARG(1) { - int other = FALSE; + bool other = false; diff_T *dp; // Return if 'diff' isn't set. if (!wp->w_p_diff) { - return FALSE; + return false; } int idx = -1; @@ -1994,13 +1982,13 @@ int diff_infold(win_T *wp, linenr_T lnum) if (curtab->tp_diffbuf[i] == wp->w_buffer) { idx = i; } else if (curtab->tp_diffbuf[i] != NULL) { - other = TRUE; + other = true; } } // return here if there are no diffs in the window if ((idx == -1) || !other) { - return FALSE; + return false; } if (curtab->tp_diff_invalid) { @@ -2010,7 +1998,7 @@ int diff_infold(win_T *wp, linenr_T lnum) // Return if there are no diff blocks. All lines will be folded. if (curtab->tp_first_diff == NULL) { - return TRUE; + return true; } for (dp = curtab->tp_first_diff; dp != NULL; dp = dp->df_next) { @@ -2021,10 +2009,10 @@ int diff_infold(win_T *wp, linenr_T lnum) // If this change ends before the line we have a match. if (dp->df_lnum[idx] + dp->df_count[idx] + diff_context > lnum) { - return FALSE; + return false; } } - return TRUE; + return true; } /// "dp" and "do" commands. @@ -2387,12 +2375,11 @@ static void diff_fold_update(diff_T *dp, int skip_idx) } } -/// Checks if the buffer is in diff-mode. -/// -/// @param buf The buffer to check. +/// Checks that the buffer is in diff-mode. /// -/// @return TRUE if buffer "buf" is in diff-mode. +/// @param buf buffer to check. bool diff_mode_buf(buf_T *buf) + FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ARG(1) { FOR_ALL_TABS(tp) { if (diff_buf_idx_tp(buf, tp) != DB_COUNT) { diff --git a/src/nvim/edit.c b/src/nvim/edit.c index dbbcf4f1b9..6313ea2e81 100644 --- a/src/nvim/edit.c +++ b/src/nvim/edit.c @@ -1247,7 +1247,7 @@ normalchar: static void insert_do_complete(InsertState *s) { compl_busy = true; - if (ins_complete(s->c) == FAIL) { + if (ins_complete(s->c, true) == FAIL) { compl_cont_status = 0; } compl_busy = false; @@ -2321,9 +2321,10 @@ static int ins_compl_make_cyclic(void) */ void set_completion(colnr_T startcol, list_T *list) { - /* If already doing completions stop it. */ - if (ctrl_x_mode != 0) + // If already doing completions stop it. + if (ctrl_x_mode != 0) { ins_compl_prep(' '); + } ins_compl_clear(); if (stop_arrow() == FAIL) @@ -2349,16 +2350,23 @@ void set_completion(colnr_T startcol, list_T *list) compl_started = TRUE; compl_used_match = TRUE; compl_cont_status = 0; + int save_w_wrow = curwin->w_wrow; compl_curr_match = compl_first_match; if (compl_no_insert) { - ins_complete(K_DOWN); + ins_complete(K_DOWN, false); } else { - ins_complete(Ctrl_N); + ins_complete(Ctrl_N, false); if (compl_no_select) { - ins_complete(Ctrl_P); + ins_complete(Ctrl_P, false); } } + + // Lazily show the popup menu, unless we got interrupted. + if (!compl_interrupted) { + show_pum(save_w_wrow); + } + ui_flush(); } @@ -2464,6 +2472,14 @@ void ins_compl_show_pum(void) /* Need to build the popup menu list. */ compl_match_arraysize = 0; compl = compl_first_match; + /* + * If it's user complete function and refresh_always, + * not use "compl_leader" as prefix filter. + */ + if (ins_compl_need_restart()){ + xfree(compl_leader); + compl_leader = NULL; + } if (compl_leader != NULL) lead_len = (int)STRLEN(compl_leader); do { @@ -2548,8 +2564,12 @@ void ins_compl_show_pum(void) } } - /* Compute the screen column of the start of the completed text. - * Use the cursor to get all wrapping and other settings right. */ + // In Replace mode when a $ is displayed at the end of the line only + // part of the screen would be updated. We do need to redraw here. + dollar_vcol = -1; + + // Compute the screen column of the start of the completed text. + // Use the cursor to get all wrapping and other settings right. col = curwin->w_cursor.col; curwin->w_cursor.col = compl_col; pum_display(compl_match_array, compl_match_arraysize, cur); @@ -2923,20 +2943,17 @@ static void ins_compl_new_leader(void) ins_bytes(compl_leader + ins_compl_len()); compl_used_match = FALSE; - if (compl_started) + if (compl_started) { ins_compl_set_original_text(compl_leader); - else { - spell_bad_len = 0; /* need to redetect bad word */ - /* - * Matches were cleared, need to search for them now. First display - * the changed text before the cursor. Set "compl_restarting" to - * avoid that the first match is inserted. - */ - update_screen(0); - compl_restarting = TRUE; - if (ins_complete(Ctrl_N) == FAIL) + } else { + spell_bad_len = 0; // need to redetect bad word + // Matches were cleared, need to search for them now. + // Set "compl_restarting" to avoid that the first match is inserted. + compl_restarting = true; + if (ins_complete(Ctrl_N, true) == FAIL) { compl_cont_status = 0; - compl_restarting = FALSE; + } + compl_restarting = false; } compl_enter_selects = !compl_used_match; @@ -2944,8 +2961,9 @@ static void ins_compl_new_leader(void) /* Show the popup menu with a different set of matches. */ ins_compl_show_pum(); - /* Don't let Enter select the original text when there is no popup menu. */ - if (compl_match_array == NULL) + /* Don't let Enter select the original text when there is no popup menu. + * Don't let Enter select when use user function and refresh_always is set */ + if (compl_match_array == NULL || ins_compl_need_restart()) compl_enter_selects = FALSE; } @@ -2976,27 +2994,18 @@ static void ins_compl_addleader(int c) (*mb_char2bytes)(c, buf); buf[cc] = NUL; ins_char_bytes(buf, cc); - if (compl_opt_refresh_always) - AppendToRedobuff(buf); } else { ins_char(c); - if (compl_opt_refresh_always) - AppendCharToRedobuff(c); } /* If we didn't complete finding matches we must search again. */ if (ins_compl_need_restart()) ins_compl_restart(); - /* When 'always' is set, don't reset compl_leader. While completing, - * cursor doesn't point original position, changing compl_leader would - * break redo. */ - if (!compl_opt_refresh_always) { - xfree(compl_leader); - compl_leader = vim_strnsave(get_cursor_line_ptr() + compl_col, - (int)(curwin->w_cursor.col - compl_col)); - ins_compl_new_leader(); - } + xfree(compl_leader); + compl_leader = vim_strnsave(get_cursor_line_ptr() + compl_col, + (int)(curwin->w_cursor.col - compl_col)); + ins_compl_new_leader(); } /* @@ -3005,6 +3014,10 @@ static void ins_compl_addleader(int c) */ static void ins_compl_restart(void) { + /* update screen before restart. + * so if complete is blocked, + * will stay to the last popup menu and reduce flicker */ + update_screen(0); ins_compl_free(); compl_started = FALSE; compl_matches = 0; @@ -4292,7 +4305,7 @@ static int ins_compl_use_match(int c) * Called when character "c" was typed, which has a meaning for completion. * Returns OK if completion was done, FAIL if something failed. */ -static int ins_complete(int c) +static int ins_complete(int c, bool enable_pum) { char_u *line; int startcol = 0; /* column where searched text starts */ @@ -4775,20 +4788,9 @@ static int ins_complete(int c) } } - /* Show the popup menu, unless we got interrupted. */ - if (!compl_interrupted) { - /* RedrawingDisabled may be set when invoked through complete(). */ - n = RedrawingDisabled; - RedrawingDisabled = 0; - - /* If the cursor moved we need to remove the pum first. */ - setcursor(); - if (save_w_wrow != curwin->w_wrow) - ins_compl_del_pum(); - - ins_compl_show_pum(); - setcursor(); - RedrawingDisabled = n; + // Show the popup menu, unless we got interrupted. + if (enable_pum && !compl_interrupted) { + show_pum(save_w_wrow); } compl_was_interrupted = compl_interrupted; compl_interrupted = FALSE; @@ -4941,15 +4943,10 @@ int get_literal(void) return cc; } -/* - * Insert character, taking care of special keys and mod_mask - */ -static void -insert_special ( - int c, - int allow_modmask, - int ctrlv /* c was typed after CTRL-V */ -) +/// Insert character, taking care of special keys and mod_mask +/// +/// @param ctrlv `c` was typed after CTRL-V +static void insert_special(int c, int allow_modmask, int ctrlv) { char_u *p; int len; @@ -4961,6 +4958,9 @@ insert_special ( * Only use mod_mask for special keys, to avoid things like <S-Space>, * unless 'allow_modmask' is TRUE. */ + if (mod_mask & MOD_MASK_CMD) { // Command-key never produces a normal key. + allow_modmask = true; + } if (IS_SPECIAL(c) || (mod_mask && allow_modmask)) { p = get_special_key_name(c, mod_mask); len = (int)STRLEN(p); @@ -8516,3 +8516,20 @@ static char_u *do_insert_char_pre(int c) return res; } + +static void show_pum(int save_w_wrow) +{ + // RedrawingDisabled may be set when invoked through complete(). + int n = RedrawingDisabled; + RedrawingDisabled = 0; + + // If the cursor moved we need to remove the pum first. + setcursor(); + if (save_w_wrow != curwin->w_wrow) { + ins_compl_del_pum(); + } + + ins_compl_show_pum(); + setcursor(); + RedrawingDisabled = n; +} diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 8cf077ec19..76deedfad0 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -1700,12 +1700,13 @@ static char_u *list_arg_vars(exarg_T *eap, char_u *arg, int *first) } error = TRUE; } else { - if (tofree != NULL) + if (tofree != NULL) { name = tofree; - if (get_var_tv(name, len, &tv, TRUE, FALSE) == FAIL) - error = TRUE; - else { - /* handle d.key, l[idx], f(expr) */ + } + if (get_var_tv(name, len, &tv, NULL, true, false) == FAIL) { + error = true; + } else { + // handle d.key, l[idx], f(expr) arg_subsc = arg; if (handle_subscript(&arg, &tv, TRUE, TRUE) == FAIL) error = TRUE; @@ -2176,10 +2177,10 @@ get_lval ( if (len == -1) clear_tv(&var1); break; - } - /* existing variable, need to check if it can be changed */ - else if (var_check_ro(lp->ll_di->di_flags, name)) + } else if (var_check_ro(lp->ll_di->di_flags, name, false)) { + // existing variable, need to check if it can be changed return NULL; + } if (len == -1) clear_tv(&var1); @@ -2274,11 +2275,16 @@ static void set_var_lval(lval_T *lp, char_u *endp, typval_T *rettv, int copy, ch if (op != NULL && *op != '=') { typval_T tv; - /* handle +=, -= and .= */ + // handle +=, -= and .= + di = NULL; if (get_var_tv(lp->ll_name, (int)STRLEN(lp->ll_name), - &tv, TRUE, FALSE) == OK) { - if (tv_op(&tv, rettv, op) == OK) - set_var(lp->ll_name, &tv, FALSE); + &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))) + && tv_op(&tv, rettv, op) == OK) { + set_var(lp->ll_name, &tv, false); + } clear_tv(&tv); } } else @@ -2286,16 +2292,17 @@ static void set_var_lval(lval_T *lp, char_u *endp, typval_T *rettv, int copy, ch *endp = cc; } } else if (tv_check_lock(lp->ll_newkey == NULL - ? lp->ll_tv->v_lock - : lp->ll_tv->vval.v_dict->dv_lock, lp->ll_name)) - ; - else if (lp->ll_range) { + ? lp->ll_tv->v_lock + : lp->ll_tv->vval.v_dict->dv_lock, + lp->ll_name, false)) { + } else if (lp->ll_range) { listitem_T *ll_li = lp->ll_li; int ll_n1 = lp->ll_n1; // Check whether any of the list items is locked - for (listitem_T *ri = rettv->vval.v_list->lv_first; ri != NULL && ll_li != NULL; ) { - if (tv_check_lock(ll_li->li_tv.v_lock, lp->ll_name)) { + for (listitem_T *ri = rettv->vval.v_list->lv_first; + ri != NULL && ll_li != NULL; ) { + if (tv_check_lock(ll_li->li_tv.v_lock, lp->ll_name, false)) { return; } ri = ri->li_next; @@ -2891,9 +2898,9 @@ static int do_unlet_var(lval_T *lp, char_u *name_end, int forceit) ret = FAIL; *name_end = cc; } else if ((lp->ll_list != NULL - && tv_check_lock(lp->ll_list->lv_lock, lp->ll_name)) + && tv_check_lock(lp->ll_list->lv_lock, lp->ll_name, false)) || (lp->ll_dict != NULL - && tv_check_lock(lp->ll_dict->dv_lock, lp->ll_name))) { + && tv_check_lock(lp->ll_dict->dv_lock, lp->ll_name, false))) { return FAIL; } else if (lp->ll_range) { listitem_T *li; @@ -2902,7 +2909,7 @@ static int do_unlet_var(lval_T *lp, char_u *name_end, int forceit) while (ll_li != NULL && (lp->ll_empty2 || lp->ll_n2 >= ll_n1)) { li = ll_li->li_next; - if (tv_check_lock(ll_li->li_tv.v_lock, lp->ll_name)) { + if (tv_check_lock(ll_li->li_tv.v_lock, lp->ll_name, false)) { return false; } ll_li = li; @@ -2975,9 +2982,9 @@ int do_unlet(char_u *name, int forceit) hi = hash_find(ht, varname); if (!HASHITEM_EMPTY(hi)) { di = HI2DI(hi); - if (var_check_fixed(di->di_flags, name) - || var_check_ro(di->di_flags, name) - || tv_check_lock(d->dv_lock, name)) { + if (var_check_fixed(di->di_flags, name, false) + || var_check_ro(di->di_flags, name, false) + || tv_check_lock(d->dv_lock, name, false)) { return FAIL; } typval_T oldtv; @@ -3045,12 +3052,13 @@ static int do_lock_var(lval_T *lp, char_u *name_end, int deep, int lock) li = li->li_next; ++lp->ll_n1; } - } else if (lp->ll_list != NULL) - /* (un)lock a List item. */ + } else if (lp->ll_list != NULL) { + // (un)lock a List item. item_lock(&lp->ll_li->li_tv, deep, lock); - else - /* un(lock) a Dictionary item. */ + } else { + // (un)lock a Dictionary item. item_lock(&lp->ll_di->di_tv, deep, lock); + } return ret; } @@ -3572,9 +3580,10 @@ static int eval4(char_u **arg, typval_T *rettv, int evaluate) type = TYPE_SEQUAL; break; case 'i': if (p[1] == 's') { - if (p[2] == 'n' && p[3] == 'o' && p[4] == 't') + if (p[2] == 'n' && p[3] == 'o' && p[4] == 't') { len = 5; - if (!vim_isIDc(p[len])) { + } + if (!isalnum(p[len]) && p[len] != '_') { type = len == 2 ? TYPE_EQUAL : TYPE_NEQUAL; type_is = TRUE; } @@ -4249,7 +4258,7 @@ static int eval7( ret = FAIL; } } else if (evaluate) { - ret = get_var_tv(s, len, rettv, true, false); + ret = get_var_tv(s, len, rettv, NULL, true, false); } else { ret = OK; } @@ -7288,8 +7297,8 @@ static struct fst { { "maparg", 1, 4, f_maparg }, { "mapcheck", 1, 3, f_mapcheck }, { "match", 2, 4, f_match }, - { "matchadd", 2, 4, f_matchadd }, - { "matchaddpos", 2, 4, f_matchaddpos }, + { "matchadd", 2, 5, f_matchadd }, + { "matchaddpos", 2, 5, f_matchaddpos }, { "matcharg", 1, 1, f_matcharg }, { "matchdelete", 1, 1, f_matchdelete }, { "matchend", 2, 4, f_matchend }, @@ -7341,10 +7350,10 @@ static struct fst { { "setcharsearch", 1, 1, f_setcharsearch }, { "setcmdpos", 1, 1, f_setcmdpos }, { "setline", 2, 2, f_setline }, - { "setloclist", 2, 3, f_setloclist }, + { "setloclist", 2, 4, f_setloclist }, { "setmatches", 1, 1, f_setmatches }, { "setpos", 2, 2, f_setpos }, - { "setqflist", 1, 2, f_setqflist }, + { "setqflist", 1, 3, f_setqflist }, { "setreg", 2, 3, f_setreg }, { "settabvar", 3, 3, f_settabvar }, { "settabwinvar", 4, 4, f_settabwinvar }, @@ -7363,7 +7372,7 @@ static struct fst { { "sqrt", 1, 1, f_sqrt }, { "str2float", 1, 1, f_str2float }, { "str2nr", 1, 2, f_str2nr }, - { "strchars", 1, 1, f_strchars }, + { "strchars", 1, 2, f_strchars }, { "strdisplaywidth", 1, 2, f_strdisplaywidth }, { "strftime", 1, 2, f_strftime }, { "stridx", 2, 3, f_stridx }, @@ -7881,7 +7890,8 @@ static void f_add(typval_T *argvars, typval_T *rettv) rettv->vval.v_number = 1; /* Default: Failed */ if (argvars[0].v_type == VAR_LIST) { if ((l = argvars[0].vval.v_list) != NULL - && !tv_check_lock(l->lv_lock, (char_u *)_("add() argument"))) { + && !tv_check_lock(l->lv_lock, + (char_u *)N_("add() argument"), true)) { list_append_tv(l, &argvars[1]); copy_tv(&argvars[0], rettv); } @@ -9156,9 +9166,10 @@ static void f_exists(typval_T *argvars, typval_T *rettv) name = p; len = get_name_len(&p, &tofree, TRUE, FALSE); if (len > 0) { - if (tofree != NULL) + if (tofree != NULL) { name = tofree; - n = (get_var_tv(name, len, &tv, FALSE, TRUE) == OK); + } + n = (get_var_tv(name, len, &tv, NULL, false, true) == OK); if (n) { /* handle d.key, l[idx], f(expr) */ n = (handle_subscript(&p, &tv, TRUE, FALSE) == OK); @@ -9256,7 +9267,7 @@ void dict_extend(dict_T *d1, dict_T *d2, char_u *action) hashitem_T *hi2; int todo; bool watched = is_watched(d1); - char *arg_errmsg = N_("extend() argument"); + char_u *arg_errmsg = (char_u *)N_("extend() argument"); todo = (int)d2->dv_hashtab.ht_used; for (hi2 = d2->dv_hashtab.ht_array; todo > 0; ++hi2) { @@ -9290,8 +9301,8 @@ void dict_extend(dict_T *d1, dict_T *d2, char_u *action) } else if (*action == 'f' && HI2DI(hi2) != di1) { typval_T oldtv; - if (tv_check_lock(di1->di_tv.v_lock, (char_u *)_(arg_errmsg)) - || var_check_ro(di1->di_flags, (char_u *)_(arg_errmsg))) { + if (tv_check_lock(di1->di_tv.v_lock, arg_errmsg, true) + || var_check_ro(di1->di_flags, arg_errmsg, true)) { break; } @@ -9317,7 +9328,7 @@ void dict_extend(dict_T *d1, dict_T *d2, char_u *action) */ static void f_extend(typval_T *argvars, typval_T *rettv) { - char *arg_errmsg = N_("extend() argument"); + char_u *arg_errmsg = (char_u *)N_("extend() argument"); if (argvars[0].v_type == VAR_LIST && argvars[1].v_type == VAR_LIST) { list_T *l1, *l2; @@ -9327,7 +9338,7 @@ static void f_extend(typval_T *argvars, typval_T *rettv) l1 = argvars[0].vval.v_list; l2 = argvars[1].vval.v_list; - if (l1 != NULL && !tv_check_lock(l1->lv_lock, (char_u *)_(arg_errmsg)) + if (l1 != NULL && !tv_check_lock(l1->lv_lock, arg_errmsg, true) && l2 != NULL) { if (argvars[2].v_type != VAR_UNKNOWN) { before = get_tv_number_chk(&argvars[2], &error); @@ -9357,7 +9368,7 @@ static void f_extend(typval_T *argvars, typval_T *rettv) d1 = argvars[0].vval.v_dict; d2 = argvars[1].vval.v_dict; - if (d1 != NULL && !tv_check_lock(d1->dv_lock, (char_u *)_(arg_errmsg)) + if (d1 != NULL && !tv_check_lock(d1->dv_lock, arg_errmsg, true) && d2 != NULL) { /* Check the third argument. */ if (argvars[2].v_type != VAR_UNKNOWN) { @@ -9503,19 +9514,19 @@ static void filter_map(typval_T *argvars, typval_T *rettv, int map) int rem; int todo; char_u *ermsg = (char_u *)(map ? "map()" : "filter()"); - char *arg_errmsg = (map ? N_("map() argument") - : N_("filter() argument")); + char_u *arg_errmsg = (char_u *)(map ? N_("map() argument") + : N_("filter() argument")); int save_did_emsg; int idx = 0; if (argvars[0].v_type == VAR_LIST) { if ((l = argvars[0].vval.v_list) == NULL - || (!map && tv_check_lock(l->lv_lock, (char_u *)_(arg_errmsg)))) { + || (!map && tv_check_lock(l->lv_lock, arg_errmsg, true))) { return; } } else if (argvars[0].v_type == VAR_DICT) { if ((d = argvars[0].vval.v_dict) == NULL - || (!map && tv_check_lock(d->dv_lock, (char_u *)_(arg_errmsg)))) { + || (!map && tv_check_lock(d->dv_lock, arg_errmsg, true))) { return; } } else { @@ -9549,8 +9560,8 @@ static void filter_map(typval_T *argvars, typval_T *rettv, int map) di = HI2DI(hi); if (map - && (tv_check_lock(di->di_tv.v_lock, (char_u *)_(arg_errmsg)) - || var_check_ro(di->di_flags, (char_u *)_(arg_errmsg)))) { + && (tv_check_lock(di->di_tv.v_lock, arg_errmsg, true) + || var_check_ro(di->di_flags, arg_errmsg, true))) { break; } @@ -9560,8 +9571,8 @@ static void filter_map(typval_T *argvars, typval_T *rettv, int map) if (r == FAIL || did_emsg) break; if (!map && rem) { - if (var_check_fixed(di->di_flags, (char_u *)_(arg_errmsg)) - || var_check_ro(di->di_flags, (char_u *)_(arg_errmsg))) { + if (var_check_fixed(di->di_flags, arg_errmsg, true) + || var_check_ro(di->di_flags, arg_errmsg, true)) { break; } dictitem_remove(d, di); @@ -9573,7 +9584,7 @@ static void filter_map(typval_T *argvars, typval_T *rettv, int map) vimvars[VV_KEY].vv_type = VAR_NUMBER; for (li = l->lv_first; li != NULL; li = nli) { - if (map && tv_check_lock(li->li_tv.v_lock, (char_u *)_(arg_errmsg))) { + if (map && tv_check_lock(li->li_tv.v_lock, arg_errmsg, true)) { break; } nli = li->li_next; @@ -10438,6 +10449,14 @@ static void f_getmatches(typval_T *argvars, typval_T *rettv) dict_add_nr_str(dict, "group", 0L, syn_id2name(cur->hlg_id)); dict_add_nr_str(dict, "priority", (long)cur->priority, NULL); dict_add_nr_str(dict, "id", (long)cur->id, NULL); + + if (cur->conceal_char) { + char_u buf[MB_MAXBYTES + 1]; + + buf[(*mb_char2bytes)((int)cur->conceal_char, buf)] = NUL; + dict_add_nr_str(dict, "conceal", 0L, (char_u *)&buf); + } + list_append_dict(rettv->vval.v_list, dict); cur = cur->next; } @@ -10609,9 +10628,10 @@ static void f_gettabvar(typval_T *argvars, typval_T *rettv) varname = get_tv_string_chk(&argvars[1]); tp = find_tabpage((int)get_tv_number_chk(&argvars[0], NULL)); if (tp != NULL && varname != NULL) { - /* Set tp to be our tabpage, temporarily. Also set the window to the - * first window in the tabpage, otherwise the window is not valid. */ - if (switch_win(&oldcurwin, &oldtabpage, tp->tp_firstwin, tp, TRUE) == OK) { + // Set tp to be our tabpage, temporarily. Also set the window to the + // first window in the tabpage, otherwise the window is not valid. + win_T *window = tp->tp_firstwin == NULL ? firstwin : tp->tp_firstwin; + if (switch_win(&oldcurwin, &oldtabpage, window, tp, true) == OK) { // look up the variable // Let gettabvar({nr}, "") return the "t:" dictionary. v = find_var_in_ht(&tp->tp_vars->dv_hashtab, 't', varname, FALSE); @@ -10704,11 +10724,11 @@ getwinvar ( int off /* 1 for gettabwinvar() */ ) { - win_T *win, *oldcurwin; - char_u *varname; - dictitem_T *v; - tabpage_T *tp = NULL; - tabpage_T *oldtabpage = NULL; + win_T *win, *oldcurwin; + char_u *varname; + dictitem_T *v; + tabpage_T *tp = NULL; + tabpage_T *oldtabpage = NULL; bool done = false; if (off == 1) @@ -10723,12 +10743,16 @@ getwinvar ( rettv->vval.v_string = NULL; if (win != NULL && varname != NULL) { - /* Set curwin to be our win, temporarily. Also set the tabpage, - * otherwise the window is not valid. */ - if (switch_win(&oldcurwin, &oldtabpage, win, tp, TRUE) == OK) { - if (*varname == '&') { /* window-local-option */ - if (get_option_tv(&varname, rettv, 1) == OK) + // Set curwin to be our win, temporarily. Also set the tabpage, + // otherwise the window is not valid. Only do this when needed, + // autocommands get blocked. + bool need_switch_win = tp != curtab || win != curwin; + if (!need_switch_win + || switch_win(&oldcurwin, &oldtabpage, win, tp, true) == OK) { + if (*varname == '&') { // window-local-option + if (get_option_tv(&varname, rettv, 1) == OK) { done = true; + } } else { // Look up the variable. // Let getwinvar({nr}, "") return the "w:" dictionary. @@ -10740,8 +10764,10 @@ getwinvar ( } } - /* restore previous notion of curwin */ - restore_win(oldcurwin, oldtabpage, TRUE); + if (need_switch_win) { + // restore previous notion of curwin + restore_win(oldcurwin, oldtabpage, true); + } } if (!done && argvars[off + 2].v_type != VAR_UNKNOWN) @@ -10956,6 +10982,7 @@ static void f_has(typval_T *argvars, typval_T *rettv) #if !defined(UNIX) "system", // TODO(SplinterOfChaos): This IS defined for UNIX! #endif + "tablineat", "tag_binary", "tag_old_static", "termresponse", @@ -11013,8 +11040,6 @@ static void f_has(typval_T *argvars, typval_T *rettv) #endif } else if (STRICMP(name, "syntax_items") == 0) { n = syntax_present(curwin); - } else if (STRICMP(name, "gui_running") == 0) { - n = ui_rgb_attached(); } } @@ -11469,14 +11494,18 @@ static void f_insert(typval_T *argvars, typval_T *rettv) list_T *l; int error = FALSE; - if (argvars[0].v_type != VAR_LIST) + if (argvars[0].v_type != VAR_LIST) { EMSG2(_(e_listarg), "insert()"); - else if ((l = argvars[0].vval.v_list) != NULL - && !tv_check_lock(l->lv_lock, (char_u *)_("insert() argument"))) { - if (argvars[2].v_type != VAR_UNKNOWN) + } else if ((l = argvars[0].vval.v_list) != NULL + && !tv_check_lock(l->lv_lock, + (char_u *)N_("insert() argument"), true)) { + if (argvars[2].v_type != VAR_UNKNOWN) { before = get_tv_number_chk(&argvars[2], &error); - if (error) - return; /* type error; errmsg already given */ + } + if (error) { + // type error; errmsg already given + return; + } if (before == l->lv_len) item = NULL; @@ -12499,7 +12528,8 @@ static void f_matchadd(typval_T *argvars, typval_T *rettv) char_u *pat = get_tv_string_buf_chk(&argvars[1], buf); /* pattern */ int prio = 10; /* default priority */ int id = -1; - int error = FALSE; + int error = false; + char_u *conceal_char = NULL; rettv->vval.v_number = -1; @@ -12507,17 +12537,31 @@ static void f_matchadd(typval_T *argvars, typval_T *rettv) return; if (argvars[2].v_type != VAR_UNKNOWN) { prio = get_tv_number_chk(&argvars[2], &error); - if (argvars[3].v_type != VAR_UNKNOWN) + if (argvars[3].v_type != VAR_UNKNOWN) { id = get_tv_number_chk(&argvars[3], &error); + if (argvars[4].v_type != VAR_UNKNOWN) { + if (argvars[4].v_type != VAR_DICT) { + EMSG(_(e_dictreq)); + return; + } + if (dict_find(argvars[4].vval.v_dict, + (char_u *)"conceal", -1) != NULL) { + conceal_char = get_dict_string(argvars[4].vval.v_dict, + (char_u *)"conceal", false); + } + } + } } - if (error == TRUE) + if (error == true) { return; + } if (id >= 1 && id <= 3) { EMSGN("E798: ID is reserved for \":match\": %" PRId64, id); return; } - rettv->vval.v_number = match_add(curwin, grp, pat, prio, id, NULL); + rettv->vval.v_number = match_add(curwin, grp, pat, prio, id, NULL, + conceal_char); } static void f_matchaddpos(typval_T *argvars, typval_T *rettv) FUNC_ATTR_NONNULL_ALL @@ -12545,12 +12589,24 @@ static void f_matchaddpos(typval_T *argvars, typval_T *rettv) FUNC_ATTR_NONNULL_ int error = false; int prio = 10; int id = -1; + char_u *conceal_char = NULL; if (argvars[2].v_type != VAR_UNKNOWN) { - prio = get_tv_number_chk(&argvars[2], &error); - if (argvars[3].v_type != VAR_UNKNOWN) { - id = get_tv_number_chk(&argvars[3], &error); + prio = get_tv_number_chk(&argvars[2], &error); + if (argvars[3].v_type != VAR_UNKNOWN) { + id = get_tv_number_chk(&argvars[3], &error); + if (argvars[4].v_type != VAR_UNKNOWN) { + if (argvars[4].v_type != VAR_DICT) { + EMSG(_(e_dictreq)); + return; + } + if (dict_find(argvars[4].vval.v_dict, + (char_u *)"conceal", -1) != NULL) { + conceal_char = get_dict_string(argvars[4].vval.v_dict, + (char_u *)"conceal", false); + } } + } } if (error == true) { return; @@ -12562,7 +12618,8 @@ static void f_matchaddpos(typval_T *argvars, typval_T *rettv) FUNC_ATTR_NONNULL_ return; } - rettv->vval.v_number = match_add(curwin, group, NULL, prio, id, l); + rettv->vval.v_number = match_add(curwin, group, NULL, prio, id, l, + conceal_char); } /* @@ -13930,20 +13987,20 @@ static void f_remove(typval_T *argvars, typval_T *rettv) char_u *key; dict_T *d; dictitem_T *di; - char *arg_errmsg = N_("remove() argument"); + char_u *arg_errmsg = (char_u *)N_("remove() argument"); if (argvars[0].v_type == VAR_DICT) { - if (argvars[2].v_type != VAR_UNKNOWN) + if (argvars[2].v_type != VAR_UNKNOWN) { EMSG2(_(e_toomanyarg), "remove()"); - else if ((d = argvars[0].vval.v_dict) != NULL - && !tv_check_lock(d->dv_lock, (char_u *)_(arg_errmsg))) { + } else if ((d = argvars[0].vval.v_dict) != NULL + && !tv_check_lock(d->dv_lock, arg_errmsg, true)) { key = get_tv_string_chk(&argvars[1]); if (key != NULL) { di = dict_find(d, key, -1); if (di == NULL) { EMSG2(_(e_dictkey), key); - } else if (!var_check_fixed(di->di_flags, (char_u *)_(arg_errmsg)) - && !var_check_ro(di->di_flags, (char_u *)_(arg_errmsg))) { + } else if (!var_check_fixed(di->di_flags, arg_errmsg, true) + && !var_check_ro(di->di_flags, arg_errmsg, true)) { *rettv = di->di_tv; init_tv(&di->di_tv); dictitem_remove(d, di); @@ -13953,11 +14010,11 @@ static void f_remove(typval_T *argvars, typval_T *rettv) } } } - } else if (argvars[0].v_type != VAR_LIST) + } else if (argvars[0].v_type != VAR_LIST) { EMSG2(_(e_listdictarg), "remove()"); - else if ((l = argvars[0].vval.v_list) != NULL - && !tv_check_lock(l->lv_lock, (char_u *)_(arg_errmsg))) { - int error = FALSE; + } else if ((l = argvars[0].vval.v_list) != NULL + && !tv_check_lock(l->lv_lock, arg_errmsg, true)) { + int error = (int)false; idx = get_tv_number_chk(&argvars[1], &error); if (error) @@ -14231,10 +14288,11 @@ static void f_reverse(typval_T *argvars, typval_T *rettv) list_T *l; listitem_T *li, *ni; - if (argvars[0].v_type != VAR_LIST) + if (argvars[0].v_type != VAR_LIST) { EMSG2(_(e_listarg), "reverse()"); - else if ((l = argvars[0].vval.v_list) != NULL - && !tv_check_lock(l->lv_lock, (char_u *)_("reverse() argument"))) { + } else if ((l = argvars[0].vval.v_list) != NULL + && !tv_check_lock(l->lv_lock, + (char_u *)N_("reverse() argument"), true)) { li = l->lv_last; l->lv_first = l->lv_last = NULL; l->lv_len = 0; @@ -15183,14 +15241,26 @@ static void f_setline(typval_T *argvars, typval_T *rettv) appended_lines_mark(lcount, added); } - -/* - * Used by "setqflist()" and "setloclist()" functions - */ -static void set_qf_ll_list(win_T *wp, typval_T *list_arg, typval_T *action_arg, typval_T *rettv) +/// Create quickfix/location list from VimL values +/// +/// Used by `setqflist()` and `setloclist()` functions. Accepts invalid +/// list_arg, action_arg and title_arg arguments in which case errors out, +/// including VAR_UNKNOWN parameters. +/// +/// @param[in,out] wp Window to create location list for. May be NULL in +/// which case quickfix list will be created. +/// @param[in] list_arg Quickfix list contents. +/// @param[in] action_arg Action to perform: append to an existing list, +/// replace its content or create a new one. +/// @param[in] title_arg New list title. Defaults to caller function name. +/// @param[out] rettv Return value: 0 in case of success, -1 otherwise. +static void set_qf_ll_list(win_T *wp, typval_T *list_arg, typval_T *action_arg, + typval_T *title_arg, typval_T *rettv) + FUNC_ATTR_NONNULL_ARG(2, 3, 4, 5) { char_u *act; int action = ' '; + char_u *title = NULL; rettv->vval.v_number = -1; @@ -15199,7 +15269,7 @@ static void set_qf_ll_list(win_T *wp, typval_T *list_arg, typval_T *action_arg, else { list_T *l = list_arg->vval.v_list; - if (action_arg->v_type == VAR_STRING) { + if (action_arg->v_type != VAR_UNKNOWN) { act = get_tv_string_chk(action_arg); if (act == NULL) return; /* type error; errmsg already given */ @@ -15207,9 +15277,20 @@ static void set_qf_ll_list(win_T *wp, typval_T *list_arg, typval_T *action_arg, action = *act; } - if (l != NULL && set_errorlist(wp, l, action, - (char_u *)(wp == NULL ? "setqflist()" : "setloclist()")) == OK) + if (title_arg->v_type == VAR_STRING) { + title = get_tv_string_chk(title_arg); + if (!title) { + return; // type error; errmsg already given + } + } + + if (!title) { + title = (char_u*)(wp ? "setloclist()" : "setqflist()"); + } + + if (l && set_errorlist(wp, l, action, title) == OK) { rettv->vval.v_number = 0; + } } } @@ -15223,8 +15304,9 @@ static void f_setloclist(typval_T *argvars, typval_T *rettv) rettv->vval.v_number = -1; win = find_win_by_nr(&argvars[0], NULL); - if (win != NULL) - set_qf_ll_list(win, &argvars[1], &argvars[2], rettv); + if (win != NULL) { + set_qf_ll_list(win, &argvars[1], &argvars[2], &argvars[3], rettv); + } } /* @@ -15270,8 +15352,8 @@ static void f_setmatches(typval_T *argvars, typval_T *rettv) int i = 0; char_u buf[5]; dictitem_T *di; - d = li->li_tv.vval.v_dict; + d = li->li_tv.vval.v_dict; if (dict_find(d, (char_u *)"pattern", -1) == NULL) { if (s == NULL) { s = list_alloc(); @@ -15296,15 +15378,19 @@ static void f_setmatches(typval_T *argvars, typval_T *rettv) } } + char_u *group = get_dict_string(d, (char_u *)"group", false); + int priority = get_dict_number(d, (char_u *)"priority"); + int id = get_dict_number(d, (char_u *)"id"); + char_u *conceal = dict_find(d, (char_u *)"conceal", -1) != NULL + ? get_dict_string(d, (char_u *)"conceal", + false) + : NULL; if (i == 0) { - match_add(curwin, get_dict_string(d, (char_u *)"group", false), + match_add(curwin, group, get_dict_string(d, (char_u *)"pattern", false), - (int)get_dict_number(d, (char_u *)"priority"), - (int)get_dict_number(d, (char_u *)"id"), NULL); + priority, id, NULL, conceal); } else { - match_add(curwin, get_dict_string(d, (char_u *)"group", false), - NULL, (int)get_dict_number(d, (char_u *)"priority"), - (int)get_dict_number(d, (char_u *)"id"), s); + match_add(curwin, group, NULL, priority, id, s, conceal); list_unref(s); s = NULL; } @@ -15356,7 +15442,7 @@ static void f_setpos(typval_T *argvars, typval_T *rettv) */ static void f_setqflist(typval_T *argvars, typval_T *rettv) { - set_qf_ll_list(NULL, &argvars[0], &argvars[1], rettv); + set_qf_ll_list(NULL, &argvars[0], &argvars[1], &argvars[2], rettv); } /* @@ -15530,26 +15616,32 @@ static void setwinvar(typval_T *argvars, typval_T *rettv, int off) varname = get_tv_string_chk(&argvars[off + 1]); varp = &argvars[off + 2]; - if (win != NULL && varname != NULL && varp != NULL - && switch_win(&save_curwin, &save_curtab, win, tp, TRUE) == OK) { - if (*varname == '&') { - long numval; - char_u *strval; - int error = FALSE; - - ++varname; - numval = get_tv_number_chk(varp, &error); - strval = get_tv_string_buf_chk(varp, nbuf); - if (!error && strval != NULL) - set_option_value(varname, numval, strval, OPT_LOCAL); - } else { - winvarname = xmalloc(STRLEN(varname) + 3); - STRCPY(winvarname, "w:"); - STRCPY(winvarname + 2, varname); - set_var(winvarname, varp, TRUE); - xfree(winvarname); + if (win != NULL && varname != NULL && varp != NULL) { + bool need_switch_win = tp != curtab || win != curwin; + if (!need_switch_win + || switch_win(&save_curwin, &save_curtab, win, tp, true) == OK) { + if (*varname == '&') { + long numval; + char_u *strval; + int error = false; + + ++varname; + numval = get_tv_number_chk(varp, &error); + strval = get_tv_string_buf_chk(varp, nbuf); + if (!error && strval != NULL) { + set_option_value(varname, numval, strval, OPT_LOCAL); + } + } else { + winvarname = xmalloc(STRLEN(varname) + 3); + STRCPY(winvarname, "w:"); + STRCPY(winvarname + 2, varname); + set_var(winvarname, varp, true); + xfree(winvarname); + } + } + if (need_switch_win) { + restore_win(save_curwin, save_curtab, true); } - restore_win(save_curwin, save_curtab, TRUE); } } @@ -15768,8 +15860,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 ? _("sort() argument") : _("uniq() argument")))) { + 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; @@ -16240,13 +16336,23 @@ static void f_strlen(typval_T *argvars, typval_T *rettv) static void f_strchars(typval_T *argvars, typval_T *rettv) { char_u *s = get_tv_string(&argvars[0]); + int skipcc = 0; varnumber_T len = 0; + int (*func_mb_ptr2char_adv)(char_u **pp); - while (*s != NUL) { - mb_cptr2char_adv(&s); - ++len; + if (argvars[1].v_type != VAR_UNKNOWN) { + skipcc = get_tv_number_chk(&argvars[1], NULL); + } + if (skipcc < 0 || skipcc > 1) { + EMSG(_(e_invarg)); + } else { + func_mb_ptr2char_adv = skipcc ? mb_ptr2char_adv : mb_cptr2char_adv; + while (*s != NUL) { + func_mb_ptr2char_adv(&s); + ++len; + } + rettv->vval.v_number = len; } - rettv->vval.v_number = len; } /* @@ -18048,23 +18154,23 @@ void set_vim_var_list(int idx, list_T *val) } /// Set Dictionary v: variable to "val". -void set_vim_var_dict(int idx, dict_T *val) FUNC_ATTR_NONNULL_ALL +void set_vim_var_dict(int idx, dict_T *val) { dict_unref(vimvars[idx].vv_dict); + vimvars[idx].vv_dict = val; - // Set readonly - int todo = (int)val->dv_hashtab.ht_used; - for (hashitem_T *hi = val->dv_hashtab.ht_array; todo > 0 ; ++hi) { - if (HASHITEM_EMPTY(hi)) { - continue; + if (val != NULL) { + ++val->dv_refcount; + // Set readonly + size_t todo = val->dv_hashtab.ht_used; + for (hashitem_T *hi = val->dv_hashtab.ht_array; todo > 0 ; ++hi) { + if (HASHITEM_EMPTY(hi)) { + continue; + } + --todo; + HI2DI(hi)->di_flags = DI_FLAGS_RO | DI_FLAGS_FIX; } - - --todo; - HI2DI(hi)->di_flags = DI_FLAGS_RO | DI_FLAGS_FIX; } - - vimvars[idx].vv_dict = val; - ++val->dv_refcount; } /* @@ -18182,10 +18288,11 @@ char_u *set_cmdarg(exarg_T *eap, char_u *oldarg) static int get_var_tv ( char_u *name, - int len, /* length of "name" */ - typval_T *rettv, /* NULL when only checking existence */ - int verbose, /* may give error message */ - int no_autoload /* do not use script autoloading */ + int len, // length of "name" + typval_T *rettv, // NULL when only checking existence + dictitem_T **dip, // non-NULL when typval's dict item is needed + int verbose, // may give error message + int no_autoload // do not use script autoloading ) { int ret = OK; @@ -18211,8 +18318,12 @@ get_var_tv ( */ else { v = find_var(name, NULL, no_autoload); - if (v != NULL) + if (v != NULL) { tv = &v->di_tv; + if (dip != NULL) { + *dip = v; + } + } } if (tv == NULL) { @@ -18603,6 +18714,9 @@ static hashtab_T *find_var_ht_dict(char_u *name, uint8_t **varname, dict_T **d) hashitem_T *hi; *d = NULL; + if (name[0] == NUL) { + return NULL; + } if (name[1] != ':') { // name has implicit scope if (name[0] == ':' || name[0] == AUTOLOAD_CHAR) { @@ -18652,6 +18766,7 @@ end: } // Find the hashtab used for a variable name. +// Return NULL if the name is not valid. // Set "varname" to the start of name without ':'. static hashtab_T *find_var_ht(uint8_t *name, uint8_t **varname) { @@ -18875,10 +18990,11 @@ set_var ( return; if (v != NULL) { - /* existing variable, need to clear the value */ - if (var_check_ro(v->di_flags, name) - || tv_check_lock(v->di_tv.v_lock, name)) + // existing variable, need to clear the value + if (var_check_ro(v->di_flags, name, false) + || tv_check_lock(v->di_tv.v_lock, name, false)) { return; + } if (v->di_tv.v_type != tv->v_type && !((v->di_tv.v_type == VAR_STRING || v->di_tv.v_type == VAR_NUMBER) @@ -18893,10 +19009,8 @@ set_var ( return; } - /* - * Handle setting internal v: variables separately: we don't change - * the type. - */ + // Handle setting internal v: variables separately where needed to + // prevent changing the type. if (ht == &vimvarht) { if (v->di_tv.v_type == VAR_STRING) { xfree(v->di_tv.vval.v_string); @@ -18907,9 +19021,8 @@ set_var ( v->di_tv.vval.v_string = tv->vval.v_string; tv->vval.v_string = NULL; } - } else if (v->di_tv.v_type != VAR_NUMBER) - EMSG2(_(e_intern2), "set_var()"); - else { + return; + } else if (v->di_tv.v_type == VAR_NUMBER) { v->di_tv.vval.v_number = get_tv_number(tv); if (STRCMP(varname, "searchforward") == 0) set_search_direction(v->di_tv.vval.v_number ? '/' : '?'); @@ -18917,8 +19030,10 @@ set_var ( no_hlsearch = !v->di_tv.vval.v_number; redraw_all_later(SOME_VALID); } + return; + } else if (v->di_tv.v_type != tv->v_type) { + EMSG2(_(e_intern2), "set_var()"); } - return; } if (watched) { @@ -18963,34 +19078,31 @@ set_var ( } } -/* - * Return TRUE if di_flags "flags" indicates variable "name" is read-only. - * Also give an error message. - */ -static int var_check_ro(int flags, char_u *name) +// Return true if di_flags "flags" indicates variable "name" is read-only. +// Also give an error message. +static bool var_check_ro(int flags, char_u *name, bool use_gettext) { if (flags & DI_FLAGS_RO) { - EMSG2(_(e_readonlyvar), name); - return TRUE; + EMSG2(_(e_readonlyvar), use_gettext ? (char_u *)_(name) : name); + return true; } if ((flags & DI_FLAGS_RO_SBX) && sandbox) { - EMSG2(_(e_readonlysbx), name); - return TRUE; + EMSG2(_(e_readonlysbx), use_gettext ? (char_u *)_(name) : name); + return true; } - return FALSE; + return false; } -/* - * Return TRUE if di_flags "flags" indicates variable "name" is fixed. - * Also give an error message. - */ -static int var_check_fixed(int flags, char_u *name) +// Return true if di_flags "flags" indicates variable "name" is fixed. +// Also give an error message. +static bool var_check_fixed(int flags, char_u *name, bool use_gettext) { if (flags & DI_FLAGS_FIX) { - EMSG2(_("E795: Cannot delete variable %s"), name); - return TRUE; + EMSG2(_("E795: Cannot delete variable %s"), + use_gettext ? (char_u *)_(name) : name); + return true; } - return FALSE; + return false; } /* @@ -19038,23 +19150,28 @@ static int valid_varname(char_u *varname) return TRUE; } -/* - * Return TRUE if typeval "tv" is set to be locked (immutable). - * Also give an error message, using "name". - */ -static int tv_check_lock(int lock, char_u *name) +// Return true if typeval "tv" is set to be locked (immutable). +// Also give an error message, using "name" or _("name") when use_gettext is +// true. +static bool tv_check_lock(int lock, char_u *name, bool use_gettext) { if (lock & VAR_LOCKED) { EMSG2(_("E741: Value is locked: %s"), - name == NULL ? (char_u *)_("Unknown") : name); - return TRUE; + name == NULL + ? (char_u *)_("Unknown") + : use_gettext ? (char_u *)_(name) + : name); + return true; } if (lock & VAR_FIXED) { EMSG2(_("E742: Cannot change value of %s"), - name == NULL ? (char_u *)_("Unknown") : name); - return TRUE; + name == NULL + ? (char_u *)_("Unknown") + : use_gettext ? (char_u *)_(name) + : name); + return true; } - return FALSE; + return false; } /* @@ -19647,7 +19764,10 @@ void ex_function(exarg_T *eap) break; } } - ++p; /* skip the ')' */ + if (*p != ')') { + goto erret; + } + ++p; // skip the ')' /* find extra arguments "range", "dict" and "abort" */ for (;; ) { @@ -19871,13 +19991,14 @@ void ex_function(exarg_T *eap) goto erret; } if (fudi.fd_di == NULL) { - /* Can't add a function to a locked dictionary */ - if (tv_check_lock(fudi.fd_dict->dv_lock, eap->arg)) + if (tv_check_lock(fudi.fd_dict->dv_lock, eap->arg, false)) { + // Can't add a function to a locked dictionary goto erret; - } - /* Can't change an existing function if it is locked */ - else if (tv_check_lock(fudi.fd_di->di_tv.v_lock, eap->arg)) + } + } else if (tv_check_lock(fudi.fd_di->di_tv.v_lock, eap->arg, false)) { + // Can't change an existing function if it is locked goto erret; + } /* Give the function a sequential number. Can only be used with a * Funcref! */ @@ -20855,14 +20976,18 @@ call_user_func ( save_sourcing_name = sourcing_name; save_sourcing_lnum = sourcing_lnum; sourcing_lnum = 1; - sourcing_name = xmalloc((save_sourcing_name == NULL ? 0 : STRLEN(save_sourcing_name)) - + STRLEN(fp->uf_name) + 13); + // need space for function name + ("function " + 3) or "[number]" + size_t len = (save_sourcing_name == NULL ? 0 : STRLEN(save_sourcing_name)) + + STRLEN(fp->uf_name) + 20; + sourcing_name = xmalloc(len); { if (save_sourcing_name != NULL - && STRNCMP(save_sourcing_name, "function ", 9) == 0) - sprintf((char *)sourcing_name, "%s..", save_sourcing_name); - else + && STRNCMP(save_sourcing_name, "function ", 9) == 0) { + vim_snprintf((char *)sourcing_name, len, "%s[%zu]..", + save_sourcing_name, save_sourcing_lnum); + } else { STRCPY(sourcing_name, "function "); + } cat_func_name(sourcing_name + STRLEN(sourcing_name), fp); if (p_verbose >= 12) { @@ -22128,7 +22253,6 @@ static void on_process_exit(Process *proc, int status, void *d) char msg[22]; snprintf(msg, sizeof msg, "\r\n[Process exited %d]", proc->status); terminal_close(data->term, msg); - apply_autocmds(EVENT_TERMCLOSE, NULL, NULL, false, curbuf); } if (data->status_ptr) { diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c index a517037431..ad21e71c51 100644 --- a/src/nvim/ex_cmds.c +++ b/src/nvim/ex_cmds.c @@ -690,9 +690,17 @@ int do_move(linenr_T line1, linenr_T line2, linenr_T dest) { char_u *str; linenr_T l; - linenr_T extra; /* Num lines added before line1 */ - linenr_T num_lines; /* Num lines moved */ - linenr_T last_line; /* Last line in file after adding new text */ + linenr_T extra; // Num lines added before line1 + linenr_T num_lines; // Num lines moved + linenr_T last_line; // Last line in file after adding new text + + // Moving lines seems to corrupt the folds, delete folding info now + // and recreate it when finished. Don't do this for manual folding, it + // would delete all folds. + bool isFolded = hasAnyFolding(curwin) && !foldmethodIsManual(curwin); + if (isFolded) { + deleteFoldRecurse(&curwin->w_folds); + } if (dest >= line1 && dest < line2) { EMSG(_("E134: Move lines into themselves")); @@ -777,8 +785,14 @@ int do_move(linenr_T line1, linenr_T line2, linenr_T dest) if (dest > last_line + 1) dest = last_line + 1; changed_lines(line1, 0, dest, 0L); - } else + } else { changed_lines(dest + 1, 0, line1 + num_lines, 0L); + } + + // recreate folds + if (isFolded) { + foldUpdateAll(curwin); + } return OK; } @@ -4765,6 +4779,7 @@ void ex_helptags(exarg_T *eap) WILD_LIST_NOTFOUND|WILD_SILENT, WILD_EXPAND_FREE); if (dirname == NULL || !os_isdir(dirname)) { EMSG2(_("E150: Not a directory: %s"), eap->arg); + xfree(dirname); return; } @@ -4862,16 +4877,13 @@ helptags_one ( int fi; char_u *s; char_u *fname; - int dirlen; int utf8 = MAYBE; int this_utf8; int firstline; int mix = FALSE; /* detected mixed encodings */ - /* - * Find all *.txt files. - */ - dirlen = (int)STRLEN(dir); + // Find all *.txt files. + size_t dirlen = STRLEN(dir); STRCPY(NameBuff, dir); STRCAT(NameBuff, "/**/*"); STRCAT(NameBuff, ext); @@ -4893,7 +4905,7 @@ helptags_one ( */ STRCPY(NameBuff, dir); add_pathsep((char *)NameBuff); - STRCAT(NameBuff, tagfname); + STRNCAT(NameBuff, tagfname, sizeof(NameBuff) - dirlen - 2); fd_tags = mch_fopen((char *)NameBuff, "w"); if (fd_tags == NULL) { EMSG2(_("E152: Cannot open %s for writing"), NameBuff); diff --git a/src/nvim/ex_cmds2.c b/src/nvim/ex_cmds2.c index 47774f5a99..71ea170e1c 100644 --- a/src/nvim/ex_cmds2.c +++ b/src/nvim/ex_cmds2.c @@ -57,23 +57,23 @@ typedef struct scriptitem_S { char_u *sn_name; bool file_id_valid; FileID file_id; - int sn_prof_on; /* TRUE when script is/was profiled */ - int sn_pr_force; /* forceit: profile functions in this script */ - proftime_T sn_pr_child; /* time set when going into first child */ - int sn_pr_nest; /* nesting for sn_pr_child */ - /* profiling the script as a whole */ - int sn_pr_count; /* nr of times sourced */ - proftime_T sn_pr_total; /* time spent in script + children */ - proftime_T sn_pr_self; /* time spent in script itself */ - proftime_T sn_pr_start; /* time at script start */ - proftime_T sn_pr_children; /* time in children after script start */ - /* profiling the script per line */ - garray_T sn_prl_ga; /* things stored for every line */ - proftime_T sn_prl_start; /* start time for current line */ - proftime_T sn_prl_children; /* time spent in children for this line */ - proftime_T sn_prl_wait; /* wait start time for current line */ - int sn_prl_idx; /* index of line being timed; -1 if none */ - int sn_prl_execed; /* line being timed was executed */ + bool sn_prof_on; ///< true when script is/was profiled + int sn_pr_force; ///< forceit: profile functions in this script + proftime_T sn_pr_child; ///< time set when going into first child + int sn_pr_nest; ///< nesting for sn_pr_child + // profiling the script as a whole + int sn_pr_count; ///< nr of times sourced + proftime_T sn_pr_total; ///< time spent in script + children + proftime_T sn_pr_self; ///< time spent in script itself + proftime_T sn_pr_start; ///< time at script start + proftime_T sn_pr_children; ///< time in children after script start + // profiling the script per line + garray_T sn_prl_ga; ///< things stored for every line + proftime_T sn_prl_start; ///< start time for current line + proftime_T sn_prl_children; ///< time spent in children for this line + proftime_T sn_prl_wait; ///< wait start time for current line + linenr_T sn_prl_idx; ///< index of line being timed; -1 if none + int sn_prl_execed; ///< line being timed was executed } scriptitem_T; static garray_T script_items = {0, 0, sizeof(scriptitem_T), 4, NULL}; @@ -81,9 +81,9 @@ static garray_T script_items = {0, 0, sizeof(scriptitem_T), 4, NULL}; /* Struct used in sn_prl_ga for every line of a script. */ typedef struct sn_prl_S { - int snp_count; /* nr of times line was executed */ - proftime_T sn_prl_total; /* time spent in a line + children */ - proftime_T sn_prl_self; /* time spent in a line itself */ + int snp_count; ///< nr of times line was executed + proftime_T sn_prl_total; ///< time spent in a line + children + proftime_T sn_prl_self; ///< time spent in a line itself } sn_prl_T; /* @@ -93,18 +93,18 @@ typedef struct sn_prl_S { * sourcing can be done recursively. */ struct source_cookie { - FILE *fp; /* opened file for sourcing */ - char_u *nextline; /* if not NULL: line that was read ahead */ - int finished; /* ":finish" used */ + FILE *fp; ///< opened file for sourcing + char_u *nextline; ///< if not NULL: line that was read ahead + int finished; ///< ":finish" used #if defined(USE_CRNL) - int fileformat; /* EOL_UNKNOWN, EOL_UNIX or EOL_DOS */ - int error; /* TRUE if LF found after CR-LF */ + int fileformat; ///< EOL_UNKNOWN, EOL_UNIX or EOL_DOS + int error; ///< TRUE if LF found after CR-LF #endif - linenr_T breakpoint; /* next line with breakpoint or zero */ - char_u *fname; /* name of sourced file */ - int dbg_tick; /* debug_tick when breakpoint was set */ - int level; /* top nesting level of sourced file */ - vimconv_T conv; /* type of conversion */ + linenr_T breakpoint; ///< next line with breakpoint or zero + char_u *fname; ///< name of sourced file + int dbg_tick; ///< debug_tick when breakpoint was set + int level; ///< top nesting level of sourced file + vimconv_T conv; ///< type of conversion }; # define PRL_ITEM(si, idx) (((sn_prl_T *)(si)->sn_prl_ga.ga_data)[(idx)]) @@ -272,7 +272,7 @@ void do_debug(char_u *cmd) xfree(cmdline); } - lines_left = Rows - 1; + lines_left = (int)(Rows - 1); } xfree(cmdline); @@ -281,7 +281,7 @@ void do_debug(char_u *cmd) redraw_all_later(NOT_VALID); need_wait_return = FALSE; msg_scroll = save_msg_scroll; - lines_left = Rows - 1; + lines_left = (int)(Rows - 1); State = save_State; did_emsg = save_did_emsg; cmd_silent = save_cmd_silent; @@ -392,12 +392,12 @@ int dbg_check_skipped(exarg_T *eap) * This is a grow-array of structs. */ struct debuggy { - int dbg_nr; /* breakpoint number */ - int dbg_type; /* DBG_FUNC or DBG_FILE */ - char_u *dbg_name; /* function or file name */ - regprog_T *dbg_prog; /* regexp program */ - linenr_T dbg_lnum; /* line number in function or file */ - int dbg_forceit; /* ! used */ + int dbg_nr; ///< breakpoint number + int dbg_type; ///< DBG_FUNC or DBG_FILE + char_u *dbg_name; ///< function or file name + regprog_T *dbg_prog; ///< regexp program + linenr_T dbg_lnum; ///< line number in function or file + int dbg_forceit; ///< ! used }; static garray_T dbg_breakp = {0, 0, sizeof(struct debuggy), 4, NULL}; @@ -563,13 +563,14 @@ void ex_breakdel(exarg_T *eap) } if (ascii_isdigit(*eap->arg)) { - /* ":breakdel {nr}" */ - nr = atol((char *)eap->arg); - for (int i = 0; i < gap->ga_len; ++i) + // ":breakdel {nr}" + nr = atoi((char *)eap->arg); + for (int i = 0; i < gap->ga_len; ++i) { if (DEBUGGY(gap, i).dbg_nr == nr) { todel = i; break; } + } } else if (*eap->arg == '*') { todel = 0; del_all = TRUE; @@ -602,11 +603,13 @@ void ex_breakdel(exarg_T *eap) --gap->ga_len; if (todel < gap->ga_len) memmove(&DEBUGGY(gap, todel), &DEBUGGY(gap, todel + 1), - (gap->ga_len - todel) * sizeof(struct debuggy)); - if (eap->cmdidx == CMD_breakdel) + (size_t)(gap->ga_len - todel) * sizeof(struct debuggy)); + if (eap->cmdidx == CMD_breakdel) { ++debug_tick; - if (!del_all) + } + if (!del_all) { break; + } } /* If all breakpoints were removed clear the array. */ @@ -810,8 +813,8 @@ void ex_pydo3(exarg_T *eap) /* Command line expansion for :profile. */ static enum { - PEXP_SUBCMD, /* expand :profile sub-commands */ - PEXP_FUNC /* expand :profile func {funcname} */ + PEXP_SUBCMD, ///< expand :profile sub-commands + PEXP_FUNC ///< expand :profile func {funcname} } pexpand_what; static char *pexpand_cmds[] = { @@ -892,7 +895,7 @@ static void profile_reset(void) for (int id = 1; id <= script_items.ga_len; id++) { scriptitem_T *si = &SCRIPT_ITEM(id); if (si->sn_prof_on) { - si->sn_prof_on = 0; + si->sn_prof_on = false; si->sn_pr_force = 0; si->sn_pr_child = profile_zero(); si->sn_pr_nest = 0; @@ -949,7 +952,7 @@ static void profile_init(scriptitem_T *si) ga_init(&si->sn_prl_ga, sizeof(sn_prl_T), 100); si->sn_prl_idx = -1; - si->sn_prof_on = TRUE; + si->sn_prof_on = true; si->sn_pr_nest = 0; } @@ -1255,7 +1258,7 @@ check_changed_any ( int save; int i; int bufnum = 0; - int bufcount = 0; + size_t bufcount = 0; int *bufnrs; FOR_ALL_BUFFERS(buf) { @@ -1520,7 +1523,7 @@ do_arglist ( didone = TRUE; xfree(ARGLIST[match].ae_fname); memmove(ARGLIST + match, ARGLIST + match + 1, - (ARGCOUNT - match - 1) * sizeof(aentry_T)); + (size_t)(ARGCOUNT - match - 1) * sizeof(aentry_T)); --ALIST(curwin)->al_ga.ga_len; if (curwin->w_arg_idx > match) --curwin->w_arg_idx; @@ -1537,9 +1540,7 @@ do_arglist ( int i = expand_wildcards(new_ga.ga_len, (char_u **)new_ga.ga_data, &exp_count, &exp_files, EW_DIR|EW_FILE|EW_ADDSLASH|EW_NOTFOUND); ga_clear(&new_ga); - if (i == FAIL) - return FAIL; - if (exp_count == 0) { + if (i == FAIL || exp_count == 0) { EMSG(_(e_nomatch)); return FAIL; } @@ -1702,10 +1703,11 @@ void ex_argument(exarg_T *eap) { int i; - if (eap->addr_count > 0) - i = eap->line2 - 1; - else + if (eap->addr_count > 0) { + i = (int)eap->line2 - 1; + } else { i = curwin->w_arg_idx; + } do_argfile(eap, i); } @@ -1844,22 +1846,25 @@ void ex_argadd(exarg_T *eap) void ex_argdelete(exarg_T *eap) { if (eap->addr_count > 0) { - /* ":1,4argdel": Delete all arguments in the range. */ - if (eap->line2 > ARGCOUNT) + // ":1,4argdel": Delete all arguments in the range. + if (eap->line2 > ARGCOUNT) { eap->line2 = ARGCOUNT; - int n = eap->line2 - eap->line1 + 1; - if (*eap->arg != NUL || n <= 0) + } + linenr_T n = eap->line2 - eap->line1 + 1; + if (*eap->arg != NUL || n <= 0) { EMSG(_(e_invarg)); - else { - for (int i = eap->line1; i <= eap->line2; ++i) + } else { + for (linenr_T i = eap->line1; i <= eap->line2; ++i) { xfree(ARGLIST[i - 1].ae_fname); + } memmove(ARGLIST + eap->line1 - 1, ARGLIST + eap->line2, - (size_t)((ARGCOUNT - eap->line2) * sizeof(aentry_T))); - ALIST(curwin)->al_ga.ga_len -= n; - if (curwin->w_arg_idx >= eap->line2) - curwin->w_arg_idx -= n; - else if (curwin->w_arg_idx > eap->line1) - curwin->w_arg_idx = eap->line1; + (size_t)(ARGCOUNT - eap->line2) * sizeof(aentry_T)); + ALIST(curwin)->al_ga.ga_len -= (int)n; + if (curwin->w_arg_idx >= eap->line2) { + curwin->w_arg_idx -= (int)n; + } else if (curwin->w_arg_idx > eap->line1) { + curwin->w_arg_idx = (int)eap->line1; + } } } else if (*eap->arg == NUL) EMSG(_(e_argreq)); @@ -1909,7 +1914,7 @@ void ex_listdo(exarg_T *eap) } break; case CMD_argdo: - i = eap->line1 - 1; + i = (int)eap->line1 - 1; break; default: break; @@ -1942,10 +1947,11 @@ void ex_listdo(exarg_T *eap) ex_cc(eap); buf = curbuf; - i = eap->line1 - 1; + i = (int)eap->line1 - 1; if (eap->addr_count <= 0) { // Default to all quickfix/location list entries. - eap->line2 = qf_size; + assert(qf_size < MAXLNUM); + eap->line2 = (linenr_T)qf_size; } } } else { @@ -2098,7 +2104,7 @@ alist_add_list ( after = ARGCOUNT; if (after < ARGCOUNT) memmove(&(ARGLIST[after + count]), &(ARGLIST[after]), - (ARGCOUNT - after) * sizeof(aentry_T)); + (size_t)(ARGCOUNT - after) * sizeof(aentry_T)); for (int i = 0; i < count; ++i) { ARGLIST[after + i].ae_fname = files[i]; ARGLIST[after + i].ae_fnum = buflist_add(files[i], BLN_LISTED); @@ -2571,7 +2577,7 @@ do_source ( while (script_items.ga_len < current_SID) { ++script_items.ga_len; SCRIPT_ITEM(script_items.ga_len).sn_name = NULL; - SCRIPT_ITEM(script_items.ga_len).sn_prof_on = FALSE; + SCRIPT_ITEM(script_items.ga_len).sn_prof_on = false; } si = &SCRIPT_ITEM(current_SID); si->sn_name = fname_exp; @@ -3386,8 +3392,8 @@ static void script_host_execute(char *name, exarg_T *eap) // script list_append_string(args, script ? script : eap->arg, -1); // current range - list_append_number(args, eap->line1); - list_append_number(args, eap->line2); + list_append_number(args, (int)eap->line1); + list_append_number(args, (int)eap->line2); (void)eval_call_provider(name, "execute", args); } @@ -3403,16 +3409,16 @@ static void script_host_execute_file(char *name, exarg_T *eap) // filename list_append_string(args, buffer, -1); // current range - list_append_number(args, eap->line1); - list_append_number(args, eap->line2); + list_append_number(args, (int)eap->line1); + list_append_number(args, (int)eap->line2); (void)eval_call_provider(name, "execute_file", args); } static void script_host_do_range(char *name, exarg_T *eap) { list_T *args = list_alloc(); - list_append_number(args, eap->line1); - list_append_number(args, eap->line2); + list_append_number(args, (int)eap->line1); + list_append_number(args, (int)eap->line2); list_append_string(args, eap->arg, -1); (void)eval_call_provider(name, "do_range", args); } diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index 1ae440c757..3a24f194c1 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -381,15 +381,14 @@ int do_cmdline(char_u *cmdline, LineGetter fgetline, suppress_errthrow = FALSE; } - /* - * If requested, store and reset the global values controlling the - * exception handling (used when debugging). Otherwise clear it to avoid - * a bogus compiler warning when the optimizer uses inline functions... - */ - if (flags & DOCMD_EXCRESET) + // If requested, store and reset the global values controlling the + // exception handling (used when debugging). Otherwise clear it to avoid + // a bogus compiler warning when the optimizer uses inline functions... + if (flags & DOCMD_EXCRESET) { save_dbg_stuff(&debug_saved); - else - memset(&debug_saved, 0, 1); + } else { + memset(&debug_saved, 0, sizeof(debug_saved)); + } initial_trylevel = trylevel; @@ -1702,9 +1701,9 @@ static char_u * do_one_cmd(char_u **cmdlinep, p = vim_strnsave(ea.cmd, p - ea.cmd); int ret = apply_autocmds(EVENT_CMDUNDEFINED, p, p, TRUE, NULL); xfree(p); - if (ret && !aborting()) { - p = find_command(&ea, NULL); - } + // If the autocommands did something and didn't cause an error, try + // finding the command again. + p = (ret && !aborting()) ? find_command(&ea, NULL) : NULL; } if (p == NULL) { @@ -2348,8 +2347,11 @@ static char_u *find_command(exarg_T *eap, int *full) eap->cmdidx = CMD_k; ++p; } else if (p[0] == 's' - && ((p[1] == 'c' && p[2] != 's' && p[2] != 'r' - && p[3] != 'i' && p[4] != 'p') + && ((p[1] == 'c' + && (p[2] == NUL + || (p[2] != 's' && p[2] != 'r' + && (p[3] == NUL + || (p[3] != 'i' && p[4] != 'p'))))) || p[1] == 'g' || (p[1] == 'i' && p[2] != 'm' && p[2] != 'l' && p[2] != 'g') || p[1] == 'I' @@ -2676,16 +2678,25 @@ set_one_cmd_context ( p = cmd + 1; } else { p = cmd; - while (ASCII_ISALPHA(*p) || *p == '*') /* Allow * wild card */ - ++p; - /* check for non-alpha command */ - if (p == cmd && vim_strchr((char_u *)"@*!=><&~#", *p) != NULL) - ++p; - /* for python 3.x: ":py3*" commands completion */ + while (ASCII_ISALPHA(*p) || *p == '*') { // Allow * wild card + p++; + } + // a user command may contain digits + if (ASCII_ISUPPER(cmd[0])) { + while (ASCII_ISALNUM(*p) || *p == '*') { + p++; + } + } + // for python 3.x: ":py3*" commands completion if (cmd[0] == 'p' && cmd[1] == 'y' && p == cmd + 2 && *p == '3') { - ++p; - while (ASCII_ISALPHA(*p) || *p == '*') - ++p; + p++; + while (ASCII_ISALPHA(*p) || *p == '*') { + p++; + } + } + // check for non-alpha command + if (p == cmd && vim_strchr((char_u *)"@*!=><&~#", *p) != NULL) { + p++; } len = (int)(p - cmd); @@ -2699,9 +2710,11 @@ set_one_cmd_context ( (size_t)len) == 0) break; - if (cmd[0] >= 'A' && cmd[0] <= 'Z') - while (ASCII_ISALNUM(*p) || *p == '*') /* Allow * wild card */ - ++p; + if (cmd[0] >= 'A' && cmd[0] <= 'Z') { + while (ASCII_ISALNUM(*p) || *p == '*') { // Allow * wild card + p++; + } + } } /* @@ -4307,7 +4320,7 @@ static void ex_unmap(exarg_T *eap) */ static void ex_mapclear(exarg_T *eap) { - map_clear(eap->cmd, eap->arg, eap->forceit, FALSE); + map_clear_mode(eap->cmd, eap->arg, eap->forceit, false); } /* @@ -4315,7 +4328,7 @@ static void ex_mapclear(exarg_T *eap) */ static void ex_abclear(exarg_T *eap) { - map_clear(eap->cmd, eap->arg, TRUE, TRUE); + map_clear_mode(eap->cmd, eap->arg, true, true); } static void ex_autocmd(exarg_T *eap) @@ -5656,8 +5669,13 @@ static void ex_quit(exarg_T *eap) || (only_one_window() && check_changed_any(eap->forceit))) { not_exiting(); } else { - if (only_one_window()) { - // quit last window + // quit last window + // Note: only_one_window() returns true, even so a help window is + // still open. In that case only quit, if no address has been + // specified. Example: + // :h|wincmd w|1q - don't quit + // :h|wincmd w|q - quit + if (only_one_window() && (firstwin == lastwin || eap->addr_count == 0)) { getout(0); } /* close window; may free buffer */ @@ -8275,16 +8293,22 @@ static char_u *arg_all(void) retval[len] = ' '; ++len; } - for (; *p != NUL; ++p) { - if (*p == ' ' || *p == '\\') { - /* insert a backslash */ - if (retval != NULL) + for (; *p != NUL; p++) { + if (*p == ' ' +#ifndef BACKSLASH_IN_FILENAME + || *p == '\\' +#endif + ) { + // insert a backslash + if (retval != NULL) { retval[len] = '\\'; - ++len; + } + len++; } - if (retval != NULL) + if (retval != NULL) { retval[len] = *p; - ++len; + } + len++; } } @@ -8363,8 +8387,7 @@ makeopens ( { int only_save_windows = TRUE; int nr; - int cnr = 1; - int restore_size = TRUE; + int restore_size = true; win_T *wp; char_u *sname; win_T *edited_win = NULL; @@ -8481,7 +8504,8 @@ makeopens ( tab_firstwin = firstwin; /* first window in tab page "tabnr" */ tab_topframe = topframe; for (tabnr = 1;; ++tabnr) { - int need_tabnew = FALSE; + int need_tabnew = false; + int cnr = 1; if ((ssop_flags & SSOP_TABPAGES)) { tabpage_T *tp = find_tabpage(tabnr); @@ -8760,19 +8784,18 @@ static int ses_do_frame(frame_T *fr) return FALSE; } -/* - * Return non-zero if window "wp" is to be stored in the Session. - */ +/// Return non-zero if window "wp" is to be stored in the Session. static int ses_do_win(win_T *wp) { if (wp->w_buffer->b_fname == NULL - /* When 'buftype' is "nofile" can't restore the window contents. */ - || bt_nofile(wp->w_buffer) - ) + // When 'buftype' is "nofile" can't restore the window contents. + || (!wp->w_buffer->terminal && bt_nofile(wp->w_buffer))) { return ssop_flags & SSOP_BLANK; - if (wp->w_buffer->b_help) + } + if (wp->w_buffer->b_help) { return ssop_flags & SSOP_HELP; - return TRUE; + } + return true; } /* @@ -9208,9 +9231,9 @@ char_u *get_behave_arg(expand_T *xp, int idx) return NULL; } -static int filetype_detect = FALSE; -static int filetype_plugin = FALSE; -static int filetype_indent = FALSE; +static TriState filetype_detect = kNone; +static TriState filetype_plugin = kNone; +static TriState filetype_indent = kNone; /* * ":filetype [plugin] [indent] {on,off,detect}" @@ -9224,27 +9247,27 @@ static int filetype_indent = FALSE; static void ex_filetype(exarg_T *eap) { char_u *arg = eap->arg; - int plugin = FALSE; - int indent = FALSE; + bool plugin = false; + bool indent = false; if (*eap->arg == NUL) { /* Print current status. */ smsg("filetype detection:%s plugin:%s indent:%s", - filetype_detect ? "ON" : "OFF", - filetype_plugin ? (filetype_detect ? "ON" : "(on)") : "OFF", - filetype_indent ? (filetype_detect ? "ON" : "(on)") : "OFF"); + filetype_detect == kTrue ? "ON" : "OFF", + filetype_plugin == kTrue ? (filetype_detect == kTrue ? "ON" : "(on)") : "OFF", // NOLINT(whitespace/line_length) + filetype_indent == kTrue ? (filetype_detect == kTrue ? "ON" : "(on)") : "OFF"); // NOLINT(whitespace/line_length) return; } /* Accept "plugin" and "indent" in any order. */ for (;; ) { if (STRNCMP(arg, "plugin", 6) == 0) { - plugin = TRUE; + plugin = true; arg = skipwhite(arg + 6); continue; } if (STRNCMP(arg, "indent", 6) == 0) { - indent = TRUE; + indent = true; arg = skipwhite(arg + 6); continue; } @@ -9252,15 +9275,15 @@ static void ex_filetype(exarg_T *eap) } if (STRCMP(arg, "on") == 0 || STRCMP(arg, "detect") == 0) { if (*arg == 'o' || !filetype_detect) { - source_runtime((char_u *)FILETYPE_FILE, TRUE); - filetype_detect = TRUE; + source_runtime((char_u *)FILETYPE_FILE, true); + filetype_detect = kTrue; if (plugin) { - source_runtime((char_u *)FTPLUGIN_FILE, TRUE); - filetype_plugin = TRUE; + source_runtime((char_u *)FTPLUGIN_FILE, true); + filetype_plugin = kTrue; } if (indent) { - source_runtime((char_u *)INDENT_FILE, TRUE); - filetype_indent = TRUE; + source_runtime((char_u *)INDENT_FILE, true); + filetype_indent = kTrue; } } if (*arg == 'd') { @@ -9270,21 +9293,37 @@ static void ex_filetype(exarg_T *eap) } else if (STRCMP(arg, "off") == 0) { if (plugin || indent) { if (plugin) { - source_runtime((char_u *)FTPLUGOF_FILE, TRUE); - filetype_plugin = FALSE; + source_runtime((char_u *)FTPLUGOF_FILE, true); + filetype_plugin = kFalse; } if (indent) { - source_runtime((char_u *)INDOFF_FILE, TRUE); - filetype_indent = FALSE; + source_runtime((char_u *)INDOFF_FILE, true); + filetype_indent = kFalse; } } else { - source_runtime((char_u *)FTOFF_FILE, TRUE); - filetype_detect = FALSE; + source_runtime((char_u *)FTOFF_FILE, true); + filetype_detect = kFalse; } } else EMSG2(_(e_invarg2), arg); } +/// Do ":filetype plugin indent on" if user did not already do some +/// permutation thereof. +void filetype_maybe_enable(void) +{ + if (filetype_detect == kNone + && filetype_plugin == kNone + && filetype_indent == kNone) { + source_runtime((char_u *)FILETYPE_FILE, true); + filetype_detect = kTrue; + source_runtime((char_u *)FTPLUGIN_FILE, true); + filetype_plugin = kTrue; + source_runtime((char_u *)INDENT_FILE, true); + filetype_indent = kTrue; + } +} + /* * ":setfiletype {name}" */ @@ -9322,59 +9361,62 @@ static void ex_nohlsearch(exarg_T *eap) redraw_all_later(SOME_VALID); } -/* - * ":[N]match {group} {pattern}" - * Sets nextcmd to the start of the next command, if any. Also called when - * skipping commands to find the next command. - */ +// ":[N]match {group} {pattern}" +// Sets nextcmd to the start of the next command, if any. Also called when +// skipping commands to find the next command. static void ex_match(exarg_T *eap) { - char_u *p; - char_u *g = NULL; - char_u *end; + char_u *p; + char_u *g = NULL; + char_u *end; int c; int id; - if (eap->line2 <= 3) + if (eap->line2 <= 3) { id = eap->line2; - else { + } else { EMSG(e_invcmd); return; } - /* First clear any old pattern. */ - if (!eap->skip) - match_delete(curwin, id, FALSE); + // First clear any old pattern. + if (!eap->skip) { + match_delete(curwin, id, false); + } - if (ends_excmd(*eap->arg)) + if (ends_excmd(*eap->arg)) { end = eap->arg; - else if ((STRNICMP(eap->arg, "none", 4) == 0 - && (ascii_iswhite(eap->arg[4]) || ends_excmd(eap->arg[4])))) + } else if ((STRNICMP(eap->arg, "none", 4) == 0 + && (ascii_iswhite(eap->arg[4]) || ends_excmd(eap->arg[4])))) { end = eap->arg + 4; - else { + } else { p = skiptowhite(eap->arg); - if (!eap->skip) + if (!eap->skip) { g = vim_strnsave(eap->arg, (int)(p - eap->arg)); + } p = skipwhite(p); if (*p == NUL) { - /* There must be two arguments. */ + // There must be two arguments. + xfree(g); EMSG2(_(e_invarg2), eap->arg); return; } - end = skip_regexp(p + 1, *p, TRUE, NULL); + end = skip_regexp(p + 1, *p, true, NULL); if (!eap->skip) { if (*end != NUL && !ends_excmd(*skipwhite(end + 1))) { + xfree(g); eap->errmsg = e_trailing; return; } if (*end != *p) { + xfree(g); EMSG2(_(e_invarg2), p); return; } c = *end; *end = NUL; - match_add(curwin, g, p + 1, 10, id, NULL); + match_add(curwin, g, p + 1, 10, id, NULL, NULL); xfree(g); *end = c; } diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index 96bf2c78d2..39bff9b2ad 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -2957,20 +2957,37 @@ ExpandOne ( } } - /* Find longest common part */ + // Find longest common part if (mode == WILD_LONGEST && xp->xp_numfiles > 0) { size_t len; - for (len = 0; xp->xp_files[0][len]; ++len) { - for (i = 0; i < xp->xp_numfiles; ++i) { + size_t mb_len = 1; + int c0; + int ci; + + for (len = 0; xp->xp_files[0][len]; len += mb_len) { + if (has_mbyte) { + mb_len = (* mb_ptr2len)(&xp->xp_files[0][len]); + c0 = (* mb_ptr2char)(&xp->xp_files[0][len]); + } else { + c0 = xp->xp_files[0][len]; + } + for (i = 1; i < xp->xp_numfiles; ++i) { + if (has_mbyte) { + ci =(* mb_ptr2char)(&xp->xp_files[i][len]); + } else { + ci = xp->xp_files[i][len]; + } + if (p_fic && (xp->xp_context == EXPAND_DIRECTORIES || xp->xp_context == EXPAND_FILES || xp->xp_context == EXPAND_SHELLCMD || xp->xp_context == EXPAND_BUFFERS)) { - if (TOLOWER_LOC(xp->xp_files[i][len]) != - TOLOWER_LOC(xp->xp_files[0][len])) + if (vim_tolower(c0) != vim_tolower(ci)) { break; - } else if (xp->xp_files[i][len] != xp->xp_files[0][len]) + } + } else if (c0 != ci) { break; + } } if (i < xp->xp_numfiles) { if (!(options & WILD_NO_BEEP)) { @@ -2979,8 +2996,9 @@ ExpandOne ( break; } } + ss = (char_u *)xstrndup((char *)xp->xp_files[0], len); - findex = -1; /* next p_wc gets first one */ + findex = -1; // next p_wc gets first one } // Concatenate all matching names @@ -5136,6 +5154,8 @@ static int ex_window(void) /* Don't execute autocommands while deleting the window. */ block_autocmds(); + // Avoid command-line window first character being concealed + curwin->w_p_cole = 0; wp = curwin; bp = curbuf; win_goto(old_curwin); diff --git a/src/nvim/file_search.c b/src/nvim/file_search.c index b213a42c52..2929790ebf 100644 --- a/src/nvim/file_search.c +++ b/src/nvim/file_search.c @@ -484,28 +484,21 @@ vim_findfile_init ( len = (int)(p - search_ctx->ffsc_fix_path) - 1; STRNCAT(ff_expand_buffer, search_ctx->ffsc_fix_path, len); add_pathsep((char *)ff_expand_buffer); - } else + } else { len = (int)STRLEN(search_ctx->ffsc_fix_path); + } if (search_ctx->ffsc_wc_path != NULL) { wc_path = vim_strsave(search_ctx->ffsc_wc_path); temp = xmalloc(STRLEN(search_ctx->ffsc_wc_path) + STRLEN(search_ctx->ffsc_fix_path + len) + 1); - } - - if (temp == NULL || wc_path == NULL) { - xfree(buf); - xfree(temp); + STRCPY(temp, search_ctx->ffsc_fix_path + len); + STRCAT(temp, search_ctx->ffsc_wc_path); + xfree(search_ctx->ffsc_wc_path); xfree(wc_path); - goto error_return; + search_ctx->ffsc_wc_path = temp; } - - STRCPY(temp, search_ctx->ffsc_fix_path + len); - STRCAT(temp, search_ctx->ffsc_wc_path); - xfree(search_ctx->ffsc_wc_path); - xfree(wc_path); - search_ctx->ffsc_wc_path = temp; } xfree(buf); } @@ -1046,41 +1039,44 @@ static ff_visited_list_hdr_T *ff_get_visited_list(char_u *filename, ff_visited_l return retptr; } -/* - * check if two wildcard paths are equal. Returns TRUE or FALSE. - * They are equal if: - * - both paths are NULL - * - they have the same length - * - char by char comparison is OK - * - the only differences are in the counters behind a '**', so - * '**\20' is equal to '**\24' - */ -static int ff_wc_equal(char_u *s1, char_u *s2) +// Check if two wildcard paths are equal. +// They are equal if: +// - both paths are NULL +// - they have the same length +// - char by char comparison is OK +// - the only differences are in the counters behind a '**', so +// '**\20' is equal to '**\24' +static bool ff_wc_equal(char_u *s1, char_u *s2) { - int i; + int i, j; + int c1 = NUL; + int c2 = NUL; int prev1 = NUL; int prev2 = NUL; - if (s1 == s2) - return TRUE; - - if (s1 == NULL || s2 == NULL) - return FALSE; + if (s1 == s2) { + return true; + } - if (STRLEN(s1) != STRLEN(s2)) - return FAIL; + if (s1 == NULL || s2 == NULL) { + return false; + } - for (i = 0; s1[i] != NUL && s2[i] != NUL; i += MB_PTR2LEN(s1 + i)) { - int c1 = PTR2CHAR(s1 + i); - int c2 = PTR2CHAR(s2 + i); + for (i = 0, j = 0; s1[i] != NUL && s2[j] != NUL;) { + c1 = PTR2CHAR(s1 + i); + c2 = PTR2CHAR(s2 + j); if ((p_fic ? vim_tolower(c1) != vim_tolower(c2) : c1 != c2) - && (prev1 != '*' || prev2 != '*')) - return FAIL; + && (prev1 != '*' || prev2 != '*')) { + return false; + } prev2 = prev1; prev1 = c1; + + i += MB_PTR2LEN(s1 + i); + j += MB_PTR2LEN(s2 + j); } - return TRUE; + return s1[i] == s2[j]; } /* @@ -1111,10 +1107,11 @@ static int ff_check_visited(ff_visited_T **visited_list, char_u *fname, char_u * if ((url && fnamecmp(vp->ffv_fname, ff_expand_buffer) == 0) || (!url && vp->file_id_valid && os_fileid_equal(&(vp->file_id), &file_id))) { - /* are the wildcard parts equal */ - if (ff_wc_equal(vp->ffv_wc_path, wc_path) == TRUE) - /* already visited */ + // are the wildcard parts equal + if (ff_wc_equal(vp->ffv_wc_path, wc_path)) { + // already visited return FAIL; + } } } diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c index badb5b85b0..383cd47dbe 100644 --- a/src/nvim/fileio.c +++ b/src/nvim/fileio.c @@ -1543,12 +1543,12 @@ rewind_retry: if (fileformat == EOL_UNKNOWN) { /* First try finding a NL, for Dos and Unix */ if (try_dos || try_unix) { - for (p = ptr; p < ptr + size; ++p) { - // Reset the carriage return counter. - if (try_mac) { - try_mac = 1; - } + // Reset the carriage return counter. + if (try_mac) { + try_mac = 1; + } + for (p = ptr; p < ptr + size; ++p) { if (*p == NL) { if (!try_unix || (try_dos && p > ptr && p[-1] == CAR)) @@ -7160,10 +7160,11 @@ char_u * file_pat_to_reg_pat( else reg_pat[i++] = '^'; endp = pat_end - 1; - if (*endp == '*') { - while (endp - pat > 0 && *endp == '*') + if (endp >= pat && *endp == '*') { + while (endp - pat > 0 && *endp == '*') { endp--; - add_dollar = FALSE; + } + add_dollar = false; } for (p = pat; *p && nested >= 0 && p <= endp; p++) { switch (*p) { @@ -7218,12 +7219,12 @@ char_u * file_pat_to_reg_pat( #ifdef BACKSLASH_IN_FILENAME && no_bslash #endif - ) + ) { reg_pat[i++] = '?'; - else if (*p == ',' || *p == '%' || *p == '#' - || *p == ' ' || *p == '{' || *p == '}') + } else if (*p == ',' || *p == '%' || *p == '#' + || ascii_isspace(*p) || *p == '{' || *p == '}') { reg_pat[i++] = *p; - else if (*p == '\\' && p[1] == '\\' && p[2] == '{') { + } else if (*p == '\\' && p[1] == '\\' && p[2] == '{') { reg_pat[i++] = '\\'; reg_pat[i++] = '{'; p += 2; diff --git a/src/nvim/fold.c b/src/nvim/fold.c index 2e32e78062..6c135ef47b 100644 --- a/src/nvim/fold.c +++ b/src/nvim/fold.c @@ -767,9 +767,9 @@ void foldUpdate(win_T *wp, linenr_T top, linenr_T bot) return; } - /* Mark all folds from top to bot as maybe-small. */ - (void)foldFind(&curwin->w_folds, top, &fp); - while (fp < (fold_T *)curwin->w_folds.ga_data + curwin->w_folds.ga_len + // Mark all folds from top to bot as maybe-small. + (void)foldFind(&wp->w_folds, top, &fp); + while (fp < (fold_T *)wp->w_folds.ga_data + wp->w_folds.ga_len && fp->fd_top < bot) { fp->fd_small = MAYBE; ++fp; diff --git a/src/nvim/getchar.c b/src/nvim/getchar.c index 89d22ad811..437495faa4 100644 --- a/src/nvim/getchar.c +++ b/src/nvim/getchar.c @@ -1380,13 +1380,15 @@ int vgetc(void) } else { mod_mask = 0x0; last_recorded_len = 0; - for (;; ) { /* this is done twice if there are modifiers */ - if (mod_mask) { /* no mapping after modifier has been read */ + for (;; ) { // this is done twice if there are modifiers + bool did_inc = false; + if (mod_mask) { // no mapping after modifier has been read ++no_mapping; ++allow_keys; + did_inc = true; // mod_mask may change value } - c = vgetorpeek(TRUE); - if (mod_mask) { + c = vgetorpeek(true); + if (did_inc) { --no_mapping; --allow_keys; } @@ -2913,9 +2915,9 @@ do_map ( did_it = TRUE; } } - if (mp->m_mode == 0) { /* entry can be deleted */ - map_free(mpp); - continue; /* continue with *mpp */ + if (mp->m_mode == 0) { // entry can be deleted + mapblock_free(mpp); + continue; // continue with *mpp } /* @@ -3010,7 +3012,7 @@ theend: * Delete one entry from the abbrlist or maphash[]. * "mpp" is a pointer to the m_next field of the PREVIOUS entry! */ -static void map_free(mapblock_T **mpp) +static void mapblock_free(mapblock_T **mpp) { mapblock_T *mp; @@ -3078,7 +3080,7 @@ int get_map_mode(char_u **cmdp, int forceit) * Clear all mappings or abbreviations. * 'abbr' should be FALSE for mappings, TRUE for abbreviations. */ -void map_clear(char_u *cmdp, char_u *arg, int forceit, int abbr) +void map_clear_mode(char_u *cmdp, char_u *arg, int forceit, int abbr) { int mode; int local; @@ -3130,8 +3132,8 @@ map_clear_int ( mp = *mpp; if (mp->m_mode & mode) { mp->m_mode &= ~mode; - if (mp->m_mode == 0) { /* entry can be deleted */ - map_free(mpp); + if (mp->m_mode == 0) { // entry can be deleted + mapblock_free(mpp); continue; } /* diff --git a/src/nvim/globals.h b/src/nvim/globals.h index b45f13de4c..69e65c3208 100644 --- a/src/nvim/globals.h +++ b/src/nvim/globals.h @@ -100,6 +100,12 @@ # define VIMRC_FILE ".nvimrc" #endif +typedef enum { + kNone = -1, + kFalse = 0, + kTrue = 1, +} TriState; + /* Values for "starting" */ #define NO_SCREEN 2 /* no screen updating yet */ #define NO_BUFFERS 1 /* not all buffers loaded yet */ @@ -159,15 +165,6 @@ EXTERN int Screen_mco INIT(= 0); /* value of p_mco used when * These are single-width. */ EXTERN schar_T *ScreenLines2 INIT(= NULL); -/* - * Indexes for tab page line: - * N > 0 for label of tab page N - * N == 0 for no label - * N < 0 for closing tab page -N - * N == -999 for closing current tab page - */ -EXTERN short *TabPageIdxs INIT(= NULL); - EXTERN int screen_Rows INIT(= 0); /* actual size of ScreenLines[] */ EXTERN int screen_Columns INIT(= 0); /* actual size of ScreenLines[] */ diff --git a/src/nvim/if_cscope.c b/src/nvim/if_cscope.c index d236501b3f..7169a1d963 100644 --- a/src/nvim/if_cscope.c +++ b/src/nvim/if_cscope.c @@ -1632,77 +1632,79 @@ static char *cs_pathcomponents(char *path) return s; } -/* - * PRIVATE: cs_print_tags_priv - * - * called from cs_manage_matches() - */ +/// Print cscope output that was converted into ctags style entries. +/// +/// Only called from cs_manage_matches(). +/// +/// @param matches Array of cscope lines in ctags style. Every entry was +// produced with a format string of the form +// "%s\t%s\t%s;\"\t%s" or +// "%s\t%s\t%s;\"" +// by cs_make_vim_style_matches(). +/// @param cntxts Context for matches. +/// @param num_matches Number of entries in matches/cntxts, always greater 0. static void cs_print_tags_priv(char **matches, char **cntxts, - size_t num_matches) + size_t num_matches) FUNC_ATTR_NONNULL_ALL { - char *ptag; - char *fname, *lno, *extra, *tbuf; - size_t num; - char *globalcntx = "GLOBAL"; - char *context; - char *cstag_msg = _("Cscope tag: %s"); + char *globalcntx = "GLOBAL"; + char *cstag_msg = _("Cscope tag: %s"); - assert (num_matches > 0); + assert(num_matches > 0); + assert(strcnt(matches[0], '\t') >= 2); - tbuf = xmalloc(strlen(matches[0]) + 1); + char *ptag = matches[0]; + char *ptag_end = strchr(ptag, '\t'); + assert(ptag_end >= ptag); + // NUL terminate tag string in matches[0]. + *ptag_end = NUL; - strcpy(tbuf, matches[0]); - ptag = strtok(tbuf, "\t"); - - size_t newsize = strlen(cstag_msg) + strlen(ptag); + // The "%s" in cstag_msg won't appear in the result string, so we don't need + // extra memory for terminating NUL. + size_t newsize = strlen(cstag_msg) + (size_t)(ptag_end - ptag); char *buf = xmalloc(newsize); size_t bufsize = newsize; // Track available bufsize - (void)sprintf(buf, cstag_msg, ptag); + (void)snprintf(buf, bufsize, cstag_msg, ptag); MSG_PUTS_ATTR(buf, hl_attr(HLF_T)); + msg_clr_eos(); - xfree(tbuf); + // restore matches[0] + *ptag_end = '\t'; - MSG_PUTS_ATTR(_("\n # line"), hl_attr(HLF_T)); /* strlen is 7 */ + // Column headers for match number, line number and filename. + MSG_PUTS_ATTR(_("\n # line"), hl_attr(HLF_T)); msg_advance(msg_col + 2); MSG_PUTS_ATTR(_("filename / context / line\n"), hl_attr(HLF_T)); - num = 1; for (size_t i = 0; i < num_matches; i++) { - size_t idx = i; - - /* if we really wanted to, we could avoid this malloc and strcpy - * by parsing matches[i] on the fly and placing stuff into buf - * directly, but that's too much of a hassle - */ - tbuf = xmalloc(strlen(matches[idx]) + 1); - (void)strcpy(tbuf, matches[idx]); - - if (strtok(tbuf, (const char *)"\t") == NULL) - continue; - if ((fname = strtok(NULL, (const char *)"\t")) == NULL) - continue; - if ((lno = strtok(NULL, (const char *)"\t")) == NULL) - continue; - extra = strtok(NULL, (const char *)"\t"); - - lno[strlen(lno)-2] = '\0'; /* ignore ;" at the end */ + assert(strcnt(matches[i], '\t') >= 2); + + // Parse filename, line number and optional part. + char *fname = strchr(matches[i], '\t') + 1; + char *fname_end = strchr(fname, '\t'); + // Replace second '\t' in matches[i] with NUL to terminate fname. + *fname_end = NUL; + + char *lno = fname_end + 1; + char *extra = xstrchrnul(lno, '\t'); + // Ignore ;" at the end of lno. + char *lno_end = extra - 2; + *lno_end = NUL; + // Do we have an optional part? + extra = *extra ? extra + 1 : NULL; const char *csfmt_str = "%4zu %6s "; - /* hopefully 'num' (num of matches) will be less than 10^16 */ - newsize = strlen(csfmt_str) + 16 + strlen(lno); + // hopefully num_matches will be less than 10^16 + newsize = strlen(csfmt_str) + 16 + (size_t)(lno_end - lno); if (bufsize < newsize) { buf = xrealloc(buf, newsize); bufsize = newsize; } - (void)sprintf(buf, csfmt_str, num, lno); + (void)snprintf(buf, bufsize, csfmt_str, i + 1, lno); MSG_PUTS_ATTR(buf, hl_attr(HLF_CM)); MSG_PUTS_LONG_ATTR(cs_pathcomponents(fname), hl_attr(HLF_CM)); - /* compute the required space for the context */ - if (cntxts[idx] != NULL) - context = cntxts[idx]; - else - context = globalcntx; + // compute the required space for the context + char *context = cntxts[i] ? cntxts[i] : globalcntx; const char *cntxformat = " <<%s>>"; // '%s' won't appear in result string, so: @@ -1713,11 +1715,13 @@ static void cs_print_tags_priv(char **matches, char **cntxts, buf = xrealloc(buf, newsize); bufsize = newsize; } - (void)sprintf(buf, cntxformat, context); + int buf_len = snprintf(buf, bufsize, cntxformat, context); + assert(buf_len >= 0); - /* print the context only if it fits on the same line */ - if (msg_col + (int)strlen(buf) >= (int)Columns) + // Print the context only if it fits on the same line. + if (msg_col + buf_len >= (int)Columns) { msg_putchar('\n'); + } msg_advance(12); MSG_PUTS_LONG(buf); msg_putchar('\n'); @@ -1726,23 +1730,23 @@ static void cs_print_tags_priv(char **matches, char **cntxts, MSG_PUTS_LONG(extra); } - xfree(tbuf); /* only after printing extra due to strtok use */ + // restore matches[i] + *fname_end = '\t'; + *lno_end = ';'; - if (msg_col) + if (msg_col) { msg_putchar('\n'); + } os_breakcheck(); if (got_int) { - got_int = FALSE; /* don't print any more matches */ + got_int = false; // don't print any more matches break; } - - num++; - } /* for all matches */ + } xfree(buf); -} /* cs_print_tags_priv */ - +} /* * PRIVATE: cs_read_prompt diff --git a/src/nvim/indent_c.c b/src/nvim/indent_c.c index 340287499e..17fadc4bfd 100644 --- a/src/nvim/indent_c.c +++ b/src/nvim/indent_c.c @@ -69,23 +69,33 @@ find_start_comment ( /* XXX */ return pos; } -/* - * Find the start of a comment or raw string, not knowing if we are in a - * comment or raw string right now. - * Search starts at w_cursor.lnum and goes backwards. - * Return NULL when not inside a comment or raw string. - * "CORS" -> Comment Or Raw String - */ +/// Find the start of a comment or raw string, not knowing if we are in a +/// comment or raw string right now. +/// Search starts at w_cursor.lnum and goes backwards. +/// +/// @returns NULL when not inside a comment or raw string. +/// +/// @note "CORS" -> Comment Or Raw String static pos_T *ind_find_start_CORS(void) -{ /* XXX */ - pos_T *comment_pos = find_start_comment(curbuf->b_ind_maxcomment); - pos_T *rs_pos = find_start_rawstring(curbuf->b_ind_maxcomment); - - /* If comment_pos is before rs_pos the raw string is inside the comment. - * If rs_pos is before comment_pos the comment is inside the raw string. */ - if (comment_pos == NULL || (rs_pos != NULL && lt(*rs_pos, *comment_pos))) - return rs_pos; - return comment_pos; +{ + // XXX + static pos_T comment_pos_copy; + + pos_T *comment_pos = find_start_comment(curbuf->b_ind_maxcomment); + if (comment_pos != NULL) { + // Need to make a copy of the static pos in findmatchlimit(), + // calling find_start_rawstring() may change it. + comment_pos_copy = *comment_pos; + comment_pos = &comment_pos_copy; + } + pos_T *rs_pos = find_start_rawstring(curbuf->b_ind_maxcomment); + + // If comment_pos is before rs_pos the raw string is inside the comment. + // If rs_pos is before comment_pos the comment is inside the raw string. + if (comment_pos == NULL || (rs_pos != NULL && lt(*rs_pos, *comment_pos))) { + return rs_pos; + } + return comment_pos; } /* @@ -847,13 +857,27 @@ static int cin_isfuncdecl(char_u **sp, linenr_T first_lnum, linenr_T min_lnum) return FALSE; while (*s && *s != '(' && *s != ';' && *s != '\'' && *s != '"') { - if (cin_iscomment(s)) /* ignore comments */ + // ignore comments + if (cin_iscomment(s)) { s = cin_skipcomment(s); - else - ++s; + } else if (*s == ':') { + if (*(s + 1) == ':') { + s += 2; + } else { + // To avoid a mistake in the following situation: + // A::A(int a, int b) + // : a(0) // <--not a function decl + // , b(0) + // {... + return false; + } + } else { + s++; + } + } + if (*s != '(') { + return false; // ';', ' or " before any () or no '(' } - if (*s != '(') - return FALSE; /* ';', ' or " before any () or no '(' */ while (*s && *s != ';' && *s != '\'' && *s != '"') { if (*s == ')' && cin_nocode(s + 1)) { @@ -1122,13 +1146,21 @@ static int cin_is_cpp_baseclass(cpp_baseclass_cache_T *cached) { pos->lnum = lnum; line = ml_get(lnum); - s = cin_skipcomment(line); + s = line; for (;; ) { if (*s == NUL) { - if (lnum == curwin->w_cursor.lnum) + if (lnum == curwin->w_cursor.lnum) { break; - /* Continue in the cursor line. */ + } + // Continue in the cursor line. line = ml_get(++lnum); + s = line; + } + if (s == line) { + // don't recognize "case (foo):" as a baseclass */ + if (cin_iscase(s, false)) { + break; + } s = cin_skipcomment(line); if (*s == NUL) continue; @@ -2707,7 +2739,8 @@ int get_c_indent(void) if (terminated == 0 || (lookfor != LOOKFOR_UNTERM && terminated == ',')) { - if (*skipwhite(l) == '[' || l[STRLEN(l) - 1] == '[') { + if (lookfor != LOOKFOR_ENUM_OR_INIT + && (*skipwhite(l) == '[' || l[STRLEN(l) - 1] == '[')) { amount += ind_continuation; } // If we're in the middle of a paren thing, Go back to the line @@ -2915,34 +2948,35 @@ int get_c_indent(void) continue; } - /* Ignore unterminated lines in between, but - * reduce indent. */ - if (amount > cur_amount) + // Ignore unterminated lines in between, but + // reduce indent. + if (amount > cur_amount) { amount = cur_amount; + } } else { - /* - * Found first unterminated line on a row, may - * line up with this line, remember its indent - * 100 + - * -> here; - */ + // Found first unterminated line on a row, may + // line up with this line, remember its indent + // 100 + // NOLINT(whitespace/tab) + // -> here; // NOLINT(whitespace/tab) l = get_cursor_line_ptr(); amount = cur_amount; - if (*skipwhite(l) == ']' || l[STRLEN(l) - 1] == ']') { + + n = (int)STRLEN(l); + if (terminated == ',' + && (*skipwhite(l) == ']' + || (n >=2 && l[n - 2] == ']'))) { break; } - /* - * If previous line ends in ',', check whether we - * are in an initialization or enum - * struct xxx = - * { - * sizeof a, - * 124 }; - * or a normal possible continuation line. - * but only, of no other statement has been found - * yet. - */ + // If previous line ends in ',', check whether we + // are in an initialization or enum + // struct xxx = + // { + // sizeof a, + // 124 }; + // or a normal possible continuation line. + // but only, of no other statement has been found + // yet. if (lookfor == LOOKFOR_INITIAL && terminated == ',') { if (curbuf->b_ind_js) { // Search for a line ending in a comma diff --git a/src/nvim/keymap.c b/src/nvim/keymap.c index 65c808eb06..6c75d8bdf4 100644 --- a/src/nvim/keymap.c +++ b/src/nvim/keymap.c @@ -1,8 +1,3 @@ -/* - * functions that use lookup tables for various things, generally to do with - * special key codes. - */ - #include <assert.h> #include <inttypes.h> #include <limits.h> @@ -39,7 +34,8 @@ static struct modmasktable { {MOD_MASK_MULTI_CLICK, MOD_MASK_2CLICK, (char_u)'2'}, {MOD_MASK_MULTI_CLICK, MOD_MASK_3CLICK, (char_u)'3'}, {MOD_MASK_MULTI_CLICK, MOD_MASK_4CLICK, (char_u)'4'}, - /* 'A' must be the last one */ + {MOD_MASK_CMD, MOD_MASK_CMD, (char_u)'D'}, + // 'A' must be the last one {MOD_MASK_ALT, MOD_MASK_ALT, (char_u)'A'}, {0, 0, NUL} }; @@ -658,9 +654,11 @@ static int extract_modifiers(int key, int *modp) { int modifiers = *modp; - if ((modifiers & MOD_MASK_SHIFT) && ASCII_ISALPHA(key)) { - key = TOUPPER_ASC(key); - modifiers &= ~MOD_MASK_SHIFT; + if (!(modifiers & MOD_MASK_CMD)) { // Command-key is special + if ((modifiers & MOD_MASK_SHIFT) && ASCII_ISALPHA(key)) { + key = TOUPPER_ASC(key); + modifiers &= ~MOD_MASK_SHIFT; + } } if ((modifiers & MOD_MASK_CTRL) && ((key >= '?' && key <= '_') || ASCII_ISALPHA(key))) { diff --git a/src/nvim/keymap.h b/src/nvim/keymap.h index 766362d145..8f9980c6b4 100644 --- a/src/nvim/keymap.h +++ b/src/nvim/keymap.h @@ -112,11 +112,11 @@ #define TO_SPECIAL(a, b) ((a) == KS_SPECIAL ? K_SPECIAL : (a) == \ KS_ZERO ? K_ZERO : TERMCAP2KEY(a, b)) -/* - * Codes for keys that do not have a termcap name. - * - * K_SPECIAL KS_EXTRA KE_xxx - */ +// Codes for keys that do not have a termcap name. +// +// K_SPECIAL KS_EXTRA KE_xxx +// +// Entries must be in the range 0x02-0x7f (see comment at K_SPECIAL). enum key_extra { KE_NAME = 3 /* name of this terminal entry */ @@ -436,11 +436,12 @@ enum key_extra { /* 0x01 cannot be used, because the modifier must be 0x02 or higher */ #define MOD_MASK_SHIFT 0x02 #define MOD_MASK_CTRL 0x04 -#define MOD_MASK_ALT 0x08 /* aka META */ -#define MOD_MASK_META 0x10 /* META when it's different from ALT */ -#define MOD_MASK_2CLICK 0x20 /* use MOD_MASK_MULTI_CLICK */ -#define MOD_MASK_3CLICK 0x40 /* use MOD_MASK_MULTI_CLICK */ -#define MOD_MASK_4CLICK 0x60 /* use MOD_MASK_MULTI_CLICK */ +#define MOD_MASK_ALT 0x08 // aka META +#define MOD_MASK_META 0x10 // META when it's different from ALT +#define MOD_MASK_2CLICK 0x20 // use MOD_MASK_MULTI_CLICK +#define MOD_MASK_3CLICK 0x40 // use MOD_MASK_MULTI_CLICK +#define MOD_MASK_4CLICK 0x60 // use MOD_MASK_MULTI_CLICK +#define MOD_MASK_CMD 0x80 // "super" key (OSX/Mac: command-key) #define MOD_MASK_MULTI_CLICK (MOD_MASK_2CLICK|MOD_MASK_3CLICK| \ MOD_MASK_4CLICK) @@ -451,14 +452,13 @@ enum key_extra { */ #define MAX_KEY_NAME_LEN 25 -/* Maximum length of a special key event as tokens. This includes modifiers. - * The longest event is something like <M-C-S-T-4-LeftDrag> which would be the - * following string of tokens: - * - * <K_SPECIAL> <KS_MODIFIER> bitmask <K_SPECIAL> <KS_EXTRA> <KT_LEFTDRAG>. - * - * This is a total of 6 tokens, and is currently the longest one possible. - */ +// Maximum length of a special key event as tokens. This includes modifiers. +// The longest event is something like <M-C-S-T-4-LeftDrag> which would be the +// following string of tokens: +// +// <K_SPECIAL> <KS_MODIFIER> bitmask <K_SPECIAL> <KS_EXTRA> <KE_LEFTDRAG>. +// +// This is a total of 6 tokens, and is currently the longest one possible. #define MAX_KEY_CODE_LEN 6 diff --git a/src/nvim/lib/khash.h b/src/nvim/lib/khash.h index 56be29d14c..8287cb14da 100644 --- a/src/nvim/lib/khash.h +++ b/src/nvim/lib/khash.h @@ -184,7 +184,7 @@ typedef khint_t khiter_t; #define kfree(P) xfree(P) #endif -static const double __ac_HASH_UPPER = 0.77; +#define __ac_HASH_UPPER 0.77 #define __KHASH_TYPE(name, khkey_t, khval_t) \ typedef struct { \ diff --git a/src/nvim/lib/kvec.h b/src/nvim/lib/kvec.h index 0466cb229c..53ecf232c6 100644 --- a/src/nvim/lib/kvec.h +++ b/src/nvim/lib/kvec.h @@ -77,10 +77,10 @@ int main() { (v).items[(v).size++] = (x); \ } while (0) -#define kv_pushp(type, v) (((v).size == (v).capacity)? \ +#define kv_pushp(type, v) ((((v).size == (v).capacity)? \ ((v).capacity = ((v).capacity? (v).capacity<<1 : 8), \ (v).items = (type*)xrealloc((v).items, sizeof(type) * (v).capacity), 0) \ - : 0), ((v).items + ((v).size++)) + : 0), ((v).items + ((v).size++))) #define kv_a(type, v, i) (((v).capacity <= (size_t)(i)? \ ((v).capacity = (v).size = (i) + 1, kv_roundup32((v).capacity), \ diff --git a/src/nvim/main.c b/src/nvim/main.c index cef10d12d5..5b5c8a22aa 100644 --- a/src/nvim/main.c +++ b/src/nvim/main.c @@ -219,9 +219,10 @@ int main(int argc, char **argv) { argv0 = (char *)path_tail((char_u *)argv[0]); - char_u *fname = NULL; /* file name from command line */ - mparm_T params; /* various parameters passed between - * main() and other functions. */ + char_u *fname = NULL; // file name from command line + mparm_T params; // various parameters passed between + // main() and other functions. + char_u *cwd = NULL; // current workding dir on startup time_init(); /* Many variables are in "params" so that we can pass them to invoked @@ -316,14 +317,16 @@ int main(int argc, char **argv) } // open terminals when opening files that start with term:// - do_cmdline_cmd("autocmd BufReadCmd term://* " +#define PROTO "term://" + do_cmdline_cmd("autocmd BufReadCmd " PROTO "* nested " ":call termopen( " // Capture the command string "matchstr(expand(\"<amatch>\"), " - "'\\c\\mterm://\\%(.\\{-}//\\%(\\d\\+:\\)\\?\\)\\?\\zs.*'), " + "'\\c\\m" PROTO "\\%(.\\{-}//\\%(\\d\\+:\\)\\?\\)\\?\\zs.*'), " // capture the working directory "{'cwd': get(matchlist(expand(\"<amatch>\"), " - "'\\c\\mterm://\\(.\\{-}\\)//'), 1, '')})"); + "'\\c\\m" PROTO "\\(.\\{-}\\)//'), 1, '')})"); +#undef PROTO /* Execute --cmd arguments. */ exe_pre_commands(¶ms); @@ -331,6 +334,14 @@ int main(int argc, char **argv) /* Source startup scripts. */ source_startup_scripts(¶ms); + // If using the runtime (-u is not NONE), enable syntax & filetype plugins. + if (params.use_vimrc != NULL && strcmp(params.use_vimrc, "NONE") != 0) { + // Does ":filetype plugin indent on". + filetype_maybe_enable(); + // Sources syntax/syntax.vim, which calls `:filetype on`. + syn_maybe_on(); + } + /* * Read all the plugin files. * Only when compiled with +eval, since most plugins need it. @@ -461,11 +472,10 @@ int main(int argc, char **argv) TIME_MSG("jump to first error"); } - /* - * If opened more than one window, start editing files in the other - * windows. - */ - edit_buffers(¶ms); + // If opened more than one window, start editing files in the other + // windows. + edit_buffers(¶ms, cwd); + xfree(cwd); if (params.diff_mode) { /* set options in each window for "nvim -d". */ @@ -649,6 +659,9 @@ static void init_locale(void) setlocale(LC_NUMERIC, "C"); # endif +# ifdef LOCALE_INSTALL_DIR // gnu/linux standard: $prefix/share/locale + bindtextdomain(PROJECT_NAME, LOCALE_INSTALL_DIR); +# else // old vim style: $runtime/lang { char_u *p; @@ -657,11 +670,12 @@ static void init_locale(void) p = (char_u *)vim_getenv("VIMRUNTIME"); if (p != NULL && *p != NUL) { vim_snprintf((char *)NameBuff, MAXPATHL, "%s/lang", p); - bindtextdomain(VIMPACKAGE, (char *)NameBuff); + bindtextdomain(PROJECT_NAME, (char *)NameBuff); } xfree(p); - textdomain(VIMPACKAGE); } +# endif + textdomain(PROJECT_NAME); TIME_MSG("locale set"); } #endif @@ -1182,12 +1196,19 @@ static char_u *get_fname(mparm_T *parmp) * Expand wildcards in file names. */ if (!parmp->literal) { - /* Temporarily add '(' and ')' to 'isfname'. These are valid - * filename characters but are excluded from 'isfname' to make - * "gf" work on a file name in parenthesis (e.g.: see vim.h). */ + cwd = xmalloc(MAXPATHL); + if (cwd != NULL) { + os_dirname(cwd, MAXPATHL); + } + // Temporarily add '(' and ')' to 'isfname'. These are valid + // filename characters but are excluded from 'isfname' to make + // "gf" work on a file name in parenthesis (e.g.: see vim.h). do_cmdline_cmd(":set isf+=(,)"); alist_expand(NULL, 0); do_cmdline_cmd(":set isf&"); + if (cwd != NULL) { + os_chdir((char *)cwd); + } } #endif return alist_name(&GARGLIST[0]); @@ -1417,11 +1438,9 @@ static void create_windows(mparm_T *parmp) } } -/* - * If opened more than one window, start editing files in the other - * windows. make_windows() has already opened the windows. - */ -static void edit_buffers(mparm_T *parmp) +/// If opened more than one window, start editing files in the other +/// windows. make_windows() has already opened the windows. +static void edit_buffers(mparm_T *parmp, char_u *cwd) { int arg_idx; /* index in argument list */ int i; @@ -1442,7 +1461,10 @@ static void edit_buffers(mparm_T *parmp) arg_idx = 1; for (i = 1; i < parmp->window_count; ++i) { - /* When w_arg_idx is -1 remove the window (see create_windows()). */ + if (cwd != NULL) { + os_chdir((char *)cwd); + } + // When w_arg_idx is -1 remove the window (see create_windows()). if (curwin->w_arg_idx == -1) { ++arg_idx; win_close(curwin, TRUE); diff --git a/src/nvim/map.c b/src/nvim/map.c index ed7bda4cce..d4262ae9a8 100644 --- a/src/nvim/map.c +++ b/src/nvim/map.c @@ -18,6 +18,9 @@ #define uint32_t_eq kh_int_hash_equal #define int_hash kh_int_hash_func #define int_eq kh_int_hash_equal +#define linenr_T_hash kh_int_hash_func +#define linenr_T_eq kh_int_hash_equal + #if defined(ARCH_64) #define ptr_t_hash(key) uint64_t_hash((uint64_t)key) @@ -78,6 +81,25 @@ return rv; \ } \ \ + U *map_##T##_##U##_ref(Map(T, U) *map, T key, bool put) \ + { \ + int ret; \ + khiter_t k; \ + if (put) { \ + k = kh_put(T##_##U##_map, map->table, key, &ret); \ + if (ret) { \ + kh_val(map->table, k) = INITIALIZER(T, U); \ + } \ + } else { \ + k = kh_get(T##_##U##_map, map->table, key); \ + if (k == kh_end(map->table)) { \ + return NULL; \ + } \ + } \ + \ + return &kh_val(map->table, k); \ + } \ + \ U map_##T##_##U##_del(Map(T, U) *map, T key) \ { \ U rv = INITIALIZER(T, U); \ @@ -118,3 +140,5 @@ MAP_IMPL(ptr_t, ptr_t, DEFAULT_INITIALIZER) MAP_IMPL(uint64_t, ptr_t, DEFAULT_INITIALIZER) #define MSGPACK_HANDLER_INITIALIZER {.fn = NULL, .async = false} MAP_IMPL(String, MsgpackRpcRequestHandler, MSGPACK_HANDLER_INITIALIZER) +#define KVEC_INITIALIZER { .size = 0, .capacity = 0, .items = NULL } +MAP_IMPL(linenr_T, bufhl_vec_T, KVEC_INITIALIZER) diff --git a/src/nvim/map.h b/src/nvim/map.h index c0e2ca3aac..e90cc360ce 100644 --- a/src/nvim/map.h +++ b/src/nvim/map.h @@ -6,6 +6,7 @@ #include "nvim/map_defs.h" #include "nvim/api/private/defs.h" #include "nvim/msgpack_rpc/defs.h" +#include "nvim/bufhl_defs.h" #define MAP_DECLS(T, U) \ KHASH_DECLARE(T##_##U##_map, T, U) \ @@ -19,6 +20,7 @@ U map_##T##_##U##_get(Map(T, U) *map, T key); \ bool map_##T##_##U##_has(Map(T, U) *map, T key); \ U map_##T##_##U##_put(Map(T, U) *map, T key, U value); \ + U *map_##T##_##U##_ref(Map(T, U) *map, T key, bool put); \ U map_##T##_##U##_del(Map(T, U) *map, T key); \ void map_##T##_##U##_clear(Map(T, U) *map); @@ -28,12 +30,14 @@ MAP_DECLS(cstr_t, ptr_t) MAP_DECLS(ptr_t, ptr_t) MAP_DECLS(uint64_t, ptr_t) MAP_DECLS(String, MsgpackRpcRequestHandler) +MAP_DECLS(linenr_T, bufhl_vec_T) #define map_new(T, U) map_##T##_##U##_new #define map_free(T, U) map_##T##_##U##_free #define map_get(T, U) map_##T##_##U##_get #define map_has(T, U) map_##T##_##U##_has #define map_put(T, U) map_##T##_##U##_put +#define map_ref(T, U) map_##T##_##U##_ref #define map_del(T, U) map_##T##_##U##_del #define map_clear(T, U) map_##T##_##U##_clear diff --git a/src/nvim/mark.c b/src/nvim/mark.c index e2f212340c..fe802e48ba 100644 --- a/src/nvim/mark.c +++ b/src/nvim/mark.c @@ -922,6 +922,7 @@ void mark_adjust(linenr_T line1, linenr_T line2, long amount, long amount_after) } sign_mark_adjust(line1, line2, amount, amount_after); + bufhl_mark_adjust(curbuf, line1, line2, amount, amount_after); } /* previous context mark */ diff --git a/src/nvim/mbyte.c b/src/nvim/mbyte.c index fdd83f9dac..f0a249919f 100644 --- a/src/nvim/mbyte.c +++ b/src/nvim/mbyte.c @@ -571,8 +571,8 @@ char_u * mb_init(void) #ifdef HAVE_WORKING_LIBINTL /* GNU gettext 0.10.37 supports this feature: set the codeset used for * translated messages independently from the current locale. */ - (void)bind_textdomain_codeset(VIMPACKAGE, - enc_utf8 ? "utf-8" : (char *)p_enc); + (void)bind_textdomain_codeset(PROJECT_NAME, + enc_utf8 ? "utf-8" : (char *)p_enc); #endif diff --git a/src/nvim/misc1.c b/src/nvim/misc1.c index 6c969a43fc..db303fd54a 100644 --- a/src/nvim/misc1.c +++ b/src/nvim/misc1.c @@ -1985,13 +1985,13 @@ changed_lines ( changed_common(lnum, col, lnume, xtra); } -static void -changed_lines_buf ( - buf_T *buf, - linenr_T lnum, /* first line with change */ - linenr_T lnume, /* line below last changed line */ - long xtra /* number of extra lines (negative when deleting) */ -) +/// Mark line range in buffer as changed. +/// +/// @param buf the buffer where lines were changed +/// @param lnum first line with change +/// @param lnume line below last changed line +/// @param xtra number of extra lines (negative when deleting) +void changed_lines_buf(buf_T *buf, linenr_T lnum, linenr_T lnume, long xtra) { if (buf->b_mod_set) { /* find the maximum area that must be redisplayed */ diff --git a/src/nvim/move.c b/src/nvim/move.c index eb55397511..ba79c0411a 100644 --- a/src/nvim/move.c +++ b/src/nvim/move.c @@ -1288,9 +1288,10 @@ void scroll_cursor_top(int min_scroll, int always) * - at least 'scrolloff' lines above and below the cursor */ validate_cheight(); - int used = curwin->w_cline_height; - if (curwin->w_cursor.lnum < curwin->w_topline) + int used = curwin->w_cline_height; // includes filler lines above + if (curwin->w_cursor.lnum < curwin->w_topline) { scrolled = used; + } if (hasFolding(curwin->w_cursor.lnum, &top, &bot)) { --top; @@ -1301,9 +1302,10 @@ void scroll_cursor_top(int min_scroll, int always) } new_topline = top + 1; - /* count filler lines of the cursor window as context */ + // "used" already contains the number of filler lines above, don't add it + // again. + // Hide filler lines above cursor line by adding them to "extra". int extra = diff_check_fill(curwin, curwin->w_cursor.lnum); - used += extra; /* * Check if the lines from "top" to "bot" fit in the window. If they do, @@ -1312,7 +1314,7 @@ void scroll_cursor_top(int min_scroll, int always) while (top > 0) { int i = hasFolding(top, &top, NULL) ? 1 // count one logical line for a sequence of folded lines - : plines(top); + : plines_nofill(top); used += i; if (extra + i <= off && bot < curbuf->b_ml.ml_line_count) { if (hasFolding(bot, NULL, &bot)) diff --git a/src/nvim/msgpack_rpc/defs.h b/src/nvim/msgpack_rpc/defs.h index d97cf28ca1..5611636d4f 100644 --- a/src/nvim/msgpack_rpc/defs.h +++ b/src/nvim/msgpack_rpc/defs.h @@ -1,8 +1,6 @@ #ifndef NVIM_MSGPACK_RPC_DEFS_H #define NVIM_MSGPACK_RPC_DEFS_H -#include <msgpack.h> - /// The rpc_method_handlers table, used in msgpack_rpc_dispatch(), stores /// functions of this type. @@ -24,22 +22,6 @@ void msgpack_rpc_add_method_handler(String method, void msgpack_rpc_init_function_metadata(Dictionary *metadata); -/// Dispatches to the actual API function after basic payload validation by -/// `msgpack_rpc_call`. It is responsible for validating/converting arguments -/// to C types, and converting the return value back to msgpack types. -/// The implementation is generated at compile time with metadata extracted -/// from the api/*.h headers, -/// -/// @param channel_id The channel id -/// @param method_id The method id -/// @param req The parsed request object -/// @param error Pointer to error structure -/// @return Some object -Object msgpack_rpc_dispatch(uint64_t channel_id, - msgpack_object *req, - Error *error) - FUNC_ATTR_NONNULL_ARG(2) FUNC_ATTR_NONNULL_ARG(3); - MsgpackRpcRequestHandler msgpack_rpc_get_handler_for(const char *name, size_t name_len) FUNC_ATTR_NONNULL_ARG(1); diff --git a/src/nvim/normal.c b/src/nvim/normal.c index cb3fc98dfa..e064d34e09 100644 --- a/src/nvim/normal.c +++ b/src/nvim/normal.c @@ -1538,9 +1538,11 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank) curbuf->b_visual_mode_eval = VIsual_mode; } - /* In Select mode, a linewise selection is operated upon like a - * characterwise selection. */ - if (VIsual_select && VIsual_mode == 'V') { + // In Select mode, a linewise selection is operated upon like a + // characterwise selection. + // Special case: gH<Del> deletes the last line. + if (VIsual_select && VIsual_mode == 'V' + && cap->oap->op_type != OP_DELETE) { if (lt(VIsual, curwin->w_cursor)) { VIsual.col = 0; curwin->w_cursor.col = @@ -1676,20 +1678,15 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank) && (include_line_break || !virtual_op) ) { oap->inclusive = false; - /* Try to include the newline, unless it's an operator - * that works on lines only. */ - if (*p_sel != 'o' && !op_on_lines(oap->op_type)) { - if (oap->end.lnum < curbuf->b_ml.ml_line_count) { - ++oap->end.lnum; - oap->end.col = 0; - oap->end.coladd = 0; - ++oap->line_count; - } else { - /* Cannot move below the last line, make the op - * inclusive to tell the operation to include the - * line break. */ - oap->inclusive = true; - } + // Try to include the newline, unless it's an operator + // that works on lines only. + if (*p_sel != 'o' + && !op_on_lines(oap->op_type) + && oap->end.lnum < curbuf->b_ml.ml_line_count) { + oap->end.lnum++; + oap->end.col = 0; + oap->end.coladd = 0; + oap->line_count++; } } } @@ -2347,8 +2344,9 @@ do_mouse ( if (mouse_row == 0 && firstwin->w_winrow > 0) { if (is_drag) { if (in_tab_line) { - c1 = TabPageIdxs[mouse_col]; - tabpage_move(c1 <= 0 ? 9999 : c1 - 1); + tabpage_move(tab_page_click_defs[mouse_col].type == kStlClickTabClose + ? 9999 + : tab_page_click_defs[mouse_col].tabnr - 1); } return false; } @@ -2358,41 +2356,114 @@ do_mouse ( && cmdwin_type == 0 && mouse_col < Columns) { in_tab_line = true; - c1 = TabPageIdxs[mouse_col]; - if (c1 >= 0) { - if ((mod_mask & MOD_MASK_MULTI_CLICK) == MOD_MASK_2CLICK) { - /* double click opens new page */ - end_visual_mode(); - tabpage_new(); - tabpage_move(c1 == 0 ? 9999 : c1 - 1); - } else { - /* Go to specified tab page, or next one if not clicking - * on a label. */ - goto_tabpage(c1); - - /* It's like clicking on the status line of a window. */ - if (curwin != old_curwin) + c1 = tab_page_click_defs[mouse_col].tabnr; + switch (tab_page_click_defs[mouse_col].type) { + case kStlClickDisabled: { + break; + } + case kStlClickTabClose: { + tabpage_T *tp; + + // Close the current or specified tab page. + if (c1 == 999) { + tp = curtab; + } else { + tp = find_tabpage(c1); + } + if (tp == curtab) { + if (first_tabpage->tp_next != NULL) { + tabpage_close(false); + } + } else if (tp != NULL) { + tabpage_close_other(tp, false); + } + break; + } + case kStlClickTabSwitch: { + if ((mod_mask & MOD_MASK_MULTI_CLICK) == MOD_MASK_2CLICK) { + // double click opens new page end_visual_mode(); + tabpage_new(); + tabpage_move(c1 == 0 ? 9999 : c1 - 1); + } else { + // Go to specified tab page, or next one if not clicking + // on a label. + goto_tabpage(c1); + + // It's like clicking on the status line of a window. + if (curwin != old_curwin) { + end_visual_mode(); + } + } + break; + } + case kStlClickFuncRun: { + typval_T argv[] = { + { + .v_lock = VAR_FIXED, + .v_type = VAR_NUMBER, + .vval = { + .v_number = (varnumber_T) tab_page_click_defs[mouse_col].tabnr + }, + }, + { + .v_lock = VAR_FIXED, + .v_type = VAR_NUMBER, + .vval = { + .v_number = (((mod_mask & MOD_MASK_MULTI_CLICK) + == MOD_MASK_4CLICK) + ? 4 + : ((mod_mask & MOD_MASK_MULTI_CLICK) + == MOD_MASK_3CLICK) + ? 3 + : ((mod_mask & MOD_MASK_MULTI_CLICK) + == MOD_MASK_2CLICK) + ? 2 + : 1) + }, + }, + { + .v_lock = VAR_FIXED, + .v_type = VAR_STRING, + .vval = { .v_string = (char_u *) (which_button == MOUSE_LEFT + ? "l" + : which_button == MOUSE_RIGHT + ? "r" + : which_button == MOUSE_MIDDLE + ? "m" + : "?") }, + }, + { + .v_lock = VAR_FIXED, + .v_type = VAR_STRING, + .vval = { + .v_string = (char_u[]) { + (char_u) (mod_mask & MOD_MASK_SHIFT ? 's' : ' '), + (char_u) (mod_mask & MOD_MASK_CTRL ? 'c' : ' '), + (char_u) (mod_mask & MOD_MASK_ALT ? 'a' : ' '), + (char_u) (mod_mask & MOD_MASK_META ? 'm' : ' '), + NUL + } + }, + } + }; + typval_T rettv; + int doesrange; + (void) call_func((char_u *) tab_page_click_defs[mouse_col].func, + (int) strlen(tab_page_click_defs[mouse_col].func), + &rettv, ARRAY_SIZE(argv), argv, + curwin->w_cursor.lnum, curwin->w_cursor.lnum, + &doesrange, true, NULL); + clear_tv(&rettv); + break; } - } else if (c1 < 0) { - tabpage_T *tp; - - /* Close the current or specified tab page. */ - if (c1 == -999) - tp = curtab; - else - tp = find_tabpage(-c1); - if (tp == curtab) { - if (first_tabpage->tp_next != NULL) - tabpage_close(false); - } else if (tp != NULL) - tabpage_close_other(tp, false); } } return true; } else if (is_drag && in_tab_line) { - c1 = TabPageIdxs[mouse_col]; - tabpage_move(c1 <= 0 ? 9999 : c1 - 1); + tabpage_move(tab_page_click_defs[mouse_col].type == kStlClickTabClose + ? 9999 + : tab_page_click_defs[mouse_col].tabnr - 1); in_tab_line = false; return false; } @@ -6881,10 +6952,16 @@ static void n_opencmd(cmdarg_T *cap) (cap->cmdchar == 'o' ? 1 : 0)) ) && open_line(cap->cmdchar == 'O' ? BACKWARD : FORWARD, - has_format_option(FO_OPEN_COMS) ? OPENLINE_DO_COM : - 0, 0)) { - if (curwin->w_p_cole > 0 && oldline != curwin->w_cursor.lnum) + has_format_option(FO_OPEN_COMS) + ? OPENLINE_DO_COM : 0, + 0)) { + if (curwin->w_p_cole > 0 && oldline != curwin->w_cursor.lnum) { update_single_line(curwin, oldline); + } + if (curwin->w_p_cul) { + // force redraw of cursorline + curwin->w_valid &= ~VALID_CROW; + } invoke_edit(cap, false, cap->cmdchar, true); } } @@ -7668,6 +7745,10 @@ static void nv_put(cmdarg_T *cap) if (was_visual) { curbuf->b_visual.vi_start = curbuf->b_op_start; curbuf->b_visual.vi_end = curbuf->b_op_end; + // need to adjust cursor position + if (*p_sel == 'e') { + inc(&curbuf->b_visual.vi_end); + } } /* When all lines were selected and deleted do_put() leaves an empty @@ -7702,7 +7783,7 @@ static void nv_open(cmdarg_T *cap) n_opencmd(cap); } -// calculate start/end virtual columns for operating in block mode +// Calculate start/end virtual columns for operating in block mode. static void get_op_vcol( oparg_T *oap, colnr_T redo_VIsual_vcol, @@ -7712,7 +7793,8 @@ static void get_op_vcol( colnr_T start; colnr_T end; - if (VIsual_mode != Ctrl_V) { + if (VIsual_mode != Ctrl_V + || (!initial && oap->end.col < curwin->w_width)) { return; } @@ -7724,20 +7806,23 @@ static void get_op_vcol( } getvvcol(curwin, &(oap->start), &oap->start_vcol, NULL, &oap->end_vcol); - getvvcol(curwin, &(oap->end), &start, NULL, &end); + if (!redo_VIsual_busy) { + getvvcol(curwin, &(oap->end), &start, NULL, &end); - if (start < oap->start_vcol) { - oap->start_vcol = start; - } - if (end > oap->end_vcol) { - if (initial && *p_sel == 'e' - && start >= 1 - && start - 1 >= oap->end_vcol) { - oap->end_vcol = start - 1; - } else { - oap->end_vcol = end; + if (start < oap->start_vcol) { + oap->start_vcol = start; + } + if (end > oap->end_vcol) { + if (initial && *p_sel == 'e' + && start >= 1 + && start - 1 >= oap->end_vcol) { + oap->end_vcol = start - 1; + } else { + oap->end_vcol = end; + } } } + // if '$' was used, get oap->end_vcol from longest line if (curwin->w_curswant == MAXCOL) { curwin->w_cursor.col = MAXCOL; diff --git a/src/nvim/ops.c b/src/nvim/ops.c index 7614e6365a..b1adc85e1d 100644 --- a/src/nvim/ops.c +++ b/src/nvim/ops.c @@ -1555,55 +1555,31 @@ int op_delete(oparg_T *oap) if (gchar_cursor() != NUL) curwin->w_cursor.coladd = 0; } - if (oap->op_type == OP_DELETE - && oap->inclusive - && oap->end.lnum == curbuf->b_ml.ml_line_count - && n > (int)STRLEN(ml_get(oap->end.lnum))) { - /* Special case: gH<Del> deletes the last line. */ - del_lines(1L, FALSE); - } else { - (void)del_bytes((long)n, !virtual_op, oap->op_type == OP_DELETE - && !oap->is_VIsual - ); - } - } else { /* delete characters between lines */ + + (void)del_bytes((long)n, !virtual_op, + oap->op_type == OP_DELETE && !oap->is_VIsual); + } else { + // delete characters between lines pos_T curpos; - int delete_last_line; /* save deleted and changed lines for undo */ if (u_save((linenr_T)(curwin->w_cursor.lnum - 1), (linenr_T)(curwin->w_cursor.lnum + oap->line_count)) == FAIL) return FAIL; - delete_last_line = (oap->end.lnum == curbuf->b_ml.ml_line_count); - truncate_line(TRUE); /* delete from cursor to end of line */ + truncate_line(true); // delete from cursor to end of line - curpos = curwin->w_cursor; /* remember curwin->w_cursor */ - ++curwin->w_cursor.lnum; - del_lines(oap->line_count - 2, FALSE); - - if (delete_last_line) - oap->end.lnum = curbuf->b_ml.ml_line_count; + curpos = curwin->w_cursor; // remember curwin->w_cursor + curwin->w_cursor.lnum++; + del_lines(oap->line_count - 2, false); + // delete from start of line until op_end n = (oap->end.col + 1 - !oap->inclusive); - if (oap->inclusive && delete_last_line - && n > (int)STRLEN(ml_get(oap->end.lnum))) { - /* Special case: gH<Del> deletes the last line. */ - del_lines(1L, FALSE); - curwin->w_cursor = curpos; /* restore curwin->w_cursor */ - if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count) - curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count; - } else { - /* delete from start of line until op_end */ - curwin->w_cursor.col = 0; - (void)del_bytes((long)n, !virtual_op, oap->op_type == OP_DELETE - && !oap->is_VIsual - ); - curwin->w_cursor = curpos; /* restore curwin->w_cursor */ - } - if (curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count) { - do_join(2, FALSE, FALSE, FALSE, false); - } + curwin->w_cursor.col = 0; + (void)del_bytes((long)n, !virtual_op, + oap->op_type == OP_DELETE && !oap->is_VIsual); + curwin->w_cursor = curpos; // restore curwin->w_cursor + (void)do_join(2, false, false, false, false); } } @@ -2688,17 +2664,27 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags) if (y_type == MLINE) { if (flags & PUT_LINE_SPLIT) { - /* "p" or "P" in Visual mode: split the lines to put the text in - * between. */ - if (u_save_cursor() == FAIL) + // "p" or "P" in Visual mode: split the lines to put the text in + // between. + if (u_save_cursor() == FAIL) { goto end; - ptr = vim_strsave(get_cursor_pos_ptr()); - ml_append(curwin->w_cursor.lnum, ptr, (colnr_T)0, FALSE); + } + char_u *p = get_cursor_pos_ptr(); + if (dir == FORWARD && *p != NUL) { + mb_ptr_adv(p); + } + ptr = vim_strsave(p); + ml_append(curwin->w_cursor.lnum, ptr, (colnr_T)0, false); xfree(ptr); - ptr = vim_strnsave(get_cursor_line_ptr(), curwin->w_cursor.col); - ml_replace(curwin->w_cursor.lnum, ptr, FALSE); - ++nr_lines; + oldp = get_cursor_line_ptr(); + p = oldp + curwin->w_cursor.col; + if (dir == FORWARD && *p != NUL) { + mb_ptr_adv(p); + } + ptr = vim_strnsave(oldp, p - oldp); + ml_replace(curwin->w_cursor.lnum, ptr, false); + nr_lines++; dir = FORWARD; } if (flags & PUT_LINE_FORWARD) { diff --git a/src/nvim/option.c b/src/nvim/option.c index d3a2ce971d..af7b272467 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -168,11 +168,12 @@ static int p_ml_nobin; static long p_tw_nobin; static long p_wm_nobin; -/* Saved values for when 'paste' is set */ +// Saved values for when 'paste' is set. +static int p_ai_nopaste; +static int p_et_nopaste; +static long p_sts_nopaste; static long p_tw_nopaste; static long p_wm_nopaste; -static long p_sts_nopaste; -static int p_ai_nopaste; typedef struct vimoption { char *fullname; /* full option name */ @@ -218,20 +219,22 @@ typedef struct vimoption { #define P_RALL 0x6000U /* redraw all windows */ #define P_RCLR 0x7000U /* clear and redraw all */ -#define P_COMMA 0x8000U /* comma separated list */ -#define P_NODUP 0x10000U /* don't allow duplicate strings */ -#define P_FLAGLIST 0x20000U /* list of single-char flags */ - -#define P_SECURE 0x40000U /* cannot change in modeline or secure mode */ -#define P_GETTEXT 0x80000U /* expand default value with _() */ -#define P_NOGLOB 0x100000U /* do not use local value for global vimrc */ -#define P_NFNAME 0x200000U /* only normal file name chars allowed */ -#define P_INSECURE 0x400000U /* option was set from a modeline */ -#define P_PRI_MKRC 0x800000U /* priority for :mkvimrc (setting option has - side effects) */ -#define P_NO_ML 0x1000000U /* not allowed in modeline */ -#define P_CURSWANT 0x2000000U /* update curswant required; not needed when - * there is a redraw flag */ +#define P_COMMA 0x8000U ///< comma separated list +#define P_ONECOMMA 0x18000U ///< P_COMMA and cannot have two consecutive + ///< commas +#define P_NODUP 0x20000U ///< don't allow duplicate strings +#define P_FLAGLIST 0x40000U ///< list of single-char flags + +#define P_SECURE 0x80000U ///< cannot change in modeline or secure mode +#define P_GETTEXT 0x100000U ///< expand default value with _() +#define P_NOGLOB 0x200000U ///< do not use local value for global vimrc +#define P_NFNAME 0x400000U ///< only normal file name chars allowed +#define P_INSECURE 0x800000U ///< option was set from a modeline +#define P_PRI_MKRC 0x1000000U ///< priority for :mkvimrc (setting option + ///< has side effects) +#define P_NO_ML 0x2000000U ///< not allowed in modeline +#define P_CURSWANT 0x4000000U ///< update curswant required; not needed + ///< when there is a redraw flag #define HIGHLIGHT_INIT \ "8:SpecialKey,~:EndOfBuffer,z:TermCursor,Z:TermCursorNC,@:NonText," \ @@ -708,15 +711,11 @@ void set_init_1(void) /* Must be before option_expand(), because that one needs vim_isIDc() */ didset_options(); - /* Use the current chartab for the generic chartab. */ + // Use the current chartab for the generic chartab. This is not in + // didset_options() because it only depends on 'encoding'. init_spell_chartab(); /* - * initialize the table for 'breakat'. - */ - fill_breakat_flags(); - - /* * Expand environment variables and things like "~" for the defaults. * If option_expand() returns non-NULL the variable is expanded. This can * only happen for non-indirect options. @@ -748,14 +747,8 @@ void set_init_1(void) } } - /* Initialize the highlight_attr[] table. */ - highlight_changed(); - save_file_ff(curbuf); /* Buffer is unchanged */ - /* Parse default for 'wildmode' */ - check_opt_wim(); - /* Detect use of mlterm. * Mlterm is a terminal emulator akin to xterm that has some special * abilities (bidi namely). @@ -765,11 +758,7 @@ void set_init_1(void) if (os_env_exists("MLTERM")) set_option_value((char_u *)"tbidi", 1L, NULL, 0); - /* Parse default for 'fillchars'. */ - (void)set_chars_option(&p_fcs); - - /* Parse default for 'listchars'. */ - (void)set_chars_option(&p_lcs); + didset_options2(); // enc_locale() will try to find the encoding of the current locale. // This will be used when 'default' is used as encoding specifier @@ -1148,9 +1137,12 @@ do_set ( */ arg += 3; if (*arg == '&') { - ++arg; - /* Only for :set command set global value of local options. */ + arg++; + // Only for :set command set global value of local options. set_options_default(OPT_FREE | opt_flags); + didset_options(); + didset_options2(); + redraw_all_later(CLEAR); } else { showoptions(1, opt_flags); did_show = TRUE; @@ -1674,9 +1666,11 @@ do_set ( if (adding) { i = (int)STRLEN(origval); // Strip a trailing comma, would get 2. - if (comma && i > 1 && origval[i - 1] == ',' + if (comma && i > 1 + && (flags & P_ONECOMMA) == P_ONECOMMA + && origval[i - 1] == ',' && origval[i - 2] != '\\') { - --i; + i--; } memmove(newval + i + comma, newval, STRLEN(newval) + 1); @@ -2068,9 +2062,31 @@ static void didset_options(void) (void)spell_check_msm(); (void)spell_check_sps(); (void)compile_cap_prog(curwin->w_s); - /* set cedit_key */ + (void)did_set_spell_option(true); + // set cedit_key (void)check_cedit(); briopt_check(curwin); + // initialize the table for 'breakat'. + fill_breakat_flags(); +} + +// More side effects of setting options. +static void didset_options2(void) +{ + // Initialize the highlight_attr[] table. + (void)highlight_changed(); + + // Parse default for 'clipboard'. + (void)opt_strings_flags(p_cb, p_cb_values, &cb_flags, true); + + // Parse default for 'fillchars'. + (void)set_chars_option(&p_fcs); + + // Parse default for 'listchars'. + (void)set_chars_option(&p_lcs); + + // Parse default for 'wildmode'. + check_opt_wim(); } /* @@ -2849,22 +2865,7 @@ did_set_string_option ( || varp == &(curwin->w_s->b_p_spf)) { // When 'spelllang' or 'spellfile' is set and there is a window for this // buffer in which 'spell' is set load the wordlists. - if (varp == &(curwin->w_s->b_p_spf)) { - int l = (int)STRLEN(curwin->w_s->b_p_spf); - if (l > 0 - && (l < 4 || STRCMP(curwin->w_s->b_p_spf + l - 4, ".add") != 0)) { - errmsg = e_invarg; - } - } - - if (errmsg == NULL) { - FOR_ALL_WINDOWS_IN_TAB(wp, curtab) { - if (wp->w_buffer == curbuf && wp->w_p_spell) { - errmsg = did_set_spelllang(wp); - break; - } - } - } + errmsg = did_set_spell_option(varp == &(curwin->w_s->b_p_spf)); } /* When 'spellcapcheck' is set compile the regexp program. */ else if (varp == &(curwin->w_s->b_p_spc)) { @@ -3420,6 +3421,30 @@ char_u *check_stl_option(char_u *s) return NULL; } +static char_u *did_set_spell_option(bool is_spellfile) +{ + char_u *errmsg = NULL; + + if (is_spellfile) { + int l = (int)STRLEN(curwin->w_s->b_p_spf); + if (l > 0 + && (l < 4 || STRCMP(curwin->w_s->b_p_spf + l - 4, ".add") != 0)) { + errmsg = e_invarg; + } + } + + if (errmsg == NULL) { + FOR_ALL_WINDOWS_IN_TAB(wp, curtab) { + if (wp->w_buffer == curbuf && wp->w_p_spell) { + errmsg = did_set_spelllang(wp); + break; + } + } + } + + return errmsg; +} + /* * Set curbuf->b_cap_prog to the regexp program for 'spellcapcheck'. * Return error message when failed, NULL when OK. @@ -5499,6 +5524,7 @@ void buf_copy_options(buf_T *buf, int flags) buf->b_p_et = p_et; buf->b_p_fixeol = p_fixeol; buf->b_p_et_nobin = p_et_nobin; + buf->b_p_et_nopaste = p_et_nopaste; buf->b_p_ml = p_ml; buf->b_p_ml_nobin = p_ml_nobin; buf->b_p_inf = p_inf; @@ -5921,13 +5947,17 @@ option_value2string ( if (opp->flags & P_NUM) { long wc = 0; - if (wc_use_keyname(varp, &wc)) - STRCPY(NameBuff, get_special_key_name((int)wc, 0)); - else if (wc != 0) - STRCPY(NameBuff, transchar((int)wc)); - else - sprintf((char *)NameBuff, "%" PRId64, (int64_t)*(long *)varp); - } else { /* P_STRING */ + if (wc_use_keyname(varp, &wc)) { + STRLCPY(NameBuff, get_special_key_name((int)wc, 0), sizeof(NameBuff)); + } else if (wc != 0) { + STRLCPY(NameBuff, transchar((int)wc), sizeof(NameBuff)); + } else { + snprintf((char *)NameBuff, + sizeof(NameBuff), + "%" PRId64, + (int64_t)*(long *)varp); + } + } else { // P_STRING varp = *(char_u **)(varp); if (varp == NULL) /* just in case */ NameBuff[0] = NUL; @@ -6156,6 +6186,7 @@ static void paste_option_changed(void) { static int old_p_paste = FALSE; static int save_sm = 0; + static int save_sta = 0; static int save_ru = 0; static int save_ri = 0; static int save_hkmap = 0; @@ -6172,40 +6203,44 @@ static void paste_option_changed(void) buf->b_p_wm_nopaste = buf->b_p_wm; buf->b_p_sts_nopaste = buf->b_p_sts; buf->b_p_ai_nopaste = buf->b_p_ai; + buf->b_p_et_nopaste = buf->b_p_et; } - /* save global options */ + // save global options save_sm = p_sm; + save_sta = p_sta; save_ru = p_ru; save_ri = p_ri; save_hkmap = p_hkmap; - /* save global values for local buffer options */ + // save global values for local buffer options + p_ai_nopaste = p_ai; + p_et_nopaste = p_et; + p_sts_nopaste = p_sts; p_tw_nopaste = p_tw; p_wm_nopaste = p_wm; - p_sts_nopaste = p_sts; - p_ai_nopaste = p_ai; } - /* - * Always set the option values, also when 'paste' is set when it is - * already on. - */ - /* set options for each buffer */ + // Always set the option values, also when 'paste' is set when it is + // already on. + // set options for each buffer FOR_ALL_BUFFERS(buf) { - buf->b_p_tw = 0; /* textwidth is 0 */ - buf->b_p_wm = 0; /* wrapmargin is 0 */ - buf->b_p_sts = 0; /* softtabstop is 0 */ - buf->b_p_ai = 0; /* no auto-indent */ - } - - /* set global options */ - p_sm = 0; /* no showmatch */ - if (p_ru) - status_redraw_all(); /* redraw to remove the ruler */ - p_ru = 0; /* no ruler */ - p_ri = 0; /* no reverse insert */ - p_hkmap = 0; /* no Hebrew keyboard */ - /* set global values for local buffer options */ + buf->b_p_tw = 0; // textwidth is 0 + buf->b_p_wm = 0; // wrapmargin is 0 + buf->b_p_sts = 0; // softtabstop is 0 + buf->b_p_ai = 0; // no auto-indent + buf->b_p_et = 0; // no expandtab + } + + // set global options + p_sm = 0; // no showmatch + p_sta = 0; // no smarttab + if (p_ru) { + status_redraw_all(); // redraw to remove the ruler + } + p_ru = 0; // no ruler + p_ri = 0; // no reverse insert + p_hkmap = 0; // no Hebrew keyboard + // set global values for local buffer options p_tw = 0; p_wm = 0; p_sts = 0; @@ -6221,20 +6256,24 @@ static void paste_option_changed(void) buf->b_p_wm = buf->b_p_wm_nopaste; buf->b_p_sts = buf->b_p_sts_nopaste; buf->b_p_ai = buf->b_p_ai_nopaste; + buf->b_p_et = buf->b_p_et_nopaste; } /* restore global options */ p_sm = save_sm; - if (p_ru != save_ru) - status_redraw_all(); /* redraw to draw the ruler */ + p_sta = save_sta; + if (p_ru != save_ru) { + status_redraw_all(); // redraw to draw the ruler + } p_ru = save_ru; p_ri = save_ri; p_hkmap = save_hkmap; - /* set global values for local buffer options */ + // set global values for local buffer options + p_ai = p_ai_nopaste; + p_et = p_et_nopaste; + p_sts = p_sts_nopaste; p_tw = p_tw_nopaste; p_wm = p_wm_nopaste; - p_sts = p_sts_nopaste; - p_ai = p_ai_nopaste; } old_p_paste = p_paste; diff --git a/src/nvim/option_defs.h b/src/nvim/option_defs.h index 7a837de45c..10706a0753 100644 --- a/src/nvim/option_defs.h +++ b/src/nvim/option_defs.h @@ -209,44 +209,58 @@ #define COM_ALL "nbsmexflrO" /* all flags for 'comments' option */ #define COM_MAX_LEN 50 /* maximum length of a part */ -/* flags for 'statusline' option */ -#define STL_FILEPATH 'f' /* path of file in buffer */ -#define STL_FULLPATH 'F' /* full path of file in buffer */ -#define STL_FILENAME 't' /* last part (tail) of file path */ -#define STL_COLUMN 'c' /* column og cursor*/ -#define STL_VIRTCOL 'v' /* virtual column */ -#define STL_VIRTCOL_ALT 'V' /* - with 'if different' display */ -#define STL_LINE 'l' /* line number of cursor */ -#define STL_NUMLINES 'L' /* number of lines in buffer */ -#define STL_BUFNO 'n' /* current buffer number */ -#define STL_KEYMAP 'k' /* 'keymap' when active */ -#define STL_OFFSET 'o' /* offset of character under cursor*/ -#define STL_OFFSET_X 'O' /* - in hexadecimal */ -#define STL_BYTEVAL 'b' /* byte value of character */ -#define STL_BYTEVAL_X 'B' /* - in hexadecimal */ -#define STL_ROFLAG 'r' /* readonly flag */ -#define STL_ROFLAG_ALT 'R' /* - other display */ -#define STL_HELPFLAG 'h' /* window is showing a help file */ -#define STL_HELPFLAG_ALT 'H' /* - other display */ -#define STL_FILETYPE 'y' /* 'filetype' */ -#define STL_FILETYPE_ALT 'Y' /* - other display */ -#define STL_PREVIEWFLAG 'w' /* window is showing the preview buf */ -#define STL_PREVIEWFLAG_ALT 'W' /* - other display */ -#define STL_MODIFIED 'm' /* modified flag */ -#define STL_MODIFIED_ALT 'M' /* - other display */ -#define STL_QUICKFIX 'q' /* quickfix window description */ -#define STL_PERCENTAGE 'p' /* percentage through file */ -#define STL_ALTPERCENT 'P' /* percentage as TOP BOT ALL or NN% */ -#define STL_ARGLISTSTAT 'a' /* argument list status as (x of y) */ -#define STL_PAGENUM 'N' /* page number (when printing)*/ -#define STL_VIM_EXPR '{' /* start of expression to substitute */ -#define STL_MIDDLEMARK '=' /* separation between left and right */ -#define STL_TRUNCMARK '<' /* truncation mark if line is too long*/ -#define STL_USER_HL '*' /* highlight from (User)1..9 or 0 */ -#define STL_HIGHLIGHT '#' /* highlight name */ -#define STL_TABPAGENR 'T' /* tab page label nr */ -#define STL_TABCLOSENR 'X' /* tab page close nr */ -#define STL_ALL ((char_u *) "fFtcvVlLknoObBrRhHmYyWwMqpPaN{#") +/// 'statusline' option flags +enum { + STL_FILEPATH = 'f', ///< Path of file in buffer. + STL_FULLPATH = 'F', ///< Full path of file in buffer. + STL_FILENAME = 't', ///< Last part (tail) of file path. + STL_COLUMN = 'c', ///< Column og cursor. + STL_VIRTCOL = 'v', ///< Virtual column. + STL_VIRTCOL_ALT = 'V', ///< - with 'if different' display. + STL_LINE = 'l', ///< Line number of cursor. + STL_NUMLINES = 'L', ///< Number of lines in buffer. + STL_BUFNO = 'n', ///< Current buffer number. + STL_KEYMAP = 'k', ///< 'keymap' when active. + STL_OFFSET = 'o', ///< Offset of character under cursor. + STL_OFFSET_X = 'O', ///< - in hexadecimal. + STL_BYTEVAL = 'b', ///< Byte value of character. + STL_BYTEVAL_X = 'B', ///< - in hexadecimal. + STL_ROFLAG = 'r', ///< Readonly flag. + STL_ROFLAG_ALT = 'R', ///< - other display. + STL_HELPFLAG = 'h', ///< Window is showing a help file. + STL_HELPFLAG_ALT = 'H', ///< - other display. + STL_FILETYPE = 'y', ///< 'filetype'. + STL_FILETYPE_ALT = 'Y', ///< - other display. + STL_PREVIEWFLAG = 'w', ///< Window is showing the preview buf. + STL_PREVIEWFLAG_ALT = 'W', ///< - other display. + STL_MODIFIED = 'm', ///< Modified flag. + STL_MODIFIED_ALT = 'M', ///< - other display. + STL_QUICKFIX = 'q', ///< Quickfix window description. + STL_PERCENTAGE = 'p', ///< Percentage through file. + STL_ALTPERCENT = 'P', ///< Percentage as TOP BOT ALL or NN%. + STL_ARGLISTSTAT = 'a', ///< Argument list status as (x of y). + STL_PAGENUM = 'N', ///< Page number (when printing). + STL_VIM_EXPR = '{', ///< Start of expression to substitute. + STL_MIDDLEMARK = '=', ///< Separation between left and right. + STL_TRUNCMARK = '<', ///< Truncation mark if line is too long. + STL_USER_HL = '*', ///< Highlight from (User)1..9 or 0. + STL_HIGHLIGHT = '#', ///< Highlight name. + STL_TABPAGENR = 'T', ///< Tab page label nr. + STL_TABCLOSENR = 'X', ///< Tab page close nr. + STL_CLICK_FUNC = '@', ///< Click region start. +}; +/// C string containing all 'statusline' option flags +#define STL_ALL ((char_u[]) { \ + STL_FILEPATH, STL_FULLPATH, STL_FILENAME, STL_COLUMN, STL_VIRTCOL, \ + STL_VIRTCOL_ALT, STL_LINE, STL_NUMLINES, STL_BUFNO, STL_KEYMAP, STL_OFFSET, \ + STL_OFFSET_X, STL_BYTEVAL, STL_BYTEVAL_X, STL_ROFLAG, STL_ROFLAG_ALT, \ + STL_HELPFLAG, STL_HELPFLAG_ALT, STL_FILETYPE, STL_FILETYPE_ALT, \ + STL_PREVIEWFLAG, STL_PREVIEWFLAG_ALT, STL_MODIFIED, STL_MODIFIED_ALT, \ + STL_QUICKFIX, STL_PERCENTAGE, STL_ALTPERCENT, STL_ARGLISTSTAT, STL_PAGENUM, \ + STL_VIM_EXPR, STL_MIDDLEMARK, STL_TRUNCMARK, STL_USER_HL, STL_HIGHLIGHT, \ + STL_TABPAGENR, STL_TABCLOSENR, STL_CLICK_FUNC, \ + 0, \ +}) /* flags used for parsed 'wildmode' */ #define WIM_FULL 1 @@ -557,41 +571,43 @@ EXTERN char_u *p_su; // 'suffixes' EXTERN char_u *p_swb; // 'switchbuf' EXTERN unsigned swb_flags; #ifdef IN_OPTION_C -static char *(p_swb_values[]) = {"useopen", "usetab", "split", "newtab", NULL}; +static char *(p_swb_values[]) = + { "useopen", "usetab", "split", "newtab", "vsplit", NULL }; #endif #define SWB_USEOPEN 0x001 #define SWB_USETAB 0x002 #define SWB_SPLIT 0x004 #define SWB_NEWTAB 0x008 -EXTERN int p_tbs; /* 'tagbsearch' */ -EXTERN long p_tl; /* 'taglength' */ -EXTERN int p_tr; /* 'tagrelative' */ -EXTERN char_u *p_tags; /* 'tags' */ -EXTERN int p_tgst; /* 'tagstack' */ -EXTERN int p_tbidi; /* 'termbidi' */ -EXTERN int p_terse; /* 'terse' */ -EXTERN int p_to; /* 'tildeop' */ -EXTERN int p_timeout; /* 'timeout' */ -EXTERN long p_tm; /* 'timeoutlen' */ -EXTERN int p_title; /* 'title' */ -EXTERN long p_titlelen; /* 'titlelen' */ -EXTERN char_u *p_titleold; /* 'titleold' */ -EXTERN char_u *p_titlestring; /* 'titlestring' */ -EXTERN char_u *p_tsr; /* 'thesaurus' */ -EXTERN int p_ttimeout; /* 'ttimeout' */ -EXTERN long p_ttm; /* 'ttimeoutlen' */ -EXTERN char_u *p_udir; /* 'undodir' */ -EXTERN long p_ul; /* 'undolevels' */ -EXTERN long p_ur; /* 'undoreload' */ -EXTERN long p_uc; /* 'updatecount' */ -EXTERN long p_ut; /* 'updatetime' */ -EXTERN char_u *p_fcs; /* 'fillchar' */ -EXTERN char_u *p_shada; /* 'shada' */ -EXTERN char_u *p_vdir; /* 'viewdir' */ -EXTERN char_u *p_vop; /* 'viewoptions' */ -EXTERN unsigned vop_flags; /* uses SSOP_ flags */ -EXTERN int p_vb; /* 'visualbell' */ -EXTERN char_u *p_ve; /* 'virtualedit' */ +#define SWB_VSPLIT 0x010 +EXTERN int p_tbs; ///< 'tagbsearch' +EXTERN long p_tl; ///< 'taglength' +EXTERN int p_tr; ///< 'tagrelative' +EXTERN char_u *p_tags; ///< 'tags' +EXTERN int p_tgst; ///< 'tagstack' +EXTERN int p_tbidi; ///< 'termbidi' +EXTERN int p_terse; ///< 'terse' +EXTERN int p_to; ///< 'tildeop' +EXTERN int p_timeout; ///< 'timeout' +EXTERN long p_tm; ///< 'timeoutlen' +EXTERN int p_title; ///< 'title' +EXTERN long p_titlelen; ///< 'titlelen' +EXTERN char_u *p_titleold; ///< 'titleold' +EXTERN char_u *p_titlestring; ///< 'titlestring' +EXTERN char_u *p_tsr; ///< 'thesaurus' +EXTERN int p_ttimeout; ///< 'ttimeout' +EXTERN long p_ttm; ///< 'ttimeoutlen' +EXTERN char_u *p_udir; ///< 'undodir' +EXTERN long p_ul; ///< 'undolevels' +EXTERN long p_ur; ///< 'undoreload' +EXTERN long p_uc; ///< 'updatecount' +EXTERN long p_ut; ///< 'updatetime' +EXTERN char_u *p_fcs; ///< 'fillchar' +EXTERN char_u *p_shada; ///< 'shada' +EXTERN char_u *p_vdir; ///< 'viewdir' +EXTERN char_u *p_vop; ///< 'viewoptions' +EXTERN unsigned vop_flags; ///< uses SSOP_ flags +EXTERN int p_vb; ///< 'visualbell' +EXTERN char_u *p_ve; ///< 'virtualedit' EXTERN unsigned ve_flags; # ifdef IN_OPTION_C static char *(p_ve_values[]) = {"block", "insert", "all", "onemore", NULL}; diff --git a/src/nvim/options.lua b/src/nvim/options.lua index 3dd37cb5dc..df77c374ec 100644 --- a/src/nvim/options.lua +++ b/src/nvim/options.lua @@ -15,7 +15,7 @@ -- } -- } -- types: bool, number, string --- lists: (nil), comma, flags, flagscomma +-- lists: (nil), comma, onecomma, flags, flagscomma -- scopes: global, buffer, window -- redraw options: statuslines, current_window, current_buffer, all_windows, -- everything, curswant @@ -133,7 +133,7 @@ return { }, { full_name='backspace', abbreviation='bs', - type='string', list='comma', scope={'global'}, + type='string', list='onecomma', scope={'global'}, deny_duplicates=true, vim=true, varname='p_bs', @@ -149,7 +149,7 @@ return { }, { full_name='backupcopy', abbreviation='bkc', - type='string', list='comma', scope={'global', 'buffer'}, + type='string', list='onecomma', scope={'global', 'buffer'}, deny_duplicates=true, vim=true, varname='p_bkc', @@ -161,7 +161,7 @@ return { }, { full_name='backupdir', abbreviation='bdir', - type='string', list='comma', scope={'global'}, + type='string', list='onecomma', scope={'global'}, deny_duplicates=true, secure=true, vi_def=true, @@ -179,7 +179,7 @@ return { }, { full_name='backupskip', abbreviation='bsk', - type='string', list='comma', scope={'global'}, + type='string', list='onecomma', scope={'global'}, vi_def=true, varname='p_bsk', defaults={if_true={vi=""}} @@ -227,7 +227,7 @@ return { }, { full_name='breakindentopt', abbreviation='briopt', - type='string', list='comma', scope={'window'}, + type='string', list='onecomma', scope={'window'}, deny_duplicates=true, vi_def=true, alloced=true, @@ -268,7 +268,7 @@ return { }, { full_name='casemap', abbreviation='cmp', - type='string', list='comma', scope={'global'}, + type='string', list='onecomma', scope={'global'}, deny_duplicates=true, vi_def=true, varname='p_cmp', @@ -307,7 +307,7 @@ return { }, { full_name='cinkeys', abbreviation='cink', - type='string', list='comma', scope={'buffer'}, + type='string', list='onecomma', scope={'buffer'}, deny_duplicates=true, vi_def=true, alloced=true, @@ -316,7 +316,7 @@ return { }, { full_name='cinoptions', abbreviation='cino', - type='string', list='comma', scope={'buffer'}, + type='string', list='onecomma', scope={'buffer'}, deny_duplicates=true, vi_def=true, alloced=true, @@ -325,7 +325,7 @@ return { }, { full_name='cinwords', abbreviation='cinw', - type='string', list='comma', scope={'buffer'}, + type='string', list='onecomma', scope={'buffer'}, deny_duplicates=true, vi_def=true, alloced=true, @@ -334,7 +334,7 @@ return { }, { full_name='clipboard', abbreviation='cb', - type='string', list='comma', scope={'global'}, + type='string', list='onecomma', scope={'global'}, deny_duplicates=true, vi_def=true, varname='p_cb', @@ -357,7 +357,7 @@ return { }, { full_name='colorcolumn', abbreviation='cc', - type='string', list='comma', scope={'window'}, + type='string', list='onecomma', scope={'window'}, deny_duplicates=true, vi_def=true, redraw={'current_window'}, @@ -375,7 +375,7 @@ return { }, { full_name='comments', abbreviation='com', - type='string', list='comma', scope={'buffer'}, + type='string', list='onecomma', scope={'buffer'}, deny_duplicates=true, vi_def=true, alloced=true, @@ -403,7 +403,7 @@ return { }, { full_name='complete', abbreviation='cpt', - type='string', list='comma', scope={'buffer'}, + type='string', list='onecomma', scope={'buffer'}, deny_duplicates=true, alloced=true, varname='p_cpt', @@ -435,7 +435,7 @@ return { }, { full_name='completeopt', abbreviation='cot', - type='string', list='comma', scope={'global'}, + type='string', list='onecomma', scope={'global'}, deny_duplicates=true, vi_def=true, varname='p_cot', @@ -483,7 +483,7 @@ return { }, { full_name='cscopequickfix', abbreviation='csqf', - type='string', list='comma', scope={'global'}, + type='string', list='onecomma', scope={'global'}, deny_duplicates=true, vi_def=true, varname='p_csqf', @@ -568,7 +568,7 @@ return { }, { full_name='dictionary', abbreviation='dict', - type='string', list='comma', scope={'global', 'buffer'}, + type='string', list='onecomma', scope={'global', 'buffer'}, deny_duplicates=true, vi_def=true, expand=true, @@ -594,7 +594,7 @@ return { }, { full_name='diffopt', abbreviation='dip', - type='string', list='comma', scope={'global'}, + type='string', list='onecomma', scope={'global'}, deny_duplicates=true, vi_def=true, alloced=true, @@ -612,7 +612,7 @@ return { }, { full_name='directory', abbreviation='dir', - type='string', list='comma', scope={'global'}, + type='string', list='onecomma', scope={'global'}, deny_duplicates=true, secure=true, vi_def=true, @@ -622,7 +622,7 @@ return { }, { full_name='display', abbreviation='dy', - type='string', list='comma', scope={'global'}, + type='string', list='onecomma', scope={'global'}, deny_duplicates=true, vim=true, redraw={'all_windows'}, @@ -696,7 +696,7 @@ return { }, { full_name='errorformat', abbreviation='efm', - type='string', list='comma', scope={'global', 'buffer'}, + type='string', list='onecomma', scope={'global', 'buffer'}, deny_duplicates=true, vi_def=true, varname='p_efm', @@ -711,7 +711,7 @@ return { }, { full_name='eventignore', abbreviation='ei', - type='string', list='comma', scope={'global'}, + type='string', list='onecomma', scope={'global'}, deny_duplicates=true, vi_def=true, varname='p_ei', @@ -745,7 +745,7 @@ return { }, { full_name='fileencodings', abbreviation='fencs', - type='string', list='comma', scope={'global'}, + type='string', list='onecomma', scope={'global'}, vi_def=true, varname='p_fencs', defaults={if_true={vi="ucs-bom,utf-8,default,latin1"}} @@ -762,7 +762,7 @@ return { }, { full_name='fileformats', abbreviation='ffs', - type='string', list='comma', scope={'global'}, + type='string', list='onecomma', scope={'global'}, deny_duplicates=true, vim=true, varname='p_ffs', @@ -791,7 +791,7 @@ return { }, { full_name='fillchars', abbreviation='fcs', - type='string', list='comma', scope={'global'}, + type='string', list='onecomma', scope={'global'}, deny_duplicates=true, vi_def=true, redraw={'all_windows'}, @@ -815,7 +815,7 @@ return { }, { full_name='foldclose', abbreviation='fcl', - type='string', list='comma', scope={'global'}, + type='string', list='onecomma', scope={'global'}, deny_duplicates=true, vi_def=true, redraw={'current_window'}, @@ -871,7 +871,7 @@ return { }, { full_name='foldmarker', abbreviation='fmr', - type='string', list='comma', scope={'window'}, + type='string', list='onecomma', scope={'window'}, deny_duplicates=true, vi_def=true, vim=true, @@ -904,7 +904,7 @@ return { }, { full_name='foldopen', abbreviation='fdo', - type='string', list='comma', scope={'global'}, + type='string', list='onecomma', scope={'global'}, deny_duplicates=true, vi_def=true, redraw={'curswant'}, @@ -972,7 +972,7 @@ return { }, { full_name='grepformat', abbreviation='gfm', - type='string', list='comma', scope={'global'}, + type='string', list='onecomma', scope={'global'}, deny_duplicates=true, vi_def=true, varname='p_gefm', @@ -995,7 +995,7 @@ return { }, { full_name='guicursor', abbreviation='gcr', - type='string', list='comma', scope={'global'}, + type='string', list='onecomma', scope={'global'}, deny_duplicates=true, vi_def=true, varname='p_guicursor', @@ -1003,7 +1003,7 @@ return { }, { full_name='guifont', abbreviation='gfn', - type='string', list='comma', scope={'global'}, + type='string', list='onecomma', scope={'global'}, deny_duplicates=true, vi_def=true, redraw={'everything'}, @@ -1011,14 +1011,14 @@ return { }, { full_name='guifontset', abbreviation='gfs', - type='string', list='comma', scope={'global'}, + type='string', list='onecomma', scope={'global'}, vi_def=true, redraw={'everything'}, enable_if=false, }, { full_name='guifontwide', abbreviation='gfw', - type='string', list='comma', scope={'global'}, + type='string', list='onecomma', scope={'global'}, deny_duplicates=true, vi_def=true, redraw={'everything'}, @@ -1070,7 +1070,7 @@ return { }, { full_name='helplang', abbreviation='hlg', - type='string', list='comma', scope={'global'}, + type='string', list='onecomma', scope={'global'}, vi_def=true, varname='p_hlg', defaults={if_true={vi=""}} @@ -1084,7 +1084,7 @@ return { }, { full_name='highlight', abbreviation='hl', - type='string', list='comma', scope={'global'}, + type='string', list='onecomma', scope={'global'}, deny_duplicates=true, vi_def=true, redraw={'everything'}, @@ -1213,7 +1213,7 @@ return { }, { full_name='indentkeys', abbreviation='indk', - type='string', list='comma', scope={'buffer'}, + type='string', list='onecomma', scope={'buffer'}, deny_duplicates=true, vi_def=true, alloced=true, @@ -1297,7 +1297,7 @@ return { }, { full_name='keymodel', abbreviation='km', - type='string', list='comma', scope={'global'}, + type='string', list='onecomma', scope={'global'}, deny_duplicates=true, vi_def=true, varname='p_km', @@ -1316,7 +1316,7 @@ return { }, { full_name='langmap', abbreviation='lmap', - type='string', list='comma', scope={'global'}, + type='string', list='onecomma', scope={'global'}, deny_duplicates=true, secure=true, vi_def=true, @@ -1385,7 +1385,7 @@ return { }, { full_name='lispwords', abbreviation='lw', - type='string', list='comma', scope={'global', 'buffer'}, + type='string', list='onecomma', scope={'global', 'buffer'}, deny_duplicates=true, vi_def=true, varname='p_lispwords', pv_name='p_lw', @@ -1400,7 +1400,7 @@ return { }, { full_name='listchars', abbreviation='lcs', - type='string', list='comma', scope={'global'}, + type='string', list='onecomma', scope={'global'}, deny_duplicates=true, vim=true, redraw={'all_windows'}, @@ -1441,7 +1441,7 @@ return { }, { full_name='matchpairs', abbreviation='mps', - type='string', list='comma', scope={'buffer'}, + type='string', list='onecomma', scope={'buffer'}, deny_duplicates=true, vi_def=true, alloced=true, @@ -1581,7 +1581,7 @@ return { }, { full_name='mouseshape', abbreviation='mouses', - type='string', list='comma', scope={'global'}, + type='string', list='onecomma', scope={'global'}, deny_duplicates=true, vi_def=true, enable_if=false, @@ -1595,7 +1595,7 @@ return { }, { full_name='nrformats', abbreviation='nf', - type='string', list='comma', scope={'buffer'}, + type='string', list='onecomma', scope={'buffer'}, deny_duplicates=true, alloced=true, varname='p_nf', @@ -1762,7 +1762,7 @@ return { }, { full_name='printoptions', abbreviation='popt', - type='string', list='comma', scope={'global'}, + type='string', list='onecomma', scope={'global'}, deny_duplicates=true, vi_def=true, varname='p_popt', @@ -1877,7 +1877,7 @@ return { }, { full_name='runtimepath', abbreviation='rtp', - type='string', list='comma', scope={'global'}, + type='string', list='onecomma', scope={'global'}, deny_duplicates=true, secure=true, vi_def=true, @@ -1919,7 +1919,7 @@ return { }, { full_name='scrollopt', abbreviation='sbo', - type='string', list='comma', scope={'global'}, + type='string', list='onecomma', scope={'global'}, deny_duplicates=true, vi_def=true, varname='p_sbo', @@ -1949,7 +1949,7 @@ return { }, { full_name='selectmode', abbreviation='slm', - type='string', list='comma', scope={'global'}, + type='string', list='onecomma', scope={'global'}, deny_duplicates=true, vi_def=true, varname='p_slm', @@ -1957,7 +1957,7 @@ return { }, { full_name='sessionoptions', abbreviation='ssop', - type='string', list='comma', scope={'global'}, + type='string', list='onecomma', scope={'global'}, deny_duplicates=true, vim=true, varname='p_ssop', @@ -1968,7 +1968,7 @@ return { }, { full_name='shada', abbreviation='sd', - type='string', list='comma', scope={'global'}, + type='string', list='onecomma', scope={'global'}, deny_duplicates=true, secure=true, varname='p_shada', @@ -2192,7 +2192,7 @@ return { }, { full_name='spellfile', abbreviation='spf', - type='string', list='comma', scope={'buffer'}, + type='string', list='onecomma', scope={'buffer'}, secure=true, vi_def=true, alloced=true, @@ -2202,7 +2202,7 @@ return { }, { full_name='spelllang', abbreviation='spl', - type='string', list='comma', scope={'buffer'}, + type='string', list='onecomma', scope={'buffer'}, vi_def=true, alloced=true, expand=true, @@ -2212,7 +2212,7 @@ return { }, { full_name='spellsuggest', abbreviation='sps', - type='string', list='comma', scope={'global'}, + type='string', list='onecomma', scope={'global'}, secure=true, vi_def=true, expand=true, @@ -2252,7 +2252,7 @@ return { }, { full_name='suffixes', abbreviation='su', - type='string', list='comma', scope={'global'}, + type='string', list='onecomma', scope={'global'}, deny_duplicates=true, vi_def=true, varname='p_su', @@ -2260,7 +2260,7 @@ return { }, { full_name='suffixesadd', abbreviation='sua', - type='string', list='comma', scope={'buffer'}, + type='string', list='onecomma', scope={'buffer'}, deny_duplicates=true, vi_def=true, alloced=true, @@ -2277,7 +2277,7 @@ return { }, { full_name='switchbuf', abbreviation='swb', - type='string', list='comma', scope={'global'}, + type='string', list='onecomma', scope={'global'}, deny_duplicates=true, vi_def=true, varname='p_swb', @@ -2347,7 +2347,7 @@ return { }, { full_name='tags', abbreviation='tag', - type='string', list='comma', scope={'global', 'buffer'}, + type='string', list='onecomma', scope={'global', 'buffer'}, deny_duplicates=true, vi_def=true, expand=true, @@ -2393,7 +2393,7 @@ return { }, { full_name='thesaurus', abbreviation='tsr', - type='string', list='comma', scope={'global', 'buffer'}, + type='string', list='onecomma', scope={'global', 'buffer'}, deny_duplicates=true, vi_def=true, expand=true, @@ -2478,7 +2478,7 @@ return { }, { full_name='undodir', abbreviation='udir', - type='string', list='comma', scope={'global'}, + type='string', list='onecomma', scope={'global'}, deny_duplicates=true, secure=true, vi_def=true, @@ -2549,7 +2549,7 @@ return { }, { full_name='viewoptions', abbreviation='vop', - type='string', list='comma', scope={'global'}, + type='string', list='onecomma', scope={'global'}, deny_duplicates=true, vi_def=true, varname='p_vop', @@ -2557,7 +2557,7 @@ return { }, { full_name='viminfo', abbreviation='vi', - type='string', list='comma', scope={'global'}, + type='string', list='onecomma', scope={'global'}, deny_duplicates=true, secure=true, varname='p_shada', @@ -2565,7 +2565,7 @@ return { }, { full_name='virtualedit', abbreviation='ve', - type='string', list='comma', scope={'global'}, + type='string', list='onecomma', scope={'global'}, deny_duplicates=true, vi_def=true, vim=true, @@ -2610,7 +2610,7 @@ return { }, { full_name='wildignore', abbreviation='wig', - type='string', list='comma', scope={'global'}, + type='string', list='onecomma', scope={'global'}, deny_duplicates=true, vi_def=true, varname='p_wig', @@ -2632,7 +2632,7 @@ return { }, { full_name='wildmode', abbreviation='wim', - type='string', list='comma', scope={'global'}, + type='string', list='onecomma', scope={'global'}, deny_duplicates=true, vim=true, varname='p_wim', diff --git a/src/nvim/os/env.c b/src/nvim/os/env.c index c1804067e9..384a17004e 100644 --- a/src/nvim/os/env.c +++ b/src/nvim/os/env.c @@ -262,8 +262,25 @@ void expand_env_esc(char_u *srcp, char_u *dst, int dstlen, bool esc, bool one, startstr_len = (int)STRLEN(startstr); src = skipwhite(srcp); - --dstlen; // leave one char space for "\," + dstlen--; // leave one char space for "\," while (*src && dstlen > 0) { + // Skip over `=expr`. + if (src[0] == '`' && src[1] == '=') { + var = src; + src += 2; + (void)skip_expr(&src); + if (*src == '`') { + src++; + } + size_t len = (size_t)(src - var); + if (len > (size_t)dstlen) { + len = (size_t)dstlen; + } + memcpy((char *)dst, (char *)var, len); + dst += len; + dstlen -= (int)len; + continue; + } copy_char = true; if ((*src == '$') || (*src == '~' && at_start)) { mustfree = false; @@ -742,15 +759,15 @@ char_u * home_replace_save(buf_T *buf, char_u *src) FUNC_ATTR_NONNULL_RET void vim_setenv(const char *name, const char *val) { os_setenv(name, val, 1); - /* - * When setting $VIMRUNTIME adjust the directory to find message - * translations to $VIMRUNTIME/lang. - */ +#ifndef LOCALE_INSTALL_DIR + // When setting $VIMRUNTIME adjust the directory to find message + // translations to $VIMRUNTIME/lang. if (*val != NUL && STRICMP(name, "VIMRUNTIME") == 0) { char *buf = (char *)concat_str((char_u *)val, (char_u *)"/lang"); - bindtextdomain(VIMPACKAGE, buf); + bindtextdomain(PROJECT_NAME, buf); xfree(buf); } +#endif } diff --git a/src/nvim/os/input.c b/src/nvim/os/input.c index e632544856..f317fd6b5a 100644 --- a/src/nvim/os/input.c +++ b/src/nvim/os/input.c @@ -250,6 +250,14 @@ static unsigned int handle_mouse_event(char **ptr, uint8_t *buf, int col, row, advance; if (sscanf(*ptr, "<%d,%d>%n", &col, &row, &advance) != EOF && advance) { if (col >= 0 && row >= 0) { + // Make sure the mouse position is valid. Some terminals may + // return weird values. + if (col >= Columns) { + col = (int)Columns - 1; + } + if (row >= Rows) { + row = (int)Rows - 1; + } mouse_row = row; mouse_col = col; } diff --git a/src/nvim/path.c b/src/nvim/path.c index 8b9a49dfc0..5cd93ab811 100644 --- a/src/nvim/path.c +++ b/src/nvim/path.c @@ -556,8 +556,9 @@ static size_t do_path_expand(garray_T *gap, const char_u *path, return 0; } - /* make room for file name */ - buf = xmalloc(STRLEN(path) + BASENAMELEN + 5); + // Make room for file name. When doing encoding conversion the actual + // length may be quite a bit longer, thus use the maximum possible length. + buf = xmalloc(MAXPATHL); /* * Find the first part in the path name that contains a wildcard. @@ -1158,12 +1159,17 @@ int gen_expand_wildcards(int num_pat, char_u **pat, int *num_file, add_pat = -1; p = pat[i]; - if (vim_backtick(p)) + if (vim_backtick(p)) { add_pat = expand_backtick(&ga, p, flags); - else { - /* - * First expand environment variables, "~/" and "~user/". - */ + if (add_pat == -1) { + recursive = false; + FreeWild(ga.ga_len, (char_u **)ga.ga_data); + *num_file = 0; + *file = NULL; + return FAIL; + } + } else { + // First expand environment variables, "~/" and "~user/". if (has_env_var(p) || *p == '~') { p = expand_env_save_opt(p, true); if (p == NULL) @@ -1246,13 +1252,10 @@ static int vim_backtick(char_u *p) return *p == '`' && *(p + 1) != NUL && *(p + STRLEN(p) - 1) == '`'; } -/* - * Expand an item in `backticks` by executing it as a command. - * Currently only works when pat[] starts and ends with a `. - * Returns number of file names found. - */ -static int -expand_backtick ( +// Expand an item in `backticks` by executing it as a command. +// Currently only works when pat[] starts and ends with a `. +// Returns number of file names found, -1 if an error is encountered. +static int expand_backtick( garray_T *gap, char_u *pat, int flags /* EW_* flags */ @@ -1273,8 +1276,9 @@ expand_backtick ( buffer = get_cmd_output(cmd, NULL, (flags & EW_SILENT) ? kShellOptSilent : 0, NULL); xfree(cmd); - if (buffer == NULL) - return 0; + if (buffer == NULL) { + return -1; + } cmd = buffer; while (*cmd != NUL) { @@ -1775,19 +1779,20 @@ bool same_directory(char_u *f1, char_u *f2) */ int pathcmp(const char *p, const char *q, int maxlen) { - int i; + int i, j; int c1, c2; const char *s = NULL; - for (i = 0; maxlen < 0 || i < maxlen; i += MB_PTR2LEN((char_u *)p + i)) { + for (i = 0, j = 0; maxlen < 0 || (i < maxlen && j < maxlen);) { c1 = PTR2CHAR((char_u *)p + i); - c2 = PTR2CHAR((char_u *)q + i); + c2 = PTR2CHAR((char_u *)q + j); /* End of "p": check if "q" also ends or just has a slash. */ if (c1 == NUL) { if (c2 == NUL) /* full match */ return 0; s = q; + i = j; break; } @@ -1811,9 +1816,13 @@ int pathcmp(const char *p, const char *q, int maxlen) return p_fic ? vim_toupper(c1) - vim_toupper(c2) : c1 - c2; /* no match */ } + + i += MB_PTR2LEN((char_u *)p + i); + j += MB_PTR2LEN((char_u *)q + j); } - if (s == NULL) /* "i" ran into "maxlen" */ + if (s == NULL) { // "i" or "j" ran into "maxlen" return 0; + } c1 = PTR2CHAR((char_u *)s + i); c2 = PTR2CHAR((char_u *)s + i + MB_PTR2LEN((char_u *)s + i)); diff --git a/src/nvim/po/CMakeLists.txt b/src/nvim/po/CMakeLists.txt index 6687918df4..184c4894b9 100644 --- a/src/nvim/po/CMakeLists.txt +++ b/src/nvim/po/CMakeLists.txt @@ -73,7 +73,7 @@ if(HAVE_WORKING_LIBINTL AND GETTEXT_FOUND AND XGETTEXT_PRG AND ICONV_PRG) install_helper( FILES ${moFile} DESTINATION ${CMAKE_INSTALL_LOCALEDIR}/${name}/LC_MESSAGES - RENAME nvim.mo) + RENAME ${PROJECT_NAME}.mo) list(APPEND LANGUAGE_MO_FILES ${moFile}) endmacro() diff --git a/src/nvim/popupmnu.c b/src/nvim/popupmnu.c index 001740943f..5ad621e666 100644 --- a/src/nvim/popupmnu.c +++ b/src/nvim/popupmnu.c @@ -545,7 +545,11 @@ static int pum_set_selected(int n, int repeat) g_do_tagpreview = (int)p_pvh; } RedrawingDisabled++; + // Prevent undo sync here, if an autocommand syncs undo weird + // things can happen to the undo tree. + no_u_sync++; resized = prepare_tagpreview(false); + no_u_sync--; RedrawingDisabled--; g_do_tagpreview = 0; @@ -629,7 +633,9 @@ static int pum_set_selected(int n, int repeat) // the window when needed, otherwise it will always be // redraw. if (resized) { + no_u_sync++; win_enter(curwin_save, true); + no_u_sync--; update_topline(); } @@ -640,7 +646,9 @@ static int pum_set_selected(int n, int repeat) pum_do_redraw = FALSE; if (!resized && win_valid(curwin_save)) { + no_u_sync++; win_enter(curwin_save, true); + no_u_sync--; } // May need to update the screen again when there are diff --git a/src/nvim/regexp_nfa.c b/src/nvim/regexp_nfa.c index 4020fa6e28..e2849fb17a 100644 --- a/src/nvim/regexp_nfa.c +++ b/src/nvim/regexp_nfa.c @@ -4048,6 +4048,7 @@ skip_add: sub->list.multi[subidx].start_col = (colnr_T)(reginput - regline + off); } + sub->list.multi[subidx].end_lnum = -1; } else { if (subidx < sub->in_use) { save_ptr = sub->list.line[subidx].start; @@ -6179,7 +6180,8 @@ static long nfa_regtry(nfa_regprog_T *prog, colnr_T col) if (prog->reghasz == REX_SET) { cleanup_zsubexpr(); re_extmatch_out = make_extmatch(); - for (i = 0; i < subs.synt.in_use; i++) { + // Loop over \z1, \z2, etc. There is no \z0. + for (i = 1; i < subs.synt.in_use; i++) { if (REG_MULTI) { struct multipos *mpos = &subs.synt.list.multi[i]; diff --git a/src/nvim/screen.c b/src/nvim/screen.c index 43bc2c1f68..cd440fe8dc 100644 --- a/src/nvim/screen.c +++ b/src/nvim/screen.c @@ -147,6 +147,9 @@ static foldinfo_T win_foldinfo; /* info for 'foldcolumn' */ */ static schar_T *current_ScreenLine; +StlClickDefinition *tab_page_click_defs = NULL; +long tab_page_click_defs_size = 0; + # define SCREEN_LINE(r, o, e, c, rl) screen_line((r), (o), (e), (c), (rl)) #ifdef INCLUDE_GENERATED_DECLARATIONS # include "screen.c.generated.h" @@ -2181,6 +2184,10 @@ win_line ( int prev_c1 = 0; /* first composing char for prev_c */ int did_line_attr = 0; + bool has_bufhl = false; // this buffer has highlight matches + int bufhl_attr = 0; // attributes desired by bufhl + bufhl_lineinfo_T bufhl_info; // bufhl data for this line + /* draw_state: items that are drawn in sequence: */ #define WL_START 0 /* nothing done yet */ # define WL_CMDLINE WL_START + 1 /* cmdline window column */ @@ -2196,11 +2203,13 @@ win_line ( int syntax_seqnr = 0; int prev_syntax_id = 0; int conceal_attr = hl_attr(HLF_CONCEAL); - int is_concealing = FALSE; - int boguscols = 0; /* nonexistent columns added to force - wrapping */ - int vcol_off = 0; /* offset for concealed characters */ - int did_wcol = FALSE; + int is_concealing = false; + int boguscols = 0; ///< nonexistent columns added to + ///< force wrapping + int vcol_off = 0; ///< offset for concealed characters + int did_wcol = false; + int match_conc = false; ///< cchar for match functions + int has_match_conc = false; ///< match wants to conceal int old_boguscols = 0; # define VCOL_HLC (vcol - vcol_off) # define FIX_FOR_BOGUSCOLS \ @@ -2239,6 +2248,11 @@ win_line ( } } + if (bufhl_start_line(wp->w_buffer, lnum, &bufhl_info)) { + has_bufhl = true; + extra_check = true; + } + /* Check for columns to display for 'colorcolumn'. */ color_cols = wp->w_buffer->terminal ? NULL : wp->w_p_cc_cols; if (color_cols != NULL) @@ -2427,13 +2441,18 @@ win_line ( } } - /* find start of trailing whitespace */ - if (wp->w_p_list && lcs_trail) { - trailcol = (colnr_T)STRLEN(ptr); - while (trailcol > (colnr_T)0 && ascii_iswhite(ptr[trailcol - 1])) - --trailcol; - trailcol += (colnr_T) (ptr - line); - extra_check = TRUE; + if (wp->w_p_list) { + if (lcs_space || lcs_trail) { + extra_check = true; + } + // find start of trailing whitespace + if (lcs_trail) { + trailcol = (colnr_T)STRLEN(ptr); + while (trailcol > (colnr_T)0 && ascii_iswhite(ptr[trailcol - 1])) { + trailcol--; + } + trailcol += (colnr_T) (ptr - line); + } } /* @@ -2630,11 +2649,10 @@ win_line ( extra_check = true; } - /* - * Repeat for the whole displayed line. - */ + // Repeat for the whole displayed line. for (;; ) { - /* Skip this quickly when working on the text. */ + has_match_conc = false; + // Skip this quickly when working on the text. if (draw_state != WL_LINE) { if (draw_state == WL_CMDLINE - 1 && n_extra == 0) { draw_state = WL_CMDLINE; @@ -2881,8 +2899,16 @@ win_line ( shl->endcol = tmp_col; } shl->attr_cur = shl->attr; + if (cur != NULL && syn_name2id((char_u *)"Conceal") + == cur->hlg_id) { + has_match_conc = true; + match_conc = cur->conceal_char; + } else { + has_match_conc = match_conc = false; + } } else if (v == (long)shl->endcol) { shl->attr_cur = 0; + prev_syntax_id = 0; next_search_hl(wp, shl, lnum, (colnr_T)v, cur); pos_inprogress = !(cur == NULL || cur->pos.cur == 0); @@ -3198,27 +3224,7 @@ win_line ( } } - ++ptr; - - // 'list': change char 160 to lcs_nbsp and space to lcs_space. - if (wp->w_p_list - && (((c == 160 || (mb_utf8 && (mb_c == 160 || mb_c == 0x202f))) - && lcs_nbsp) - || (c == ' ' && lcs_space && ptr - line <= trailcol))) { - c = (c == ' ') ? lcs_space : lcs_nbsp; - if (area_attr == 0 && search_attr == 0) { - n_attr = 1; - extra_attr = hl_attr(HLF_8); - saved_attr2 = char_attr; /* save current attr */ - } - mb_c = c; - if (enc_utf8 && (*mb_char2len)(c) > 1) { - mb_utf8 = TRUE; - u8cc[0] = 0; - c = 0xc0; - } else - mb_utf8 = FALSE; - } + ptr++; if (extra_check) { bool can_spell = true; @@ -3338,6 +3344,17 @@ win_line ( char_attr = hl_combine_attr(spell_attr, char_attr); } + if (has_bufhl && v > 0) { + bufhl_attr = bufhl_get_attr(&bufhl_info, (colnr_T)v); + if (bufhl_attr != 0) { + if (!attr_pri) { + char_attr = hl_combine_attr(char_attr, bufhl_attr); + } else { + char_attr = hl_combine_attr(bufhl_attr, char_attr); + } + } + } + if (wp->w_buffer->terminal) { char_attr = hl_combine_attr(char_attr, term_attrs[vcol]); } @@ -3365,6 +3382,28 @@ win_line ( } } + // 'list': change char 160 to lcs_nbsp and space to lcs_space. + if (wp->w_p_list + && (((c == 160 + || (mb_utf8 && (mb_c == 160 || mb_c == 0x202f))) + && lcs_nbsp) + || (c == ' ' && lcs_space && ptr - line <= trailcol))) { + c = (c == ' ') ? lcs_space : lcs_nbsp; + if (area_attr == 0 && search_attr == 0) { + n_attr = 1; + extra_attr = hl_attr(HLF_8); + saved_attr2 = char_attr; // save current attr + } + mb_c = c; + if (enc_utf8 && (*mb_char2len)(c) > 1) { + mb_utf8 = true; + u8cc[0] = 0; + c = 0xc0; + } else { + mb_utf8 = false; + } + } + if (trailcol != MAXCOL && ptr > line + trailcol && c == ' ') { c = lcs_trail; if (!attr_pri) { @@ -3599,24 +3638,28 @@ win_line ( } } - if ( wp->w_p_cole > 0 - && (wp != curwin || lnum != wp->w_cursor.lnum || - conceal_cursor_line(wp)) - && (syntax_flags & HL_CONCEAL) != 0 - && !(lnum_in_visual_area - && vim_strchr(wp->w_p_cocu, 'v') == NULL)) { + if (wp->w_p_cole > 0 + && (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)) { char_attr = conceal_attr; if (prev_syntax_id != syntax_seqnr - && (syn_get_sub_char() != NUL || wp->w_p_cole == 1) + && (syn_get_sub_char() != NUL || match_conc + || wp->w_p_cole == 1) && wp->w_p_cole != 3) { - /* First time at this concealed item: display one - * character. */ - if (syn_get_sub_char() != NUL) + // First time at this concealed item: display one + // character. + if (match_conc) { + c = match_conc; + } else if (syn_get_sub_char() != NUL) { c = syn_get_sub_char(); - else if (lcs_conceal != NUL) + } else if (lcs_conceal != NUL) { c = lcs_conceal; - else + } else { c = ' '; + } prev_syntax_id = syntax_seqnr; @@ -5009,8 +5052,8 @@ win_redr_custom ( char_u *stl; char_u *p; struct stl_hlrec hltab[STL_MAX_ITEM]; - struct stl_hlrec tabtab[STL_MAX_ITEM]; - int use_sandbox = FALSE; + StlClickRecord tabtab[STL_MAX_ITEM]; + int use_sandbox = false; win_T *ewp; int p_crb_save; @@ -5126,20 +5169,24 @@ win_redr_custom ( screen_puts(p >= buf + len ? (char_u *)"" : p, row, col, curattr); if (wp == NULL) { - /* Fill the TabPageIdxs[] array for clicking in the tab pagesline. */ + // Fill the tab_page_click_defs array for clicking in the tab pages line. col = 0; len = 0; p = buf; - fillchar = 0; + StlClickDefinition cur_click_def = { + .type = kStlClickDisabled, + }; for (n = 0; tabtab[n].start != NULL; n++) { - len += vim_strnsize(p, (int)(tabtab[n].start - p)); - while (col < len) - TabPageIdxs[col++] = fillchar; - p = tabtab[n].start; - fillchar = tabtab[n].userhl; + len += vim_strnsize(p, (int)(tabtab[n].start - (char *) p)); + while (col < len) { + tab_page_click_defs[col++] = cur_click_def; + } + p = (char_u *) tabtab[n].start; + cur_click_def = tabtab[n].def; + } + while (col < Columns) { + tab_page_click_defs[col++] = cur_click_def; } - while (col < Columns) - TabPageIdxs[col++] = fillchar; } theend: @@ -5958,9 +6005,9 @@ void screenalloc(bool doclear) sattr_T *new_ScreenAttrs; unsigned *new_LineOffset; char_u *new_LineWraps; - short *new_TabPageIdxs; - static int entered = FALSE; /* avoid recursiveness */ - static int done_outofmem_msg = FALSE; /* did outofmem message */ + StlClickDefinition *new_tab_page_click_defs; + static bool entered = false; // avoid recursiveness + static bool done_outofmem_msg = false; int retry_count = 0; const bool l_enc_utf8 = enc_utf8; const int l_enc_dbcs = enc_dbcs; @@ -6033,7 +6080,8 @@ retry: new_ScreenAttrs = xmalloc((size_t)((Rows + 1) * Columns * sizeof(sattr_T))); new_LineOffset = xmalloc((size_t)(Rows * sizeof(unsigned))); new_LineWraps = xmalloc((size_t)(Rows * sizeof(char_u))); - new_TabPageIdxs = xmalloc((size_t)(Columns * sizeof(short))); + new_tab_page_click_defs = xcalloc( + (size_t) Columns, sizeof(*new_tab_page_click_defs)); FOR_ALL_TAB_WINDOWS(tp, wp) { win_alloc_lines(wp); @@ -6051,7 +6099,7 @@ retry: || new_ScreenAttrs == NULL || new_LineOffset == NULL || new_LineWraps == NULL - || new_TabPageIdxs == NULL + || new_tab_page_click_defs == NULL || outofmem) { if (ScreenLines != NULL || !done_outofmem_msg) { /* guess the size */ @@ -6077,8 +6125,8 @@ retry: new_LineOffset = NULL; xfree(new_LineWraps); new_LineWraps = NULL; - xfree(new_TabPageIdxs); - new_TabPageIdxs = NULL; + xfree(new_tab_page_click_defs); + new_tab_page_click_defs = NULL; } else { done_outofmem_msg = FALSE; @@ -6157,7 +6205,8 @@ retry: ScreenAttrs = new_ScreenAttrs; LineOffset = new_LineOffset; LineWraps = new_LineWraps; - TabPageIdxs = new_TabPageIdxs; + tab_page_click_defs = new_tab_page_click_defs; + tab_page_click_defs_size = Columns; /* It's important that screen_Rows and screen_Columns reflect the actual * size of ScreenLines[]. Set them before calling anything. */ @@ -6196,7 +6245,25 @@ void free_screenlines(void) xfree(ScreenAttrs); xfree(LineOffset); xfree(LineWraps); - xfree(TabPageIdxs); + clear_tab_page_click_defs(tab_page_click_defs, tab_page_click_defs_size); + xfree(tab_page_click_defs); +} + +/// Clear tab_page_click_defs table +/// +/// @param[out] tpcd Table to clear. +/// @param[in] tpcd_size Size of the table. +void clear_tab_page_click_defs(StlClickDefinition *const tpcd, + const long tpcd_size) +{ + if (tpcd != NULL) { + for (long i = 0; i < tpcd_size; i++) { + if (i == 0 || tpcd[i].func != tpcd[i - 1].func) { + xfree(tpcd[i].func); + } + } + memset(tpcd, 0, (size_t) tpcd_size * sizeof(tpcd[0])); + } } void screenclear(void) @@ -6804,9 +6871,9 @@ static void draw_tabline(void) return; - /* Init TabPageIdxs[] to zero: Clicking outside of tabs has no effect. */ - for (scol = 0; scol < Columns; ++scol) - TabPageIdxs[scol] = 0; + // Init TabPageIdxs[] to zero: Clicking outside of tabs has no effect. + assert(Columns == tab_page_click_defs_size); + clear_tab_page_click_defs(tab_page_click_defs, tab_page_click_defs_size); /* Use the 'tabline' option if it's set. */ if (*p_tal != NUL) { @@ -6904,11 +6971,16 @@ static void draw_tabline(void) } screen_putchar(' ', 0, col++, attr); - /* Store the tab page number in TabPageIdxs[], so that - * jump_to_mouse() knows where each one is. */ - ++tabcount; - while (scol < col) - TabPageIdxs[scol++] = tabcount; + // Store the tab page number in tab_page_click_defs[], so that + // jump_to_mouse() knows where each one is. + tabcount++; + while (scol < col) { + tab_page_click_defs[scol++] = (StlClickDefinition) { + .type = kStlClickTabSwitch, + .tabnr = tabcount, + .func = NULL, + }; + } } if (use_sep_chars) @@ -6920,7 +6992,11 @@ static void draw_tabline(void) /* Put an "X" for closing the current tab if there are several. */ if (first_tabpage->tp_next != NULL) { screen_putchar('X', 0, (int)Columns - 1, attr_nosel); - TabPageIdxs[Columns - 1] = -999; + tab_page_click_defs[Columns - 1] = (StlClickDefinition) { + .type = kStlClickTabClose, + .tabnr = 999, + .func = NULL, + }; } } diff --git a/src/nvim/screen.h b/src/nvim/screen.h index debf86ae67..81a8b9ed4c 100644 --- a/src/nvim/screen.h +++ b/src/nvim/screen.h @@ -16,6 +16,29 @@ #define NOT_VALID 40 /* buffer needs complete redraw */ #define CLEAR 50 /* screen messed up, clear it */ +/// Status line click definition +typedef struct { + enum { + kStlClickDisabled = 0, ///< Clicks to this area are ignored. + kStlClickTabSwitch, ///< Switch to the given tab. + kStlClickTabClose, ///< Close given tab. + kStlClickFuncRun, ///< Run user function. + } type; ///< Type of the click. + int tabnr; ///< Tab page number. + char *func; ///< Function to run. +} StlClickDefinition; + +/// Used for tabline clicks +typedef struct { + StlClickDefinition def; ///< Click definition. + const char *start; ///< Location where region starts. +} StlClickRecord; + +/// Array defining what should be done when tabline is clicked +extern StlClickDefinition *tab_page_click_defs; + +/// Size of the tab_page_click_defs array +extern long tab_page_click_defs_size; #ifdef INCLUDE_GENERATED_DECLARATIONS # include "screen.h.generated.h" diff --git a/src/nvim/search.c b/src/nvim/search.c index d393ee7d02..fffae1ecb2 100644 --- a/src/nvim/search.c +++ b/src/nvim/search.c @@ -497,6 +497,7 @@ int searchit( pos_T start_pos; int at_first_line; int extra_col; + int start_char_len; int match_ok; long nmatched; int submatch = 0; @@ -519,16 +520,21 @@ int searchit( // When not accepting a match at the start position set "extra_col" to a // non-zero value. Don't do that when starting at MAXCOL, since MAXCOL + 1 // is zero. - if ((options & SEARCH_START) || pos->col == MAXCOL) { - extra_col = 0; - } else if (dir != BACKWARD && has_mbyte - && pos->lnum >= 1 && pos->lnum <= buf->b_ml.ml_line_count - && pos->col < MAXCOL - 2) { + if (pos->col == MAXCOL) { + start_char_len = 0; + } else if (has_mbyte + && pos->lnum >= 1 && pos->lnum <= buf->b_ml.ml_line_count + && pos->col < MAXCOL - 2) { // Watch out for the "col" being MAXCOL - 2, used in a closed fold. - ptr = ml_get_buf(buf, pos->lnum, FALSE) + pos->col; - extra_col = *ptr == NUL ? 1 : (*mb_ptr2len)(ptr); + ptr = ml_get_buf(buf, pos->lnum, false) + pos->col; + start_char_len = *ptr == NUL ? 1 : (*mb_ptr2len)(ptr); } else { - extra_col = 1; + start_char_len = 1; + } + if (dir == FORWARD) { + extra_col = (options & SEARCH_START) ? 0 : start_char_len; + } else { + extra_col = (options & SEARCH_START) ? start_char_len : 0; } start_pos = *pos; /* remember start pos for detecting no match */ @@ -679,16 +685,14 @@ int searchit( || (lnum + regmatch.endpos[0].lnum == start_pos.lnum && (int)regmatch.endpos[0].col - 1 - + extra_col - <= (int)start_pos.col)) + < (int)start_pos.col + extra_col)) : (lnum + regmatch.startpos[0].lnum < start_pos.lnum || (lnum + regmatch.startpos[0].lnum == start_pos.lnum && (int)regmatch.startpos[0].col - + extra_col - <= (int)start_pos.col)))) { - match_ok = TRUE; + < (int)start_pos.col + extra_col)))) { + match_ok = true; matchpos = regmatch.startpos[0]; endpos = regmatch.endpos[0]; submatch = first_submatch(®match); @@ -3076,18 +3080,18 @@ current_block ( } else old_end = VIsual; - /* - * Search backwards for unclosed '(', '{', etc.. - * Put this position in start_pos. - * Ignore quotes here. - */ + // Search backwards for unclosed '(', '{', etc.. + // Put this position in start_pos. + // Ignore quotes here. Keep the "M" flag in 'cpo', as that is what the + // user wants. save_cpo = p_cpo; - p_cpo = (char_u *)"%"; + p_cpo = (char_u *)(vim_strchr(p_cpo, CPO_MATCHBSL) != NULL ? "%M" : "%"); while (count-- > 0) { - if ((pos = findmatch(NULL, what)) == NULL) + if ((pos = findmatch(NULL, what)) == NULL) { break; + } curwin->w_cursor = *pos; - start_pos = *pos; /* the findmatch for end_pos will overwrite *pos */ + start_pos = *pos; // the findmatch for end_pos will overwrite *pos } p_cpo = save_cpo; @@ -3140,10 +3144,12 @@ current_block ( } if (VIsual_active) { - if (*p_sel == 'e') - ++curwin->w_cursor.col; - if (sol && gchar_cursor() != NUL) - inc(&curwin->w_cursor); /* include the line break */ + if (*p_sel == 'e') { + inc(&curwin->w_cursor); + } + if (sol && gchar_cursor() != NUL) { + inc(&curwin->w_cursor); // include the line break + } VIsual = start_pos; VIsual_mode = 'v'; redraw_curbuf_later(INVERTED); /* update the inversion */ diff --git a/src/nvim/syntax.c b/src/nvim/syntax.c index 24422c71fb..478fa973a1 100644 --- a/src/nvim/syntax.c +++ b/src/nvim/syntax.c @@ -41,6 +41,8 @@ #include "nvim/os/os.h" #include "nvim/os/time.h" +static bool did_syntax_onoff = false; + // Structure that stores information about a highlight group. // The ID of a highlight group is also called group ID. It is the index in // the highlight_ga array PLUS ONE. @@ -3004,14 +3006,19 @@ static void syn_cmd_spell(exarg_T *eap, int syncing) return; next = skiptowhite(arg); - if (STRNICMP(arg, "toplevel", 8) == 0 && next - arg == 8) + if (STRNICMP(arg, "toplevel", 8) == 0 && next - arg == 8) { curwin->w_s->b_syn_spell = SYNSPL_TOP; - else if (STRNICMP(arg, "notoplevel", 10) == 0 && next - arg == 10) + } else if (STRNICMP(arg, "notoplevel", 10) == 0 && next - arg == 10) { curwin->w_s->b_syn_spell = SYNSPL_NOTOP; - else if (STRNICMP(arg, "default", 7) == 0 && next - arg == 7) + } else if (STRNICMP(arg, "default", 7) == 0 && next - arg == 7) { curwin->w_s->b_syn_spell = SYNSPL_DEFAULT; - else + } else { EMSG2(_("E390: Illegal argument: %s"), arg); + return; + } + + // assume spell checking changed, force a redraw + redraw_win_later(curwin, NOT_VALID); } /* @@ -3281,17 +3288,28 @@ static void syn_cmd_off(exarg_T *eap, int syncing) } static void syn_cmd_onoff(exarg_T *eap, char *name) + FUNC_ATTR_NONNULL_ALL { - char buf[100]; - + did_syntax_onoff = true; eap->nextcmd = check_nextcmd(eap->arg); if (!eap->skip) { - strcpy(buf, "so "); + char buf[100]; + strncpy(buf, "so ", 4); vim_snprintf(buf + 3, sizeof(buf) - 3, SYNTAX_FNAME, name); do_cmdline_cmd(buf); } } +void syn_maybe_on(void) +{ + if (!did_syntax_onoff) { + exarg_T ea; + ea.arg = (char_u *)""; + ea.skip = false; + syn_cmd_onoff(&ea, "syntax"); + } +} + /* * Handle ":syntax [list]" command: list current syntax words. */ @@ -4183,12 +4201,16 @@ static void syn_cmd_keyword(exarg_T *eap, int syncing) break; if (p[1] == NUL) { EMSG2(_("E789: Missing ']': %s"), kw); - kw = p + 2; /* skip over the NUL */ - break; + goto error; } if (p[1] == ']') { - kw = p + 1; /* skip over the "]" */ - break; + if (p[2] != NUL) { + EMSG3(_("E890: trailing char after ']': %s]%s"), + kw, &p[2]); + goto error; + } + kw = p + 1; + break; // skip over the "]" } if (has_mbyte) { int l = (*mb_ptr2len)(p + 1); @@ -4203,6 +4225,7 @@ static void syn_cmd_keyword(exarg_T *eap, int syncing) } } +error: xfree(keyword_copy); xfree(syn_opt_arg.cont_in_list); xfree(syn_opt_arg.next_list); @@ -4843,9 +4866,10 @@ static char_u *get_syn_pattern(char_u *arg, synpat_T *ci) int idx; char_u *cpo_save; - /* need at least three chars */ - if (arg == NULL || arg[1] == NUL || arg[2] == NUL) + // need at least three chars + if (arg == NULL || arg[0] == NUL || arg[1] == NUL || arg[2] == NUL) { return NULL; + } end = skip_regexp(arg + 1, *arg, TRUE, NULL); if (*end != *arg) { /* end delimiter not found */ @@ -5395,8 +5419,10 @@ void ex_ownsyntax(exarg_T *eap) if (curwin->w_s == &curwin->w_buffer->b_s) { curwin->w_s = xmalloc(sizeof(synblock_T)); memset(curwin->w_s, 0, sizeof(synblock_T)); - // TODO: Keep the spell checking as it was. - curwin->w_p_spell = FALSE; /* No spell checking */ + hash_init(&curwin->w_s->b_keywtab); + hash_init(&curwin->w_s->b_keywtab_ic); + // TODO: Keep the spell checking as it was. NOLINT(readability/todo) + curwin->w_p_spell = false; // No spell checking clear_string_option(&curwin->w_s->b_p_spc); clear_string_option(&curwin->w_s->b_p_spf); clear_string_option(&curwin->w_s->b_p_spl); diff --git a/src/nvim/terminal.c b/src/nvim/terminal.c index 0a7807d811..42fd81f643 100644 --- a/src/nvim/terminal.c +++ b/src/nvim/terminal.c @@ -141,10 +141,6 @@ struct terminal { int pressed_button; // pending width/height bool pending_resize; - // color palette. this isn't set directly in the vterm instance because - // the default values are used to obtain the color numbers passed to cterm - // colors - RgbValue colors[256]; // With a reference count of 0 the terminal can be freed. size_t refcount; }; @@ -205,6 +201,7 @@ void terminal_teardown(void) Terminal *terminal_open(TerminalOptions opts) { + bool true_color = ui_rgb_attached(); // Create a new terminal instance and configure it Terminal *rv = xcalloc(1, sizeof(Terminal)); rv->opts = opts; @@ -220,7 +217,7 @@ Terminal *terminal_open(TerminalOptions opts) // Set up screen rv->vts = vterm_obtain_screen(rv->vt); vterm_screen_enable_altscreen(rv->vts, true); - // delete empty lines at the end of the buffer + // delete empty lines at the end of the buffer vterm_screen_set_callbacks(rv->vts, &vterm_screen_callbacks, rv); vterm_screen_set_damage_merge(rv->vts, VTERM_DAMAGE_SCROLL); vterm_screen_reset(rv->vts, 1); @@ -236,7 +233,7 @@ Terminal *terminal_open(TerminalOptions opts) set_option_value((uint8_t *)"relativenumber", false, NULL, OPT_LOCAL); RESET_BINDING(curwin); // Apply TermOpen autocmds so the user can configure the terminal - apply_autocmds(EVENT_TERMOPEN, NULL, NULL, true, curbuf); + apply_autocmds(EVENT_TERMOPEN, NULL, NULL, false, curbuf); // Configure the scrollback buffer. Try to get the size from: // @@ -250,12 +247,18 @@ Terminal *terminal_open(TerminalOptions opts) rv->sb_size = MIN(rv->sb_size, 100000); rv->sb_buffer = xmalloc(sizeof(ScrollbackLine *) * rv->sb_size); + if (!true_color) { + return rv; + } + + vterm_state_set_bold_highbright(state, true); + // Configure the color palette. Try to get the color from: // // - b:terminal_color_{NUM} // - g:terminal_color_{NUM} // - the VTerm instance - for (int i = 0; i < (int)ARRAY_SIZE(rv->colors); i++) { + for (int i = 0; i < 16; i++) { RgbValue color_val = -1; char var[64]; snprintf(var, sizeof(var), "terminal_color_%d", i); @@ -265,16 +268,13 @@ Terminal *terminal_open(TerminalOptions opts) xfree(name); if (color_val != -1) { - rv->colors[i] = color_val; + VTermColor color; + color.red = (uint8_t)((color_val >> 16) & 0xFF); + color.green = (uint8_t)((color_val >> 8) & 0xFF); + color.blue = (uint8_t)((color_val >> 0) & 0xFF); + vterm_state_set_palette_color(state, i, &color); } } - - if (color_val == -1) { - // the default is taken from vterm - VTermColor color; - vterm_state_get_palette_color(state, i, &color); - rv->colors[i] = RGB(color.red, color.green, color.blue); - } } return rv; @@ -288,8 +288,9 @@ void terminal_close(Terminal *term, char *msg) term->forward_mouse = false; term->closed = true; + buf_T *buf = handle_get_buffer(term->buf_handle); + if (!msg || exiting) { - buf_T *buf = handle_get_buffer(term->buf_handle); // If no msg was given, this was called by close_buffer(buffer.c). Or if // exiting, we must inform the buffer the terminal no longer exists so that // close_buffer() doesn't call this again. @@ -304,6 +305,10 @@ void terminal_close(Terminal *term, char *msg) } else { terminal_receive(term, msg, strlen(msg)); } + + if (buf) { + apply_autocmds(EVENT_TERMCLOSE, NULL, NULL, false, buf); + } } void terminal_resize(Terminal *term, uint16_t width, uint16_t height) @@ -543,10 +548,6 @@ void terminal_get_line_attributes(Terminal *term, win_T *wp, int linenr, map_get(int, int)(color_indexes, vt_fg) : 0; int vt_bg_idx = vt_bg != default_vt_bg ? map_get(int, int)(color_indexes, vt_bg) : 0; - // The index is now used to get the final rgb value from the - // user-customizable palette. - int vt_fg_rgb = vt_fg_idx != 0 ? term->colors[vt_fg_idx - 1] : -1; - int vt_bg_rgb = vt_bg_idx != 0 ? term->colors[vt_bg_idx - 1] : -1; int hl_attrs = (cell.attrs.bold ? HL_BOLD : 0) | (cell.attrs.italic ? HL_ITALIC : 0) @@ -561,8 +562,8 @@ void terminal_get_line_attributes(Terminal *term, win_T *wp, int linenr, .cterm_fg_color = vt_fg_idx, .cterm_bg_color = vt_bg_idx, .rgb_ae_attr = (int16_t)hl_attrs, - .rgb_fg_color = vt_fg_rgb, - .rgb_bg_color = vt_bg_rgb, + .rgb_fg_color = vt_fg, + .rgb_bg_color = vt_bg, }); } diff --git a/src/nvim/testdir/Makefile b/src/nvim/testdir/Makefile index fe511166f2..63ca4cf6c4 100644 --- a/src/nvim/testdir/Makefile +++ b/src/nvim/testdir/Makefile @@ -7,28 +7,37 @@ export SHELL := sh VIMPROG := ../../../build/bin/nvim SCRIPTSOURCE := ../../../runtime -SCRIPTS := \ - test8.out test10.out \ - test11.out test12.out test13.out test14.out \ - test17.out \ - test24.out \ - test30.out \ - test32.out test34.out \ - test36.out test37.out test40.out \ - test42.out test45.out \ - test47.out test48.out test49.out \ - test52.out test53.out test55.out \ - test64.out \ - test68.out test69.out \ - test73.out \ - test79.out \ - test88.out \ - test_listlbr.out \ - test_breakindent.out \ - test_charsearch.out \ - test_close_count.out \ - test_command_count.out \ - test_marks.out \ +SCRIPTS := \ + test8.out \ + test10.out \ + test12.out \ + test13.out \ + test14.out \ + test17.out \ + test24.out \ + test30.out \ + test32.out \ + test34.out \ + test37.out \ + test40.out \ + test42.out \ + test47.out \ + test48.out \ + test49.out \ + test52.out \ + test53.out \ + test55.out \ + test64.out \ + test68.out \ + test69.out \ + test73.out \ + test79.out \ + test88.out \ + test_listlbr.out \ + test_breakindent.out \ + test_close_count.out \ + test_marks.out \ + test_match_conceal.out \ NEW_TESTS = diff --git a/src/nvim/testdir/test11.in b/src/nvim/testdir/test11.in deleted file mode 100644 index 9e9e257c1d..0000000000 --- a/src/nvim/testdir/test11.in +++ /dev/null @@ -1,84 +0,0 @@ -Tests for autocommands: -- FileWritePre writing a compressed file -- FileReadPost reading a compressed file -- BufNewFile reading a file template -- BufReadPre decompressing the file to be read -- FilterReadPre substituting characters in the temp file -- FilterReadPost substituting characters after filtering -- FileReadPre set options for decompression -- FileReadPost decompress the file - -Note: This test is skipped if "gzip" is not available. -$GZIP is made empty, "-v" would cause trouble. -Use a FileChangedShell autocommand to avoid a prompt for "Xtestfile.gz" being -modified outside of Vim (noticed on Solaris). - -STARTTEST -:so small.vim -:" drop out when there is no gzip program -:if !executable("gzip") -: e! test.ok -: w! test.out -: qa! -:endif -:let $GZIP = "" -:au FileChangedShell * echo "caught FileChangedShell" -:set bin -:au FileWritePre *.gz '[,']!gzip -:au FileWritePost *.gz undo -:/^start of testfile/,/^end of testfile/w! Xtestfile.gz -:au FileReadPost *.gz '[,']!gzip -d -:$r Xtestfile.gz " Read and decompress the testfile -:?startstart?,$w! test.out " Write contents of this file -:au BufNewFile *.c read Xtest.c -:/^start of test.c/+1,/^end of test.c/-1w! Xtest.c -:e! foo.c " Will load Xtest.c -:au FileAppendPre *.out '[,']s/new/NEW/ -:au FileAppendPost *.out !cat Xtest.c >>test.out -:w>>test.out " Append it to the output file -:au! FileAppendPre -:" setup autocommands to decompress before reading and re-compress afterwards -:au BufReadPre *.gz exe '!gzip -d ' . shellescape(expand("<afile>")) -:au BufReadPre *.gz call rename(expand("<afile>:r"), expand("<afile>")) -:au BufReadPost *.gz call rename(expand("<afile>"), expand("<afile>:r")) -:au BufReadPost *.gz exe '!gzip ' . shellescape(expand("<afile>:r")) -:e! Xtestfile.gz " Edit compressed file -:w>>test.out " Append it to the output file -:set shelltemp " need temp files here -:au FilterReadPre *.out call rename(expand("<afile>"), expand("<afile>") . ".t") -:au FilterReadPre *.out exe 'silent !sed s/e/E/ ' . shellescape(expand("<afile>")) . ".t >" . shellescape(expand("<afile>")) -:au FilterReadPre *.out exe 'silent !rm ' . shellescape(expand("<afile>")) . '.t' -:au FilterReadPost *.out '[,']s/x/X/g -:e! test.out " Edit the output file -:23,$!cat -:23,$s/\r$// " remove CR for when sed adds them -:au! FileReadPre *.gz exe 'silent !gzip -d ' . shellescape(expand("<afile>")) -:au FileReadPre *.gz call rename(expand("<afile>:r"), expand("<afile>")) -:au! FileReadPost *.gz '[,']s/l/L/ -:$r Xtestfile.gz " Read compressed file -:w " write it, after filtering -:au! " remove all autocommands -:e " Edit test.out again -:set nobin ff& " use the default fileformat for writing -:w -:qa! -ENDTEST - -startstart -start of testfile -line 2 Abcdefghijklmnopqrstuvwxyz -line 3 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx -line 4 Abcdefghijklmnopqrstuvwxyz -line 5 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx -line 6 Abcdefghijklmnopqrstuvwxyz -line 7 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx -line 8 Abcdefghijklmnopqrstuvwxyz -line 9 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx -line 10 Abcdefghijklmnopqrstuvwxyz -end of testfile - -start of test.c -/* - * Here is a new .c file - */ -end of test.c diff --git a/src/nvim/testdir/test11.ok b/src/nvim/testdir/test11.ok deleted file mode 100644 index af8c5ce261..0000000000 --- a/src/nvim/testdir/test11.ok +++ /dev/null @@ -1,61 +0,0 @@ -startstart -start of testfile -line 2 Abcdefghijklmnopqrstuvwxyz -line 3 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx -line 4 Abcdefghijklmnopqrstuvwxyz -line 5 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx -line 6 Abcdefghijklmnopqrstuvwxyz -line 7 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx -line 8 Abcdefghijklmnopqrstuvwxyz -line 9 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx -line 10 Abcdefghijklmnopqrstuvwxyz -end of testfile - -start of test.c -/* - * Here is a new .c file - */ -end of test.c -start of testfile -line 2 Abcdefghijklmnopqrstuvwxyz -line 3 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx -line 4 Abcdefghijklmnopqrstuvwxyz -linE 5 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX -linE 6 AbcdefghijklmnopqrstuvwXyz -linE 7 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX -linE 8 AbcdefghijklmnopqrstuvwXyz -linE 9 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX -linE 10 AbcdefghijklmnopqrstuvwXyz -End of testfile - -/* - * HEre is a NEW .c file - */ -/* - * HEre is a new .c file - */ -start of tEstfile -linE 2 AbcdefghijklmnopqrstuvwXyz -linE 3 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX -linE 4 AbcdefghijklmnopqrstuvwXyz -linE 5 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX -linE 6 AbcdefghijklmnopqrstuvwXyz -linE 7 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX -linE 8 AbcdefghijklmnopqrstuvwXyz -linE 9 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX -linE 10 AbcdefghijklmnopqrstuvwXyz -End of testfile -/* - * HEre is a new .c file - */ -start of testfiLe -Line 2 Abcdefghijklmnopqrstuvwxyz -Line 3 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx -Line 4 Abcdefghijklmnopqrstuvwxyz -Line 5 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx -Line 6 Abcdefghijklmnopqrstuvwxyz -Line 7 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx -Line 8 Abcdefghijklmnopqrstuvwxyz -Line 9 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx -Line 10 Abcdefghijklmnopqrstuvwxyz -end of testfiLe diff --git a/src/nvim/testdir/test13.in b/src/nvim/testdir/test13.in index cb8a6fff89..6713f80e88 100644 --- a/src/nvim/testdir/test13.in +++ b/src/nvim/testdir/test13.in @@ -48,6 +48,12 @@ otestje3 :au BufWipeout Xtestje1 buf Xtestje1 :bwipe :w >>test.out +:only +:new|set buftype=help +:wincmd w +:1quit +:$put ='Final line' +:$w >>test.out :qa! ENDTEST diff --git a/src/nvim/testdir/test13.ok b/src/nvim/testdir/test13.ok index 0f1fc347a4..66ebce63f7 100644 --- a/src/nvim/testdir/test13.ok +++ b/src/nvim/testdir/test13.ok @@ -28,3 +28,4 @@ testje1 contents contents end of testfile +Final line diff --git a/src/nvim/testdir/test30.in b/src/nvim/testdir/test30.in index 3f7b9eb472..2a89eac73d 100644 --- a/src/nvim/testdir/test30.in +++ b/src/nvim/testdir/test30.in @@ -7,32 +7,27 @@ STARTTEST :" first write three test files, one in each format :set fileformat=unix :set fileformats= -:/^1/w! XX1 -:/^2/w! XX2 -:/^3/w! XX3 -:/^4/w! XX4 -:/^5/w! XX5 -:/^6/w! XX6 -:/^7/w! XX7 -:/^8/w! XX8 -:/^9/w! XX9 -:/^10/w! XX10 :/^unix/;/eof/-1w! XXUnix :/^dos/;/eof/-1w! XXDos :set bin noeol :$w! XXMac +Gonoeol +:$w! XXEol :set nobin eol +:enew! :bwipe XXUnix XXDos XXMac :" create mixed format files :if has("win32") : !copy /b XXUnix+XXDos XXUxDs : !copy /b XXUnix+XXMac XXUxMac : !copy /b XXDos+XXMac XXDosMac +: !copy /b XXMac+XXEol XXMacEol : !copy /b XXUnix+XXDos+XXMac XXUxDsMc :else : !cat XXUnix XXDos >XXUxDs : !cat XXUnix XXMac >XXUxMac : !cat XXDos XXMac >XXDosMac +: !cat XXMac XXEol >XXMacEol : !cat XXUnix XXDos XXMac >XXUxDsMc :endif :" @@ -97,26 +92,48 @@ STARTTEST :e! XXDosMac :w! XXtt53 :bwipe XXDosMac +:e! XXEol +ggO=&ffs +:=&ff +:w! XXtt54 +:bwipe XXEol :set fileformats=dos,mac :e! XXUxDs :w! XXtt61 :bwipe XXUxDs :e! XXUxMac -:w! XXtt62 +ggO=&ffs +:=&ff +:w! XXtt62 :bwipe XXUxMac :e! XXUxDsMc :w! XXtt63 :bwipe XXUxDsMc +:e! XXMacEol +ggO=&ffs +:=&ff +:w! XXtt64 +:bwipe XXMacEol :" :" try reading and writing with 'fileformats' set to three formats :set fileformats=unix,dos,mac :e! XXUxDsMc :w! XXtt71 :bwipe XXUxDsMc +:e! XXEol +ggO=&ffs +:=&ff +:w! XXtt72 +:bwipe XXEol :set fileformats=mac,dos,unix :e! XXUxDsMc :w! XXtt81 :bwipe XXUxDsMc +:e! XXEol +ggO=&ffs +:=&ff +:w! XXtt82 +:bwipe XXEol :" try with 'binary' set :set fileformats=mac,unix,dos :set binary @@ -150,11 +167,15 @@ ggdGaEND:w >>XXtt01 :w >>XXtt51 :w >>XXtt52 :w >>XXtt53 +:w >>XXtt54 :w >>XXtt61 :w >>XXtt62 :w >>XXtt63 +:w >>XXtt64 :w >>XXtt71 +:w >>XXtt72 :w >>XXtt81 +:w >>XXtt82 :w >>XXtt91 :w >>XXtt92 :w >>XXtt93 @@ -181,11 +202,15 @@ Go4:$r XXtt41 Go5:$r XXtt51 :$r XXtt52 :$r XXtt53 +:$r XXtt54 Go6:$r XXtt61 :$r XXtt62 :$r XXtt63 +:$r XXtt64 Go7:$r XXtt71 +:$r XXtt72 Go8:$r XXtt81 +:$r XXtt82 Go9:$r XXtt91 :$r XXtt92 :$r XXtt93 @@ -195,17 +220,6 @@ Go10:$r XXUnix :qa! ENDTEST -1 -2 -3 -4 -5 -6 -7 -8 -9 -10 - unix unix eof diff --git a/src/nvim/testdir/test30.ok b/src/nvim/testdir/test30.ok index 380ce67061..b35f4f5904 100644 --- a/src/nvim/testdir/test30.ok +++ b/src/nvim/testdir/test30.ok @@ -70,12 +70,16 @@ END dos
dos
mac
mac
END +unix,mac:unix +noeol +END 6 unix
unix
dos
dos
END +dos,mac:dos
unix
unix
mac
mac
@@ -86,6 +90,7 @@ dos dos
mac
mac
END +dos,mac:mac
mac
mac
noeol
END 7 unix unix @@ -93,6 +98,9 @@ dos dos
mac
mac
END +unix,dos,mac:unix +noeol +END 8 unix unix @@ -100,6 +108,7 @@ dos dos
mac
mac
END +mac,dos,unix:mac
noeol
END 9 unix unix diff --git a/src/nvim/testdir/test36.in b/src/nvim/testdir/test36.in deleted file mode 100644 index 8cdb5262bd..0000000000 --- a/src/nvim/testdir/test36.in +++ /dev/null @@ -1,105 +0,0 @@ -Test character classes in regexp using regexpengine 0, 1, 2. - -STARTTEST -/^start-here/+1 -Y:s/\%#=0\d//g -p:s/\%#=1\d//g -p:s/\%#=2\d//g -p:s/\%#=0[0-9]//g -p:s/\%#=1[0-9]//g -p:s/\%#=2[0-9]//g -p:s/\%#=0\D//g -p:s/\%#=1\D//g -p:s/\%#=2\D//g -p:s/\%#=0[^0-9]//g -p:s/\%#=1[^0-9]//g -p:s/\%#=2[^0-9]//g -p:s/\%#=0\o//g -p:s/\%#=1\o//g -p:s/\%#=2\o//g -p:s/\%#=0[0-7]//g -p:s/\%#=1[0-7]//g -p:s/\%#=2[0-7]//g -p:s/\%#=0\O//g -p:s/\%#=1\O//g -p:s/\%#=2\O//g -p:s/\%#=0[^0-7]//g -p:s/\%#=1[^0-7]//g -p:s/\%#=2[^0-7]//g -p:s/\%#=0\x//g -p:s/\%#=1\x//g -p:s/\%#=2\x//g -p:s/\%#=0[0-9A-Fa-f]//g -p:s/\%#=1[0-9A-Fa-f]//g -p:s/\%#=2[0-9A-Fa-f]//g -p:s/\%#=0\X//g -p:s/\%#=1\X//g -p:s/\%#=2\X//g -p:s/\%#=0[^0-9A-Fa-f]//g -p:s/\%#=1[^0-9A-Fa-f]//g -p:s/\%#=2[^0-9A-Fa-f]//g -p:s/\%#=0\w//g -p:s/\%#=1\w//g -p:s/\%#=2\w//g -p:s/\%#=0[0-9A-Za-z_]//g -p:s/\%#=1[0-9A-Za-z_]//g -p:s/\%#=2[0-9A-Za-z_]//g -p:s/\%#=0\W//g -p:s/\%#=1\W//g -p:s/\%#=2\W//g -p:s/\%#=0[^0-9A-Za-z_]//g -p:s/\%#=1[^0-9A-Za-z_]//g -p:s/\%#=2[^0-9A-Za-z_]//g -p:s/\%#=0\h//g -p:s/\%#=1\h//g -p:s/\%#=2\h//g -p:s/\%#=0[A-Za-z_]//g -p:s/\%#=1[A-Za-z_]//g -p:s/\%#=2[A-Za-z_]//g -p:s/\%#=0\H//g -p:s/\%#=1\H//g -p:s/\%#=2\H//g -p:s/\%#=0[^A-Za-z_]//g -p:s/\%#=1[^A-Za-z_]//g -p:s/\%#=2[^A-Za-z_]//g -p:s/\%#=0\a//g -p:s/\%#=1\a//g -p:s/\%#=2\a//g -p:s/\%#=0[A-Za-z]//g -p:s/\%#=1[A-Za-z]//g -p:s/\%#=2[A-Za-z]//g -p:s/\%#=0\A//g -p:s/\%#=1\A//g -p:s/\%#=2\A//g -p:s/\%#=0[^A-Za-z]//g -p:s/\%#=1[^A-Za-z]//g -p:s/\%#=2[^A-Za-z]//g -p:s/\%#=0\l//g -p:s/\%#=1\l//g -p:s/\%#=2\l//g -p:s/\%#=0[a-z]//g -p:s/\%#=1[a-z]//g -p:s/\%#=2[a-z]//g -p:s/\%#=0\L//g -p:s/\%#=1\L//g -p:s/\%#=2\L//g -p:s/\%#=0[^a-z]//g -p:s/\%#=1[^a-z]//g -p:s/\%#=2[^a-z]//g -p:s/\%#=0\u//g -p:s/\%#=1\u//g -p:s/\%#=2\u//g -p:s/\%#=0[A-Z]//g -p:s/\%#=1[A-Z]//g -p:s/\%#=2[A-Z]//g -p:s/\%#=0\U//g -p:s/\%#=1\U//g -p:s/\%#=2\U//g -p:s/\%#=0[^A-Z]//g -p:s/\%#=1[^A-Z]//g -p:s/\%#=2[^A-Z]//g -:/^start-here/+1,$wq! test.out -ENDTEST - -start-here -
!"#$%&'()#+'-./0123456789:;<=>?@ABCDEFGHIXYZ[\]^_`abcdefghiwxyz{|}~€‚›¦±¼ÇÓé diff --git a/src/nvim/testdir/test36.ok b/src/nvim/testdir/test36.ok deleted file mode 100644 index f72a74b2b7..0000000000 --- a/src/nvim/testdir/test36.ok +++ /dev/null @@ -1,96 +0,0 @@ -
!"#$%&'()#+'-./:;<=>?@ABCDEFGHIXYZ[\]^_`abcdefghiwxyz{|}~€‚›¦±¼ÇÓé -
!"#$%&'()#+'-./:;<=>?@ABCDEFGHIXYZ[\]^_`abcdefghiwxyz{|}~€‚›¦±¼ÇÓé -
!"#$%&'()#+'-./:;<=>?@ABCDEFGHIXYZ[\]^_`abcdefghiwxyz{|}~€‚›¦±¼ÇÓé -
!"#$%&'()#+'-./:;<=>?@ABCDEFGHIXYZ[\]^_`abcdefghiwxyz{|}~€‚›¦±¼ÇÓé -
!"#$%&'()#+'-./:;<=>?@ABCDEFGHIXYZ[\]^_`abcdefghiwxyz{|}~€‚›¦±¼ÇÓé -
!"#$%&'()#+'-./:;<=>?@ABCDEFGHIXYZ[\]^_`abcdefghiwxyz{|}~€‚›¦±¼ÇÓé -0123456789 -0123456789 -0123456789 -0123456789 -0123456789 -0123456789 -
!"#$%&'()#+'-./89:;<=>?@ABCDEFGHIXYZ[\]^_`abcdefghiwxyz{|}~€‚›¦±¼ÇÓé -
!"#$%&'()#+'-./89:;<=>?@ABCDEFGHIXYZ[\]^_`abcdefghiwxyz{|}~€‚›¦±¼ÇÓé -
!"#$%&'()#+'-./89:;<=>?@ABCDEFGHIXYZ[\]^_`abcdefghiwxyz{|}~€‚›¦±¼ÇÓé -
!"#$%&'()#+'-./89:;<=>?@ABCDEFGHIXYZ[\]^_`abcdefghiwxyz{|}~€‚›¦±¼ÇÓé -
!"#$%&'()#+'-./89:;<=>?@ABCDEFGHIXYZ[\]^_`abcdefghiwxyz{|}~€‚›¦±¼ÇÓé -
!"#$%&'()#+'-./89:;<=>?@ABCDEFGHIXYZ[\]^_`abcdefghiwxyz{|}~€‚›¦±¼ÇÓé -01234567 -01234567 -01234567 -01234567 -01234567 -01234567 -
!"#$%&'()#+'-./:;<=>?@GHIXYZ[\]^_`ghiwxyz{|}~€‚›¦±¼ÇÓé -
!"#$%&'()#+'-./:;<=>?@GHIXYZ[\]^_`ghiwxyz{|}~€‚›¦±¼ÇÓé -
!"#$%&'()#+'-./:;<=>?@GHIXYZ[\]^_`ghiwxyz{|}~€‚›¦±¼ÇÓé -
!"#$%&'()#+'-./:;<=>?@GHIXYZ[\]^_`ghiwxyz{|}~€‚›¦±¼ÇÓé -
!"#$%&'()#+'-./:;<=>?@GHIXYZ[\]^_`ghiwxyz{|}~€‚›¦±¼ÇÓé -
!"#$%&'()#+'-./:;<=>?@GHIXYZ[\]^_`ghiwxyz{|}~€‚›¦±¼ÇÓé -0123456789ABCDEFabcdef -0123456789ABCDEFabcdef -0123456789ABCDEFabcdef -0123456789ABCDEFabcdef -0123456789ABCDEFabcdef -0123456789ABCDEFabcdef -
!"#$%&'()#+'-./:;<=>?@[\]^`{|}~€‚›¦±¼ÇÓé -
!"#$%&'()#+'-./:;<=>?@[\]^`{|}~€‚›¦±¼ÇÓé -
!"#$%&'()#+'-./:;<=>?@[\]^`{|}~€‚›¦±¼ÇÓé -
!"#$%&'()#+'-./:;<=>?@[\]^`{|}~€‚›¦±¼ÇÓé -
!"#$%&'()#+'-./:;<=>?@[\]^`{|}~€‚›¦±¼ÇÓé -
!"#$%&'()#+'-./:;<=>?@[\]^`{|}~€‚›¦±¼ÇÓé -0123456789ABCDEFGHIXYZ_abcdefghiwxyz -0123456789ABCDEFGHIXYZ_abcdefghiwxyz -0123456789ABCDEFGHIXYZ_abcdefghiwxyz -0123456789ABCDEFGHIXYZ_abcdefghiwxyz -0123456789ABCDEFGHIXYZ_abcdefghiwxyz -0123456789ABCDEFGHIXYZ_abcdefghiwxyz -
!"#$%&'()#+'-./0123456789:;<=>?@[\]^`{|}~€‚›¦±¼ÇÓé -
!"#$%&'()#+'-./0123456789:;<=>?@[\]^`{|}~€‚›¦±¼ÇÓé -
!"#$%&'()#+'-./0123456789:;<=>?@[\]^`{|}~€‚›¦±¼ÇÓé -
!"#$%&'()#+'-./0123456789:;<=>?@[\]^`{|}~€‚›¦±¼ÇÓé -
!"#$%&'()#+'-./0123456789:;<=>?@[\]^`{|}~€‚›¦±¼ÇÓé -
!"#$%&'()#+'-./0123456789:;<=>?@[\]^`{|}~€‚›¦±¼ÇÓé -ABCDEFGHIXYZ_abcdefghiwxyz -ABCDEFGHIXYZ_abcdefghiwxyz -ABCDEFGHIXYZ_abcdefghiwxyz -ABCDEFGHIXYZ_abcdefghiwxyz -ABCDEFGHIXYZ_abcdefghiwxyz -ABCDEFGHIXYZ_abcdefghiwxyz -
!"#$%&'()#+'-./0123456789:;<=>?@[\]^_`{|}~€‚›¦±¼ÇÓé -
!"#$%&'()#+'-./0123456789:;<=>?@[\]^_`{|}~€‚›¦±¼ÇÓé -
!"#$%&'()#+'-./0123456789:;<=>?@[\]^_`{|}~€‚›¦±¼ÇÓé -
!"#$%&'()#+'-./0123456789:;<=>?@[\]^_`{|}~€‚›¦±¼ÇÓé -
!"#$%&'()#+'-./0123456789:;<=>?@[\]^_`{|}~€‚›¦±¼ÇÓé -
!"#$%&'()#+'-./0123456789:;<=>?@[\]^_`{|}~€‚›¦±¼ÇÓé -ABCDEFGHIXYZabcdefghiwxyz -ABCDEFGHIXYZabcdefghiwxyz -ABCDEFGHIXYZabcdefghiwxyz -ABCDEFGHIXYZabcdefghiwxyz -ABCDEFGHIXYZabcdefghiwxyz -ABCDEFGHIXYZabcdefghiwxyz -
!"#$%&'()#+'-./0123456789:;<=>?@ABCDEFGHIXYZ[\]^_`{|}~€‚›¦±¼ÇÓé -
!"#$%&'()#+'-./0123456789:;<=>?@ABCDEFGHIXYZ[\]^_`{|}~€‚›¦±¼ÇÓé -
!"#$%&'()#+'-./0123456789:;<=>?@ABCDEFGHIXYZ[\]^_`{|}~€‚›¦±¼ÇÓé -
!"#$%&'()#+'-./0123456789:;<=>?@ABCDEFGHIXYZ[\]^_`{|}~€‚›¦±¼ÇÓé -
!"#$%&'()#+'-./0123456789:;<=>?@ABCDEFGHIXYZ[\]^_`{|}~€‚›¦±¼ÇÓé -
!"#$%&'()#+'-./0123456789:;<=>?@ABCDEFGHIXYZ[\]^_`{|}~€‚›¦±¼ÇÓé -abcdefghiwxyz -abcdefghiwxyz -abcdefghiwxyz -abcdefghiwxyz -abcdefghiwxyz -abcdefghiwxyz -
!"#$%&'()#+'-./0123456789:;<=>?@[\]^_`abcdefghiwxyz{|}~€‚›¦±¼ÇÓé -
!"#$%&'()#+'-./0123456789:;<=>?@[\]^_`abcdefghiwxyz{|}~€‚›¦±¼ÇÓé -
!"#$%&'()#+'-./0123456789:;<=>?@[\]^_`abcdefghiwxyz{|}~€‚›¦±¼ÇÓé -
!"#$%&'()#+'-./0123456789:;<=>?@[\]^_`abcdefghiwxyz{|}~€‚›¦±¼ÇÓé -
!"#$%&'()#+'-./0123456789:;<=>?@[\]^_`abcdefghiwxyz{|}~€‚›¦±¼ÇÓé -
!"#$%&'()#+'-./0123456789:;<=>?@[\]^_`abcdefghiwxyz{|}~€‚›¦±¼ÇÓé -ABCDEFGHIXYZ -ABCDEFGHIXYZ -ABCDEFGHIXYZ -ABCDEFGHIXYZ -ABCDEFGHIXYZ -ABCDEFGHIXYZ diff --git a/src/nvim/testdir/test45.in b/src/nvim/testdir/test45.in deleted file mode 100644 index e5af5073d9..0000000000 --- a/src/nvim/testdir/test45.in +++ /dev/null @@ -1,80 +0,0 @@ -Tests for folding. vim: set ft=vim : - -STARTTEST -:so small.vim -:" We also need the +syntax feature here. -:if !has("syntax") - e! test.ok - w! test.out - qa! -:endif -:" basic test if a fold can be created, opened, moving to the end and closed -/^1 -zf2j:call append("$", "manual " . getline(foldclosed("."))) -zo:call append("$", foldclosed(".")) -]z:call append("$", getline(".")) -zc:call append("$", getline(foldclosed("."))) -:" test folding with markers. -:set fdm=marker fdl=1 fdc=3 -/^5 -:call append("$", "marker " . foldlevel(".")) -[z:call append("$", foldlevel(".")) -jo{{ r{jj:call append("$", foldlevel(".")) -kYpj:call append("$", foldlevel(".")) -:" test folding with indent -:set fdm=indent sw=2 -/^2 b -i jI :call append("$", "indent " . foldlevel(".")) -k:call append("$", foldlevel(".")) -:" test syntax folding -:set fdm=syntax fdl=0 -:syn region Hup start="dd" end="ii" fold contains=Fd1,Fd2,Fd3 -:syn region Fd1 start="ee" end="ff" fold contained -:syn region Fd2 start="gg" end="hh" fold contained -:syn region Fd3 start="commentstart" end="commentend" fold contained -Gzk:call append("$", "folding " . getline(".")) -k:call append("$", getline(".")) -jAcommentstart Acommentend:set fdl=1 -3j:call append("$", getline(".")) -:set fdl=0 -zOj:call append("$", getline(".")) -:" test expression folding -:fun Flvl() - let l = getline(v:lnum) - if l =~ "bb$" - return 2 - elseif l =~ "gg$" - return "s1" - elseif l =~ "ii$" - return ">2" - elseif l =~ "kk$" - return "0" - endif - return "=" -endfun -:set fdm=expr fde=Flvl() -/bb$ -:call append("$", "expr " . foldlevel(".")) -/hh$ -:call append("$", foldlevel(".")) -/ii$ -:call append("$", foldlevel(".")) -/kk$ -:call append("$", foldlevel(".")) -:/^last/+1,$w! test.out -:delfun Flvl -:qa! -ENDTEST - -1 aa -2 bb -3 cc -4 dd {{{ -5 ee {{{ }}} -6 ff }}} -7 gg -8 hh -9 ii -a jj -b kk -last diff --git a/src/nvim/testdir/test45.ok b/src/nvim/testdir/test45.ok deleted file mode 100644 index f04996e337..0000000000 --- a/src/nvim/testdir/test45.ok +++ /dev/null @@ -1,18 +0,0 @@ -manual 1 aa --1 -3 cc -1 aa -marker 2 -1 -1 -0 -indent 2 -1 -folding 9 ii - 3 cc -7 gg -8 hh -expr 2 -1 -2 -0 diff --git a/src/nvim/testdir/test47.in b/src/nvim/testdir/test47.in index 13ad82462f..f15eaf0f8f 100644 --- a/src/nvim/testdir/test47.in +++ b/src/nvim/testdir/test47.in @@ -1,5 +1,7 @@ Tests for vertical splits and filler lines in diff mode +Also tests restoration of saved options by :diffoff. + STARTTEST :so small.vim :" Disable the title to avoid xterm keeping the wrong one. @@ -10,8 +12,19 @@ pkdd:w! Xtest ddGpkkrXoxxx:w! Xtest2 :file Nop ggoyyyjjjozzzz +:set foldmethod=marker foldcolumn=4 +:redir => nodiffsettings +:silent! :set diff? fdm? fdc? scb? crb? wrap? +:redir END :vert diffsplit Xtest :vert diffsplit Xtest2 +:redir => diffsettings +:silent! :set diff? fdm? fdc? scb? crb? wrap? +:redir END +:let diff_fdm = &fdm +:let diff_fdc = &fdc +:" repeat entering diff mode here to see if this saves the wrong settings +:diffthis :" jump to second window for a moment to have filler line appear at start of :" first window ggpgg:let one = winline() @@ -36,8 +49,36 @@ j:let three = three . "-" . winline() :call append("$", two) :call append("$", three) :$-2,$w! test.out -:" Test that diffing shows correct filler lines +:" +:" Test diffoff :diffoff! +1 +:let &diff = 1 +:let &fdm = diff_fdm +:let &fdc = diff_fdc +4 +:diffoff! +:$put =nodiffsettings +:$put =diffsettings +1 +:redir => nd1 +:silent! :set diff? fdm? fdc? scb? crb? wrap? +:redir END + +:redir => nd2 +:silent! :set diff? fdm? fdc? scb? crb? wrap? +:redir END + +:redir => nd3 +:silent! :set diff? fdm? fdc? scb? crb? wrap? +:redir END + +:$put =nd1 +:$put =nd2 +:$put =nd3 +:$-39,$w >> test.out +:" +:" Test that diffing shows correct filler lines :windo :bw! :enew :put =range(4,10) @@ -51,7 +92,7 @@ j:let three = three . "-" . winline() :enew :put =w0 :.w >> test.out -:unlet! one two three w0 +:unlet! one two three nodiffsettings diffsettings diff_fdm diff_fdc nd1 nd2 nd3 w0 :qa! ENDTEST diff --git a/src/nvim/testdir/test47.ok b/src/nvim/testdir/test47.ok index b1cba92b1c..83e96571ad 100644 --- a/src/nvim/testdir/test47.ok +++ b/src/nvim/testdir/test47.ok @@ -1,4 +1,44 @@ 2-4-5-6-8-9 1-2-4-5-8 2-3-4-5-6-7-8 + + +nodiff + foldmethod=marker + foldcolumn=4 +noscrollbind +nocursorbind + wrap + + + diff + foldmethod=diff + foldcolumn=2 + scrollbind + cursorbind +nowrap + + +nodiff + foldmethod=marker + foldcolumn=4 +noscrollbind +nocursorbind + wrap + + +nodiff + foldmethod=marker + foldcolumn=4 +noscrollbind +nocursorbind + wrap + + +nodiff + foldmethod=marker + foldcolumn=4 +noscrollbind +nocursorbind + wrap 1 diff --git a/src/nvim/testdir/test49.vim b/src/nvim/testdir/test49.vim index afee9d882c..70d388b06a 100644 --- a/src/nvim/testdir/test49.vim +++ b/src/nvim/testdir/test49.vim @@ -1,6 +1,6 @@ " Vim script language tests " Author: Servatius Brandt <Servatius.Brandt@fujitsu-siemens.com> -" Last Change: 2013 Jun 06 +" Last Change: 2015 Sep 25 "------------------------------------------------------------------------------- " Test environment {{{1 @@ -5188,19 +5188,19 @@ catch /.*/ Xpath 65536 " X: 65536 let exception = v:exception let throwpoint = v:throwpoint - call CHECK(1, "oops", '\<F\.\.G\.\.T\>', '\<2\>') + call CHECK(1, "oops", '\<F\[1]\.\.G\[1]\.\.T\>', '\<2\>') exec "let exception = v:exception" exec "let throwpoint = v:throwpoint" - call CHECK(2, "oops", '\<F\.\.G\.\.T\>', '\<2\>') + call CHECK(2, "oops", '\<F\[1]\.\.G\[1]\.\.T\>', '\<2\>') CmdException CmdThrowpoint - call CHECK(3, "oops", '\<F\.\.G\.\.T\>', '\<2\>') + call CHECK(3, "oops", '\<F\[1]\.\.G\[1]\.\.T\>', '\<2\>') call FuncException() call FuncThrowpoint() - call CHECK(4, "oops", '\<F\.\.G\.\.T\>', '\<2\>') + call CHECK(4, "oops", '\<F\[1]\.\.G\[1]\.\.T\>', '\<2\>') exec "source" scriptException exec "source" scriptThrowPoint - call CHECK(5, "oops", '\<F\.\.G\.\.T\>', '\<2\>') + call CHECK(5, "oops", '\<F\[1]\.\.G\[1]\.\.T\>', '\<2\>') try Xpath 131072 " X: 131072 call G("arrgh", 4) @@ -5208,7 +5208,7 @@ catch /.*/ Xpath 262144 " X: 262144 let exception = v:exception let throwpoint = v:throwpoint - call CHECK(6, "arrgh", '\<G\.\.T\>', '\<4\>') + call CHECK(6, "arrgh", '\<G\[1]\.\.T\>', '\<4\>') try Xpath 524288 " X: 524288 let g:arg = "autsch" @@ -5226,7 +5226,7 @@ catch /.*/ Xpath 2097152 " X: 2097152 let exception = v:exception let throwpoint = v:throwpoint - call CHECK(8, "arrgh", '\<G\.\.T\>', '\<4\>') + call CHECK(8, "arrgh", '\<G\[1]\.\.T\>', '\<4\>') try Xpath 4194304 " X: 4194304 let g:arg = "brrrr" @@ -5242,27 +5242,27 @@ catch /.*/ Xpath 16777216 " X: 16777216 let exception = v:exception let throwpoint = v:throwpoint - call CHECK(10, "arrgh", '\<G\.\.T\>', '\<4\>') + call CHECK(10, "arrgh", '\<G\[1]\.\.T\>', '\<4\>') endtry Xpath 33554432 " X: 33554432 let exception = v:exception let throwpoint = v:throwpoint - call CHECK(11, "arrgh", '\<G\.\.T\>', '\<4\>') + call CHECK(11, "arrgh", '\<G\[1]\.\.T\>', '\<4\>') endtry Xpath 67108864 " X: 67108864 let exception = v:exception let throwpoint = v:throwpoint - call CHECK(12, "arrgh", '\<G\.\.T\>', '\<4\>') + call CHECK(12, "arrgh", '\<G\[1]\.\.T\>', '\<4\>') finally Xpath 134217728 " X: 134217728 let exception = v:exception let throwpoint = v:throwpoint - call CHECK(13, "oops", '\<F\.\.G\.\.T\>', '\<2\>') + call CHECK(13, "oops", '\<F\[1]\.\.G\[1]\.\.T\>', '\<2\>') endtry Xpath 268435456 " X: 268435456 let exception = v:exception let throwpoint = v:throwpoint - call CHECK(14, "oops", '\<F\.\.G\.\.T\>', '\<2\>') + call CHECK(14, "oops", '\<F\[1]\.\.G\[1]\.\.T\>', '\<2\>') finally Xpath 536870912 " X: 536870912 let exception = v:exception diff --git a/src/nvim/testdir/test55.in b/src/nvim/testdir/test55.in index 7b6f684caa..9e3c1168cc 100644 --- a/src/nvim/testdir/test55.in +++ b/src/nvim/testdir/test55.in @@ -442,6 +442,17 @@ let l = [0, 1, 2, 3] :unlockvar 1 b: :unlet! b:testvar :" +:$put ='No :let += of locked list variable:' +:let l = ['a', 'b', 3] +:lockvar 1 l +:try +: let l += ['x'] +: $put ='did :let +=' +:catch +: $put =v:exception[:14] +:endtry +:$put =string(l) +:" :unlet l :let l = [1, 2, 3, 4] :lockvar! l diff --git a/src/nvim/testdir/test55.ok b/src/nvim/testdir/test55.ok index 4e0303c26e..607a95ead9 100644 --- a/src/nvim/testdir/test55.ok +++ b/src/nvim/testdir/test55.ok @@ -144,6 +144,9 @@ No extend() of write-protected scope-level variable: Vim(put):E742: No :unlet of variable in locked scope: Vim(unlet):E741: +No :let += of locked list variable: +Vim(let):E741: +['a', 'b', 3] [1, 2, 3, 4] [1, 2, 3, 4] [1, 2, 3, 4] diff --git a/src/nvim/testdir/test_charsearch.in b/src/nvim/testdir/test_charsearch.in deleted file mode 100644 index 5085cb39bc..0000000000 --- a/src/nvim/testdir/test_charsearch.in +++ /dev/null @@ -1,25 +0,0 @@ -Test for character searches - -STARTTEST -:so small.vim -:" check that "fe" and ";" work -/^X -ylfep;;p,,p: -:" check that save/restore works -/^Y -ylfep:let csave = getcharsearch() -fip:call setcharsearch(csave) -;p;p: -:" check that setcharsearch() changes the settins. -/^Z -ylfep:call setcharsearch({'char': 'k'}) -;p:call setcharsearch({'forward': 0}) -$;p:call setcharseearch({'until'}: 1}) -;;p: -:/^X/,$w! test.out -:qa! -ENDTEST - -Xabcdefghijkemnopqretuvwxyz -Yabcdefghijkemnopqretuvwxyz -Zabcdefghijkemnokqretkvwxyz diff --git a/src/nvim/testdir/test_charsearch.ok b/src/nvim/testdir/test_charsearch.ok deleted file mode 100644 index a0c90e24f9..0000000000 --- a/src/nvim/testdir/test_charsearch.ok +++ /dev/null @@ -1,3 +0,0 @@ -XabcdeXfghijkeXmnopqreXtuvwxyz -YabcdeYfghiYjkeYmnopqreYtuvwxyz -ZabcdeZfghijkZemnokZqretkZvwxyz diff --git a/src/nvim/testdir/test_command_count.in b/src/nvim/testdir/test_command_count.in deleted file mode 100644 index 170c810923..0000000000 --- a/src/nvim/testdir/test_command_count.in +++ /dev/null @@ -1,158 +0,0 @@ -Test for user command counts vim: set ft=vim : - -STARTTEST -:so tiny.vim -:lang C -:let g:lines = [] -:com -range=% RangeLines :call add(g:lines, 'RangeLines '.<line1>.' '.<line2>) -:com -range -addr=arguments RangeArguments :call add(g:lines, 'RangeArguments '.<line1>.' '.<line2>) -:com -range=% -addr=arguments RangeArgumentsAll :call add(g:lines, 'RangeArgumentsAll '.<line1>.' '.<line2>) -:com -range -addr=loaded_buffers RangeLoadedBuffers :call add(g:lines, 'RangeLoadedBuffers '.<line1>.' '.<line2>) -:com -range=% -addr=loaded_buffers RangeLoadedBuffersAll :call add(g:lines, 'RangeLoadedBuffersAll '.<line1>.' '.<line2>) -:com -range -addr=buffers RangeBuffers :call add(g:lines, 'RangeBuffers '.<line1>.' '.<line2>) -:com -range=% -addr=buffers RangeBuffersAll :call add(g:lines, 'RangeBuffersAll '.<line1>.' '.<line2>) -:com -range -addr=windows RangeWindows :call add(g:lines, 'RangeWindows '.<line1>.' '.<line2>) -:com -range=% -addr=windows RangeWindowsAll :call add(g:lines, 'RangeWindowsAll '.<line1>.' '.<line2>) -:com -range -addr=tabs RangeTabs :call add(g:lines, 'RangeTabs '.<line1>.' '.<line2>) -:com -range=% -addr=tabs RangeTabsAll :call add(g:lines, 'RangeTabsAll '.<line1>.' '.<line2>) -:set hidden -:arga a b c d -:argdo echo "loading buffers" -:argu 3 -:.-,$-RangeArguments -:%RangeArguments -:RangeArgumentsAll -:N -:.RangeArguments -:split|split|split|split -:3wincmd w -:.,$RangeWindows -:%RangeWindows -:RangeWindowsAll -:only -:blast|bd -:.,$RangeLoadedBuffers -:%RangeLoadedBuffers -:RangeLoadedBuffersAll -:.,$RangeBuffers -:%RangeBuffers -:RangeBuffersAll -:tabe|tabe|tabe|tabe -:normal 2gt -:.,$RangeTabs -:%RangeTabs -:RangeTabsAll -:1tabonly -:s/\n/\r\r\r\r\r/ -:2ma< -:$-ma> -:'<,'>RangeLines -:com -range=% -buffer LocalRangeLines :call add(g:lines, 'LocalRangeLines '.<line1>.' '.<line2>) -:'<,'>LocalRangeLines -:b1 -ENDTEST - -STARTTEST -:call add(g:lines, '') -:%argd -:arga a b c d -:let v:errmsg = '' -:5argu -:call add(g:lines, '5argu ' . v:errmsg) -:$argu -:call add(g:lines, '4argu ' . expand('%:t')) -:let v:errmsg = '' -:1argu -:call add(g:lines, '1argu ' . expand('%:t')) -:let v:errmsg = '' -:100b -:call add(g:lines, '100b ' . v:errmsg) -:split|split|split|split -:let v:errmsg = '' -:0close -:call add(g:lines, '0close ' . v:errmsg) -:$wincmd w -:$close -:call add(g:lines, '$close ' . winnr()) -:let v:errmsg = '' -:$+close -:call add(g:lines, '$+close ' . v:errmsg) -:$tabe -:call add(g:lines, '$tabe ' . tabpagenr()) -:let v:errmsg = '' -:$+tabe -:call add(g:lines, '$+tabe ' . v:errmsg) -:only! -:e x -:0tabm -:normal 1gt -:call add(g:lines, '0tabm ' . expand('%:t')) -:tabonly! -:only! -:e! test.out -:call append(0, g:lines) -:unlet g:lines -:w|bd -:b1 -ENDTEST - -STARTTEST -:let g:lines = [] -:func BufStatus() -: call add(g:lines, 'aaa: ' . buflisted(g:buf_aaa) . ' bbb: ' . buflisted(g:buf_bbb) . ' ccc: ' . buflisted(g:buf_ccc)) -:endfunc -:se nohidden -:e aaa -:let buf_aaa = bufnr('%') -:e bbb -:let buf_bbb = bufnr('%') -:e ccc -:let buf_ccc = bufnr('%') -:b1 -:call BufStatus() -:exe buf_bbb . "," . buf_ccc . "bdelete" -:call BufStatus() -:exe buf_aaa . "bdelete" -:call BufStatus() -:e! test.out -:call append('$', g:lines) -:unlet g:lines -:delfunc BufStatus -:w|bd -:b1 -ENDTEST - -STARTTEST -:se hidden -:only! -:let g:lines = [] -:%argd -:arga a b c d e f -:3argu -:let args = '' -:.,$-argdo let args .= ' '.expand('%') -:call add(g:lines, 'argdo:' . args) -:split|split|split|split -:2wincmd w -:let windows = '' -:.,$-windo let windows .= ' '.winnr() -:call add(g:lines, 'windo:'. windows) -:b2 -:let buffers = '' -:.,$-bufdo let buffers .= ' '.bufnr('%') -:call add(g:lines, 'bufdo:' . buffers) -:3bd -:let buffers = '' -:3,7bufdo let buffers .= ' '.bufnr('%') -:call add(g:lines, 'bufdo:' . buffers) -:tabe|tabe|tabe|tabe -:normal! 2gt -:let tabpages = '' -:.,$-tabdo let tabpages .= ' '.tabpagenr() -:call add(g:lines, 'tabdo:' . tabpages) -:e! test.out -:call append('$', g:lines) -:w|qa! -ENDTEST - - diff --git a/src/nvim/testdir/test_command_count.ok b/src/nvim/testdir/test_command_count.ok deleted file mode 100644 index e74155ec1b..0000000000 --- a/src/nvim/testdir/test_command_count.ok +++ /dev/null @@ -1,38 +0,0 @@ -RangeArguments 2 4 -RangeArguments 1 5 -RangeArgumentsAll 1 5 -RangeArguments 2 2 -RangeWindows 3 5 -RangeWindows 1 5 -RangeWindowsAll 1 5 -RangeLoadedBuffers 2 4 -RangeLoadedBuffers 1 4 -RangeLoadedBuffersAll 1 4 -RangeBuffers 2 5 -RangeBuffers 1 5 -RangeBuffersAll 1 5 -RangeTabs 2 5 -RangeTabs 1 5 -RangeTabsAll 1 5 -RangeLines 2 5 -LocalRangeLines 2 5 - -5argu E16: Invalid range -4argu d -1argu a -100b E16: Invalid range -0close -$close 3 -$+close E16: Invalid range -$tabe 2 -$+tabe E16: Invalid range -0tabm x - -aaa: 1 bbb: 1 ccc: 1 -aaa: 1 bbb: 0 ccc: 0 -aaa: 0 bbb: 0 ccc: 0 -argdo: c d e -windo: 2 3 4 -bufdo: 2 3 4 5 6 7 8 9 10 15 -bufdo: 4 5 6 7 -tabdo: 2 3 4 diff --git a/src/nvim/testdir/test_listlbr.in b/src/nvim/testdir/test_listlbr.in index 57202b46eb..6084711786 100644 --- a/src/nvim/testdir/test_listlbr.in +++ b/src/nvim/testdir/test_listlbr.in @@ -24,20 +24,24 @@ STARTTEST : $put =g:line : wincmd p :endfu +:" :let g:test="Test 1: set linebreak" :redraw! :let line=ScreenChar(winwidth(0)) :call DoRecordScreen() +:" :let g:test="Test 2: set linebreak + set list" :set linebreak list listchars= :redraw! :let line=ScreenChar(winwidth(0)) :call DoRecordScreen() +:" :let g:test ="Test 3: set linebreak nolist" :set nolist linebreak :redraw! :let line=ScreenChar(winwidth(0)) :call DoRecordScreen() +:" :let g:test ="Test 4: set linebreak with tab and 1 line as long as screen: should break!" :set nolist linebreak ts=8 :let line="1\t".repeat('a', winwidth(0)-2) @@ -51,6 +55,7 @@ STARTTEST :$put =line :$ :norm! zt +:" :let g:test ="Test 5: set linebreak with conceal and set list and tab displayed by different char (line may not be truncated)" :set cpo&vim list linebreak conceallevel=2 concealcursor=nv listchars=tab:ab :syn match ConcealVar contained /_/ conceal @@ -58,6 +63,7 @@ STARTTEST :let line=ScreenChar(winwidth(0)) :call DoRecordScreen() :set cpo&vim linebreak +:" :let g:test ="Test 6: set linebreak with visual block mode" :let line="REMOVE: this not" :$put =g:test @@ -67,14 +73,47 @@ STARTTEST :1/^REMOVE: 0jf x:$put :set cpo&vim linebreak +:" :let g:test ="Test 7: set linebreak with visual block mode and v_b_A" :$put =g:test Golong line: 40afoobar aTARGET at end :exe "norm! $3B\<C-v>eAx\<Esc>" :set cpo&vim linebreak sbr= +:" :let g:test ="Test 8: set linebreak with visual char mode and changing block" :$put =g:test Go1111-1111-1111-11-1111-1111-11110f-lv3lc2222bgj. +:" +:let g:test ="Test 9: using redo after block visual mode" +:$put =g:test +Go +aaa +aaa +a2k2j~e. +:" +:let g:test ="Test 10: using normal commands after block-visual" +:$put =g:test +:set linebreak +Go +abcd{ef +ghijklm +no}pqrs2k0f{c% +:" +:let g:test ="Test 11: using block replace mode after wrapping" +:$put =g:test +:set linebreak wrap +Go150aayypk147|jr0 +:" +:let g:test ="Test 12: set linebreak list listchars=space:_,tab:>-,tail:-,eol:$" +:set list listchars=space:_,trail:-,tab:>-,eol:$ +:$put =g:test +:let line="a aaaaaaaaaaaaaaaaaaaaaa\ta " +:$put =line +:$ +:norm! zt +:redraw! +:let line=ScreenChar(winwidth(0)) +:call DoRecordScreen() :%w! test.out :qa! ENDTEST diff --git a/src/nvim/testdir/test_listlbr.ok b/src/nvim/testdir/test_listlbr.ok index 82881234c4..b32a54969e 100644 --- a/src/nvim/testdir/test_listlbr.ok +++ b/src/nvim/testdir/test_listlbr.ok @@ -41,3 +41,22 @@ Test 7: set linebreak with visual block mode and v_b_A long line: foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar TARGETx at end Test 8: set linebreak with visual char mode and changing block 1111-2222-1111-11-1111-2222-1111 +Test 9: using redo after block visual mode + +AaA +AaA +A +Test 10: using normal commands after block-visual + +abcdpqrs +Test 11: using block replace mode after wrapping +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa0aaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa0aaa +Test 12: set linebreak list listchars=space:_,tab:>-,tail:-,eol:$ +a aaaaaaaaaaaaaaaaaaaaaa a + +Test 12: set linebreak list listchars=space:_,tab:>-,tail:-,eol:$ +a_ +aaaaaaaaaaaaaaaaaaaa +aa>-----a-$ +~ diff --git a/src/nvim/undo.c b/src/nvim/undo.c index b8cdffcda0..4a8a24d79d 100644 --- a/src/nvim/undo.c +++ b/src/nvim/undo.c @@ -4,29 +4,29 @@ * The saved lines are stored in a list of lists (one for each buffer): * * b_u_oldhead------------------------------------------------+ - * | - * V - * +--------------+ +--------------+ +--------------+ - * b_u_newhead--->| u_header | | u_header | | u_header | - * | uh_next------>| uh_next------>| uh_next---->NULL - * NULL<--------uh_prev |<---------uh_prev |<---------uh_prev | - * | uh_entry | | uh_entry | | uh_entry | - * +--------|-----+ +--------|-----+ +--------|-----+ - * | | | - * V V V - * +--------------+ +--------------+ +--------------+ - * | u_entry | | u_entry | | u_entry | - * | ue_next | | ue_next | | ue_next | - * +--------|-----+ +--------|-----+ +--------|-----+ - * | | | - * V V V - * +--------------+ NULL NULL - * | u_entry | - * | ue_next | - * +--------|-----+ - * | - * V - * etc. + * | + * V + * +--------------+ +--------------+ +--------------+ + * b_u_newhead--->| u_header | | u_header | | u_header | + * | uh_next------>| uh_next------>| uh_next---->NULL + * NULL<--------uh_prev |<---------uh_prev |<---------uh_prev | + * | uh_entry | | uh_entry | | uh_entry | + * +--------|-----+ +--------|-----+ +--------|-----+ + * | | | + * V V V + * +--------------+ +--------------+ +--------------+ + * | u_entry | | u_entry | | u_entry | + * | ue_next | | ue_next | | ue_next | + * +--------|-----+ +--------|-----+ +--------|-----+ + * | | | + * V V V + * +--------------+ NULL NULL + * | u_entry | + * | ue_next | + * +--------|-----+ + * | + * V + * etc. * * Each u_entry list contains the information for one undo or redo. * curbuf->b_u_curhead points to the header of the last undo (the next redo), @@ -37,30 +37,30 @@ * uh_seq field is numbered sequentially to be able to find a newer or older * branch. * - * +---------------+ +---------------+ - * b_u_oldhead --->| u_header | | u_header | - * | uh_alt_next ---->| uh_alt_next ----> NULL - * NULL <----- uh_alt_prev |<------ uh_alt_prev | - * | uh_prev | | uh_prev | - * +-----|---------+ +-----|---------+ - * | | - * V V - * +---------------+ +---------------+ - * | u_header | | u_header | - * | uh_alt_next | | uh_alt_next | - * b_u_newhead --->| uh_alt_prev | | uh_alt_prev | - * | uh_prev | | uh_prev | - * +-----|---------+ +-----|---------+ - * | | - * V V - * NULL +---------------+ +---------------+ - * | u_header | | u_header | - * | uh_alt_next ---->| uh_alt_next | - * | uh_alt_prev |<------ uh_alt_prev | - * | uh_prev | | uh_prev | - * +-----|---------+ +-----|---------+ - * | | - * etc. etc. + * +---------------+ +---------------+ + * b_u_oldhead --->| u_header | | u_header | + * | uh_alt_next ---->| uh_alt_next ----> NULL + * NULL <----- uh_alt_prev |<------ uh_alt_prev | + * | uh_prev | | uh_prev | + * +-----|---------+ +-----|---------+ + * | | + * V V + * +---------------+ +---------------+ + * | u_header | | u_header | + * | uh_alt_next | | uh_alt_next | + * b_u_newhead --->| uh_alt_prev | | uh_alt_prev | + * | uh_prev | | uh_prev | + * +-----|---------+ +-----|---------+ + * | | + * V V + * NULL +---------------+ +---------------+ + * | u_header | | u_header | + * | uh_alt_next ---->| uh_alt_next | + * | uh_alt_prev |<------ uh_alt_prev | + * | uh_prev | | uh_prev | + * +-----|---------+ +-----|---------+ + * | | + * etc. etc. * * * All data is allocated and will all be freed when the buffer is unloaded. diff --git a/src/nvim/version.c b/src/nvim/version.c index 33211cdf14..3acecf2b40 100644 --- a/src/nvim/version.c +++ b/src/nvim/version.c @@ -69,6 +69,8 @@ static char *features[] = { // clang-format off static int included_patches[] = { + 1366, + // 1219 NA // 1218 NA // 1217 NA @@ -176,7 +178,7 @@ static int included_patches[] = { // 1115 NA // 1114, // 1113, - // 1112, + 1112, // 1111, // 1110, // 1109 NA @@ -247,7 +249,7 @@ static int included_patches[] = { // 1044 NA, // 1043 NA, // 1042, - // 1041, + 1041, // 1040 NA, // 1039, // 1038 NA, @@ -295,7 +297,7 @@ static int included_patches[] = { // 996 NA // 995 NA // 994 NA - // 993, + // 993 NA // 992 NA 991, // 990 NA @@ -311,15 +313,15 @@ static int included_patches[] = { 980, // 979 NA 978, - // 977, + 977, // 976 NA 975, - // 974, + 974, // 973, 972, // 971 NA // 970 NA - // 969, + // 969 NA // 968 NA // 967 NA // 966 NA @@ -332,7 +334,7 @@ static int included_patches[] = { // 959 NA // 958, // 957, - // 956, + // 956 NA 955, // 954 NA 953, @@ -341,162 +343,162 @@ static int included_patches[] = { 950, 949, // 948 NA - // 947, + // 947 NA 946, 945, 944, - // 943, + // 943 NA // 942, // 941, // 940 NA - // 939, + 939, // 938 NA - // 937, - // 936, - // 935, + 937, + 936, + // 935 NA // 934 NA - // 933, - // 932, - // 931, + 933, + 932, + // 931 NA // 930 NA - // 929, + 929, // 928 NA // 927 NA - // 926, + 926, // 925, // 924 NA // 923 NA - // 922, + 922, // 921 NA // 920 NA // 919 NA // 918 NA // 917 NA 916, - // 915, - // 914, + 915, + // 914 NA // 913 NA - // 912, + 912, // 911 NA // 910 NA - // 909, + // 909 NA // 908 NA // 907 NA // 906 NA - // 905, - // 904, - // 903, + // 905 NA + // 904 NA + 903, // 902 NA - // 901, + 901, // 900 NA // 899 NA 898, - // 897, + // 897 NA // 896, - // 895, + 895, // 894 NA - // 893, - // 892, - // 891, + 893, + // 892 NA + 891, // 890 NA // 889, - // 888, - // 887, + 888, + 887, // 886 NA - // 885, + 885, // 884 NA - // 883, + 883, // 882, - // 881, + 881, // 880 NA - // 879, - // 878, - // 877, + 879, + 878, + 877, // 876 NA // 875 NA // 874 NA - // 873, + // 873 NA // 872 NA // 871, - // 870, + 870, // 869 NA - // 868, + 868, // 867 NA - // 866, - // 865, + // 866 NA + // 865 NA // 864 NA // 863 NA // 862 NA // 861 NA - // 860, - // 859, + // 860 NA + 859, 858, // 857, - // 856, + 856, // 855 NA // 854 NA - // 853, + 853, // 852 NA // 851 NA // 850 NA 849, 848, - // 847, + 847, // 846 NA - // 845, - // 844, - // 843, + 845, + 844, + 843, // 842 NA // 841 NA // 840 NA - // 839, - // 838, + // 839 NA + // 838 NA // 837 NA 836, - // 835, - // 834, - // 833, - // 832, - // 831, - // 830, + 835, + 834, + 833, + 832, + 831, + 830, // 829 NA - // 828, - // 827, + 828, + // 827 NA 826, - // 825, + 825, // 824 NA 823, // 822, - // 821, - // 820, + // 821 NA + 820, // 819, - // 818, - // 817, - // 816, - // 815, - // 814, + 818, + 817, + 816, + 815, + 814, 813, - // 812, - // 811, - // 810, + // 812 NA + 811, + 810, 809, // 808 NA 807, 806, - // 805, - // 804, + 805, + // 804 NA 803, 802, - // 801, - // 800, + 801, + 800, 799, - // 798, + 798, // 797, // 796 NA 795, // 794 NA 793, - // 792, + 792, 791, 790, 789, @@ -517,53 +519,53 @@ static int included_patches[] = { 774, 773, // 772 NA - // 771, + 771, // 770 NA - // 769, - // 768, - // 767, + 769, + 768, + // 767 NA // 766 NA 765, 764, // 763 NA // 762 NA // 761 NA - // 760, + 760, // 759 NA - // 758, + 758, // 757 NA // 756 NA - // 755, + 755, 754, 753, - // 752, + // 752 NA // 751 NA // 750 NA - // 749, + 749, 748, 747, 746, 745, // 744 NA - // 743, - // 742, + 743, + 742, 741, - // 740, + 740, 739, // 738 NA - // 737, + 737, 736, - // 735, - // 734, + // 735 NA + 734, // 733, - // 732, + 732, // 731 NA // 730 NA 729, // 728 NA // 727 NA // 726 NA - // 725, + // 725 NA // 724 NA 723, 722, @@ -571,7 +573,7 @@ static int included_patches[] = { // 720 NA 719, 718, - // 717, + 717, 716, 715, 714, @@ -580,7 +582,7 @@ static int included_patches[] = { 711, 710, 709, - // 708, + 708, 707, 706, // 705 NA @@ -588,23 +590,23 @@ static int included_patches[] = { // 703 NA 702, // 701 NA - // 700, + 700, 699, 698, 697, 696, 695, - // 694, - // 693, + 694, + 693, // 692 NA // 691 NA 690, - // 689, - // 688, + 689, + 688, // 687 NA 686, 685, - // 684, + // 684 NA // 683 NA 682, // 681 NA @@ -626,7 +628,7 @@ static int included_patches[] = { 665, // 664 NA // 663 NA - // 662, + 662, // 661 NA 660, 659, @@ -645,7 +647,7 @@ static int included_patches[] = { 646, 645, // 644 NA - // 643, + 643, 642, // 641 NA 640, diff --git a/src/nvim/vim.h b/src/nvim/vim.h index 5f9785a9a9..545b903d2f 100644 --- a/src/nvim/vim.h +++ b/src/nvim/vim.h @@ -27,12 +27,6 @@ Error: configure did not run properly.Check auto/config.log. # endif #endif - -/* Can't use "PACKAGE" here, conflicts with a Perl include file. */ -#ifndef VIMPACKAGE -# define VIMPACKAGE "vim" -#endif - #include "nvim/os/os_defs.h" /* bring lots of system header files */ /// length of a buffer to store a number in ASCII (64 bits binary + NUL) diff --git a/src/nvim/window.c b/src/nvim/window.c index e84d8df36b..39106a7b8d 100644 --- a/src/nvim/window.c +++ b/src/nvim/window.c @@ -4575,10 +4575,19 @@ void win_drag_vsep_line(win_T *dragwin, int offset) } assert(fr); - if (room < offset) /* Not enough room */ - offset = room; /* Move as far as we can */ - if (offset <= 0) /* No room at all, quit. */ + // Not enough room + if (room < offset) { + offset = room; // Move as far as we can + } + + // No room at all, quit. + if (offset <= 0) { return; + } + + if (fr == NULL) { + return; // Safety check, should not happen. + } /* grow frame fr by offset lines */ frame_new_width(fr, fr->fr_width + offset, left, FALSE); @@ -5342,14 +5351,14 @@ void restore_buffer(buf_T *save_curbuf) } -/* - * Add match to the match list of window 'wp'. The pattern 'pat' will be - * highlighted with the group 'grp' with priority 'prio'. - * Optionally, a desired ID 'id' can be specified (greater than or equal to 1). - * If no particular ID is desired, -1 must be specified for 'id'. - * Return ID of added match, -1 on failure. - */ -int match_add(win_T *wp, char_u *grp, char_u *pat, int prio, int id, list_T *pos_list) +// Add match to the match list of window 'wp'. The pattern 'pat' will be +// highlighted with the group 'grp' with priority 'prio'. +// Optionally, a desired ID 'id' can be specified (greater than or equal to 1). +// If no particular ID is desired, -1 must be specified for 'id'. +// Return ID of added match, -1 on failure. +int match_add(win_T *wp, char_u *grp, char_u *pat, + int prio, int id, list_T *pos_list, + char_u *conceal_char) { matchitem_T *cur; matchitem_T *prev; @@ -5405,6 +5414,10 @@ int match_add(win_T *wp, char_u *grp, char_u *pat, int prio, int id, list_T *pos m->match.regprog = regprog; m->match.rmm_ic = FALSE; m->match.rmm_maxcol = 0; + m->conceal_char = 0; + if (conceal_char != NULL) { + m->conceal_char = (*mb_ptr2char)(conceal_char); + } // Set up position matches if (pos_list != NULL) |