aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/nvim/api/buffer.c87
-rw-r--r--src/nvim/api/deprecated.c82
-rw-r--r--src/nvim/api/private/helpers.c36
-rw-r--r--src/nvim/decoration.c26
-rw-r--r--src/nvim/decoration.h13
-rw-r--r--src/nvim/eval.lua1
-rw-r--r--src/nvim/eval/funcs.c41
-rw-r--r--src/nvim/ex_session.c37
-rw-r--r--src/nvim/extmark.c2
-rw-r--r--src/nvim/globals.h2
-rw-r--r--src/nvim/main.c5
-rw-r--r--src/nvim/normal.c2
-rw-r--r--src/nvim/screen.c128
-rw-r--r--src/nvim/state.c3
-rw-r--r--src/nvim/syntax.c96
-rw-r--r--src/nvim/testdir/test_functions.vim19
-rw-r--r--src/nvim/testdir/test_mksession.vim23
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()