diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/nvim/api/buffer.c | 87 | ||||
-rw-r--r-- | src/nvim/api/deprecated.c | 82 | ||||
-rw-r--r-- | src/nvim/api/private/helpers.c | 36 | ||||
-rw-r--r-- | src/nvim/decoration.c | 26 | ||||
-rw-r--r-- | src/nvim/decoration.h | 13 | ||||
-rw-r--r-- | src/nvim/eval.lua | 1 | ||||
-rw-r--r-- | src/nvim/eval/funcs.c | 41 | ||||
-rw-r--r-- | src/nvim/ex_session.c | 37 | ||||
-rw-r--r-- | src/nvim/extmark.c | 2 | ||||
-rw-r--r-- | src/nvim/globals.h | 2 | ||||
-rw-r--r-- | src/nvim/main.c | 5 | ||||
-rw-r--r-- | src/nvim/normal.c | 2 | ||||
-rw-r--r-- | src/nvim/screen.c | 128 | ||||
-rw-r--r-- | src/nvim/state.c | 3 | ||||
-rw-r--r-- | src/nvim/syntax.c | 96 | ||||
-rw-r--r-- | src/nvim/testdir/test_functions.vim | 19 | ||||
-rw-r--r-- | src/nvim/testdir/test_mksession.vim | 23 |
17 files changed, 353 insertions, 250 deletions
diff --git a/src/nvim/api/buffer.c b/src/nvim/api/buffer.c index 78e36e5ef0..77cff0cb4f 100644 --- a/src/nvim/api/buffer.c +++ b/src/nvim/api/buffer.c @@ -1433,8 +1433,14 @@ Array nvim_buf_get_extmarks(Buffer buffer, Integer ns_id, /// - hl_group : name of the highlight group used to highlight /// this mark. /// - virt_text : virtual text to link to this mark. -/// - virt_text_pos : positioning of virtual text. Possible -/// values: +/// A list of [text, highlight] tuples, each representing a +/// text chunk with specified highlight. `highlight` element +/// can either be a a single highlight group, or an array of +/// multiple highlight groups that will be stacked +/// (highest priority last). A highlight group can be supplied +/// either as a string or as an integer, the latter which +/// can be obtained using |nvim_get_hl_id_by_name|. +/// - virt_text_pos : position of virtual text. Possible values: /// - "eol": right after eol character (default) /// - "overlay": display over the specified column, without /// shifting the underlying text. @@ -1560,7 +1566,8 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, "virt_text is not an Array"); goto error; } - decor.virt_text = parse_virt_text(v->data.array, err); + decor.virt_text = parse_virt_text(v->data.array, err, + &decor.virt_text_width); if (ERROR_SET(err)) { goto error; } @@ -1892,80 +1899,6 @@ void nvim_buf_clear_namespace(Buffer buffer, (int)line_end-1, MAXCOL); } -/// Set the virtual text (annotation) for a buffer line. -/// -/// By default (and currently the only option) the text will be placed after -/// the buffer text. Virtual text will never cause reflow, rather virtual -/// text will be truncated at the end of the screen line. The virtual text will -/// begin one cell (|lcs-eol| or space) after the ordinary text. -/// -/// Namespaces are used to support batch deletion/updating of virtual text. -/// To create a namespace, use |nvim_create_namespace()|. Virtual text is -/// cleared using |nvim_buf_clear_namespace()|. The same `ns_id` can be used for -/// both virtual text and highlights added by |nvim_buf_add_highlight()|, both -/// can then be cleared with a single call to |nvim_buf_clear_namespace()|. If -/// the virtual text never will be cleared by an API call, pass `ns_id = -1`. -/// -/// As a shorthand, `ns_id = 0` can be used to create a new namespace for the -/// virtual text, the allocated id is then returned. -/// -/// @param buffer Buffer handle, or 0 for current buffer -/// @param ns_id Namespace to use or 0 to create a namespace, -/// or -1 for a ungrouped annotation -/// @param line Line to annotate with virtual text (zero-indexed) -/// @param chunks A list of [text, hl_group] arrays, each representing a -/// text chunk with specified highlight. `hl_group` element -/// can be omitted for no highlight. -/// @param opts Optional parameters. Currently not used. -/// @param[out] err Error details, if any -/// @return The ns_id that was used -Integer nvim_buf_set_virtual_text(Buffer buffer, - Integer src_id, - Integer line, - Array chunks, - Dictionary opts, - Error *err) - FUNC_API_SINCE(5) -{ - buf_T *buf = find_buffer_by_handle(buffer, err); - if (!buf) { - return 0; - } - - if (line < 0 || line >= MAXLNUM) { - api_set_error(err, kErrorTypeValidation, "Line number outside range"); - return 0; - } - - if (opts.size > 0) { - api_set_error(err, kErrorTypeValidation, "opts dict isn't empty"); - return 0; - } - - uint64_t ns_id = src2ns(&src_id); - - VirtText virt_text = parse_virt_text(chunks, err); - if (ERROR_SET(err)) { - return 0; - } - - - VirtText *existing = decor_find_virttext(buf, (int)line, ns_id); - - if (existing) { - clear_virttext(existing); - *existing = virt_text; - return src_id; - } - - Decoration *decor = xcalloc(1, sizeof(*decor)); - decor->virt_text = virt_text; - - extmark_set(buf, ns_id, 0, (int)line, 0, -1, -1, decor, true, - false, kExtmarkNoUndo); - return src_id; -} - /// call a function with buffer as temporary current buffer /// /// This temporarily switches current buffer to "buffer". diff --git a/src/nvim/api/deprecated.c b/src/nvim/api/deprecated.c index 3989386bb9..554966e266 100644 --- a/src/nvim/api/deprecated.c +++ b/src/nvim/api/deprecated.c @@ -12,6 +12,7 @@ #include "nvim/api/private/helpers.h" #include "nvim/api/private/defs.h" #include "nvim/lua/executor.h" +#include "nvim/extmark.h" #ifdef INCLUDE_GENERATED_DECLARATIONS # include "api/deprecated.c.generated.h" @@ -80,6 +81,87 @@ void nvim_buf_clear_highlight(Buffer buffer, } +/// Set the virtual text (annotation) for a buffer line. +/// +/// @deprecated use nvim_buf_set_extmark to use full virtual text +/// functionality. +/// +/// The text will be placed after the buffer text. Virtual text will never +/// cause reflow, rather virtual text will be truncated at the end of the screen +/// line. The virtual text will begin one cell (|lcs-eol| or space) after the +/// ordinary text. +/// +/// Namespaces are used to support batch deletion/updating of virtual text. +/// To create a namespace, use |nvim_create_namespace()|. Virtual text is +/// cleared using |nvim_buf_clear_namespace()|. The same `ns_id` can be used for +/// both virtual text and highlights added by |nvim_buf_add_highlight()|, both +/// can then be cleared with a single call to |nvim_buf_clear_namespace()|. If +/// the virtual text never will be cleared by an API call, pass `ns_id = -1`. +/// +/// As a shorthand, `ns_id = 0` can be used to create a new namespace for the +/// virtual text, the allocated id is then returned. +/// +/// @param buffer Buffer handle, or 0 for current buffer +/// @param ns_id Namespace to use or 0 to create a namespace, +/// or -1 for a ungrouped annotation +/// @param line Line to annotate with virtual text (zero-indexed) +/// @param chunks A list of [text, hl_group] arrays, each representing a +/// text chunk with specified highlight. `hl_group` element +/// can be omitted for no highlight. +/// @param opts Optional parameters. Currently not used. +/// @param[out] err Error details, if any +/// @return The ns_id that was used +Integer nvim_buf_set_virtual_text(Buffer buffer, + Integer src_id, + Integer line, + Array chunks, + Dictionary opts, + Error *err) + FUNC_API_SINCE(5) + FUNC_API_DEPRECATED_SINCE(8) +{ + buf_T *buf = find_buffer_by_handle(buffer, err); + if (!buf) { + return 0; + } + + if (line < 0 || line >= MAXLNUM) { + api_set_error(err, kErrorTypeValidation, "Line number outside range"); + return 0; + } + + if (opts.size > 0) { + api_set_error(err, kErrorTypeValidation, "opts dict isn't empty"); + return 0; + } + + uint64_t ns_id = src2ns(&src_id); + int width; + + VirtText virt_text = parse_virt_text(chunks, err, &width); + if (ERROR_SET(err)) { + return 0; + } + + + Decoration *existing = decor_find_virttext(buf, (int)line, ns_id); + + if (existing) { + clear_virttext(&existing->virt_text); + existing->virt_text = virt_text; + existing->virt_text_width = width; + return src_id; + } + + Decoration *decor = xcalloc(1, sizeof(*decor)); + decor->virt_text = virt_text; + decor->virt_text_width = width; + + extmark_set(buf, ns_id, 0, (int)line, 0, -1, -1, decor, true, + false, kExtmarkNoUndo); + return src_id; +} + /// Inserts a sequence of lines to a buffer at a certain index /// /// @deprecated use nvim_buf_set_lines(buffer, lnum, lnum, true, lines) diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c index 9f2e94f31e..3ec6151090 100644 --- a/src/nvim/api/private/helpers.c +++ b/src/nvim/api/private/helpers.c @@ -1592,9 +1592,10 @@ bool extmark_get_index_from_obj(buf_T *buf, Integer ns_id, Object obj, int } } -VirtText parse_virt_text(Array chunks, Error *err) +VirtText parse_virt_text(Array chunks, Error *err, int *width) { VirtText virt_text = KV_INITIAL_VALUE; + int w = 0; for (size_t i = 0; i < chunks.size; i++) { if (chunks.items[i].type != kObjectTypeArray) { api_set_error(err, kErrorTypeValidation, "Chunk is not an array"); @@ -1602,26 +1603,44 @@ VirtText parse_virt_text(Array chunks, Error *err) } Array chunk = chunks.items[i].data.array; if (chunk.size == 0 || chunk.size > 2 - || chunk.items[0].type != kObjectTypeString - || (chunk.size == 2 && chunk.items[1].type != kObjectTypeString)) { + || chunk.items[0].type != kObjectTypeString) { api_set_error(err, kErrorTypeValidation, "Chunk is not an array with one or two strings"); goto free_exit; } String str = chunk.items[0].data.string; - char *text = transstr(str.size > 0 ? str.data : ""); // allocates int hl_id = 0; if (chunk.size == 2) { - String hl = chunk.items[1].data.string; - if (hl.size > 0) { - hl_id = syn_check_group((char_u *)hl.data, (int)hl.size); + Object hl = chunk.items[1]; + if (hl.type == kObjectTypeArray) { + Array arr = hl.data.array; + for (size_t j = 0; j < arr.size; j++) { + hl_id = object_to_hl_id(arr.items[j], "virt_text highlight", err); + if (ERROR_SET(err)) { + goto free_exit; + } + if (j < arr.size-1) { + kv_push(virt_text, ((VirtTextChunk){ .text = NULL, + .hl_id = hl_id })); + } + } + } else { + hl_id = object_to_hl_id(hl, "virt_text highlight", err); + if (ERROR_SET(err)) { + goto free_exit; + } } } + + char *text = transstr(str.size > 0 ? str.data : ""); // allocates + w += (int)mb_string2cells((char_u *)text); + kv_push(virt_text, ((VirtTextChunk){ .text = text, .hl_id = hl_id })); } + *width = w; return virt_text; free_exit: @@ -1656,7 +1675,7 @@ int object_to_hl_id(Object obj, const char *what, Error *err) String str = obj.data.string; return str.size ? syn_check_group((char_u *)str.data, (int)str.size) : 0; } else if (obj.type == kObjectTypeInteger) { - return (int)obj.data.integer; + return MAX((int)obj.data.integer, 0); } else { api_set_error(err, kErrorTypeValidation, "%s is not a valid highlight", what); @@ -1687,6 +1706,7 @@ HlMessage parse_hl_msg(Array chunks, Error *err) if (chunk.size == 2) { String hl = chunk.items[1].data.string; if (hl.size > 0) { + // TODO(bfredl): use object_to_hl_id and allow integer int hl_id = syn_check_group((char_u *)hl.data, (int)hl.size); attr = hl_id > 0 ? syn_id2attr(hl_id) : 0; } diff --git a/src/nvim/decoration.c b/src/nvim/decoration.c index 9d969ada89..74cb9a26b7 100644 --- a/src/nvim/decoration.c +++ b/src/nvim/decoration.c @@ -119,7 +119,7 @@ void clear_virttext(VirtText *text) *text = (VirtText)KV_INITIAL_VALUE; } -VirtText *decor_find_virttext(buf_T *buf, int row, uint64_t ns_id) +Decoration *decor_find_virttext(buf_T *buf, int row, uint64_t ns_id) { MarkTreeIter itr[1] = { 0 }; marktree_itr_get(buf->b_marktree, row, 0, itr); @@ -132,7 +132,7 @@ VirtText *decor_find_virttext(buf_T *buf, int row, uint64_t ns_id) mark.id, false); if (item && (ns_id == 0 || ns_id == item->ns_id) && item->decor && kv_size(item->decor->virt_text)) { - return &item->decor->virt_text; + return item->decor; } marktree_itr_next(buf->b_marktree, itr); } @@ -218,6 +218,7 @@ bool decor_redraw_line(buf_T *buf, int row, DecorState *state) } state->row = row; state->col_until = -1; + state->eol_col = -1; return true; // TODO(bfredl): be more precise } @@ -230,10 +231,6 @@ static void decor_add(DecorState *state, int start_row, int start_col, *decor, attr_id, kv_size(decor->virt_text) && owned, -1 }; - if (decor->virt_text_pos == kVTEndOfLine) { - range.win_col = -2; // handled separately - } - kv_pushp(state->active); size_t index; for (index = kv_size(state->active)-1; index > 0; index--) { @@ -345,29 +342,22 @@ void decor_redraw_end(DecorState *state) state->buf = NULL; } -VirtText decor_redraw_eol(buf_T *buf, DecorState *state, int *eol_attr, - bool *aligned) +bool decor_redraw_eol(buf_T *buf, DecorState *state, int *eol_attr, int eol_col) { decor_redraw_col(buf, MAXCOL, MAXCOL, false, state); - VirtText text = VIRTTEXT_EMPTY; + state->eol_col = eol_col; + bool has_virttext = false; for (size_t i = 0; i < kv_size(state->active); i++) { DecorRange item = kv_A(state->active, i); if (item.start_row == state->row && kv_size(item.decor.virt_text)) { - if (!kv_size(text) && item.decor.virt_text_pos == kVTEndOfLine) { - text = item.decor.virt_text; - } else if (item.decor.virt_text_pos == kVTRightAlign - || item.decor.virt_text_pos == kVTWinCol) { - *aligned = true; - } + has_virttext = true; } - if (item.decor.hl_eol && item.start_row <= state->row) { *eol_attr = hl_combine_attr(*eol_attr, item.attr_id); } } - - return text; + return has_virttext; } void decor_add_ephemeral(int start_row, int start_col, int end_row, int end_col, diff --git a/src/nvim/decoration.h b/src/nvim/decoration.h index 4cebc0b731..28dabeeada 100644 --- a/src/nvim/decoration.h +++ b/src/nvim/decoration.h @@ -34,19 +34,20 @@ typedef enum { struct Decoration { - int hl_id; // highlight group VirtText virt_text; + int hl_id; // highlight group VirtTextPos virt_text_pos; - bool virt_text_hide; HlMode hl_mode; + bool virt_text_hide; bool hl_eol; + bool shared; // shared decoration, don't free // TODO(bfredl): style, signs, etc DecorPriority priority; - bool shared; // shared decoration, don't free int col; // fixed col value, like win_col + int virt_text_width; // width of virt_text }; -#define DECORATION_INIT { 0, KV_INITIAL_VALUE, kVTEndOfLine, false, \ - kHlModeUnknown, false, DECOR_PRIORITY_BASE, false, 0 } +#define DECORATION_INIT { KV_INITIAL_VALUE, 0, kVTEndOfLine, kHlModeUnknown, \ + false, false, false, DECOR_PRIORITY_BASE, 0, 0 } typedef struct { int start_row; @@ -67,6 +68,8 @@ typedef struct { int row; int col_until; int current; + + int eol_col; VirtText *virt_text; } DecorState; diff --git a/src/nvim/eval.lua b/src/nvim/eval.lua index 33c6fae5cf..eb20cd1bc8 100644 --- a/src/nvim/eval.lua +++ b/src/nvim/eval.lua @@ -136,6 +136,7 @@ return { getchar={args={0, 1}}, getcharmod={}, getcharsearch={}, + getcharstr={args={0, 1}}, getcmdline={}, getcmdpos={}, getcmdtype={}, diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 3d7a440856..f4735b3751 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -3028,10 +3028,9 @@ static void f_getchangelist(typval_T *argvars, typval_T *rettv, FunPtr fptr) } } -/* - * "getchar()" function - */ -static void f_getchar(typval_T *argvars, typval_T *rettv, FunPtr fptr) +// "getchar()" and "getcharstr()" functions +static void getchar_common(typval_T *argvars, typval_T *rettv) + FUNC_ATTR_NONNULL_ALL { varnumber_T n; bool error = false; @@ -3098,6 +3097,7 @@ static void f_getchar(typval_T *argvars, typval_T *rettv, FunPtr fptr) } else { i += utf_char2bytes(n, temp + i); } + assert(i < 10); temp[i++] = NUL; rettv->v_type = VAR_STRING; rettv->vval.v_string = vim_strsave(temp); @@ -3106,15 +3106,14 @@ static void f_getchar(typval_T *argvars, typval_T *rettv, FunPtr fptr) int row = mouse_row; int col = mouse_col; int grid = mouse_grid; - win_T *win; linenr_T lnum; win_T *wp; int winnr = 1; if (row >= 0 && col >= 0) { - /* Find the window at the mouse coordinates and compute the - * text position. */ - win = mouse_find_win(&grid, &row, &col); + // Find the window at the mouse coordinates and compute the + // text position. + win_T *const win = mouse_find_win(&grid, &row, &col); if (win == NULL) { return; } @@ -3130,6 +3129,32 @@ static void f_getchar(typval_T *argvars, typval_T *rettv, FunPtr fptr) } } +// "getchar()" function +static void f_getchar(typval_T *argvars, typval_T *rettv, FunPtr fptr) +{ + getchar_common(argvars, rettv); +} + +// "getcharstr()" function +static void f_getcharstr(typval_T *argvars, typval_T *rettv, FunPtr fptr) +{ + getchar_common(argvars, rettv); + + if (rettv->v_type == VAR_NUMBER) { + char_u temp[7]; // mbyte-char: 6, NUL: 1 + const varnumber_T n = rettv->vval.v_number; + int i = 0; + + if (n != 0) { + i += utf_char2bytes(n, temp); + } + assert(i < 7); + temp[i++] = NUL; + rettv->v_type = VAR_STRING; + rettv->vval.v_string = vim_strsave(temp); + } +} + /* * "getcharmod()" function */ diff --git a/src/nvim/ex_session.c b/src/nvim/ex_session.c index 67b8e7e92f..3038ed3947 100644 --- a/src/nvim/ex_session.c +++ b/src/nvim/ex_session.c @@ -583,22 +583,6 @@ static int makeopens(FILE *fd, char_u *dirnow) return FAIL; } - // Now put the other buffers into the buffer list. - FOR_ALL_BUFFERS(buf) { - if (!(only_save_windows && buf->b_nwindows == 0) - && !(buf->b_help && !(ssop_flags & SSOP_HELP)) - && buf->b_fname != NULL - && buf->b_p_bl) { - if (fprintf(fd, "badd +%" PRId64 " ", - buf->b_wininfo == NULL - ? (int64_t)1L - : (int64_t)buf->b_wininfo->wi_fpos.lnum) < 0 - || ses_fname(fd, buf, &ssop_flags, true) == FAIL) { - return FAIL; - } - } - } - // the global argument list if (ses_arglist(fd, "argglobal", &global_alist.al_ga, !(ssop_flags & SSOP_CURDIR), &ssop_flags) == FAIL) { @@ -813,12 +797,31 @@ static int makeopens(FILE *fd, char_u *dirnow) return FAIL; } + // Now put the remaining buffers into the buffer list. + // This is near the end, so that when 'hidden' is set we don't create extra + // buffers. If the buffer was already created with another command the + // ":badd" will have no effect. + FOR_ALL_BUFFERS(buf) { + if (!(only_save_windows && buf->b_nwindows == 0) + && !(buf->b_help && !(ssop_flags & SSOP_HELP)) + && buf->b_fname != NULL + && buf->b_p_bl) { + if (fprintf(fd, "badd +%" PRId64 " ", + buf->b_wininfo == NULL + ? (int64_t)1L + : (int64_t)buf->b_wininfo->wi_fpos.lnum) < 0 + || ses_fname(fd, buf, &ssop_flags, true) == FAIL) { + return FAIL; + } + } + } + // // Wipe out an empty unnamed buffer we started in. // if (fprintf(fd, "%s", "if exists('s:wipebuf') " - "&& len(win_findbuf(s:wipebuf)) == 0" + "&& len(win_findbuf(s:wipebuf)) == 0 " "&& getbufvar(s:wipebuf, '&buftype') isnot# 'terminal'\n" " silent exe 'bwipe ' . s:wipebuf\n" "endif\n" diff --git a/src/nvim/extmark.c b/src/nvim/extmark.c index 60b7b024f1..4b2dccd8a4 100644 --- a/src/nvim/extmark.c +++ b/src/nvim/extmark.c @@ -268,7 +268,7 @@ bool extmark_clear(buf_T *buf, uint64_t ns_id, } ExtmarkNs *my_ns = all_ns ? buf_ns_ref(buf, item.ns_id, false) : ns; map_del(uint64_t, uint64_t)(my_ns->map, item.mark_id); - map_del(uint64_t, ExtmarkItem)(buf->b_extmark_index, mark.id); + map_del(uint64_t, ExtmarkItem)(buf->b_extmark_index, start_id); marktree_del_itr(buf->b_marktree, itr, false); } else { marktree_itr_next(buf->b_marktree, itr); diff --git a/src/nvim/globals.h b/src/nvim/globals.h index 13370ff47e..4012cc5897 100644 --- a/src/nvim/globals.h +++ b/src/nvim/globals.h @@ -524,6 +524,8 @@ EXTERN pos_T VIsual; EXTERN int VIsual_active INIT(= false); /// Whether Select mode is active. EXTERN int VIsual_select INIT(= false); +/// Restart Select mode when next cmd finished +EXTERN int restart_VIsual_select INIT(= 0); /// Whether to restart the selection after a Select-mode mapping or menu. EXTERN int VIsual_reselect; /// Type of Visual mode. diff --git a/src/nvim/main.c b/src/nvim/main.c index 25593134fd..252aa81825 100644 --- a/src/nvim/main.c +++ b/src/nvim/main.c @@ -372,11 +372,6 @@ int main(int argc, char **argv) // If using the runtime (-u is not NONE), enable syntax & filetype plugins. if (params.use_vimrc == NULL || !strequal(params.use_vimrc, "NONE")) { - // Source syncolor.vim to set up default UI highlights if the user didn't - // already enable a colorscheme - if (!get_var_value("g:colors_name")) { - source_runtime((char_u *)"syntax/syncolor.vim", DIP_ALL); - } // Does ":filetype plugin indent on". filetype_maybe_enable(); // Sources syntax/syntax.vim, which calls `:filetype on`. diff --git a/src/nvim/normal.c b/src/nvim/normal.c index 4213e6f946..9185062f94 100644 --- a/src/nvim/normal.c +++ b/src/nvim/normal.c @@ -92,8 +92,6 @@ static linenr_T resel_VIsual_line_count; /* number of lines */ static colnr_T resel_VIsual_vcol; /* nr of cols or end col */ static int VIsual_mode_orig = NUL; /* saved Visual mode */ -static int restart_VIsual_select = 0; - #ifdef INCLUDE_GENERATED_DECLARATIONS # include "normal.c.generated.h" diff --git a/src/nvim/screen.c b/src/nvim/screen.c index b9628385cd..aee10c06ad 100644 --- a/src/nvim/screen.c +++ b/src/nvim/screen.c @@ -165,7 +165,7 @@ static bool resizing = false; #endif #define SEARCH_HL_PRIORITY 0 -static char * provider_first_error = NULL; +static char * provider_err = NULL; static bool provider_invoke(NS ns_id, const char *name, LuaRef ref, Array args, bool default_true) @@ -187,10 +187,10 @@ static bool provider_invoke(NS ns_id, const char *name, LuaRef ref, const char *ns_name = describe_ns(ns_id); ELOG("error in provider %s:%s: %s", ns_name, name, err.msg); bool verbose_errs = true; // TODO(bfredl): - if (verbose_errs && provider_first_error == NULL) { + if (verbose_errs && provider_err == NULL) { static char errbuf[IOSIZE]; snprintf(errbuf, sizeof errbuf, "%s: %s", ns_name, err.msg); - provider_first_error = xstrdup(errbuf); + provider_err = xstrdup(errbuf); } } @@ -2103,7 +2103,6 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool search_attr_from_match = false; // if search_attr is from :match bool has_decor = false; // this buffer has decoration - bool do_virttext = false; // draw virtual text for this line int win_col_offset = 0; // offset for window columns char_u buf_fold[FOLD_TEXT_LEN + 1]; // Hold value returned by get_foldtext @@ -2148,8 +2147,6 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, row = startrow; - char *err_text = NULL; - buf_T *buf = wp->w_buffer; if (!number_only) { @@ -2194,14 +2191,20 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, } } - if (has_decor) { - extra_check = true; + if (provider_err) { + Decoration err_decor = DECORATION_INIT; + int hl_err = syn_check_group((char_u *)S_LEN("ErrorMsg")); + kv_push(err_decor.virt_text, + ((VirtTextChunk){ .text = provider_err, + .hl_id = hl_err })); + err_decor.virt_text_width = mb_string2cells((char_u *)provider_err); + decor_add_ephemeral(lnum-1, 0, lnum-1, 0, &err_decor); + provider_err = NULL; + has_decor = true; } - if (provider_first_error) { - err_text = provider_first_error; - provider_first_error = NULL; - do_virttext = true; + if (has_decor) { + extra_check = true; } // Check for columns to display for 'colorcolumn'. @@ -3953,19 +3956,15 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, if (draw_color_col) draw_color_col = advance_color_col(VCOL_HLC, &color_cols); - VirtText virt_text = KV_INITIAL_VALUE; - bool has_aligned = false; - if (err_text) { - int hl_err = syn_check_group((char_u *)S_LEN("ErrorMsg")); - kv_push(virt_text, ((VirtTextChunk){ .text = err_text, - .hl_id = hl_err })); - do_virttext = true; - } else if (has_decor) { - virt_text = decor_redraw_eol(wp->w_buffer, &decor_state, &line_attr, - &has_aligned); - if (kv_size(virt_text)) { - do_virttext = true; - } + bool has_virttext = false; + // Make sure alignment is the same regardless + // if listchars=eol:X is used or not. + int eol_skip = (wp->w_p_lcs_chars.eol == lcs_eol_one && eol_hl_off == 0 + ? 1 : 0); + + if (has_decor) { + has_virttext = decor_redraw_eol(wp->w_buffer, &decor_state, &line_attr, + col + eol_skip); } if (((wp->w_p_cuc @@ -3974,20 +3973,10 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, grid->Columns * (row - startrow + 1) + v && lnum != wp->w_cursor.lnum) || draw_color_col || line_attr_lowprio || line_attr - || diff_hlf != (hlf_T)0 || do_virttext - || has_aligned)) { + || diff_hlf != (hlf_T)0 || has_virttext)) { int rightmost_vcol = 0; int i; - size_t virt_pos = 0; - LineState s = LINE_STATE(""); - int virt_attr = 0; - - // Make sure alignment is the same regardless - // if listchars=eol:X is used or not. - bool delay_virttext = wp->w_p_lcs_chars.eol == lcs_eol_one - && eol_hl_off == 0; - if (wp->w_p_cuc) { rightmost_vcol = wp->w_virtcol; } @@ -4013,37 +4002,15 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, } int base_attr = hl_combine_attr(line_attr_lowprio, diff_attr); - if (base_attr || line_attr || has_aligned) { + if (base_attr || line_attr || has_virttext) { rightmost_vcol = INT_MAX; } int col_stride = wp->w_p_rl ? -1 : 1; while (wp->w_p_rl ? col >= 0 : col < grid->Columns) { - int cells = -1; - if (do_virttext && !delay_virttext) { - if (*s.p == NUL) { - if (virt_pos < virt_text.size) { - s.p = kv_A(virt_text, virt_pos).text; - int hl_id = kv_A(virt_text, virt_pos).hl_id; - virt_attr = hl_id > 0 ? syn_id2attr(hl_id) : 0; - virt_pos++; - } else { - do_virttext = false; - } - } - if (*s.p != NUL) { - cells = line_putchar(&s, &linebuf_char[off], grid->Columns - col, - false); - } - } - delay_virttext = false; - - if (cells == -1) { - schar_from_ascii(linebuf_char[off], ' '); - cells = 1; - } - col += cells * col_stride; + schar_from_ascii(linebuf_char[off], ' '); + col += col_stride; if (draw_color_col) { draw_color_col = advance_color_col(VCOL_HLC, &color_cols); } @@ -4056,24 +4023,16 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, col_attr = mc_attr; } - if (do_virttext) { - col_attr = hl_combine_attr(col_attr, virt_attr); - } - col_attr = hl_combine_attr(col_attr, line_attr); linebuf_attr[off] = col_attr; - if (cells == 2) { - linebuf_attr[off+1] = col_attr; - } - off += cells * col_stride; + off += col_stride; - if (VCOL_HLC >= rightmost_vcol && *s.p == NUL - && virt_pos >= virt_text.size) { + if (VCOL_HLC >= rightmost_vcol) { break; } - vcol += cells; + vcol += 1; } } @@ -4392,7 +4351,6 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, } xfree(p_extra_free); - xfree(err_text); return row; } @@ -4400,13 +4358,17 @@ void draw_virt_text(buf_T *buf, int col_off, int *end_col, int max_col) { DecorState *state = &decor_state; int right_pos = max_col; + bool do_eol = state->eol_col > -1; for (size_t i = 0; i < kv_size(state->active); i++) { DecorRange *item = &kv_A(state->active, i); if (item->start_row == state->row && kv_size(item->decor.virt_text)) { if (item->win_col == -1) { if (item->decor.virt_text_pos == kVTRightAlign) { - right_pos -= item->decor.col; + right_pos -= item->decor.virt_text_width; item->win_col = right_pos; + } else if (item->decor.virt_text_pos == kVTEndOfLine && do_eol) { + item->win_col = state->eol_col; + state->eol_col += item->decor.virt_text_width; } else if (item->decor.virt_text_pos == kVTWinCol) { item->win_col = MAX(item->decor.col+col_off, 0); } @@ -4424,14 +4386,20 @@ void draw_virt_text(buf_T *buf, int col_off, int *end_col, int max_col) while (col < max_col) { if (!*s.p) { - if (virt_pos == kv_size(vt)) { + if (virt_pos >= kv_size(vt)) { + break; + } + virt_attr = 0; + do { + s.p = kv_A(vt, virt_pos).text; + int hl_id = kv_A(vt, virt_pos).hl_id; + virt_attr = hl_combine_attr(virt_attr, + hl_id > 0 ? syn_id2attr(hl_id) : 0); + virt_pos++; + } while (!s.p && virt_pos < kv_size(vt)); + if (!s.p) { break; } - s.p = kv_A(vt, virt_pos).text; - int hl_id = kv_A(vt, virt_pos).hl_id; - virt_attr = hl_id > 0 ? syn_id2attr(hl_id) : 0; - virt_pos++; - continue; } int attr; bool through = false; diff --git a/src/nvim/state.c b/src/nvim/state.c index 437cb0db47..02d63d8ab1 100644 --- a/src/nvim/state.c +++ b/src/nvim/state.c @@ -144,6 +144,9 @@ char *get_mode(void) buf[0] = (char)(VIsual_mode + 's' - 'v'); } else { buf[0] = (char)VIsual_mode; + if (restart_VIsual_select) { + buf[1] = 's'; + } } } else if (State == HITRETURN || State == ASKMORE || State == SETWSIZE || State == CONFIRM) { diff --git a/src/nvim/syntax.c b/src/nvim/syntax.c index d20bc6026d..d9089eb821 100644 --- a/src/nvim/syntax.c +++ b/src/nvim/syntax.c @@ -3417,16 +3417,6 @@ static void syn_cmd_on(exarg_T *eap, int syncing) } /* - * Handle ":syntax enable" command. - */ -static void syn_cmd_enable(exarg_T *eap, int syncing) -{ - set_internal_string_var("syntax_cmd", (char_u *)"enable"); - syn_cmd_onoff(eap, "syntax"); - do_unlet(S_LEN("g:syntax_cmd"), true); -} - -/* * Handle ":syntax reset" command. * It actually resets highlighting, not syntax. */ @@ -3434,9 +3424,7 @@ static void syn_cmd_reset(exarg_T *eap, int syncing) { eap->nextcmd = check_nextcmd(eap->arg); if (!eap->skip) { - set_internal_string_var("syntax_cmd", (char_u *)"reset"); - do_cmdline_cmd("runtime! syntax/syncolor.vim"); - do_unlet(S_LEN("g:syntax_cmd"), true); + init_highlight(true, true); } } @@ -3475,7 +3463,7 @@ void syn_maybe_enable(void) exarg_T ea; ea.arg = (char_u *)""; ea.skip = false; - syn_cmd_enable(&ea, false); + syn_cmd_on(&ea, false); } } @@ -5534,7 +5522,7 @@ static struct subcommand subcommands[] = { "clear", syn_cmd_clear }, { "cluster", syn_cmd_cluster }, { "conceal", syn_cmd_conceal }, - { "enable", syn_cmd_enable }, + { "enable", syn_cmd_on }, { "foldlevel", syn_cmd_foldlevel }, { "include", syn_cmd_include }, { "iskeyword", syn_cmd_iskeyword }, @@ -6057,6 +6045,34 @@ static const char *highlight_init_both[] = { "RedrawDebugClear ctermbg=Yellow guibg=Yellow", "RedrawDebugComposed ctermbg=Green guibg=Green", "RedrawDebugRecompose ctermbg=Red guibg=Red", + "Error term=reverse cterm=NONE ctermfg=White ctermbg=Red gui=NONE " + "guifg=White guibg=Red", + "Todo term=standout cterm=NONE ctermfg=Black ctermbg=Yellow gui=NONE " + "guifg=Blue guibg=Yellow", + "default link String Constant", + "default link Character Constant", + "default link Number Constant", + "default link Boolean Constant", + "default link Float Number", + "default link Function Identifier", + "default link Conditional Statement", + "default link Repeat Statement", + "default link Label Statement", + "default link Operator Statement", + "default link Keyword Statement", + "default link Exception Statement", + "default link Include PreProc", + "default link Define PreProc", + "default link Macro PreProc", + "default link PreCondit PreProc", + "default link StorageClass Type", + "default link Structure Type", + "default link Typedef Type", + "default link Tag Special", + "default link SpecialChar Special", + "default link Delimiter Special", + "default link SpecialComment Special", + "default link Debug Special", NULL }; @@ -6090,6 +6106,24 @@ static const char *highlight_init_light[] = { "Title ctermfg=DarkMagenta gui=bold guifg=Magenta", "Visual guibg=LightGrey", "WarningMsg ctermfg=DarkRed guifg=Red", + "Comment term=bold cterm=NONE ctermfg=DarkBlue ctermbg=NONE " + "gui=NONE guifg=Blue guibg=NONE", + "Constant term=underline cterm=NONE ctermfg=DarkRed ctermbg=NONE " + "gui=NONE guifg=Magenta guibg=NONE", + "Special term=bold cterm=NONE ctermfg=DarkMagenta ctermbg=NONE " + "gui=NONE guifg=#6a5acd guibg=NONE", + "Identifier term=underline cterm=NONE ctermfg=DarkCyan ctermbg=NONE " + "gui=NONE guifg=DarkCyan guibg=NONE", + "Statement term=bold cterm=NONE ctermfg=Brown ctermbg=NONE " + "gui=bold guifg=Brown guibg=NONE", + "PreProc term=underline cterm=NONE ctermfg=DarkMagenta ctermbg=NONE " + "gui=NONE guifg=#6a0dad guibg=NONE", + "Type term=underline cterm=NONE ctermfg=DarkGreen ctermbg=NONE " + "gui=bold guifg=SeaGreen guibg=NONE", + "Underlined term=underline cterm=underline ctermfg=DarkMagenta " + "gui=underline guifg=SlateBlue", + "Ignore term=NONE cterm=NONE ctermfg=white ctermbg=NONE " + "gui=NONE guifg=bg guibg=NONE", NULL }; @@ -6123,6 +6157,24 @@ static const char *highlight_init_dark[] = { "Title ctermfg=LightMagenta gui=bold guifg=Magenta", "Visual guibg=DarkGrey", "WarningMsg ctermfg=LightRed guifg=Red", + "Comment term=bold cterm=NONE ctermfg=Cyan ctermbg=NONE " + "gui=NONE guifg=#80a0ff guibg=NONE", + "Constant term=underline cterm=NONE ctermfg=Magenta ctermbg=NONE " + "gui=NONE guifg=#ffa0a0 guibg=NONE", + "Special term=bold cterm=NONE ctermfg=LightRed ctermbg=NONE " + "gui=NONE guifg=Orange guibg=NONE", + "Identifier term=underline cterm=bold ctermfg=Cyan ctermbg=NONE " + "gui=NONE guifg=#40ffff guibg=NONE", + "Statement term=bold cterm=NONE ctermfg=Yellow ctermbg=NONE " + "gui=bold guifg=#ffff60 guibg=NONE", + "PreProc term=underline cterm=NONE ctermfg=LightBlue ctermbg=NONE " + "gui=NONE guifg=#ff80ff guibg=NONE", + "Type term=underline cterm=NONE ctermfg=LightGreen ctermbg=NONE " + "gui=bold guifg=#60ff60 guibg=NONE", + "Underlined term=underline cterm=underline ctermfg=LightBlue " + "gui=underline guifg=#80a0ff", + "Ignore term=NONE cterm=NONE ctermfg=black ctermbg=NONE " + "gui=NONE guifg=bg guibg=NONE", NULL }; @@ -6398,20 +6450,6 @@ void init_highlight(bool both, bool reset) } } - /* - * If syntax highlighting is enabled load the highlighting for it. - */ - if (get_var_value("g:syntax_on") != NULL) { - static int recursive = 0; - - if (recursive >= 5) { - EMSG(_("E679: recursive loop loading syncolor.vim")); - } else { - recursive++; - (void)source_runtime((char_u *)"syntax/syncolor.vim", DIP_ALL); - recursive--; - } - } syn_init_cmdline_highlight(false, false); } diff --git a/src/nvim/testdir/test_functions.vim b/src/nvim/testdir/test_functions.vim index 224ca257ab..bcf2edcc93 100644 --- a/src/nvim/testdir/test_functions.vim +++ b/src/nvim/testdir/test_functions.vim @@ -534,6 +534,7 @@ func Test_mode() set complete=. inoremap <F2> <C-R>=Save_mode()<CR> + xnoremap <F2> <Cmd>call Save_mode()<CR> normal! 3G exe "normal i\<F2>\<Esc>" @@ -645,6 +646,14 @@ func Test_mode() call assert_equal("\<C-S>", mode(1)) call feedkeys("\<Esc>", 'xt') + " v_CTRL-O + exe "normal gh\<C-O>\<F2>\<Esc>" + call assert_equal("v-vs", g:current_modes) + exe "normal gH\<C-O>\<F2>\<Esc>" + call assert_equal("V-Vs", g:current_modes) + exe "normal g\<C-H>\<C-O>\<F2>\<Esc>" + call assert_equal("\<C-V>-\<C-V>s", g:current_modes) + call feedkeys(":echo \<C-R>=Save_mode()\<C-U>\<CR>", 'xt') call assert_equal('c-c', g:current_modes) call feedkeys("gQecho \<C-R>=Save_mode()\<CR>\<CR>vi\<CR>", 'xt') @@ -653,6 +662,7 @@ func Test_mode() bwipe! iunmap <F2> + xunmap <F2> set complete& endfunc @@ -1315,7 +1325,15 @@ endfunc func Test_getchar() call feedkeys('a', '') call assert_equal(char2nr('a'), getchar()) + call assert_equal(0, getchar(0)) + call assert_equal(0, getchar(1)) + + call feedkeys('a', '') + call assert_equal('a', getcharstr()) + call assert_equal('', getcharstr(0)) + call assert_equal('', getcharstr(1)) + call setline(1, 'xxxx') " call test_setmouse(1, 3) " let v:mouse_win = 9 " let v:mouse_winid = 9 @@ -1328,6 +1346,7 @@ func Test_getchar() call assert_equal(win_getid(1), v:mouse_winid) call assert_equal(1, v:mouse_lnum) call assert_equal(3, v:mouse_col) + enew! endfunc func Test_libcall_libcallnr() diff --git a/src/nvim/testdir/test_mksession.vim b/src/nvim/testdir/test_mksession.vim index 4026f2bf98..fbe764bbf2 100644 --- a/src/nvim/testdir/test_mksession.vim +++ b/src/nvim/testdir/test_mksession.vim @@ -287,6 +287,29 @@ func Test_mksession_blank_windows() call delete('Xtest_mks.out') endfunc +func Test_mksession_buffer_count() + set hidden + + " Edit exactly three files in the current session. + %bwipe! + e Xfoo | tabe Xbar | tabe Xbaz + tabdo write + mksession! Xtest_mks.out + + " Verify that loading the session does not create additional buffers. + %bwipe! + source Xtest_mks.out + call assert_equal(3, len(getbufinfo())) + + " Clean up. + call delete('Xfoo') + call delete('Xbar') + call delete('Xbaz') + call delete('Xtest_mks.out') + %bwipe! + set hidden& +endfunc + if has('extra_search') func Test_mksession_hlsearch() |