aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--runtime/doc/ui.txt8
-rw-r--r--runtime/doc/various.txt15
-rw-r--r--src/nvim/api/ui.c1
-rw-r--r--src/nvim/api/ui_events.in.h2
-rw-r--r--src/nvim/edit.c4
-rw-r--r--src/nvim/eval.c17
-rw-r--r--src/nvim/ex_docmd.c51
-rw-r--r--src/nvim/globals.h9
-rw-r--r--src/nvim/highlight.c20
-rw-r--r--src/nvim/highlight_defs.h1
-rw-r--r--src/nvim/mark.c73
-rw-r--r--src/nvim/message.c4
-rw-r--r--src/nvim/normal.c23
-rw-r--r--src/nvim/ops.c33
-rw-r--r--src/nvim/option.c5
-rw-r--r--src/nvim/profile.c4
-rw-r--r--src/nvim/regexp_nfa.c4
-rw-r--r--src/nvim/screen.c22
-rw-r--r--src/nvim/spell.c2
-rw-r--r--src/nvim/syntax.c13
-rw-r--r--src/nvim/testdir/runtest.vim9
-rw-r--r--src/nvim/testdir/test_filter_cmd.vim58
-rw-r--r--src/nvim/testdir/test_suspend.vim2
-rw-r--r--src/nvim/testdir/test_window_cmd.vim37
-rw-r--r--src/nvim/window.c155
-rw-r--r--test/functional/autocmd/cursorhold_spec.lua31
-rw-r--r--test/functional/ui/highlight_spec.lua32
-rw-r--r--test/functional/ui/screen.lua33
-rw-r--r--third-party/cmake/BuildLuarocks.cmake2
29 files changed, 478 insertions, 192 deletions
diff --git a/runtime/doc/ui.txt b/runtime/doc/ui.txt
index c56f9467a3..1440e2ac78 100644
--- a/runtime/doc/ui.txt
+++ b/runtime/doc/ui.txt
@@ -316,6 +316,14 @@ numerical highlight ids to the actual attributes.
`info` is an empty array by default, and will be used by the
|ui-hlstate| extension explained below.
+["hl_group_set", name, hl_id]
+ The bulitin highlight group `name` was set to use the attributes `hl_id`
+ defined by a previous `hl_attr_define` call. This event is not needed
+ to render the grids which use attribute ids directly, but is useful
+ for an UI who want to render its own elements with consistent
+ highlighting. For instance an UI using |ui-popupmenu| events, might
+ use the |hl-Pmenu| family of builtin highlights.
+
*ui-event-grid_line*
["grid_line", grid, row, col_start, cells]
Redraw a continuous part of a `row` on a `grid`, starting at the column
diff --git a/runtime/doc/various.txt b/runtime/doc/various.txt
index c7fcd698db..bfb00f74c4 100644
--- a/runtime/doc/various.txt
+++ b/runtime/doc/various.txt
@@ -358,7 +358,20 @@ g8 Print the hex values of the bytes used in the
The pattern is matched against the relevant part of
the output, not necessarily the whole line. Only some
commands support filtering, try it out to check if it
- works.
+ works. Some of the commands that support filtering:
+ |:#| - filter whole line
+ |:clist| - filter by file name or module name
+ |:command| - filter by command name
+ |:files| - filter by file name
+ |:highlight| - filter by highlight group
+ |:jumps| - filter by file name
+ |:let| - filter by variable name
+ |:list| - filter whole line
+ |:llist| - filter by file name or module name
+ |:marks| - filter by text in the current file,
+ or file name for other files
+ |:oldfiles| - filter by file name
+ |:set| - filter by variable name
Only normal messages are filtered, error messages are
not.
diff --git a/src/nvim/api/ui.c b/src/nvim/api/ui.c
index 4f28ea5af3..20ed77afad 100644
--- a/src/nvim/api/ui.c
+++ b/src/nvim/api/ui.c
@@ -123,6 +123,7 @@ void nvim_ui_attach(uint64_t channel_id, Integer width, Integer height,
ui->mode_change = remote_ui_mode_change;
ui->grid_scroll = remote_ui_grid_scroll;
ui->hl_attr_define = remote_ui_hl_attr_define;
+ ui->hl_group_set = remote_ui_hl_group_set;
ui->raw_line = remote_ui_raw_line;
ui->bell = remote_ui_bell;
ui->visual_bell = remote_ui_visual_bell;
diff --git a/src/nvim/api/ui_events.in.h b/src/nvim/api/ui_events.in.h
index a1d25766fe..41bf0af65b 100644
--- a/src/nvim/api/ui_events.in.h
+++ b/src/nvim/api/ui_events.in.h
@@ -73,6 +73,8 @@ void default_colors_set(Integer rgb_fg, Integer rgb_bg, Integer rgb_sp,
void hl_attr_define(Integer id, HlAttrs rgb_attrs, HlAttrs cterm_attrs,
Array info)
FUNC_API_SINCE(5) FUNC_API_REMOTE_IMPL FUNC_API_BRIDGE_IMPL;
+void hl_group_set(String name, Integer id)
+ FUNC_API_SINCE(6) FUNC_API_BRIDGE_IMPL;
void grid_resize(Integer grid, Integer width, Integer height)
FUNC_API_SINCE(5) FUNC_API_REMOTE_IMPL FUNC_API_COMPOSITOR_IMPL;
void grid_clear(Integer grid)
diff --git a/src/nvim/edit.c b/src/nvim/edit.c
index 57c4a5395c..6a37c52e3f 100644
--- a/src/nvim/edit.c
+++ b/src/nvim/edit.c
@@ -649,7 +649,9 @@ static int insert_execute(VimState *state, int key)
s->c = key;
// Don't want K_EVENT with cursorhold for the second key, e.g., after CTRL-V.
- did_cursorhold = true;
+ if (key != K_EVENT) {
+ did_cursorhold = true;
+ }
if (p_hkmap && KeyTyped) {
s->c = hkmap(s->c); // Hebrew mode mapping
diff --git a/src/nvim/eval.c b/src/nvim/eval.c
index 6a5149614b..67aaf3c25c 100644
--- a/src/nvim/eval.c
+++ b/src/nvim/eval.c
@@ -1782,6 +1782,15 @@ static void list_hashtable_vars(hashtab_T *ht, const char *prefix, int empty,
if (!HASHITEM_EMPTY(hi)) {
todo--;
di = TV_DICT_HI2DI(hi);
+ char buf[IOSIZE];
+
+ // apply :filter /pat/ to variable name
+ xstrlcpy(buf, prefix, IOSIZE - 1);
+ xstrlcat(buf, (char *)di->di_key, IOSIZE);
+ if (message_filtered((char_u *)buf)) {
+ continue;
+ }
+
if (empty || di->di_tv.v_type != VAR_STRING
|| di->di_tv.vval.v_string != NULL) {
list_one_var(di, prefix, first);
@@ -2360,6 +2369,7 @@ static char_u *get_lval(char_u *const name, typval_T *const rettv,
/* Can't add "v:" variable. */
if (lp->ll_dict == &vimvardict) {
EMSG2(_(e_illvar), name);
+ tv_clear(&var1);
return NULL;
}
@@ -4326,7 +4336,7 @@ static int eval7(
// Dictionary: {key: val, key: val}
case '{': ret = get_lambda_tv(arg, rettv, evaluate);
if (ret == NOTDONE) {
- ret = get_dict_tv(arg, rettv, evaluate);
+ ret = dict_get_tv(arg, rettv, evaluate);
}
break;
@@ -5710,7 +5720,7 @@ static bool set_ref_in_funccal(funccall_T *fc, int copyID)
* Allocate a variable for a Dictionary and fill it from "*arg".
* Return OK or FAIL. Returns NOTDONE for {expr}.
*/
-static int get_dict_tv(char_u **arg, typval_T *rettv, int evaluate)
+static int dict_get_tv(char_u **arg, typval_T *rettv, int evaluate)
{
dict_T *d = NULL;
typval_T tvkey;
@@ -20851,6 +20861,9 @@ void ex_function(exarg_T *eap)
if (!HASHITEM_EMPTY(hi)) {
--todo;
fp = HI2UF(hi);
+ if (message_filtered(fp->uf_name)) {
+ continue;
+ }
if (!func_name_refcount(fp->uf_name)) {
list_func_head(fp, false);
}
diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c
index 1d27cf338e..072f2fab40 100644
--- a/src/nvim/ex_docmd.c
+++ b/src/nvim/ex_docmd.c
@@ -8453,24 +8453,23 @@ static void ex_tag_cmd(exarg_T *eap, char_u *name)
int cmd;
switch (name[1]) {
- case 'j': cmd = DT_JUMP; /* ":tjump" */
+ case 'j': cmd = DT_JUMP; // ":tjump"
break;
- case 's': cmd = DT_SELECT; /* ":tselect" */
+ case 's': cmd = DT_SELECT; // ":tselect"
break;
- case 'p': cmd = DT_PREV; /* ":tprevious" */
+ case 'p': // ":tprevious"
+ case 'N': cmd = DT_PREV; // ":tNext"
break;
- case 'N': cmd = DT_PREV; /* ":tNext" */
+ case 'n': cmd = DT_NEXT; // ":tnext"
break;
- case 'n': cmd = DT_NEXT; /* ":tnext" */
+ case 'o': cmd = DT_POP; // ":pop"
break;
- case 'o': cmd = DT_POP; /* ":pop" */
+ case 'f': // ":tfirst"
+ case 'r': cmd = DT_FIRST; // ":trewind"
break;
- case 'f': /* ":tfirst" */
- case 'r': cmd = DT_FIRST; /* ":trewind" */
+ case 'l': cmd = DT_LAST; // ":tlast"
break;
- case 'l': cmd = DT_LAST; /* ":tlast" */
- break;
- default: /* ":tag" */
+ default: // ":tag"
if (p_cst && *eap->arg != NUL) {
ex_cstag(eap);
return;
@@ -9323,26 +9322,30 @@ static frame_T *ses_skipframe(frame_T *fr)
{
frame_T *frc;
- for (frc = fr; frc != NULL; frc = frc->fr_next)
- if (ses_do_frame(frc))
+ FOR_ALL_FRAMES(frc, fr) {
+ if (ses_do_frame(frc)) {
break;
+ }
+ }
return frc;
}
-/*
- * Return TRUE if frame "fr" has a window somewhere that we want to save in
- * the Session.
- */
-static int ses_do_frame(frame_T *fr)
+// Return true if frame "fr" has a window somewhere that we want to save in
+// the Session.
+static bool ses_do_frame(const frame_T *fr)
+ FUNC_ATTR_NONNULL_ARG(1)
{
- frame_T *frc;
+ const frame_T *frc;
- if (fr->fr_layout == FR_LEAF)
+ if (fr->fr_layout == FR_LEAF) {
return ses_do_win(fr->fr_win);
- for (frc = fr->fr_child; frc != NULL; frc = frc->fr_next)
- if (ses_do_frame(frc))
- return TRUE;
- return FALSE;
+ }
+ FOR_ALL_FRAMES(frc, fr->fr_child) {
+ if (ses_do_frame(frc)) {
+ return true;
+ }
+ }
+ return false;
}
/// Return non-zero if window "wp" is to be stored in the Session.
diff --git a/src/nvim/globals.h b/src/nvim/globals.h
index 139ffe2144..1cb2f4592a 100644
--- a/src/nvim/globals.h
+++ b/src/nvim/globals.h
@@ -435,10 +435,11 @@ EXTERN win_T *firstwin; /* first window */
EXTERN win_T *lastwin; /* last window */
EXTERN win_T *prevwin INIT(= NULL); /* previous window */
# define ONE_WINDOW (firstwin == lastwin)
-/*
- * When using this macro "break" only breaks out of the inner loop. Use "goto"
- * to break out of the tabpage loop.
- */
+# define FOR_ALL_FRAMES(frp, first_frame) \
+ for (frp = first_frame; frp != NULL; frp = frp->fr_next) // NOLINT
+
+// When using this macro "break" only breaks out of the inner loop. Use "goto"
+// to break out of the tabpage loop.
# define FOR_ALL_TAB_WINDOWS(tp, wp) \
FOR_ALL_TABS(tp) \
FOR_ALL_WINDOWS_IN_TAB(wp, tp)
diff --git a/src/nvim/highlight.c b/src/nvim/highlight.c
index e5cbb4f944..f11880cb2b 100644
--- a/src/nvim/highlight.c
+++ b/src/nvim/highlight.c
@@ -106,14 +106,19 @@ static int get_attr_entry(HlEntry entry)
/// When a UI connects, we need to send it the table of highlights used so far.
void ui_send_all_hls(UI *ui)
{
- if (!ui->hl_attr_define) {
- return;
+ if (ui->hl_attr_define) {
+ for (size_t i = 1; i < kv_size(attr_entries); i++) {
+ Array inspect = hl_inspect((int)i);
+ ui->hl_attr_define(ui, (Integer)i, kv_A(attr_entries, i).attr,
+ kv_A(attr_entries, i).attr, inspect);
+ api_free_array(inspect);
+ }
}
- for (size_t i = 1; i < kv_size(attr_entries); i++) {
- Array inspect = hl_inspect((int)i);
- ui->hl_attr_define(ui, (Integer)i, kv_A(attr_entries, i).attr,
- kv_A(attr_entries, i).attr, inspect);
- api_free_array(inspect);
+ if (ui->hl_group_set) {
+ for (size_t hlf = 0; hlf < HLF_COUNT; hlf++) {
+ ui->hl_group_set(ui, cstr_as_string((char *)hlf_names[hlf]),
+ highlight_attr[hlf]);
+ }
}
}
@@ -251,6 +256,7 @@ void clear_hl_tables(bool reinit)
map_clear(int, int)(combine_attr_entries);
map_clear(int, int)(blend_attr_entries);
map_clear(int, int)(blendthrough_attr_entries);
+ memset(highlight_attr_last, -1, sizeof(highlight_attr_last));
highlight_attr_set_all();
highlight_changed();
screen_invalidate_highlights();
diff --git a/src/nvim/highlight_defs.h b/src/nvim/highlight_defs.h
index 25d859c55d..afccf9e6f6 100644
--- a/src/nvim/highlight_defs.h
+++ b/src/nvim/highlight_defs.h
@@ -150,6 +150,7 @@ EXTERN const char *hlf_names[] INIT(= {
EXTERN int highlight_attr[HLF_COUNT]; // Highl. attr for each context.
+EXTERN int highlight_attr_last[HLF_COUNT]; // copy for detecting changed groups
EXTERN int highlight_user[9]; // User[1-9] attributes
EXTERN int highlight_stlnc[9]; // On top of user
EXTERN int cterm_normal_fg_color INIT(= 0);
diff --git a/src/nvim/mark.c b/src/nvim/mark.c
index 2f2f2a7d74..3736004527 100644
--- a/src/nvim/mark.c
+++ b/src/nvim/mark.c
@@ -656,48 +656,51 @@ show_one_mark(
int c,
char_u *arg,
pos_T *p,
- char_u *name,
- int current /* in current file */
+ char_u *name_arg,
+ int current // in current file
)
{
- static int did_title = FALSE;
- int mustfree = FALSE;
-
- if (c == -1) { /* finish up */
- if (did_title)
- did_title = FALSE;
- else {
- if (arg == NULL)
+ static bool did_title = false;
+ bool mustfree = false;
+ char_u *name = name_arg;
+
+ if (c == -1) { // finish up
+ if (did_title) {
+ did_title = false;
+ } else {
+ if (arg == NULL) {
MSG(_("No marks set"));
- else
+ } else {
EMSG2(_("E283: No marks matching \"%s\""), arg);
+ }
}
- }
- /* don't output anything if 'q' typed at --more-- prompt */
- else if (!got_int
- && (arg == NULL || vim_strchr(arg, c) != NULL)
- && p->lnum != 0) {
- if (!did_title) {
- /* Highlight title */
- MSG_PUTS_TITLE(_("\nmark line col file/text"));
- did_title = TRUE;
+ } else if (!got_int
+ && (arg == NULL || vim_strchr(arg, c) != NULL)
+ && p->lnum != 0) {
+ // don't output anything if 'q' typed at --more-- prompt
+ if (name == NULL && current) {
+ name = mark_line(p, 15);
+ mustfree = true;
}
- msg_putchar('\n');
- if (!got_int) {
- sprintf((char *)IObuff, " %c %6ld %4d ", c, p->lnum, p->col);
- msg_outtrans(IObuff);
- if (name == NULL && current) {
- name = mark_line(p, 15);
- mustfree = TRUE;
+ if (!message_filtered(name)) {
+ if (!did_title) {
+ // Highlight title
+ msg_puts_title(_("\nmark line col file/text"));
+ did_title = true;
}
- if (name != NULL) {
- msg_outtrans_attr(name, current ? HL_ATTR(HLF_D) : 0);
- if (mustfree) {
- xfree(name);
+ msg_putchar('\n');
+ if (!got_int) {
+ snprintf((char *)IObuff, IOSIZE, " %c %6ld %4d ", c, p->lnum, p->col);
+ msg_outtrans(IObuff);
+ if (name != NULL) {
+ msg_outtrans_attr(name, current ? HL_ATTR(HLF_D) : 0);
}
}
+ ui_flush(); // show one line at a time
+ }
+ if (mustfree) {
+ xfree(name);
}
- ui_flush(); /* show one line at a time */
}
}
@@ -786,8 +789,12 @@ void ex_jumps(exarg_T *eap)
for (i = 0; i < curwin->w_jumplistlen && !got_int; ++i) {
if (curwin->w_jumplist[i].fmark.mark.lnum != 0) {
name = fm_getname(&curwin->w_jumplist[i].fmark, 16);
- if (name == NULL) /* file name not available */
+
+ // apply :filter /pat/ or file name not available
+ if (name == NULL || message_filtered(name)) {
+ xfree(name);
continue;
+ }
msg_putchar('\n');
if (got_int) {
diff --git a/src/nvim/message.c b/src/nvim/message.c
index 86c185dbc2..df130565e0 100644
--- a/src/nvim/message.c
+++ b/src/nvim/message.c
@@ -1878,8 +1878,8 @@ static void msg_puts_display(const char_u *str, int maxlen, int attr,
msg_ext_last_attr = attr;
}
// Concat pieces with the same highlight
- size_t len = strnlen((char *)str, maxlen);
- ga_concat_len(&msg_ext_last_chunk, (char *)str, len); // -V781
+ size_t len = strnlen((char *)str, maxlen); // -V781
+ ga_concat_len(&msg_ext_last_chunk, (char *)str, len);
msg_ext_cur_len += len;
return;
}
diff --git a/src/nvim/normal.c b/src/nvim/normal.c
index de8ff52fe1..4ef4b69def 100644
--- a/src/nvim/normal.c
+++ b/src/nvim/normal.c
@@ -1376,9 +1376,8 @@ static void set_vcount_ca(cmdarg_T *cap, bool *set_prevcount)
*set_prevcount = false; /* only set v:prevcount once */
}
-/*
- * Handle an operator after visual mode or when the movement is finished
- */
+// Handle an operator after Visual mode or when the movement is finished.
+// "gui_yank" is true when yanking text for the clipboard.
void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank)
{
oparg_T *oap = cap->oap;
@@ -1402,8 +1401,12 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank)
* If an operation is pending, handle it...
*/
if ((finish_op
- || VIsual_active
- ) && oap->op_type != OP_NOP) {
+ || VIsual_active)
+ && oap->op_type != OP_NOP) {
+ // Yank can be redone when 'y' is in 'cpoptions', but not when yanking
+ // for the clipboard.
+ const bool redo_yank = vim_strchr(p_cpo, CPO_YANK) != NULL && !gui_yank;
+
// Avoid a problem with unwanted linebreaks in block mode
if (curwin->w_p_lbr) {
curwin->w_valid &= ~VALID_VIRTCOL;
@@ -1433,9 +1436,9 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank)
VIsual_reselect = false;
}
- /* Only redo yank when 'y' flag is in 'cpoptions'. */
- /* Never redo "zf" (define fold). */
- if ((vim_strchr(p_cpo, CPO_YANK) != NULL || oap->op_type != OP_YANK)
+ // Only redo yank when 'y' flag is in 'cpoptions'.
+ // Never redo "zf" (define fold).
+ if ((redo_yank || oap->op_type != OP_YANK)
&& ((!VIsual_active || oap->motion_force)
// Also redo Operator-pending Visual mode mappings.
|| (cap->cmdchar == ':' && oap->op_type != OP_COLON))
@@ -1608,8 +1611,8 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank)
resel_VIsual_line_count = oap->line_count;
}
- /* can't redo yank (unless 'y' is in 'cpoptions') and ":" */
- if ((vim_strchr(p_cpo, CPO_YANK) != NULL || oap->op_type != OP_YANK)
+ // can't redo yank (unless 'y' is in 'cpoptions') and ":"
+ if ((redo_yank || oap->op_type != OP_YANK)
&& oap->op_type != OP_COLON
&& oap->op_type != OP_FOLD
&& oap->op_type != OP_FOLDOPEN
diff --git a/src/nvim/ops.c b/src/nvim/ops.c
index 828a8fac46..5fbcd54a19 100644
--- a/src/nvim/ops.c
+++ b/src/nvim/ops.c
@@ -1471,7 +1471,8 @@ int op_delete(oparg_T *oap)
// copy up to deleted part
memmove(newp, oldp, (size_t)bd.textcol);
// insert spaces
- memset(newp + bd.textcol, ' ', (size_t)(bd.startspaces + bd.endspaces));
+ memset(newp + bd.textcol, ' ', (size_t)bd.startspaces +
+ (size_t)bd.endspaces);
// copy the part after the deleted part
oldp += bd.textcol + bd.textlen;
STRMOVE(newp + bd.textcol + bd.startspaces + bd.endspaces, oldp);
@@ -1743,7 +1744,7 @@ int op_replace(oparg_T *oap, int c)
oldp = get_cursor_line_ptr();
oldlen = (int)STRLEN(oldp);
- size_t newp_size = (size_t)(bd.textcol + bd.startspaces);
+ size_t newp_size = (size_t)bd.textcol + (size_t)bd.startspaces;
if (had_ctrl_v_cr || (c != '\r' && c != '\n')) {
newp_size += (size_t)numc;
if (!bd.is_short) {
@@ -1760,6 +1761,8 @@ int op_replace(oparg_T *oap, int c)
// insert replacement chars CHECK FOR ALLOCATED SPACE
// REPLACE_CR_NCHAR/REPLACE_NL_NCHAR is used for entering CR literally.
size_t after_p_len = 0;
+ int col = oldlen - bd.textcol - bd.textlen + 1;
+ assert(col >= 0);
if (had_ctrl_v_cr || (c != '\r' && c != '\n')) {
// strlen(newp) at this point
int newp_len = bd.textcol + bd.startspaces;
@@ -1771,12 +1774,11 @@ int op_replace(oparg_T *oap, int c)
memset(newp + newp_len, ' ', (size_t)bd.endspaces);
newp_len += bd.endspaces;
// copy the part after the changed part
- memmove(newp + newp_len, oldp,
- (size_t)(oldlen - bd.textcol - bd.textlen + 1));
+ memmove(newp + newp_len, oldp, (size_t)col);
}
} else {
// Replacing with \r or \n means splitting the line.
- after_p_len = (size_t)(oldlen - bd.textcol - bd.textlen + 1);
+ after_p_len = (size_t)col;
after_p = (char_u *)xmalloc(after_p_len);
memmove(after_p, oldp, after_p_len);
}
@@ -3085,8 +3087,9 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags)
memset(ptr, ' ', (size_t)bd.endspaces);
ptr += bd.endspaces;
// move the text after the cursor to the end of the line.
- memmove(ptr, oldp + bd.textcol + delcount,
- (size_t)((int)oldlen - bd.textcol - delcount + 1));
+ int columns = (int)oldlen - bd.textcol - delcount + 1;
+ assert(columns >= 0);
+ memmove(ptr, oldp + bd.textcol + delcount, (size_t)columns);
ml_replace(curwin->w_cursor.lnum, newp, false);
++curwin->w_cursor.lnum;
@@ -3209,11 +3212,11 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags)
xfree(newp);
oldp = ml_get(lnum);
- newp = (char_u *) xmalloc((size_t)(col + yanklen + 1));
- /* copy first part of line */
+ newp = (char_u *)xmalloc((size_t)col + (size_t)yanklen + 1);
+ // copy first part of line
memmove(newp, oldp, (size_t)col);
- /* append to first line */
- memmove(newp + col, y_array[0], (size_t)(yanklen + 1));
+ // append to first line
+ memmove(newp + col, y_array[0], (size_t)yanklen + 1);
ml_replace(lnum, newp, false);
curwin->w_cursor.lnum = lnum;
@@ -3705,11 +3708,11 @@ int do_join(size_t count,
}
}
- /* store the column position before last line */
+ // store the column position before last line
col = sumsize - currsize - spaces[count - 1];
- /* allocate the space for the new line */
- newp = (char_u *) xmalloc((size_t)(sumsize + 1));
+ // allocate the space for the new line
+ newp = (char_u *)xmalloc((size_t)sumsize + 1);
cend = newp + sumsize;
*cend = 0;
@@ -5472,7 +5475,7 @@ void cursor_pos_info(dict_T *dict)
byte_count_cursor = byte_count
+ line_count_info(ml_get(lnum), &word_count_cursor,
&char_count_cursor,
- (varnumber_T)(curwin->w_cursor.col + 1),
+ (varnumber_T)curwin->w_cursor.col + 1,
eol_size);
}
}
diff --git a/src/nvim/option.c b/src/nvim/option.c
index d6dbb14653..8483c02bbe 100644
--- a/src/nvim/option.c
+++ b/src/nvim/option.c
@@ -5047,6 +5047,11 @@ showoptions(
// collect the items in items[]
item_count = 0;
for (p = &options[0]; p->fullname != NULL; p++) {
+ // apply :filter /pat/
+ if (message_filtered((char_u *)p->fullname)) {
+ continue;
+ }
+
varp = NULL;
if (opt_flags != 0) {
if (p->indir != PV_NONE) {
diff --git a/src/nvim/profile.c b/src/nvim/profile.c
index e486095fe7..52e03c895e 100644
--- a/src/nvim/profile.c
+++ b/src/nvim/profile.c
@@ -66,8 +66,10 @@ proftime_T profile_setlimit(int64_t msec) FUNC_ATTR_WARN_UNUSED_RESULT
}
assert(msec <= (INT64_MAX / 1000000LL) - 1);
proftime_T nsec = msec * 1000000LL;
+ uint64_t now = os_hrtime();
+ assert(now <= INT64_MAX);
int64_t rv;
- STRICT_ADD(os_hrtime(), nsec, &rv, int64_t);
+ STRICT_ADD((proftime_T)now, nsec, &rv, int64_t);
return rv;
}
diff --git a/src/nvim/regexp_nfa.c b/src/nvim/regexp_nfa.c
index dc1ab971ab..a28e05bd7e 100644
--- a/src/nvim/regexp_nfa.c
+++ b/src/nvim/regexp_nfa.c
@@ -3002,8 +3002,8 @@ static nfa_state_T *post2nfa(int *postfix, int *end, int nfa_calc_size)
return NULL; \
}
- if (nfa_calc_size == FALSE) {
- /* Allocate space for the stack. Max states on the stack : nstate */
+ if (nfa_calc_size == false) {
+ // Allocate space for the stack. Max states on the stack: "nstate".
stack = xmalloc((nstate + 1) * sizeof(Frag_T));
stackp = stack;
stack_end = stack + (nstate + 1);
diff --git a/src/nvim/screen.c b/src/nvim/screen.c
index 63a465f332..2f8b1b6b02 100644
--- a/src/nvim/screen.c
+++ b/src/nvim/screen.c
@@ -4571,17 +4571,21 @@ void redraw_statuslines(void)
/*
* Redraw all status lines at the bottom of frame "frp".
*/
-void win_redraw_last_status(frame_T *frp)
+void win_redraw_last_status(const frame_T *frp)
+ FUNC_ATTR_NONNULL_ARG(1)
{
- if (frp->fr_layout == FR_LEAF)
- frp->fr_win->w_redr_status = TRUE;
- else if (frp->fr_layout == FR_ROW) {
- for (frp = frp->fr_child; frp != NULL; frp = frp->fr_next)
+ if (frp->fr_layout == FR_LEAF) {
+ frp->fr_win->w_redr_status = true;
+ } else if (frp->fr_layout == FR_ROW) {
+ FOR_ALL_FRAMES(frp, frp->fr_child) {
win_redraw_last_status(frp);
- } else { /* frp->fr_layout == FR_COL */
+ }
+ } else {
+ assert(frp->fr_layout == FR_COL);
frp = frp->fr_child;
- while (frp->fr_next != NULL)
+ while (frp->fr_next != NULL) {
frp = frp->fr_next;
+ }
win_redraw_last_status(frp);
}
}
@@ -6079,8 +6083,8 @@ void grid_alloc(ScreenGrid *grid, int rows, int columns, bool copy, bool valid)
{
int new_row;
ScreenGrid new = *grid;
-
- size_t ncells = (size_t)((rows+1) * columns);
+ assert(rows >= 0 && columns >= 0);
+ size_t ncells = (size_t)rows * columns;
new.chars = xmalloc(ncells * sizeof(schar_T));
new.attrs = xmalloc(ncells * sizeof(sattr_T));
new.line_offset = xmalloc((size_t)(rows * sizeof(unsigned)));
diff --git a/src/nvim/spell.c b/src/nvim/spell.c
index 6fd22a6537..17306744ad 100644
--- a/src/nvim/spell.c
+++ b/src/nvim/spell.c
@@ -5283,7 +5283,7 @@ add_sound_suggest (
}
// Go over the list of good words that produce this soundfold word
- nrline = ml_get_buf(slang->sl_sugbuf, (linenr_T)(sfwordnr + 1), FALSE);
+ nrline = ml_get_buf(slang->sl_sugbuf, (linenr_T)sfwordnr + 1, false);
orgnr = 0;
while (*nrline != NUL) {
// The wordnr was stored in a minimal nr of bytes as an offset to the
diff --git a/src/nvim/syntax.c b/src/nvim/syntax.c
index 3066ffbb0c..84392680c5 100644
--- a/src/nvim/syntax.c
+++ b/src/nvim/syntax.c
@@ -14,6 +14,7 @@
#include "nvim/vim.h"
#include "nvim/ascii.h"
+#include "nvim/api/private/helpers.h"
#include "nvim/syntax.h"
#include "nvim/charset.h"
#include "nvim/cursor_shape.h"
@@ -350,7 +351,7 @@ static reg_extmatch_T *next_match_extmatch = NULL;
/*
* A state stack is an array of integers or stateitem_T, stored in a
- * garray_T. A state stack is invalid if it's itemsize entry is zero.
+ * garray_T. A state stack is invalid if its itemsize entry is zero.
*/
#define INVALID_STATE(ssp) ((ssp)->ga_itemsize == 0)
#define VALID_STATE(ssp) ((ssp)->ga_itemsize != 0)
@@ -7028,6 +7029,10 @@ static void highlight_list_one(const int id)
struct hl_group *const sgp = &HL_TABLE()[id - 1]; // index is ID minus one
bool didh = false;
+ if (message_filtered(sgp->sg_name)) {
+ return;
+ }
+
didh = highlight_list_arg(id, didh, LIST_ATTR,
sgp->sg_cterm, NULL, "cterm");
didh = highlight_list_arg(id, didh, LIST_INT,
@@ -7504,6 +7509,12 @@ void highlight_changed(void)
highlight_attr[hlf] = hl_get_ui_attr(hlf, final_id,
hlf == (int)HLF_INACTIVE);
+
+ if (highlight_attr[hlf] != highlight_attr_last[hlf]) {
+ ui_call_hl_group_set(cstr_as_string((char *)hlf_names[hlf]),
+ highlight_attr[hlf]);
+ highlight_attr_last[hlf] = highlight_attr[hlf];
+ }
}
/* Setup the user highlights
diff --git a/src/nvim/testdir/runtest.vim b/src/nvim/testdir/runtest.vim
index 605e7c73eb..009908ec09 100644
--- a/src/nvim/testdir/runtest.vim
+++ b/src/nvim/testdir/runtest.vim
@@ -263,7 +263,7 @@ else
endif
" Names of flaky tests.
-let s:flaky = [
+let s:flaky_tests = [
\ 'Test_cursorhold_insert()',
\ 'Test_exit_callback_interval()',
\ 'Test_oneshot()',
@@ -281,6 +281,9 @@ let s:flaky = [
\ 'Test_lambda_with_timer()',
\ ]
+" Pattern indicating a common flaky test failure.
+let s:flaky_errors_re = 'StopVimInTerminal\|VerifyScreenDump'
+
" Locate Test_ functions and execute them.
redir @q
silent function /^Test_
@@ -305,7 +308,9 @@ for s:test in sort(s:tests)
" Repeat a flaky test. Give up when:
" - it fails again with the same message
" - it fails five times (with a different mesage)
- if len(v:errors) > 0 && index(s:flaky, s:test) >= 0
+ if len(v:errors) > 0
+ \ && (index(s:flaky_tests, s:test) >= 0
+ \ || v:errors[0] =~ s:flaky_errors_re)
while 1
call add(s:messages, 'Found errors in ' . s:test . ':')
call extend(s:messages, v:errors)
diff --git a/src/nvim/testdir/test_filter_cmd.vim b/src/nvim/testdir/test_filter_cmd.vim
index 86347ab77f..0c45db049b 100644
--- a/src/nvim/testdir/test_filter_cmd.vim
+++ b/src/nvim/testdir/test_filter_cmd.vim
@@ -87,3 +87,61 @@ func Test_filter_cmd_with_filter()
call assert_equal('a|b', out)
set shelltemp&
endfunction
+
+func Test_filter_commands()
+ let g:test_filter_a = 1
+ let b:test_filter_b = 2
+ let test_filter_c = 3
+
+ " Test filtering :let command
+ let res = split(execute("filter /^test_filter/ let"), "\n")
+ call assert_equal(["test_filter_a #1"], res)
+
+ let res = split(execute("filter /\\v^(b:)?test_filter/ let"), "\n")
+ call assert_equal(["test_filter_a #1", "b:test_filter_b #2"], res)
+
+ unlet g:test_filter_a
+ unlet b:test_filter_b
+ unlet test_filter_c
+
+ " Test filtering :set command
+ let helplang=&helplang
+ set helplang=en
+ let res = join(split(execute("filter /^help/ set"), "\n")[1:], " ")
+ call assert_match('^\s*helplang=\w*$', res)
+ let &helplang=helplang
+
+ " Test filtering :llist command
+ call setloclist(0, [{"filename": "/path/vim.c"}, {"filename": "/path/vim.h"}, {"module": "Main.Test"}])
+ let res = split(execute("filter /\\.c$/ llist"), "\n")
+ call assert_equal([" 1 /path/vim.c: "], res)
+
+ let res = split(execute("filter /\\.Test$/ llist"), "\n")
+ call assert_equal([" 3 Main.Test: "], res)
+
+ " Test filtering :jump command
+ e file.c
+ e file.h
+ e file.hs
+ let res = split(execute("filter /\.c$/ jumps"), "\n")[1:]
+ call assert_equal([" 2 1 0 file.c", ">"], res)
+
+ " Test filtering :marks command
+ b file.c
+ mark A
+ b file.h
+ mark B
+ let res = split(execute("filter /\.c$/ marks"), "\n")[1:]
+ call assert_equal([" A 1 0 file.c"], res)
+
+ call setline(1, ['one', 'two', 'three'])
+ 1mark a
+ 2mark b
+ 3mark c
+ let res = split(execute("filter /two/ marks abc"), "\n")[1:]
+ call assert_equal([" b 2 0 two"], res)
+
+ bwipe! file.c
+ bwipe! file.h
+ bwipe! file.hs
+endfunc
diff --git a/src/nvim/testdir/test_suspend.vim b/src/nvim/testdir/test_suspend.vim
index efda68de9b..ef5a96bd72 100644
--- a/src/nvim/testdir/test_suspend.vim
+++ b/src/nvim/testdir/test_suspend.vim
@@ -53,6 +53,8 @@ func Test_suspend()
" Quit gracefully to dump coverage information.
call term_sendkeys(buf, ":qall!\<CR>")
call term_wait(buf)
+ " Wait until Vim actually exited and shell shows a prompt
+ call WaitForAssert({-> assert_match('[$#] $', term_getline(buf, '.'))})
call Stop_shell_in_terminal(buf)
exe buf . 'bwipe!'
diff --git a/src/nvim/testdir/test_window_cmd.vim b/src/nvim/testdir/test_window_cmd.vim
index 003a23ea7b..2a07a04401 100644
--- a/src/nvim/testdir/test_window_cmd.vim
+++ b/src/nvim/testdir/test_window_cmd.vim
@@ -518,6 +518,43 @@ func Test_winrestcmd()
only
endfunc
+function! Fun_RenewFile()
+ sleep 2
+ silent execute '!echo "1" > tmp.txt'
+ sp
+ wincmd p
+ edit! tmp.txt
+endfunction
+
+func Test_window_prevwin()
+ " Can we make this work on MS-Windows?
+ if !has('unix')
+ return
+ endif
+
+ set hidden autoread
+ call writefile(['2'], 'tmp.txt')
+ new tmp.txt
+ q
+ " Need to wait a bit for the timestamp to be older.
+ call Fun_RenewFile()
+ call assert_equal(2, winnr())
+ wincmd p
+ call assert_equal(1, winnr())
+ wincmd p
+ q
+ call Fun_RenewFile()
+ call assert_equal(2, winnr())
+ wincmd p
+ call assert_equal(1, winnr())
+ wincmd p
+ " reset
+ q
+ call delete('tmp.txt')
+ set hidden&vim autoread&vim
+ delfunc Fun_RenewFile
+endfunc
+
func Test_relative_cursor_position_in_one_line_window()
new
only
diff --git a/src/nvim/window.c b/src/nvim/window.c
index 6ce095f976..38246bfe2a 100644
--- a/src/nvim/window.c
+++ b/src/nvim/window.c
@@ -1024,7 +1024,7 @@ int win_split_ins(int size, int flags, win_T *new_wp, int dir)
for (frp = oldwin->w_frame->fr_parent; frp != NULL;
frp = frp->fr_parent) {
if (frp->fr_layout == FR_ROW) {
- for (frp2 = frp->fr_child; frp2 != NULL; frp2 = frp2->fr_next) {
+ FOR_ALL_FRAMES(frp2, frp->fr_child) {
if (frp2 != prevfrp) {
minwidth += frame_minwidth(frp2, NOWIN);
}
@@ -1102,7 +1102,7 @@ int win_split_ins(int size, int flags, win_T *new_wp, int dir)
for (frp = oldwin->w_frame->fr_parent; frp != NULL;
frp = frp->fr_parent) {
if (frp->fr_layout == FR_COL) {
- for (frp2 = frp->fr_child; frp2 != NULL; frp2 = frp2->fr_next) {
+ FOR_ALL_FRAMES(frp2, frp->fr_child) {
if (frp2 != prevfrp) {
minheight += frame_minheight(frp2, NOWIN);
}
@@ -1247,11 +1247,13 @@ int win_split_ins(int size, int flags, win_T *new_wp, int dir)
curfrp->fr_child = frp;
curfrp->fr_win = NULL;
curfrp = frp;
- if (frp->fr_win != NULL)
+ if (frp->fr_win != NULL) {
oldwin->w_frame = frp;
- else
- for (frp = frp->fr_child; frp != NULL; frp = frp->fr_next)
+ } else {
+ FOR_ALL_FRAMES(frp, frp->fr_child) {
frp->fr_parent = curfrp;
+ }
+ }
}
if (new_wp == NULL)
@@ -1717,13 +1719,13 @@ static void win_rotate(bool upwards, int count)
return;
}
- /* Check if all frames in this row/col have one window. */
- for (frp = curwin->w_frame->fr_parent->fr_child; frp != NULL;
- frp = frp->fr_next)
+ // Check if all frames in this row/col have one window.
+ FOR_ALL_FRAMES(frp, curwin->w_frame->fr_parent->fr_child) {
if (frp->fr_win == NULL) {
EMSG(_("E443: Cannot rotate when another window is split"));
return;
}
+ }
while (count--) {
if (upwards) { /* first window becomes last window */
@@ -1961,10 +1963,10 @@ static void win_equal_rec(
room = 0;
} else {
next_curwin_size = -1;
- for (fr = topfr->fr_child; fr != NULL; fr = fr->fr_next) {
- /* If 'winfixwidth' set keep the window width if
- * possible.
- * Watch out for this window being the next_curwin. */
+ FOR_ALL_FRAMES(fr, topfr->fr_child) {
+ // If 'winfixwidth' set keep the window width if
+ // possible.
+ // Watch out for this window being the next_curwin.
if (!frame_fixed_width(fr)) {
continue;
}
@@ -2007,7 +2009,7 @@ static void win_equal_rec(
--totwincount; /* don't count curwin */
}
- for (fr = topfr->fr_child; fr != NULL; fr = fr->fr_next) {
+ FOR_ALL_FRAMES(fr, topfr->fr_child) {
wincount = 1;
if (fr->fr_next == NULL)
/* last frame gets all that remains (avoid roundoff error) */
@@ -2082,10 +2084,10 @@ static void win_equal_rec(
room = 0;
} else {
next_curwin_size = -1;
- for (fr = topfr->fr_child; fr != NULL; fr = fr->fr_next) {
- /* If 'winfixheight' set keep the window height if
- * possible.
- * Watch out for this window being the next_curwin. */
+ FOR_ALL_FRAMES(fr, topfr->fr_child) {
+ // If 'winfixheight' set keep the window height if
+ // possible.
+ // Watch out for this window being the next_curwin.
if (!frame_fixed_height(fr)) {
continue;
}
@@ -2128,7 +2130,7 @@ static void win_equal_rec(
--totwincount; /* don't count curwin */
}
- for (fr = topfr->fr_child; fr != NULL; fr = fr->fr_next) {
+ FOR_ALL_FRAMES(fr, topfr->fr_child) {
wincount = 1;
if (fr->fr_next == NULL)
/* last frame gets all that remains (avoid roundoff error) */
@@ -2815,8 +2817,9 @@ winframe_remove (
* and remove it. */
frp2->fr_parent->fr_layout = frp2->fr_layout;
frp2->fr_parent->fr_child = frp2->fr_child;
- for (frp = frp2->fr_child; frp != NULL; frp = frp->fr_next)
+ FOR_ALL_FRAMES(frp, frp2->fr_child) {
frp->fr_parent = frp2->fr_parent;
+ }
frp2->fr_parent->fr_win = frp2->fr_win;
if (frp2->fr_win != NULL)
frp2->fr_win->w_frame = frp2->fr_parent;
@@ -2937,13 +2940,14 @@ static win_T *frame2win(frame_T *frp)
///
/// @param frp frame
/// @param wp window
-static bool frame_has_win(frame_T *frp, win_T *wp)
+static bool frame_has_win(const frame_T *frp, const win_T *wp)
FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ARG(1)
{
if (frp->fr_layout == FR_LEAF) {
return frp->fr_win == wp;
}
- for (frame_T *p = frp->fr_child; p != NULL; p = p->fr_next) {
+ const frame_T *p;
+ FOR_ALL_FRAMES(p, frp->fr_child) {
if (frame_has_win(p, wp)) {
return true;
}
@@ -2974,8 +2978,8 @@ frame_new_height (
height - topfrp->fr_win->w_status_height);
} else if (topfrp->fr_layout == FR_ROW) {
do {
- /* All frames in this row get the same new height. */
- for (frp = topfrp->fr_child; frp != NULL; frp = frp->fr_next) {
+ // All frames in this row get the same new height.
+ FOR_ALL_FRAMES(frp, topfrp->fr_child) {
frame_new_height(frp, height, topfirst, wfh);
if (frp->fr_height > height) {
/* Could not fit the windows, make the whole row higher. */
@@ -3056,7 +3060,7 @@ static bool frame_fixed_height(frame_T *frp)
if (frp->fr_layout == FR_ROW) {
// The frame is fixed height if one of the frames in the row is fixed
// height.
- for (frp = frp->fr_child; frp != NULL; frp = frp->fr_next) {
+ FOR_ALL_FRAMES(frp, frp->fr_child) {
if (frame_fixed_height(frp)) {
return true;
}
@@ -3066,7 +3070,7 @@ static bool frame_fixed_height(frame_T *frp)
// frp->fr_layout == FR_COL: The frame is fixed height if all of the
// frames in the row are fixed height.
- for (frp = frp->fr_child; frp != NULL; frp = frp->fr_next) {
+ FOR_ALL_FRAMES(frp, frp->fr_child) {
if (!frame_fixed_height(frp)) {
return false;
}
@@ -3090,7 +3094,7 @@ static bool frame_fixed_width(frame_T *frp)
if (frp->fr_layout == FR_COL) {
// The frame is fixed width if one of the frames in the row is fixed
// width.
- for (frp = frp->fr_child; frp != NULL; frp = frp->fr_next) {
+ FOR_ALL_FRAMES(frp, frp->fr_child) {
if (frame_fixed_width(frp)) {
return true;
}
@@ -3100,7 +3104,7 @@ static bool frame_fixed_width(frame_T *frp)
// frp->fr_layout == FR_ROW: The frame is fixed width if all of the
// frames in the row are fixed width.
- for (frp = frp->fr_child; frp != NULL; frp = frp->fr_next) {
+ FOR_ALL_FRAMES(frp, frp->fr_child) {
if (!frame_fixed_width(frp)) {
return false;
}
@@ -3124,13 +3128,15 @@ static void frame_add_statusline(frame_T *frp)
wp->w_status_height = STATUS_HEIGHT;
}
} else if (frp->fr_layout == FR_ROW) {
- /* Handle all the frames in the row. */
- for (frp = frp->fr_child; frp != NULL; frp = frp->fr_next)
+ // Handle all the frames in the row.
+ FOR_ALL_FRAMES(frp, frp->fr_child) {
frame_add_statusline(frp);
- } else { /* frp->fr_layout == FR_COL */
- /* Only need to handle the last frame in the column. */
- for (frp = frp->fr_child; frp->fr_next != NULL; frp = frp->fr_next)
- ;
+ }
+ } else {
+ assert(frp->fr_layout == FR_COL);
+ // Only need to handle the last frame in the column.
+ for (frp = frp->fr_child; frp->fr_next != NULL; frp = frp->fr_next) {
+ }
frame_add_statusline(frp);
}
}
@@ -3165,8 +3171,8 @@ frame_new_width (
win_new_width(wp, width - wp->w_vsep_width);
} else if (topfrp->fr_layout == FR_COL) {
do {
- /* All frames in this column get the same new width. */
- for (frp = topfrp->fr_child; frp != NULL; frp = frp->fr_next) {
+ // All frames in this column get the same new width.
+ FOR_ALL_FRAMES(frp, topfrp->fr_child) {
frame_new_width(frp, width, leftfirst, wfw);
if (frp->fr_width > width) {
/* Could not fit the windows, make whole column wider. */
@@ -3235,7 +3241,8 @@ frame_new_width (
* Add the vertical separator to windows at the right side of "frp".
* Note: Does not check if there is room!
*/
-static void frame_add_vsep(frame_T *frp)
+static void frame_add_vsep(const frame_T *frp)
+ FUNC_ATTR_NONNULL_ARG(1)
{
win_T *wp;
@@ -3247,11 +3254,13 @@ static void frame_add_vsep(frame_T *frp)
wp->w_vsep_width = 1;
}
} else if (frp->fr_layout == FR_COL) {
- /* Handle all the frames in the column. */
- for (frp = frp->fr_child; frp != NULL; frp = frp->fr_next)
+ // Handle all the frames in the column.
+ FOR_ALL_FRAMES(frp, frp->fr_child) {
frame_add_vsep(frp);
- } else { /* frp->fr_layout == FR_ROW */
- /* Only need to handle the last frame in the row. */
+ }
+ } else {
+ assert(frp->fr_layout == FR_ROW);
+ // Only need to handle the last frame in the row.
frp = frp->fr_child;
while (frp->fr_next != NULL)
frp = frp->fr_next;
@@ -3301,7 +3310,7 @@ static int frame_minheight(frame_T *topfrp, win_T *next_curwin)
} else if (topfrp->fr_layout == FR_ROW) {
/* get the minimal height from each frame in this row */
m = 0;
- for (frp = topfrp->fr_child; frp != NULL; frp = frp->fr_next) {
+ FOR_ALL_FRAMES(frp, topfrp->fr_child) {
n = frame_minheight(frp, next_curwin);
if (n > m)
m = n;
@@ -3309,8 +3318,9 @@ static int frame_minheight(frame_T *topfrp, win_T *next_curwin)
} else {
/* Add up the minimal heights for all frames in this column. */
m = 0;
- for (frp = topfrp->fr_child; frp != NULL; frp = frp->fr_next)
+ FOR_ALL_FRAMES(frp, topfrp->fr_child) {
m += frame_minheight(frp, next_curwin);
+ }
}
return m;
@@ -3344,7 +3354,7 @@ frame_minwidth (
} else if (topfrp->fr_layout == FR_COL) {
/* get the minimal width from each frame in this column */
m = 0;
- for (frp = topfrp->fr_child; frp != NULL; frp = frp->fr_next) {
+ FOR_ALL_FRAMES(frp, topfrp->fr_child) {
n = frame_minwidth(frp, next_curwin);
if (n > m)
m = n;
@@ -3352,8 +3362,9 @@ frame_minwidth (
} else {
/* Add up the minimal widths for all frames in this row. */
m = 0;
- for (frp = topfrp->fr_child; frp != NULL; frp = frp->fr_next)
+ FOR_ALL_FRAMES(frp, topfrp->fr_child) {
m += frame_minwidth(frp, next_curwin);
+ }
}
return m;
@@ -4830,11 +4841,12 @@ static void frame_comp_pos(frame_T *topfrp, int *row, int *col)
} else {
startrow = *row;
startcol = *col;
- for (frp = topfrp->fr_child; frp != NULL; frp = frp->fr_next) {
- if (topfrp->fr_layout == FR_ROW)
- *row = startrow; /* all frames are at the same row */
- else
- *col = startcol; /* all frames are at the same col */
+ FOR_ALL_FRAMES(frp, topfrp->fr_child) {
+ if (topfrp->fr_layout == FR_ROW) {
+ *row = startrow; // all frames are at the same row
+ } else {
+ *col = startcol; // all frames are at the same col
+ }
frame_comp_pos(frp, row, col);
}
}
@@ -4943,15 +4955,16 @@ static void frame_setheight(frame_T *curfrp, int height)
for (run = 1; run <= 2; ++run) {
room = 0;
room_reserved = 0;
- for (frp = curfrp->fr_parent->fr_child; frp != NULL;
- frp = frp->fr_next) {
+ FOR_ALL_FRAMES(frp, curfrp->fr_parent->fr_child) {
if (frp != curfrp
&& frp->fr_win != NULL
- && frp->fr_win->w_p_wfh)
+ && frp->fr_win->w_p_wfh) {
room_reserved += frp->fr_height;
+ }
room += frp->fr_height;
- if (frp != curfrp)
+ if (frp != curfrp) {
room -= frame_minheight(frp, NULL);
+ }
}
if (curfrp->fr_width != Columns) {
room_cmdline = 0;
@@ -5124,15 +5137,16 @@ static void frame_setwidth(frame_T *curfrp, int width)
for (run = 1; run <= 2; ++run) {
room = 0;
room_reserved = 0;
- for (frp = curfrp->fr_parent->fr_child; frp != NULL;
- frp = frp->fr_next) {
+ FOR_ALL_FRAMES(frp, curfrp->fr_parent->fr_child) {
if (frp != curfrp
&& frp->fr_win != NULL
- && frp->fr_win->w_p_wfw)
+ && frp->fr_win->w_p_wfw) {
room_reserved += frp->fr_width;
+ }
room += frp->fr_width;
- if (frp != curfrp)
+ if (frp != curfrp) {
room -= frame_minwidth(frp, NULL);
+ }
}
if (width <= room)
@@ -5296,10 +5310,11 @@ void win_drag_status_line(win_T *dragwin, int offset)
room -= p_ch;
if (room < 0)
room = 0;
- /* sum up the room of frames below of the current one */
- for (fr = curfr->fr_next; fr != NULL; fr = fr->fr_next)
+ // sum up the room of frames below of the current one
+ FOR_ALL_FRAMES(fr, curfr->fr_next) {
room += fr->fr_height - frame_minheight(fr, NULL);
- fr = curfr; /* put fr at window that grows */
+ }
+ fr = curfr; // put fr at window that grows
}
if (room < offset) /* Not enough room */
@@ -5399,9 +5414,10 @@ void win_drag_vsep_line(win_T *dragwin, int offset)
left = FALSE;
/* sum up the room of frames right of the current one */
room = 0;
- for (fr = curfr->fr_next; fr != NULL; fr = fr->fr_next)
+ FOR_ALL_FRAMES(fr, curfr->fr_next) {
room += fr->fr_width - frame_minwidth(fr, NULL);
- fr = curfr; /* put fr at window that grows */
+ }
+ fr = curfr; // put fr at window that grows
}
assert(fr);
@@ -5933,9 +5949,10 @@ static void last_status_rec(frame_T *fr, int statusline)
redraw_all_later(SOME_VALID);
}
} else if (fr->fr_layout == FR_ROW) {
- /* vertically split windows, set status line for each one */
- for (fp = fr->fr_child; fp != NULL; fp = fp->fr_next)
+ // vertically split windows, set status line for each one
+ FOR_ALL_FRAMES(fp, fr->fr_child) {
last_status_rec(fp, statusline);
+ }
} else {
/* horizontally split window, set status line for last one */
for (fp = fr->fr_child; fp->fr_next != NULL; fp = fp->fr_next)
@@ -6551,14 +6568,15 @@ matchitem_T *get_match(win_T *wp, int id)
///
/// @param topfrp top frame pointer
/// @param height expected height
-static bool frame_check_height(frame_T *topfrp, int height)
+static bool frame_check_height(const frame_T *topfrp, int height)
FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL
{
if (topfrp->fr_height != height) {
return false;
}
if (topfrp->fr_layout == FR_ROW) {
- for (frame_T *frp = topfrp->fr_child; frp != NULL; frp = frp->fr_next) {
+ const frame_T *frp;
+ FOR_ALL_FRAMES(frp, topfrp->fr_child) {
if (frp->fr_height != height) {
return false;
}
@@ -6571,14 +6589,15 @@ static bool frame_check_height(frame_T *topfrp, int height)
///
/// @param topfrp top frame pointer
/// @param width expected width
-static bool frame_check_width(frame_T *topfrp, int width)
+static bool frame_check_width(const frame_T *topfrp, int width)
FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL
{
if (topfrp->fr_width != width) {
return false;
}
if (topfrp->fr_layout == FR_COL) {
- for (frame_T *frp = topfrp->fr_child; frp != NULL; frp = frp->fr_next) {
+ const frame_T *frp;
+ FOR_ALL_FRAMES(frp, topfrp->fr_child) {
if (frp->fr_width != width) {
return false;
}
diff --git a/test/functional/autocmd/cursorhold_spec.lua b/test/functional/autocmd/cursorhold_spec.lua
new file mode 100644
index 0000000000..506b688853
--- /dev/null
+++ b/test/functional/autocmd/cursorhold_spec.lua
@@ -0,0 +1,31 @@
+local helpers = require('test.functional.helpers')(after_each)
+
+local clear = helpers.clear
+local eq = helpers.eq
+local eval = helpers.eval
+local feed = helpers.feed
+local retry = helpers.retry
+local source = helpers.source
+local sleep = helpers.sleep
+
+describe('CursorHoldI', function()
+ before_each(clear)
+
+ -- NOTE: since this test uses RPC it is not necessary to trigger the initial
+ -- issue (#3757) via timer's or RPC callbacks in the first place.
+ it('is triggered after input', function()
+ source([[
+ set updatetime=1
+
+ let g:cursorhold = 0
+ augroup test
+ au CursorHoldI * let g:cursorhold += 1
+ augroup END
+ ]])
+ feed('ifoo')
+ retry(5, nil, function()
+ sleep(1)
+ eq(1, eval('g:cursorhold'))
+ end)
+ end)
+end)
diff --git a/test/functional/ui/highlight_spec.lua b/test/functional/ui/highlight_spec.lua
index 85b5aed2f8..08566fe493 100644
--- a/test/functional/ui/highlight_spec.lua
+++ b/test/functional/ui/highlight_spec.lua
@@ -311,6 +311,38 @@ describe('highlight defaults', function()
[1] = {foreground=Screen.colors.Blue},
})
end)
+
+ it('are sent to UIs', function()
+ screen:try_resize(53, 4)
+ screen:set_default_attr_ids({
+ [0] = {},
+ [1] = {bold = true, foreground = Screen.colors.Blue1},
+ [2] = {bold = true, reverse = true},
+ [3] = {italic=true}
+ })
+ screen:expect{grid=[[
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ |
+ ]], hl_groups={EndOfBuffer=1, MsgSeparator=2}}
+
+ command('highlight EndOfBuffer gui=italic')
+ screen:expect{grid=[[
+ ^ |
+ {3:~ }|
+ {3:~ }|
+ |
+ ]], hl_groups={EndOfBuffer=3, MsgSeparator=2}}
+
+ command('highlight clear EndOfBuffer')
+ screen:expect{grid=[[
+ ^ |
+ ~ |
+ ~ |
+ |
+ ]], hl_groups={EndOfBuffer=0, MsgSeparator=2}}
+ end)
end)
describe('highlight', function()
diff --git a/test/functional/ui/screen.lua b/test/functional/ui/screen.lua
index 31669f5578..eb059c38ee 100644
--- a/test/functional/ui/screen.lua
+++ b/test/functional/ui/screen.lua
@@ -165,6 +165,7 @@ function Screen.new(width, height)
showmode = {},
showcmd = {},
ruler = {},
+ hl_groups = {},
_default_attr_ids = nil,
_default_attr_ignore = nil,
_mouse_enabled = true,
@@ -322,7 +323,7 @@ function Screen:expect(expected, attr_ids, attr_ignore)
assert(not (attr_ids ~= nil or attr_ignore ~= nil))
local is_key = {grid=true, attr_ids=true, attr_ignore=true, condition=true,
any=true, mode=true, unchanged=true, intermediate=true,
- reset=true, timeout=true, request_cb=true}
+ reset=true, timeout=true, request_cb=true, hl_groups=true}
for _, v in ipairs(ext_keys) do
is_key[v] = true
end
@@ -418,9 +419,10 @@ screen:redraw_debug() to show all intermediate screen states. ]])
-- (e.g. no external cmdline visible). Some extensions require
-- preprocessing to represent highlights in a reproducible way.
local extstate = self:_extstate_repr(attr_state)
- if expected['mode'] ~= nil then
- extstate['mode'] = self.mode
+ if expected.mode ~= nil then
+ extstate.mode = self.mode
end
+
-- Convert assertion errors into invalid screen state descriptions.
for _, k in ipairs(concat_tables(ext_keys, {'mode'})) do
-- Empty states are considered the default and need not be mentioned.
@@ -431,6 +433,17 @@ screen:redraw_debug() to show all intermediate screen states. ]])
end
end
end
+
+ if expected.hl_groups ~= nil then
+ for name, id in pairs(expected.hl_groups) do
+ local expected_hl = attr_state.ids[id]
+ local actual_hl = self._attr_table[self.hl_groups[name]][(self._options.rgb and 1) or 2]
+ local status, res = pcall(eq, expected_hl, actual_hl, "highlight "..name)
+ if not status then
+ return tostring(res)
+ end
+ end
+ end
end, expected)
end
@@ -836,6 +849,10 @@ function Screen:_handle_hl_attr_define(id, rgb_attrs, cterm_attrs, info)
self._new_attrs = true
end
+function Screen:_handle_hl_group_set(name, id)
+ self.hl_groups[name] = id
+end
+
function Screen:get_hl(val)
if self._options.ext_newgrid then
return self._attr_table[val][1]
@@ -1411,17 +1428,17 @@ function Screen:_get_attr_id(attr_state, attrs, hl_id)
end
return "UNEXPECTED "..self:_pprint_attrs(self._attr_table[hl_id][1])
else
- for id, a in pairs(attr_state.ids) do
- if self:_equal_attrs(a, attrs) then
- return id
- end
- end
if self:_equal_attrs(attrs, {}) or
attr_state.ignore == true or
self:_attr_index(attr_state.ignore, attrs) ~= nil then
-- ignore this attrs
return nil
end
+ for id, a in pairs(attr_state.ids) do
+ if self:_equal_attrs(a, attrs) then
+ return id
+ end
+ end
if attr_state.mutable then
table.insert(attr_state.ids, attrs)
attr_state.modified = true
diff --git a/third-party/cmake/BuildLuarocks.cmake b/third-party/cmake/BuildLuarocks.cmake
index 7f038c732d..87e2946c96 100644
--- a/third-party/cmake/BuildLuarocks.cmake
+++ b/third-party/cmake/BuildLuarocks.cmake
@@ -163,7 +163,7 @@ if(USE_BUNDLED_BUSTED)
endif()
add_custom_command(OUTPUT ${BUSTED_EXE}
COMMAND ${LUAROCKS_BINARY}
- ARGS build busted 2.0.rc13-0 ${LUAROCKS_BUILDARGS}
+ ARGS build busted 2.0.0 ${LUAROCKS_BUILDARGS}
DEPENDS penlight)
add_custom_target(busted DEPENDS ${BUSTED_EXE})