aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/nvim/CMakeLists.txt4
-rw-r--r--src/nvim/api/ui.c1
-rw-r--r--src/nvim/api/ui_events.in.h2
-rw-r--r--src/nvim/api/vim.c18
-rw-r--r--src/nvim/api/window.c5
-rw-r--r--src/nvim/auevents.lua1
-rw-r--r--src/nvim/buffer.c5
-rw-r--r--src/nvim/buffer_defs.h14
-rw-r--r--src/nvim/edit.c4
-rw-r--r--src/nvim/eval.c66
-rw-r--r--src/nvim/eval.lua2
-rw-r--r--src/nvim/eval/typval_encode.c.h2
-rw-r--r--src/nvim/event/process.c10
-rw-r--r--src/nvim/ex_cmds2.c15
-rw-r--r--src/nvim/ex_docmd.c75
-rw-r--r--src/nvim/generators/gen_api_dispatch.lua3
-rw-r--r--src/nvim/getchar.c29
-rw-r--r--src/nvim/globals.h9
-rw-r--r--src/nvim/highlight.c41
-rw-r--r--src/nvim/highlight_defs.h2
-rw-r--r--src/nvim/main.c2
-rw-r--r--src/nvim/mark.c73
-rw-r--r--src/nvim/message.c4
-rw-r--r--src/nvim/misc1.c20
-rw-r--r--src/nvim/move.c1
-rw-r--r--src/nvim/msgpack_rpc/helpers.c5
-rw-r--r--src/nvim/normal.c23
-rw-r--r--src/nvim/ops.c48
-rw-r--r--src/nvim/option.c13
-rw-r--r--src/nvim/option_defs.h7
-rw-r--r--src/nvim/options.lua7
-rw-r--r--src/nvim/os/fs.c2
-rw-r--r--src/nvim/os/pty_process_unix.c10
-rw-r--r--src/nvim/os/time.c21
-rw-r--r--src/nvim/profile.c48
-rw-r--r--src/nvim/regexp_nfa.c29
-rw-r--r--src/nvim/screen.c27
-rw-r--r--src/nvim/search.c2
-rw-r--r--src/nvim/sign.c47
-rw-r--r--src/nvim/spell.c2
-rw-r--r--src/nvim/syntax.c47
-rw-r--r--src/nvim/testdir/Makefile33
-rw-r--r--src/nvim/testdir/runtest.vim9
-rw-r--r--src/nvim/testdir/test_assert.vim6
-rw-r--r--src/nvim/testdir/test_filter_cmd.vim58
-rw-r--r--src/nvim/testdir/test_functions.vim42
-rw-r--r--src/nvim/testdir/test_source.vim37
-rw-r--r--src/nvim/testdir/test_suspend.vim29
-rw-r--r--src/nvim/testdir/test_window_cmd.vim37
-rw-r--r--src/nvim/ugrid.c4
-rw-r--r--src/nvim/ui.c20
-rw-r--r--src/nvim/ui_compositor.c91
-rw-r--r--src/nvim/window.c232
53 files changed, 922 insertions, 422 deletions
diff --git a/src/nvim/CMakeLists.txt b/src/nvim/CMakeLists.txt
index 7807125b92..95ca1052af 100644
--- a/src/nvim/CMakeLists.txt
+++ b/src/nvim/CMakeLists.txt
@@ -164,8 +164,8 @@ if(NOT MSVC)
set_source_files_properties(
${CONV_SOURCES} PROPERTIES COMPILE_FLAGS "${COMPILE_FLAGS} -Wno-conversion")
# gperf generates ANSI-C with incorrect linkage, ignore it.
- check_c_compiler_flag(-Wno-static-in-inline HAS_WNO_STATIC_IN_INLINE_FLAG)
- if(HAS_WNO_STATIC_IN_INLINE_FLAG)
+ check_c_compiler_flag(-Wstatic-in-inline HAS_WSTATIC_IN_INLINE)
+ if(HAS_WSTATIC_IN_INLINE)
set_source_files_properties(
eval.c PROPERTIES COMPILE_FLAGS "${COMPILE_FLAGS} -Wno-static-in-inline -Wno-conversion")
else()
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/api/vim.c b/src/nvim/api/vim.c
index 8e5650633a..dbe3b66fd5 100644
--- a/src/nvim/api/vim.c
+++ b/src/nvim/api/vim.c
@@ -1064,6 +1064,19 @@ fail:
/// - `external`: GUI should display the window as an external
/// top-level window. Currently accepts no other positioning
/// configuration together with this.
+/// - `style`: Configure the apparance of the window. Currently only takes
+/// one non-empty value:
+/// - "minimal" Nvim will display the window with many UI options
+/// disabled. This is useful when displaing a temporary
+/// float where the text should not be edited. Disables
+/// 'number', 'relativenumber', 'cursorline', 'cursorcolumn',
+/// 'spell' and 'list' options. 'signcolumn' is changed to
+/// `auto`. The end-of-buffer region is hidden by setting
+/// `eob` flag of 'fillchars' to a space char, and clearing
+/// the |EndOfBuffer| region in 'winhighlight'.
+///
+/// top-level window. Currently accepts no other positioning
+/// configuration together with this.
/// @param[out] err Error details, if any
///
/// @return Window handle, or 0 on error
@@ -1085,6 +1098,11 @@ Window nvim_open_win(Buffer buffer, Boolean enter, Dictionary config,
if (buffer > 0) {
nvim_win_set_buf(wp->handle, buffer, err);
}
+
+ if (fconfig.style == kWinStyleMinimal) {
+ win_set_minimal_style(wp);
+ didset_window_options(wp);
+ }
return wp->handle;
}
diff --git a/src/nvim/api/window.c b/src/nvim/api/window.c
index 9fd1818a5c..4922dd7efc 100644
--- a/src/nvim/api/window.c
+++ b/src/nvim/api/window.c
@@ -13,6 +13,7 @@
#include "nvim/vim.h"
#include "nvim/buffer.h"
#include "nvim/cursor.h"
+#include "nvim/option.h"
#include "nvim/window.h"
#include "nvim/screen.h"
#include "nvim/move.h"
@@ -475,6 +476,10 @@ void nvim_win_set_config(Window window, Dictionary config, Error *err)
win_config_float(win, fconfig);
win->w_pos_changed = true;
}
+ if (fconfig.style == kWinStyleMinimal) {
+ win_set_minimal_style(win);
+ didset_window_options(win);
+ }
}
/// Return window configuration.
diff --git a/src/nvim/auevents.lua b/src/nvim/auevents.lua
index ef528f72b8..12fc8fd02a 100644
--- a/src/nvim/auevents.lua
+++ b/src/nvim/auevents.lua
@@ -77,6 +77,7 @@ return {
'Signal', -- after nvim process received a signal
'SourceCmd', -- sourcing a Vim script using command
'SourcePre', -- before sourcing a Vim script
+ 'SourcePost', -- after sourcing a Vim script
'SpellFileMissing', -- spell file missing
'StdinReadPost', -- after reading from stdin
'StdinReadPre', -- before reading from stdin
diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c
index d9ed9c6861..34fe52c10e 100644
--- a/src/nvim/buffer.c
+++ b/src/nvim/buffer.c
@@ -2543,6 +2543,11 @@ void get_winopts(buf_T *buf)
} else
copy_winopt(&curwin->w_allbuf_opt, &curwin->w_onebuf_opt);
+ if (curwin->w_float_config.style == kWinStyleMinimal) {
+ didset_window_options(curwin);
+ win_set_minimal_style(curwin);
+ }
+
// Set 'foldlevel' to 'foldlevelstart' if it's not negative.
if (p_fdls >= 0) {
curwin->w_p_fdl = p_fdls;
diff --git a/src/nvim/buffer_defs.h b/src/nvim/buffer_defs.h
index ad10f6baa2..a27672488e 100644
--- a/src/nvim/buffer_defs.h
+++ b/src/nvim/buffer_defs.h
@@ -972,7 +972,6 @@ struct matchitem {
};
typedef int FloatAnchor;
-typedef int FloatRelative;
enum {
kFloatAnchorEast = 1,
@@ -985,15 +984,20 @@ enum {
// SE -> kFloatAnchorSouth | kFloatAnchorEast
EXTERN const char *const float_anchor_str[] INIT(= { "NW", "NE", "SW", "SE" });
-enum {
+typedef enum {
kFloatRelativeEditor = 0,
kFloatRelativeWindow = 1,
kFloatRelativeCursor = 2,
-};
+} FloatRelative;
EXTERN const char *const float_relative_str[] INIT(= { "editor", "window",
"cursor" });
+typedef enum {
+ kWinStyleUnused = 0,
+ kWinStyleMinimal, /// Minimal UI: no number column, eob markers, etc
+} WinStyle;
+
typedef struct {
Window window;
int height, width;
@@ -1002,12 +1006,14 @@ typedef struct {
FloatRelative relative;
bool external;
bool focusable;
+ WinStyle style;
} FloatConfig;
#define FLOAT_CONFIG_INIT ((FloatConfig){ .height = 0, .width = 0, \
.row = 0, .col = 0, .anchor = 0, \
.relative = 0, .external = false, \
- .focusable = true })
+ .focusable = true, \
+ .style = kWinStyleUnused })
// Structure to store last cursor position and topline. Used by check_lnums()
// and reset_lnums().
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 becd4eaca1..7a8402a6bb 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;
@@ -7097,10 +7107,14 @@ static void f_assert_fails(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
const char *const cmd = tv_get_string_chk(&argvars[0]);
garray_T ga;
+ int save_trylevel = trylevel;
+ // trylevel must be zero for a ":throw" command to be considered failed
+ trylevel = 0;
called_emsg = false;
suppress_errthrow = true;
emsg_silent = true;
+
do_cmdline_cmd(cmd);
if (!called_emsg) {
prepare_assert_error(&ga);
@@ -7122,6 +7136,7 @@ static void f_assert_fails(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
}
+ trylevel = save_trylevel;
called_emsg = false;
suppress_errthrow = false;
emsg_silent = false;
@@ -7289,6 +7304,14 @@ static buf_T *find_buffer(typval_T *avar)
return buf;
}
+// "bufadd(expr)" function
+static void f_bufadd(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+{
+ char_u *name = (char_u *)tv_get_string(&argvars[0]);
+
+ rettv->vval.v_number = buflist_add(*name == NUL ? NULL : name, 0);
+}
+
/*
* "bufexists(expr)" function
*/
@@ -7308,6 +7331,21 @@ static void f_buflisted(typval_T *argvars, typval_T *rettv, FunPtr fptr)
rettv->vval.v_number = (buf != NULL && buf->b_p_bl);
}
+// "bufload(expr)" function
+static void f_bufload(typval_T *argvars, typval_T *unused, FunPtr fptr)
+{
+ buf_T *buf = get_buf_arg(&argvars[0]);
+
+ if (buf != NULL && buf->b_ml.ml_mfp == NULL) {
+ aco_save_T aco;
+
+ aucmd_prepbuf(&aco, buf);
+ swap_exists_action = SEA_NONE;
+ open_buffer(false, NULL, 0);
+ aucmd_restbuf(&aco);
+ }
+}
+
/*
* "bufloaded(expr)" function
*/
@@ -12189,8 +12227,16 @@ static void f_jobstop(typval_T *argvars, typval_T *rettv, FunPtr fptr)
return;
}
+ const char *error = NULL;
+ if (data->is_rpc) {
+ // Ignore return code, but show error later.
+ (void)channel_close(data->id, kChannelPartRpc, &error);
+ }
process_stop((Process *)&data->stream.proc);
rettv->vval.v_number = 1;
+ if (error) {
+ EMSG(error);
+ }
}
// "jobwait(ids[, timeout])" function
@@ -13802,7 +13848,7 @@ static void f_reltimestr(typval_T *argvars, typval_T *rettv, FunPtr fptr)
rettv->v_type = VAR_STRING;
rettv->vval.v_string = NULL;
if (list2proftime(&argvars[0], &tm) == OK) {
- rettv->vval.v_string = (char_u *) xstrdup(profile_msg(tm));
+ rettv->vval.v_string = (char_u *)xstrdup(profile_msg(tm));
}
}
@@ -15850,11 +15896,10 @@ static void f_sign_getplaced(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
if ((di = tv_dict_find(dict, "lnum", -1)) != NULL) {
// get signs placed at this line
- lnum = (linenr_T)tv_get_number_chk(&di->di_tv, &notanum);
- if (notanum) {
+ lnum = tv_get_lnum(&di->di_tv);
+ if (lnum <= 0) {
return;
}
- lnum = tv_get_lnum(&di->di_tv);
}
if ((di = tv_dict_find(dict, "id", -1)) != NULL) {
// get sign placed with this identifier
@@ -16536,7 +16581,7 @@ static void f_reltimefloat(typval_T *argvars , typval_T *rettv, FunPtr fptr)
rettv->v_type = VAR_FLOAT;
rettv->vval.v_float = 0;
if (list2proftime(&argvars[0], &tm) == OK) {
- rettv->vval.v_float = ((float_T)tm) / 1000000;
+ rettv->vval.v_float = ((float_T)tm) / 1000000000;
}
}
@@ -20682,11 +20727,11 @@ void ex_echohl(exarg_T *eap)
*/
void ex_execute(exarg_T *eap)
{
- char_u *arg = eap->arg;
+ char_u *arg = eap->arg;
typval_T rettv;
int ret = OK;
garray_T ga;
- int save_did_emsg = did_emsg;
+ int save_did_emsg;
ga_init(&ga, 1, 80);
@@ -20824,6 +20869,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/eval.lua b/src/nvim/eval.lua
index 9deee69f32..089b08d5d1 100644
--- a/src/nvim/eval.lua
+++ b/src/nvim/eval.lua
@@ -40,11 +40,13 @@ return {
atan2={args=2},
browse={args=4},
browsedir={args=2},
+ bufadd={args=1},
bufexists={args=1},
buffer_exists={args=1, func='f_bufexists'}, -- obsolete
buffer_name={args=1, func='f_bufname'}, -- obsolete
buffer_number={args=1, func='f_bufnr'}, -- obsolete
buflisted={args=1},
+ bufload={args=1},
bufloaded={args=1},
bufname={args=1},
bufnr={args={1, 2}},
diff --git a/src/nvim/eval/typval_encode.c.h b/src/nvim/eval/typval_encode.c.h
index 623bdfc93b..289c3ee99c 100644
--- a/src/nvim/eval/typval_encode.c.h
+++ b/src/nvim/eval/typval_encode.c.h
@@ -382,7 +382,7 @@ static int _TYPVAL_ENCODE_CONVERT_ONE_VALUE(
case VAR_SPECIAL: {
switch (tv->vval.v_special) {
case kSpecialVarNull: {
- TYPVAL_ENCODE_CONV_NIL(tv);
+ TYPVAL_ENCODE_CONV_NIL(tv); // -V1037
break;
}
case kSpecialVarTrue:
diff --git a/src/nvim/event/process.c b/src/nvim/event/process.c
index 7a8a39dbcf..990dee0c7f 100644
--- a/src/nvim/event/process.c
+++ b/src/nvim/event/process.c
@@ -26,6 +26,11 @@
// For PTY processes SIGTERM is sent first (in case SIGHUP was not enough).
#define KILL_TIMEOUT_MS 2000
+/// Externally defined with gcov.
+#ifdef USE_GCOV
+void __gcov_flush(void);
+#endif
+
static bool process_is_tearing_down = false;
/// @returns zero on success, or negative error code
@@ -50,6 +55,11 @@ int process_spawn(Process *proc, bool in, bool out, bool err)
proc->err.closed = true;
}
+#ifdef USE_GCOV
+ // Flush coverage data before forking, to avoid "Merge mismatch" errors.
+ __gcov_flush();
+#endif
+
int status;
switch (proc->type) {
case kProcessTypeUv:
diff --git a/src/nvim/ex_cmds2.c b/src/nvim/ex_cmds2.c
index 2fb818760a..c092036ce9 100644
--- a/src/nvim/ex_cmds2.c
+++ b/src/nvim/ex_cmds2.c
@@ -3039,6 +3039,7 @@ int do_source(char_u *fname, int check_other, int is_vimrc)
int save_debug_break_level = debug_break_level;
scriptitem_T *si = NULL;
proftime_T wait_start;
+ bool trigger_source_post = false;
p = expand_env_save(fname);
if (p == NULL) {
@@ -3059,6 +3060,10 @@ int do_source(char_u *fname, int check_other, int is_vimrc)
&& apply_autocmds(EVENT_SOURCECMD, fname_exp, fname_exp,
false, curbuf)) {
retval = aborting() ? FAIL : OK;
+ if (retval == OK) {
+ // Apply SourcePost autocommands.
+ apply_autocmds(EVENT_SOURCEPOST, fname_exp, fname_exp, false, curbuf);
+ }
goto theend;
}
@@ -3181,7 +3186,7 @@ int do_source(char_u *fname, int check_other, int is_vimrc)
}
si = &SCRIPT_ITEM(current_SID);
si->sn_name = fname_exp;
- fname_exp = NULL;
+ fname_exp = vim_strsave(si->sn_name); // used for autocmd
if (file_id_ok) {
si->file_id_valid = true;
si->file_id = file_id;
@@ -3261,6 +3266,10 @@ int do_source(char_u *fname, int check_other, int is_vimrc)
time_pop(rel_time);
}
+ if (!got_int) {
+ trigger_source_post = true;
+ }
+
// After a "finish" in debug mode, need to break at first command of next
// sourced file.
if (save_debug_break_level > ex_nesting_level
@@ -3278,6 +3287,10 @@ int do_source(char_u *fname, int check_other, int is_vimrc)
xfree(firstline);
convert_setup(&cookie.conv, NULL, NULL);
+ if (trigger_source_post) {
+ apply_autocmds(EVENT_SOURCEPOST, fname_exp, fname_exp, false, curbuf);
+ }
+
theend:
xfree(fname_exp);
return retval;
diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c
index a494463f89..59e6f227e4 100644
--- a/src/nvim/ex_docmd.c
+++ b/src/nvim/ex_docmd.c
@@ -1108,9 +1108,8 @@ static int current_tab_nr(tabpage_T *tab)
#define CURRENT_TAB_NR current_tab_nr(curtab)
#define LAST_TAB_NR current_tab_nr(NULL)
-/*
-* Figure out the address type for ":wincmd".
-*/
+
+/// Figure out the address type for ":wincmd".
static void get_wincmd_addr_type(char_u *arg, exarg_T *eap)
{
switch (*arg) {
@@ -1156,13 +1155,13 @@ static void get_wincmd_addr_type(char_u *arg, exarg_T *eap)
case Ctrl_I:
case 'd':
case Ctrl_D:
- /* window size or any count */
- eap->addr_type = ADDR_LINES;
+ // window size or any count
+ eap->addr_type = ADDR_LINES; // -V1037
break;
case Ctrl_HAT:
case '^':
- /* buffer number */
+ // buffer number
eap->addr_type = ADDR_BUFFERS;
break;
@@ -1177,7 +1176,7 @@ static void get_wincmd_addr_type(char_u *arg, exarg_T *eap)
case 'W':
case 'x':
case Ctrl_X:
- /* window number */
+ // window number
eap->addr_type = ADDR_WINDOWS;
break;
@@ -1192,7 +1191,7 @@ static void get_wincmd_addr_type(char_u *arg, exarg_T *eap)
case Ctrl_P:
case '=':
case CAR:
- /* no count */
+ // no count
eap->addr_type = 0;
break;
}
@@ -6922,16 +6921,17 @@ static void ex_resize(exarg_T *eap)
n = atol((char *)eap->arg);
if (cmdmod.split & WSP_VERT) {
- if (*eap->arg == '-' || *eap->arg == '+')
+ if (*eap->arg == '-' || *eap->arg == '+') {
n += curwin->w_width;
- else if (n == 0 && eap->arg[0] == NUL) /* default is very wide */
- n = 9999;
+ } else if (n == 0 && eap->arg[0] == NUL) { // default is very wide
+ n = Columns;
+ }
win_setwidth_win(n, wp);
} else {
if (*eap->arg == '-' || *eap->arg == '+') {
n += curwin->w_height;
} else if (n == 0 && eap->arg[0] == NUL) { // default is very high
- n = 9999;
+ n = Rows-1;
}
win_setheight_win(n, wp);
}
@@ -8452,24 +8452,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;
@@ -9322,26 +9321,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/generators/gen_api_dispatch.lua b/src/nvim/generators/gen_api_dispatch.lua
index 95dcbc732e..76dcf849d1 100644
--- a/src/nvim/generators/gen_api_dispatch.lua
+++ b/src/nvim/generators/gen_api_dispatch.lua
@@ -198,7 +198,8 @@ for i = 1, #functions do
output:write('Object handle_'..fn.name..'(uint64_t channel_id, Array args, Error *error)')
output:write('\n{')
output:write('\n#if MIN_LOG_LEVEL <= DEBUG_LOG_LEVEL')
- output:write('\n logmsg(DEBUG_LOG_LEVEL, "RPC: ", NULL, -1, true, "invoke '..fn.name..'");')
+ output:write('\n logmsg(DEBUG_LOG_LEVEL, "RPC: ", NULL, -1, true, "ch %" PRIu64 ": invoke '
+ ..fn.name..'", channel_id);')
output:write('\n#endif')
output:write('\n Object ret = NIL;')
-- Declare/initialize variables that will hold converted arguments
diff --git a/src/nvim/getchar.c b/src/nvim/getchar.c
index 7efae1e637..64722ef35d 100644
--- a/src/nvim/getchar.c
+++ b/src/nvim/getchar.c
@@ -15,6 +15,7 @@
#include <string.h>
#include <inttypes.h>
+#include "nvim/assert.h"
#include "nvim/vim.h"
#include "nvim/ascii.h"
#include "nvim/getchar.h"
@@ -905,18 +906,19 @@ int ins_typebuf(char_u *str, int noremap, int offset, int nottyped, bool silent)
s2 = xmalloc((size_t)newlen);
typebuf.tb_buflen = newlen;
- /* copy the old chars, before the insertion point */
- memmove(s1 + newoff, typebuf.tb_buf + typebuf.tb_off,
- (size_t)offset);
- /* copy the new chars */
+ // copy the old chars, before the insertion point
+ memmove(s1 + newoff, typebuf.tb_buf + typebuf.tb_off, (size_t)offset);
+ // copy the new chars
memmove(s1 + newoff + offset, str, (size_t)addlen);
- /* copy the old chars, after the insertion point, including the NUL at
- * the end */
+ // copy the old chars, after the insertion point, including the NUL at
+ // the end
+ int bytes = typebuf.tb_len - offset + 1;
+ assert(bytes > 0);
memmove(s1 + newoff + offset + addlen,
- typebuf.tb_buf + typebuf.tb_off + offset,
- (size_t)(typebuf.tb_len - offset + 1));
- if (typebuf.tb_buf != typebuf_init)
+ typebuf.tb_buf + typebuf.tb_off + offset, (size_t)bytes);
+ if (typebuf.tb_buf != typebuf_init) {
xfree(typebuf.tb_buf);
+ }
typebuf.tb_buf = s1;
memmove(s2 + newoff, typebuf.tb_noremap + typebuf.tb_off,
@@ -1062,11 +1064,12 @@ void del_typebuf(int len, int offset)
typebuf.tb_noremap + typebuf.tb_off, (size_t)offset);
typebuf.tb_off = MAXMAPLEN;
}
- /* adjust typebuf.tb_buf (include the NUL at the end) */
+ // adjust typebuf.tb_buf (include the NUL at the end)
+ int bytes = typebuf.tb_len - offset + 1;
+ assert(bytes > 0);
memmove(typebuf.tb_buf + typebuf.tb_off + offset,
- typebuf.tb_buf + i + len,
- (size_t)(typebuf.tb_len - offset + 1));
- /* adjust typebuf.tb_noremap[] */
+ typebuf.tb_buf + i + len, (size_t)bytes);
+ // adjust typebuf.tb_noremap[]
memmove(typebuf.tb_noremap + typebuf.tb_off + offset,
typebuf.tb_noremap + i + len,
(size_t)(typebuf.tb_len - offset));
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 15c3d0eb7b..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]);
+ }
}
}
@@ -141,10 +146,12 @@ int hl_get_ui_attr(int idx, int final_id, bool optional)
HlAttrs attrs = HLATTRS_INIT;
bool available = false;
- int syn_attr = syn_id2attr(final_id);
- if (syn_attr != 0) {
- attrs = syn_attr2entry(syn_attr);
- available = true;
+ if (final_id > 0) {
+ int syn_attr = syn_id2attr(final_id);
+ if (syn_attr != 0) {
+ attrs = syn_attr2entry(syn_attr);
+ available = true;
+ }
}
if (HLF_PNI <= idx && idx <= HLF_PST) {
@@ -176,15 +183,14 @@ void update_window_hl(win_T *wp, bool invalid)
// determine window specific background set in 'winhighlight'
bool float_win = wp->w_floating && !wp->w_float_config.external;
- if (wp != curwin && wp->w_hl_ids[HLF_INACTIVE] > 0) {
+ if (wp != curwin && wp->w_hl_ids[HLF_INACTIVE] != 0) {
wp->w_hl_attr_normal = hl_get_ui_attr(HLF_INACTIVE,
wp->w_hl_ids[HLF_INACTIVE],
!has_blend);
- } else if (float_win && wp->w_hl_ids[HLF_NFLOAT] > 0) {
+ } else if (float_win && wp->w_hl_ids[HLF_NFLOAT] != 0) {
wp->w_hl_attr_normal = hl_get_ui_attr(HLF_NFLOAT,
- // 'cursorline'
wp->w_hl_ids[HLF_NFLOAT], !has_blend);
- } else if (wp->w_hl_id_normal > 0) {
+ } else if (wp->w_hl_id_normal != 0) {
wp->w_hl_attr_normal = hl_get_ui_attr(-1, wp->w_hl_id_normal, !has_blend);
} else {
wp->w_hl_attr_normal = float_win ? HL_ATTR(HLF_NFLOAT) : 0;
@@ -199,14 +205,14 @@ void update_window_hl(win_T *wp, bool invalid)
}
}
- if (wp != curwin) {
+ if (wp != curwin && wp->w_hl_ids[HLF_INACTIVE] == 0) {
wp->w_hl_attr_normal = hl_combine_attr(HL_ATTR(HLF_INACTIVE),
wp->w_hl_attr_normal);
}
for (int hlf = 0; hlf < (int)HLF_COUNT; hlf++) {
int attr;
- if (wp->w_hl_ids[hlf] > 0) {
+ if (wp->w_hl_ids[hlf] != 0) {
attr = hl_get_ui_attr(hlf, wp->w_hl_ids[hlf], false);
} else {
attr = HL_ATTR(hlf);
@@ -250,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 60f571ff0f..afccf9e6f6 100644
--- a/src/nvim/highlight_defs.h
+++ b/src/nvim/highlight_defs.h
@@ -36,6 +36,7 @@ typedef struct attr_entry {
.rgb_sp_color = -1, \
.cterm_fg_color = 0, \
.cterm_bg_color = 0, \
+ .hl_blend = -1, \
}
/// Values for index in highlight_attr[].
@@ -149,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/main.c b/src/nvim/main.c
index 306d2f7bf5..b3654a0690 100644
--- a/src/nvim/main.c
+++ b/src/nvim/main.c
@@ -54,6 +54,7 @@
#include "nvim/strings.h"
#include "nvim/syntax.h"
#include "nvim/ui.h"
+#include "nvim/ui_compositor.h"
#include "nvim/version.h"
#include "nvim/window.h"
#include "nvim/shada.h"
@@ -220,6 +221,7 @@ void early_init(void)
set_lang_var(); // set v:lang and v:ctype
init_signs();
+ ui_comp_syn_init();
}
#ifdef MAKE_LIB
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/misc1.c b/src/nvim/misc1.c
index 6738e59bb2..5a5bd16b98 100644
--- a/src/nvim/misc1.c
+++ b/src/nvim/misc1.c
@@ -495,9 +495,14 @@ open_line (
}
if (lead_len > 0) {
// allocate buffer (may concatenate p_extra later)
- leader = xmalloc((size_t)(lead_len + lead_repl_len + extra_space
- + extra_len + (second_line_indent > 0
- ? second_line_indent : 0) + 1));
+ int bytes = lead_len
+ + lead_repl_len
+ + extra_space
+ + extra_len
+ + (second_line_indent > 0 ? second_line_indent : 0)
+ + 1;
+ assert(bytes >= 0);
+ leader = xmalloc((size_t)bytes);
allocated = leader; // remember to free it later
STRLCPY(leader, saved_line, lead_len + 1);
@@ -1556,11 +1561,14 @@ void ins_str(char_u *s)
oldp = ml_get(lnum);
oldlen = (int)STRLEN(oldp);
- newp = (char_u *) xmalloc((size_t)(oldlen + newlen + 1));
- if (col > 0)
+ newp = (char_u *)xmalloc((size_t)oldlen + (size_t)newlen + 1);
+ if (col > 0) {
memmove(newp, oldp, (size_t)col);
+ }
memmove(newp + col, s, (size_t)newlen);
- memmove(newp + col + newlen, oldp + col, (size_t)(oldlen - col + 1));
+ int bytes = oldlen - col + 1;
+ assert(bytes >= 0);
+ memmove(newp + col + newlen, oldp + col, (size_t)bytes);
ml_replace(lnum, newp, false);
changed_bytes(lnum, col);
curwin->w_cursor.col += newlen;
diff --git a/src/nvim/move.c b/src/nvim/move.c
index e076543614..05db39b981 100644
--- a/src/nvim/move.c
+++ b/src/nvim/move.c
@@ -119,7 +119,6 @@ static void redraw_for_cursorline(win_T *wp)
// the current window.
redrawWinline(wp, wp->w_last_cursorline);
redrawWinline(wp, wp->w_cursor.lnum);
- redraw_win_later(wp, VALID);
} else {
redraw_win_later(wp, SOME_VALID);
}
diff --git a/src/nvim/msgpack_rpc/helpers.c b/src/nvim/msgpack_rpc/helpers.c
index 3f768dcc0c..18b0bf3c16 100644
--- a/src/nvim/msgpack_rpc/helpers.c
+++ b/src/nvim/msgpack_rpc/helpers.c
@@ -384,10 +384,7 @@ void msgpack_rpc_from_object(const Object result, msgpack_packer *const res)
&& kObjectTypeTabpage == kObjectTypeWindow + 1,
"Buffer, window and tabpage enum items are in order");
switch (cur.aobj->type) {
- case kObjectTypeNil: {
- msgpack_pack_nil(res);
- break;
- }
+ case kObjectTypeNil:
case kObjectTypeLuaRef: {
// TODO(bfredl): could also be an error. Though kObjectTypeLuaRef
// should only appear when the caller has opted in to handle references,
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 b96e075f66..0f26d83597 100644
--- a/src/nvim/ops.c
+++ b/src/nvim/ops.c
@@ -379,8 +379,10 @@ static void shift_block(oparg_T *oap, int amount)
/* if we're splitting a TAB, allow for it */
bd.textcol -= bd.pre_whitesp_c - (bd.startspaces != 0);
const int len = (int)STRLEN(bd.textstart) + 1;
- newp = (char_u *)xmalloc((size_t)(bd.textcol + i + j + len));
- memset(newp, NUL, (size_t)(bd.textcol + i + j + len));
+ int col = bd.textcol + i +j + len;
+ assert(col >= 0);
+ newp = (char_u *)xmalloc((size_t)col);
+ memset(newp, NUL, (size_t)col);
memmove(newp, oldp, (size_t)bd.textcol);
memset(newp + bd.textcol, TAB, (size_t)i);
memset(newp + bd.textcol + i, ' ', (size_t)j);
@@ -1471,7 +1473,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 +1746,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 +1763,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 +1776,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);
}
@@ -2602,8 +2606,9 @@ static void op_yank_reg(oparg_T *oap, bool message, yankreg_T *reg, bool append)
static void yank_copy_line(yankreg_T *reg, struct block_def *bd, size_t y_idx)
{
- char_u *pnew = xmallocz((size_t)(bd->startspaces + bd->endspaces
- + bd->textlen));
+ int size = bd->startspaces + bd->endspaces + bd->textlen;
+ assert(size >= 0);
+ char_u *pnew = xmallocz((size_t)size);
reg->y_array[y_idx] = pnew;
memset(pnew, ' ', (size_t)bd->startspaces);
pnew += bd->startspaces;
@@ -3085,8 +3090,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 +3215,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 +3711,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 +5478,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);
}
}
@@ -5490,8 +5496,10 @@ void cursor_pos_info(dict_T *dict)
if (l_VIsual_active) {
if (l_VIsual_mode == Ctrl_V && curwin->w_curswant < MAXCOL) {
getvcols(curwin, &min_pos, &max_pos, &min_pos.col, &max_pos.col);
+ int64_t cols;
+ STRICT_SUB(oparg.end_vcol + 1, oparg.start_vcol, &cols, int64_t);
vim_snprintf((char *)buf1, sizeof(buf1), _("%" PRId64 " Cols; "),
- (int64_t)(oparg.end_vcol - oparg.start_vcol + 1));
+ cols);
} else {
buf1[0] = NUL;
}
diff --git a/src/nvim/option.c b/src/nvim/option.c
index 62f736ea31..8483c02bbe 100644
--- a/src/nvim/option.c
+++ b/src/nvim/option.c
@@ -2191,6 +2191,7 @@ static void didset_options(void)
(void)opt_strings_flags(p_vop, p_ssop_values, &vop_flags, true);
(void)opt_strings_flags(p_fdo, p_fdo_values, &fdo_flags, true);
(void)opt_strings_flags(p_dy, p_dy_values, &dy_flags, true);
+ (void)opt_strings_flags(p_rdb, p_rdb_values, &rdb_flags, true);
(void)opt_strings_flags(p_tc, p_tc_values, &tc_flags, false);
(void)opt_strings_flags(p_ve, p_ve_values, &ve_flags, true);
(void)opt_strings_flags(p_wop, p_wop_values, &wop_flags, true);
@@ -2650,6 +2651,10 @@ did_set_string_option(
if (opt_strings_flags(p_vop, p_ssop_values, &vop_flags, true) != OK) {
errmsg = e_invarg;
}
+ } else if (varp == &p_rdb) { // 'redrawdebug'
+ if (opt_strings_flags(p_rdb, p_rdb_values, &rdb_flags, true) != OK) {
+ errmsg = e_invarg;
+ }
} else if (varp == &p_sbo) { // 'scrollopt'
if (check_opt_strings(p_sbo, p_scbopt_values, true) != OK) {
errmsg = e_invarg;
@@ -3762,7 +3767,8 @@ static bool parse_winhl_opt(win_T *wp)
size_t nlen = (size_t)(colon-p);
char *hi = colon+1;
char *commap = xstrchrnul(hi, ',');
- int hl_id = syn_check_group((char_u *)hi, (int)(commap-hi));
+ int len = (int)(commap-hi);
+ int hl_id = len ? syn_check_group((char_u *)hi, len) : -1;
if (strncmp("Normal", p, nlen) == 0) {
w_hl_id_normal = hl_id;
@@ -5041,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/option_defs.h b/src/nvim/option_defs.h
index 35fe3b5b00..a480de735d 100644
--- a/src/nvim/option_defs.h
+++ b/src/nvim/option_defs.h
@@ -511,6 +511,13 @@ EXTERN char_u *p_pm; // 'patchmode'
EXTERN char_u *p_path; // 'path'
EXTERN char_u *p_cdpath; // 'cdpath'
EXTERN long p_pyx; // 'pyxversion'
+EXTERN char_u *p_rdb; // 'redrawdebug'
+EXTERN unsigned rdb_flags;
+# ifdef IN_OPTION_C
+static char *(p_rdb_values[]) = { "compositor", NULL };
+# endif
+# define RDB_COMPOSITOR 0x001
+
EXTERN long p_rdt; // 'redrawtime'
EXTERN int p_remap; // 'remap'
EXTERN long p_re; // 'regexpengine'
diff --git a/src/nvim/options.lua b/src/nvim/options.lua
index 27f72f6441..c48366e205 100644
--- a/src/nvim/options.lua
+++ b/src/nvim/options.lua
@@ -1848,6 +1848,13 @@ return {
defaults={if_true={vi=false}}
},
{
+ full_name='redrawdebug', abbreviation='rdb',
+ type='string', list='onecomma', scope={'global'},
+ vi_def=true,
+ varname='p_rdb',
+ defaults={if_true={vi=''}}
+ },
+ {
full_name='redrawtime', abbreviation='rdt',
type='number', scope={'global'},
vi_def=true,
diff --git a/src/nvim/os/fs.c b/src/nvim/os/fs.c
index 65362b545f..4a10b5199c 100644
--- a/src/nvim/os/fs.c
+++ b/src/nvim/os/fs.c
@@ -364,7 +364,7 @@ static bool is_executable_in_path(const char_u *name, char_u **abspath)
#ifdef WIN32
// Prepend ".;" to $PATH.
size_t pathlen = strlen(path_env);
- char *path = memcpy(xmallocz(pathlen + 3), "." ENV_SEPSTR, 2);
+ char *path = memcpy(xmallocz(pathlen + 2), "." ENV_SEPSTR, 2);
memcpy(path + 2, path_env, pathlen);
#else
char *path = xstrdup(path_env);
diff --git a/src/nvim/os/pty_process_unix.c b/src/nvim/os/pty_process_unix.c
index 97545a6cb1..5fdf0e6181 100644
--- a/src/nvim/os/pty_process_unix.c
+++ b/src/nvim/os/pty_process_unix.c
@@ -36,11 +36,6 @@
# include "os/pty_process_unix.c.generated.h"
#endif
-/// Externally defined with gcov.
-#ifdef USE_GCOV
-void __gcov_flush(void);
-#endif
-
/// termios saved at startup (for TUI) or initialized by pty_process_spawn().
static struct termios termios_default;
@@ -64,11 +59,6 @@ int pty_process_spawn(PtyProcess *ptyproc)
init_termios(&termios_default);
}
-#ifdef USE_GCOV
- // Flush coverage data before forking, to avoid "Merge mismatch" errors.
- __gcov_flush();
-#endif
-
int status = 0; // zero or negative error code (libuv convention)
Process *proc = (Process *)ptyproc;
assert(proc->err.closed);
diff --git a/src/nvim/os/time.c b/src/nvim/os/time.c
index 18239c5566..4dd0614fe2 100644
--- a/src/nvim/os/time.c
+++ b/src/nvim/os/time.c
@@ -31,27 +31,6 @@ void time_init(void)
uv_cond_init(&delay_cond);
}
-/// Gets the current time with microsecond (μs) precision.
-///
-/// Subject to system-clock quirks (drift, going backwards, skipping).
-/// But it is much faster than os_hrtime() on some systems. #10328
-///
-/// @see gettimeofday(2)
-///
-/// @return Current time in microseconds.
-uint64_t os_utime(void)
- FUNC_ATTR_WARN_UNUSED_RESULT
-{
- uv_timeval64_t tm;
- int e = uv_gettimeofday(&tm);
- if (e != 0 || tm.tv_sec < 0 || tm.tv_usec < 0) {
- return 0;
- }
- uint64_t rv = (uint64_t)tm.tv_sec * 1000 * 1000; // s => μs
- STRICT_ADD(rv, tm.tv_usec, &rv, uint64_t);
- return rv;
-}
-
/// Gets a high-resolution (nanosecond), monotonically-increasing time relative
/// to an arbitrary time in the past.
///
diff --git a/src/nvim/profile.c b/src/nvim/profile.c
index cc12e00396..a6314e7b9d 100644
--- a/src/nvim/profile.c
+++ b/src/nvim/profile.c
@@ -5,6 +5,7 @@
#include <math.h>
#include <assert.h>
+#include "nvim/assert.h"
#include "nvim/profile.h"
#include "nvim/os/time.h"
#include "nvim/func_attr.h"
@@ -23,7 +24,7 @@ static proftime_T prof_wait_time;
/// @return the current time
proftime_T profile_start(void) FUNC_ATTR_WARN_UNUSED_RESULT
{
- return os_utime();
+ return os_hrtime();
}
/// Computes the time elapsed.
@@ -31,7 +32,7 @@ proftime_T profile_start(void) FUNC_ATTR_WARN_UNUSED_RESULT
/// @return Elapsed time from `tm` until now.
proftime_T profile_end(proftime_T tm) FUNC_ATTR_WARN_UNUSED_RESULT
{
- return profile_sub(os_utime(), tm);
+ return profile_sub(os_hrtime(), tm);
}
/// Gets a string representing time `tm`.
@@ -43,7 +44,8 @@ proftime_T profile_end(proftime_T tm) FUNC_ATTR_WARN_UNUSED_RESULT
const char *profile_msg(proftime_T tm) FUNC_ATTR_WARN_UNUSED_RESULT
{
static char buf[50];
- snprintf(buf, sizeof(buf), "%10.6lf", (double)tm / 1000000.0);
+ snprintf(buf, sizeof(buf), "%10.6lf",
+ (double)profile_signed(tm) / 1000000000.0);
return buf;
}
@@ -59,10 +61,9 @@ proftime_T profile_setlimit(int64_t msec) FUNC_ATTR_WARN_UNUSED_RESULT
// no limit
return profile_zero();
}
- assert(msec <= (INT64_MAX / 1000LL) - 1);
-
- proftime_T usec = (proftime_T)msec * 1000ULL;
- return os_utime() + usec;
+ assert(msec <= (INT64_MAX / 1000000LL) - 1);
+ proftime_T nsec = (proftime_T)msec * 1000000ULL;
+ return os_hrtime() + nsec;
}
/// Checks if current time has passed `tm`.
@@ -75,7 +76,8 @@ bool profile_passed_limit(proftime_T tm) FUNC_ATTR_WARN_UNUSED_RESULT
// timer was not set
return false;
}
- return profile_cmp(os_utime(), tm) < 0;
+
+ return profile_cmp(os_hrtime(), tm) < 0;
}
/// Gets the zero time.
@@ -108,10 +110,15 @@ proftime_T profile_add(proftime_T tm1, proftime_T tm2) FUNC_ATTR_CONST
/// Subtracts time `tm2` from `tm1`.
///
+/// Unsigned overflow (wraparound) occurs if `tm2` is greater than `tm1`.
+/// Use `profile_signed()` to get the signed integer value.
+///
+/// @see profile_signed
+///
/// @return `tm1` - `tm2`
proftime_T profile_sub(proftime_T tm1, proftime_T tm2) FUNC_ATTR_CONST
{
- return tm1 > tm2 ? tm1 - tm2 : 0; // os_utime() may go backwards.
+ return tm1 - tm2;
}
/// Adds the `self` time from the total time and the `children` time.
@@ -162,22 +169,31 @@ bool profile_equal(proftime_T tm1, proftime_T tm2) FUNC_ATTR_CONST
return tm1 == tm2;
}
-/// Calculates the sign of a 64-bit integer.
+/// Converts a proftime_T value `tm` to a signed integer.
///
-/// @return -1, 0, or +1
-static inline int sgn64(int64_t x) FUNC_ATTR_CONST
+/// @return signed representation of the given time value
+int64_t profile_signed(proftime_T tm)
+ FUNC_ATTR_CONST
{
- return (int) ((x > 0) - (x < 0));
+ // (tm > INT64_MAX) is >=150 years, so we can assume it was produced by
+ // arithmetic of two proftime_T values. For human-readable representation
+ // (and Vim-compat) we want the difference after unsigned wraparound. #10452
+ return (tm <= INT64_MAX) ? (int64_t)tm : -(int64_t)(UINT64_MAX - tm);
}
/// Compares profiling times.
///
/// Times `tm1` and `tm2` must be less than 150 years apart.
///
-/// @return <0, 0 or >0 if `tm2` < `tm1`, `tm2` == `tm1` or `tm2` > `tm1`
+/// @return <0: `tm2` < `tm1`
+/// 0: `tm2` == `tm1`
+/// >0: `tm2` > `tm1`
int profile_cmp(proftime_T tm1, proftime_T tm2) FUNC_ATTR_CONST
{
- return sgn64((int64_t)(tm2 - tm1));
+ if (tm1 == tm2) {
+ return 0;
+ }
+ return profile_signed(tm2 - tm1) < 0 ? -1 : 1;
}
/// globals for use in the startuptime related functionality (time_*).
@@ -219,7 +235,7 @@ void time_pop(proftime_T tp)
static void time_diff(proftime_T then, proftime_T now)
{
proftime_T diff = profile_sub(now, then);
- fprintf(time_fd, "%07.3lf", (double)diff / 1.0E3);
+ fprintf(time_fd, "%07.3lf", (double)diff / 1.0E6);
}
/// Initializes the startuptime code.
diff --git a/src/nvim/regexp_nfa.c b/src/nvim/regexp_nfa.c
index dc1ab971ab..a8919560a0 100644
--- a/src/nvim/regexp_nfa.c
+++ b/src/nvim/regexp_nfa.c
@@ -1263,8 +1263,8 @@ static int nfa_regatom(void)
IEMSGN("INTERNAL: Unknown character class char: %" PRId64, c);
return FAIL;
}
- /* When '.' is followed by a composing char ignore the dot, so that
- * the composing char is matched here. */
+ // When '.' is followed by a composing char ignore the dot, so that
+ // the composing char is matched here.
if (enc_utf8 && c == Magic('.') && utf_iscomposing(peekchr())) {
old_regparse = regparse;
c = getchr();
@@ -1279,25 +1279,26 @@ static int nfa_regatom(void)
break;
case Magic('n'):
- if (reg_string)
- /* In a string "\n" matches a newline character. */
+ if (reg_string) {
+ // In a string "\n" matches a newline character.
EMIT(NL);
- else {
- /* In buffer text "\n" matches the end of a line. */
+ } else {
+ // In buffer text "\n" matches the end of a line.
EMIT(NFA_NEWL);
regflags |= RF_HASNL;
}
break;
case Magic('('):
- if (nfa_reg(REG_PAREN) == FAIL)
- return FAIL; /* cascaded error */
+ if (nfa_reg(REG_PAREN) == FAIL) {
+ return FAIL; // cascaded error
+ }
break;
case Magic('|'):
case Magic('&'):
case Magic(')'):
- EMSGN(_(e_misplaced), no_Magic(c));
+ EMSGN(_(e_misplaced), no_Magic(c)); // -V1037
return FAIL;
case Magic('='):
@@ -1306,7 +1307,7 @@ static int nfa_regatom(void)
case Magic('@'):
case Magic('*'):
case Magic('{'):
- /* these should follow an atom, not form an atom */
+ // these should follow an atom, not form an atom
EMSGN(_(e_misplaced), no_Magic(c));
return FAIL;
@@ -1314,8 +1315,8 @@ static int nfa_regatom(void)
{
char_u *lp;
- /* Previous substitute pattern.
- * Generated as "\%(pattern\)". */
+ // Previous substitute pattern.
+ // Generated as "\%(pattern\)".
if (reg_prev_sub == NULL) {
EMSG(_(e_nopresub));
return FAIL;
@@ -3002,8 +3003,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 846ffeb442..2f8b1b6b02 100644
--- a/src/nvim/screen.c
+++ b/src/nvim/screen.c
@@ -1612,7 +1612,8 @@ static void win_draw_end(win_T *wp, int c1, int c2, bool draw_margin, int row,
}
}
- int attr = hl_combine_attr(wp->w_hl_attr_normal, win_hl_attr(wp, hl));
+ int attr = hl_combine_attr(wp->w_hl_attr_normal,
+ hl ? win_hl_attr(wp, hl) : 0);
if (wp->w_p_rl) {
grid_fill(&wp->w_grid, row, endrow, wp->w_wincol, W_ENDCOL(wp) - 1 - n,
@@ -3777,7 +3778,7 @@ win_line (
* At end of the text line or just after the last character.
*/
if (c == NUL) {
- long prevcol = (long)(ptr - line) - (c == NUL);
+ long prevcol = (long)(ptr - line) - 1;
/* we're not really at that column when skipping some text */
if ((long)(wp->w_p_wrap ? wp->w_skipcol : wp->w_leftcol) > prevcol)
@@ -4570,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);
}
}
@@ -6078,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/search.c b/src/nvim/search.c
index ed18df3877..ed5934cec2 100644
--- a/src/nvim/search.c
+++ b/src/nvim/search.c
@@ -1217,7 +1217,7 @@ int do_search(
xfree(msgbuf);
msgbuf = r;
// move reversed text to beginning of buffer
- while (*r != NUL && *r == ' ') {
+ while (*r == ' ') {
r++;
}
size_t pat_len = msgbuf + STRLEN(msgbuf) - r;
diff --git a/src/nvim/sign.c b/src/nvim/sign.c
index 8c85fbdaa7..9c391428ca 100644
--- a/src/nvim/sign.c
+++ b/src/nvim/sign.c
@@ -83,11 +83,8 @@ static signgroup_T * sign_group_ref(const char_u *groupname)
hi = hash_lookup(&sg_table, (char *)groupname, STRLEN(groupname), hash);
if (HASHITEM_EMPTY(hi)) {
// new group
- group = (signgroup_T *)xmalloc(
- (unsigned)(sizeof(signgroup_T) + STRLEN(groupname)));
- if (group == NULL) {
- return NULL;
- }
+ group = xmalloc((unsigned)(sizeof(signgroup_T) + STRLEN(groupname)));
+
STRCPY(group->sg_name, groupname);
group->refcount = 1;
group->next_sign_id = 1;
@@ -188,10 +185,6 @@ static void insert_sign(
newsign->typenr = typenr;
if (group != NULL) {
newsign->group = sign_group_ref(group);
- if (newsign->group == NULL) {
- xfree(newsign);
- return;
- }
} else {
newsign->group = NULL;
}
@@ -1347,8 +1340,8 @@ static void sign_getinfo(sign_T *sp, dict_T *retdict)
/// Otherwise, return information about the specified sign.
void sign_getlist(const char_u *name, list_T *retlist)
{
- sign_T *sp = first_sign;
- dict_T *dict;
+ sign_T *sp = first_sign;
+ dict_T *dict;
if (name != NULL) {
sp = sign_find(name, NULL);
@@ -1358,9 +1351,7 @@ void sign_getlist(const char_u *name, list_T *retlist)
}
for (; sp != NULL && !got_int; sp = sp->sn_next) {
- if ((dict = tv_dict_alloc()) == NULL) {
- return;
- }
+ dict = tv_dict_alloc();
tv_list_append_dict(retlist, dict);
sign_getinfo(sp, dict);
@@ -1374,14 +1365,13 @@ void sign_getlist(const char_u *name, list_T *retlist)
list_T *get_buffer_signs(buf_T *buf)
FUNC_ATTR_NONNULL_RET FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
{
- signlist_T *sign;
- dict_T *d;
+ signlist_T *sign;
+ dict_T *d;
list_T *const l = tv_list_alloc(kListLenMayKnow);
FOR_ALL_SIGNS_IN_BUF(buf, sign) {
- if ((d = sign_get_info(sign)) != NULL) {
- tv_list_append_dict(l, d);
- }
+ d = sign_get_info(sign);
+ tv_list_append_dict(l, d);
}
return l;
}
@@ -1394,21 +1384,16 @@ static void sign_get_placed_in_buf(
const char_u *sign_group,
list_T *retlist)
{
- dict_T *d;
- list_T *l;
- signlist_T *sign;
- dict_T *sdict;
+ dict_T *d;
+ list_T *l;
+ signlist_T *sign;
- if ((d = tv_dict_alloc()) == NULL) {
- return;
- }
+ d = tv_dict_alloc();
tv_list_append_dict(retlist, d);
tv_dict_add_nr(d, S_LEN("bufnr"), (long)buf->b_fnum);
- if ((l = tv_list_alloc(kListLenMayKnow)) == NULL) {
- return;
- }
+ l = tv_list_alloc(kListLenMayKnow);
tv_dict_add_list(d, S_LEN("signs"), l);
FOR_ALL_SIGNS_IN_BUF(buf, sign) {
@@ -1419,9 +1404,7 @@ static void sign_get_placed_in_buf(
|| (sign_id == 0 && lnum == sign->lnum)
|| (lnum == 0 && sign_id == sign->id)
|| (lnum == sign->lnum && sign_id == sign->id)) {
- if ((sdict = sign_get_info(sign)) != NULL) {
- tv_list_append_dict(l, sdict);
- }
+ tv_list_append_dict(l, sign_get_info(sign));
}
}
}
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 0d204b2f43..4fa70c0684 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)
@@ -3608,7 +3609,7 @@ syn_list_one(
continue;
}
- (void)syn_list_header(did_header, 999, id);
+ (void)syn_list_header(did_header, 0, id, true);
did_header = true;
last_matchgroup = 0;
if (spp->sp_type == SPTYPE_MATCH) {
@@ -3657,7 +3658,7 @@ syn_list_one(
/* list the link, if there is one */
if (HL_TABLE()[id - 1].sg_link && (did_header || link_only) && !got_int) {
- (void)syn_list_header(did_header, 999, id);
+ (void)syn_list_header(did_header, 0, id, true);
msg_puts_attr("links to", attr);
msg_putchar(' ');
msg_outtrans(HL_TABLE()[HL_TABLE()[id - 1].sg_link - 1].sg_name);
@@ -3799,7 +3800,6 @@ static bool syn_list_keywords(
const int attr
)
{
- int outlen;
int prev_contained = 0;
const int16_t *prev_next_list = NULL;
const int16_t *prev_cont_in_list = NULL;
@@ -3817,17 +3817,20 @@ static bool syn_list_keywords(
todo--;
for (keyentry_T *kp = HI2KE(hi); kp != NULL && !got_int; kp = kp->ke_next) {
if (kp->k_syn.id == id) {
+ int outlen = 0;
+ bool force_newline = false;
if (prev_contained != (kp->flags & HL_CONTAINED)
|| prev_skipnl != (kp->flags & HL_SKIPNL)
|| prev_skipwhite != (kp->flags & HL_SKIPWHITE)
|| prev_skipempty != (kp->flags & HL_SKIPEMPTY)
|| prev_cont_in_list != kp->k_syn.cont_in_list
- || prev_next_list != kp->next_list)
- outlen = 9999;
- else
+ || prev_next_list != kp->next_list) {
+ force_newline = true;
+ } else {
outlen = (int)STRLEN(kp->keyword);
- /* output "contained" and "nextgroup" on each line */
- if (syn_list_header(did_header, outlen, id)) {
+ }
+ // output "contained" and "nextgroup" on each line
+ if (syn_list_header(did_header, outlen, id, force_newline)) {
prev_contained = 0;
prev_next_list = NULL;
prev_cont_in_list = NULL;
@@ -5970,6 +5973,10 @@ static const char *highlight_init_both[] = {
"default link Whitespace NonText",
"default link MsgSeparator StatusLine",
"default link NormalFloat Pmenu",
+ "RedrawDebugNormal cterm=reverse gui=reverse",
+ "RedrawDebugClear ctermbg=Yellow guibg=Yellow",
+ "RedrawDebugComposed ctermbg=Green guibg=Green",
+ "RedrawDebugRecompose ctermbg=Red guibg=Red",
NULL
};
@@ -7044,6 +7051,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,
@@ -7064,7 +7075,7 @@ static void highlight_list_one(const int id)
sgp->sg_blend+1, NULL, "blend");
if (sgp->sg_link && !got_int) {
- (void)syn_list_header(didh, 9999, id);
+ (void)syn_list_header(didh, 0, id, true);
didh = true;
msg_puts_attr("links to", HL_ATTR(HLF_D));
msg_putchar(' ');
@@ -7109,7 +7120,8 @@ static bool highlight_list_arg(
}
}
- (void)syn_list_header(didh, (int)(vim_strsize(ts) + STRLEN(name) + 1), id);
+ (void)syn_list_header(didh, (int)(vim_strsize(ts) + STRLEN(name) + 1), id,
+ false);
didh = true;
if (!got_int) {
if (*name != NUL) {
@@ -7227,9 +7239,10 @@ const char *highlight_color(const int id, const char *const what,
/// @param did_header did header already
/// @param outlen length of string that comes
/// @param id highlight group id
+/// @param force_newline always start a new line
/// @return true when started a new line.
static bool syn_list_header(const bool did_header, const int outlen,
- const int id)
+ const int id, bool force_newline)
{
int endcol = 19;
bool newline = true;
@@ -7242,10 +7255,10 @@ static bool syn_list_header(const bool did_header, const int outlen,
}
msg_outtrans(HL_TABLE()[id - 1].sg_name);
endcol = 15;
- } else if (ui_has(kUIMessages) || msg_silent) {
+ } else if ((ui_has(kUIMessages) || msg_silent) && !force_newline) {
msg_putchar(' ');
adjust = false;
- } else if (msg_col + outlen + 1 >= Columns) {
+ } else if (msg_col + outlen + 1 >= Columns || force_newline) {
msg_putchar('\n');
if (got_int) {
return true;
@@ -7518,6 +7531,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/Makefile b/src/nvim/testdir/Makefile
index fe9e0bc9c8..8b43d91e25 100644
--- a/src/nvim/testdir/Makefile
+++ b/src/nvim/testdir/Makefile
@@ -99,23 +99,24 @@ RM_ON_RUN := test.out X* viminfo
RM_ON_START := test.ok
RUN_VIM := $(TOOL) $(NVIM_PRG) -u unix.vim -U NONE -i viminfo --headless --noplugin -s dotest.in
+CLEAN_FILES := *.out \
+ *.failed \
+ *.res \
+ *.rej \
+ *.orig \
+ *.tlog \
+ test.log \
+ messages \
+ $(RM_ON_RUN) \
+ $(RM_ON_START) \
+ valgrind.* \
+ .*.swp \
+ .*.swo \
+ .gdbinit \
+ $(TMPDIR) \
+ del
clean:
- -rm -rf *.out \
- *.failed \
- *.res \
- *.rej \
- *.orig \
- *.tlog \
- test.log \
- messages \
- $(RM_ON_RUN) \
- $(RM_ON_START) \
- valgrind.* \
- .*.swp \
- .*.swo \
- .gdbinit \
- $(TMPDIR) \
- del
+ $(RM) -rf $(CLEAN_FILES)
test1.out: .gdbinit test1.in
@echo "[OLDTEST-PREP] Running test1"
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_assert.vim b/src/nvim/testdir/test_assert.vim
index fe87bd6ef5..a4c8ce7e43 100644
--- a/src/nvim/testdir/test_assert.vim
+++ b/src/nvim/testdir/test_assert.vim
@@ -1,5 +1,11 @@
" Test that the methods used for testing work.
+func Test_assert_fails_in_try_block()
+ try
+ call assert_equal(0, assert_fails('throw "error"'))
+ endtry
+endfunc
+
" Must be last.
func Test_zz_quit_detected()
" Verify that if a test function ends Vim the test script detects this.
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_functions.vim b/src/nvim/testdir/test_functions.vim
index 0c3c356622..615536baef 100644
--- a/src/nvim/testdir/test_functions.vim
+++ b/src/nvim/testdir/test_functions.vim
@@ -1188,3 +1188,45 @@ func Test_libcall_libcallnr()
call assert_fails("call libcall('Xdoesnotexist_', 'getenv', 'HOME')", 'E364:')
call assert_fails("call libcallnr('Xdoesnotexist_', 'strlen', 'abcd')", 'E364:')
endfunc
+
+func Test_bufadd_bufload()
+ call assert_equal(0, bufexists('someName'))
+ let buf = bufadd('someName')
+ call assert_notequal(0, buf)
+ call assert_equal(1, bufexists('someName'))
+ call assert_equal(0, getbufvar(buf, '&buflisted'))
+ call assert_equal(0, bufloaded(buf))
+ call bufload(buf)
+ call assert_equal(1, bufloaded(buf))
+ call assert_equal([''], getbufline(buf, 1, '$'))
+
+ let curbuf = bufnr('')
+ call writefile(['some', 'text'], 'otherName')
+ let buf = bufadd('otherName')
+ call assert_notequal(0, buf)
+ call assert_equal(1, bufexists('otherName'))
+ call assert_equal(0, getbufvar(buf, '&buflisted'))
+ call assert_equal(0, bufloaded(buf))
+ call bufload(buf)
+ call assert_equal(1, bufloaded(buf))
+ call assert_equal(['some', 'text'], getbufline(buf, 1, '$'))
+ call assert_equal(curbuf, bufnr(''))
+
+ let buf1 = bufadd('')
+ let buf2 = bufadd('')
+ call assert_notequal(0, buf1)
+ call assert_notequal(0, buf2)
+ call assert_notequal(buf1, buf2)
+ call assert_equal(1, bufexists(buf1))
+ call assert_equal(1, bufexists(buf2))
+ call assert_equal(0, bufloaded(buf1))
+ exe 'bwipe ' .. buf1
+ call assert_equal(0, bufexists(buf1))
+ call assert_equal(1, bufexists(buf2))
+ exe 'bwipe ' .. buf2
+ call assert_equal(0, bufexists(buf2))
+
+ bwipe someName
+ bwipe otherName
+ call assert_equal(0, bufexists('someName'))
+endfunc
diff --git a/src/nvim/testdir/test_source.vim b/src/nvim/testdir/test_source.vim
index 42ac0c4d0f..697b552df4 100644
--- a/src/nvim/testdir/test_source.vim
+++ b/src/nvim/testdir/test_source.vim
@@ -8,3 +8,40 @@ func Test_source_sandbox()
call assert_fails('sandbox source! Xsourcehello', 'E48:')
bwipe!
endfunc
+
+func Test_source_autocmd()
+ call writefile([
+ \ 'let did_source = 1',
+ \ ], 'Xsourced')
+ au SourcePre *source* let did_source_pre = 1
+ au SourcePost *source* let did_source_post = 1
+
+ source Xsourced
+
+ call assert_equal(g:did_source, 1)
+ call assert_equal(g:did_source_pre, 1)
+ call assert_equal(g:did_source_post, 1)
+
+ call delete('Xsourced')
+ au! SourcePre
+ au! SourcePost
+ unlet g:did_source
+ unlet g:did_source_pre
+ unlet g:did_source_post
+endfunc
+
+func Test_source_cmd()
+ au SourceCmd *source* let did_source = expand('<afile>')
+ au SourcePre *source* let did_source_pre = 2
+ au SourcePost *source* let did_source_post = 2
+
+ source Xsourced
+
+ call assert_equal(g:did_source, 'Xsourced')
+ call assert_false(exists('g:did_source_pre'))
+ call assert_equal(g:did_source_post, 2)
+
+ au! SourceCmd
+ au! SourcePre
+ au! SourcePost
+endfunc
diff --git a/src/nvim/testdir/test_suspend.vim b/src/nvim/testdir/test_suspend.vim
index e569e49055..ef5a96bd72 100644
--- a/src/nvim/testdir/test_suspend.vim
+++ b/src/nvim/testdir/test_suspend.vim
@@ -2,6 +2,20 @@
source shared.vim
+func CheckSuspended(buf, fileExists)
+ call WaitForAssert({-> assert_match('[$#] $', term_getline(a:buf, '.'))})
+
+ if a:fileExists
+ call assert_equal(['foo'], readfile('Xfoo'))
+ else
+ " Without 'autowrite', buffer should not be written.
+ call assert_equal(0, filereadable('Xfoo'))
+ endif
+
+ call term_sendkeys(a:buf, "fg\<CR>\<C-L>")
+ call WaitForAssert({-> assert_equal(' 1 foo', term_getline(a:buf, '.'))})
+endfunc
+
func Test_suspend()
if !has('terminal') || !executable('/bin/sh')
return
@@ -26,13 +40,7 @@ func Test_suspend()
\ "\<C-Z>"]
" Suspend and wait for shell prompt.
call term_sendkeys(buf, suspend_cmd)
- call WaitForAssert({-> assert_match('[$#] $', term_getline(buf, '.'))})
-
- " Without 'autowrite', buffer should not be written.
- call assert_equal(0, filereadable('Xfoo'))
-
- call term_sendkeys(buf, "fg\<CR>")
- call WaitForAssert({-> assert_equal(' 1 foo', term_getline(buf, '.'))})
+ call CheckSuspended(buf, 0)
endfor
" Test that :suspend! with 'autowrite' writes content of buffers if modified.
@@ -40,14 +48,13 @@ func Test_suspend()
call assert_equal(0, filereadable('Xfoo'))
call term_sendkeys(buf, ":suspend\<CR>")
" Wait for shell prompt.
- call WaitForAssert({-> assert_match('[$#] $', term_getline(buf, '.'))})
- call assert_equal(['foo'], readfile('Xfoo'))
- call term_sendkeys(buf, "fg\<CR>")
- call WaitForAssert({-> assert_equal(' 1 foo', term_getline(buf, '.'))})
+ call CheckSuspended(buf, 1)
" 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/ugrid.c b/src/nvim/ugrid.c
index 8adb421ee1..9e4aaff878 100644
--- a/src/nvim/ugrid.c
+++ b/src/nvim/ugrid.c
@@ -6,6 +6,7 @@
#include <stdio.h>
#include <limits.h>
+#include "nvim/assert.h"
#include "nvim/vim.h"
#include "nvim/ui.h"
#include "nvim/ugrid.h"
@@ -72,8 +73,9 @@ void ugrid_scroll(UGrid *grid, int top, int bot, int left, int right, int count)
for (i = start; i != stop; i += step) {
UCell *target_row = grid->cells[i] + left;
UCell *source_row = grid->cells[i + count] + left;
+ assert(right >= left && left >= 0);
memcpy(target_row, source_row,
- sizeof(UCell) * (size_t)(right - left + 1));
+ sizeof(UCell) * ((size_t)right - (size_t)left + 1));
}
}
diff --git a/src/nvim/ui.c b/src/nvim/ui.c
index 7dbb8ec790..fc4a3a403d 100644
--- a/src/nvim/ui.c
+++ b/src/nvim/ui.c
@@ -341,15 +341,15 @@ void ui_line(ScreenGrid *grid, int row, int startcol, int endcol, int clearcol,
flags, (const schar_T *)grid->chars + off,
(const sattr_T *)grid->attrs + off);
- if (p_wd) { // 'writedelay': flush & delay each time.
- int old_row = cursor_row, old_col = cursor_col;
- handle_T old_grid = cursor_grid_handle;
+ // 'writedelay': flush & delay each time.
+ if (p_wd && !(rdb_flags & RDB_COMPOSITOR)) {
// If 'writedelay' is active, set the cursor to indicate what was drawn.
- ui_grid_cursor_goto(grid->handle, row, MIN(clearcol, (int)Columns-1));
- ui_flush();
+ ui_call_grid_cursor_goto(grid->handle, row,
+ MIN(clearcol, (int)grid->Columns-1));
+ ui_call_flush();
uint64_t wd = (uint64_t)labs(p_wd);
os_microdelay(wd * 1000u, true);
- ui_grid_cursor_goto(old_grid, old_row, old_col);
+ pending_cursor_update = true; // restore the cursor later
}
}
@@ -372,6 +372,14 @@ void ui_grid_cursor_goto(handle_T grid_handle, int new_row, int new_col)
pending_cursor_update = true;
}
+/// moving the cursor grid will implicitly move the cursor
+void ui_check_cursor_grid(handle_T grid_handle)
+{
+ if (cursor_grid_handle == grid_handle) {
+ pending_cursor_update = true;
+ }
+}
+
void ui_mode_info_set(void)
{
pending_mode_info_update = true;
diff --git a/src/nvim/ui_compositor.c b/src/nvim/ui_compositor.c
index d12a411019..d0b21ae591 100644
--- a/src/nvim/ui_compositor.c
+++ b/src/nvim/ui_compositor.c
@@ -49,6 +49,8 @@ static bool valid_screen = true;
static bool msg_scroll_mode = false;
static int msg_first_invalid = 0;
+static int dbghl_normal, dbghl_clear, dbghl_composed, dbghl_recompose;
+
void ui_comp_init(void)
{
if (compositor != NULL) {
@@ -81,6 +83,13 @@ void ui_comp_init(void)
ui_attach_impl(compositor);
}
+void ui_comp_syn_init(void)
+{
+ dbghl_normal = syn_check_group((char_u *)S_LEN("RedrawDebugNormal"));
+ dbghl_clear = syn_check_group((char_u *)S_LEN("RedrawDebugClear"));
+ dbghl_composed = syn_check_group((char_u *)S_LEN("RedrawDebugComposed"));
+ dbghl_recompose = syn_check_group((char_u *)S_LEN("RedrawDebugRecompose"));
+}
void ui_comp_attach(UI *ui)
{
@@ -290,10 +299,14 @@ static void compose_line(Integer row, Integer startcol, Integer endcol,
{
// in case we start on the right half of a double-width char, we need to
// check the left half. But skip it in output if it wasn't doublewidth.
- int skip = 0;
+ int skipstart = 0, skipend = 0;
if (startcol > 0 && (flags & kLineFlagInvalid)) {
startcol--;
- skip = 1;
+ skipstart = 1;
+ }
+ if (endcol < default_grid.Columns && (flags & kLineFlagInvalid)) {
+ endcol++;
+ skipend = 1;
}
int col = (int)startcol;
@@ -331,11 +344,22 @@ static void compose_line(Integer row, Integer startcol, Integer endcol,
// 'pumblend' and 'winblend'
if (grid->blending) {
- for (int i = col-(int)startcol; i < until-startcol; i++) {
- bool thru = strequal((char *)linebuf[i], " "); // negative space
+ int width;
+ for (int i = col-(int)startcol; i < until-startcol; i += width) {
+ width = 1;
+ // negative space
+ bool thru = strequal((char *)linebuf[i], " ") && bg_line[i][0] != NUL;
+ if (i+1 < endcol-startcol && bg_line[i+1][0] == NUL) {
+ width = 2;
+ thru &= strequal((char *)linebuf[i+1], " ");
+ }
attrbuf[i] = (sattr_T)hl_blend_attrs(bg_attrs[i], attrbuf[i], &thru);
+ if (width == 2) {
+ attrbuf[i+1] = (sattr_T)hl_blend_attrs(bg_attrs[i+1],
+ attrbuf[i+1], &thru);
+ }
if (thru) {
- memcpy(linebuf[i], bg_line[i], sizeof(linebuf[i]));
+ memcpy(linebuf[i], bg_line[i], (size_t)width * sizeof(linebuf[i]));
}
}
}
@@ -345,20 +369,27 @@ static void compose_line(Integer row, Integer startcol, Integer endcol,
if (linebuf[col-startcol][0] == NUL) {
linebuf[col-startcol][0] = ' ';
linebuf[col-startcol][1] = NUL;
+ if (col == endcol-1) {
+ skipend = 0;
+ }
} else if (n > 1 && linebuf[col-startcol+1][0] == NUL) {
- skip = 0;
+ skipstart = 0;
}
if (grid->comp_col+grid->Columns > until
&& grid->chars[off+n][0] == NUL) {
linebuf[until-1-startcol][0] = ' ';
linebuf[until-1-startcol][1] = '\0';
if (col == startcol && n == 1) {
- skip = 0;
+ skipstart = 0;
}
}
col = until;
}
+ if (linebuf[endcol-startcol-1][0] == NUL) {
+ skipend = 0;
+ }
+
assert(endcol <= chk_width);
assert(row < chk_height);
@@ -368,14 +399,48 @@ static void compose_line(Integer row, Integer startcol, Integer endcol,
flags = flags & ~kLineFlagWrap;
}
- ui_composed_call_raw_line(1, row, startcol+skip, endcol, endcol, 0, flags,
- (const schar_T *)linebuf+skip,
- (const sattr_T *)attrbuf+skip);
+ ui_composed_call_raw_line(1, row, startcol+skipstart,
+ endcol-skipend, endcol-skipend, 0, flags,
+ (const schar_T *)linebuf+skipstart,
+ (const sattr_T *)attrbuf+skipstart);
}
+static void compose_debug(Integer startrow, Integer endrow, Integer startcol,
+ Integer endcol, int syn_id, bool delay)
+{
+ if (!(rdb_flags & RDB_COMPOSITOR)) {
+ return;
+ }
+
+ endrow = MIN(endrow, default_grid.Rows);
+ endcol = MIN(endcol, default_grid.Columns);
+ int attr = syn_id2attr(syn_id);
+
+ for (int row = (int)startrow; row < endrow; row++) {
+ ui_composed_call_raw_line(1, row, startcol, startcol, endcol, attr, false,
+ (const schar_T *)linebuf,
+ (const sattr_T *)attrbuf);
+ }
+
+
+ if (delay) {
+ debug_delay(endrow-startrow);
+ }
+}
+
+static void debug_delay(Integer lines)
+{
+ ui_call_flush();
+ uint64_t wd = (uint64_t)labs(p_wd);
+ uint64_t factor = (uint64_t)MAX(MIN(lines, 5), 1);
+ os_microdelay(factor * wd * 1000u, true);
+}
+
+
static void compose_area(Integer startrow, Integer endrow,
Integer startcol, Integer endcol)
{
+ compose_debug(startrow, endrow, startcol, endcol, dbghl_recompose, true);
endrow = MIN(endrow, default_grid.Rows);
endcol = MIN(endcol, default_grid.Columns);
if (endcol <= startcol) {
@@ -420,8 +485,11 @@ static void ui_comp_raw_line(UI *ui, Integer grid, Integer row,
if (flags & kLineFlagInvalid
|| kv_size(layers) > curgrid->comp_index+1
|| curgrid->blending) {
+ compose_debug(row, row+1, startcol, clearcol, dbghl_composed, true);
compose_line(row, startcol, clearcol, flags);
} else {
+ compose_debug(row, row+1, startcol, endcol, dbghl_normal, false);
+ compose_debug(row, row+1, endcol, clearcol, dbghl_clear, true);
ui_composed_call_raw_line(1, row, startcol, endcol, clearcol, clearattr,
flags, chunk, attrs);
}
@@ -481,6 +549,9 @@ static void ui_comp_grid_scroll(UI *ui, Integer grid, Integer top,
} else {
msg_first_invalid = MIN(msg_first_invalid, (int)top);
ui_composed_call_grid_scroll(1, top, bot, left, right, rows, cols);
+ if (rdb_flags & RDB_COMPOSITOR) {
+ debug_delay(2);
+ }
}
}
diff --git a/src/nvim/window.c b/src/nvim/window.c
index a3b1efeaaa..38246bfe2a 100644
--- a/src/nvim/window.c
+++ b/src/nvim/window.c
@@ -375,7 +375,7 @@ newwindow:
/* set current window height */
case Ctrl__:
case '_':
- win_setheight(Prenum ? (int)Prenum : 9999);
+ win_setheight(Prenum ? (int)Prenum : Rows-1);
break;
/* increase current window width */
@@ -390,7 +390,7 @@ newwindow:
/* set current window width */
case '|':
- win_setwidth(Prenum != 0 ? (int)Prenum : 9999);
+ win_setwidth(Prenum != 0 ? (int)Prenum : Columns);
break;
/* jump to tag and split window if tag exists (in preview window) */
@@ -584,15 +584,43 @@ win_T *win_new_float(win_T *wp, FloatConfig fconfig, Error *err)
wp->w_status_height = 0;
wp->w_vsep_width = 0;
- // TODO(bfredl): use set_option_to() after merging #9110 ?
- wp->w_p_nu = false;
- wp->w_allbuf_opt.wo_nu = false;
win_config_float(wp, fconfig);
wp->w_pos_changed = true;
redraw_win_later(wp, VALID);
return wp;
}
+void win_set_minimal_style(win_T *wp)
+{
+ wp->w_p_nu = false;
+ wp->w_p_rnu = false;
+ wp->w_p_cul = false;
+ wp->w_p_cuc = false;
+ wp->w_p_spell = false;
+ wp->w_p_list = false;
+
+ // Hide EOB region: use " " fillchar and cleared highlighting
+ if (wp->w_p_fcs_chars.eob != ' ') {
+ char_u *old = wp->w_p_fcs;
+ wp->w_p_fcs = ((*old == NUL)
+ ? (char_u *)xstrdup("eob: ")
+ : concat_str(old, (char_u *)",eob: "));
+ xfree(old);
+ }
+ if (wp->w_hl_ids[HLF_EOB] != -1) {
+ char_u *old = wp->w_p_winhl;
+ wp->w_p_winhl = ((*old == NUL)
+ ? (char_u *)xstrdup("EndOfBuffer:")
+ : concat_str(old, (char_u *)",EndOfBuffer:"));
+ xfree(old);
+ }
+
+ if (wp->w_p_scl[0] != 'a') {
+ xfree(wp->w_p_scl);
+ wp->w_p_scl = (char_u *)xstrdup("auto");
+ }
+}
+
void win_config_float(win_T *wp, FloatConfig fconfig)
{
wp->w_width = MAX(fconfig.width, 1);
@@ -666,6 +694,7 @@ static void ui_ext_win_position(win_T *wp)
bool on_top = (curwin == wp) || !curwin->w_floating;
ui_comp_put_grid(&wp->w_grid, comp_row, comp_col, wp->w_height,
wp->w_width, valid, on_top);
+ ui_check_cursor_grid(wp->w_grid.handle);
if (!valid) {
wp->w_grid.valid = false;
redraw_win_later(wp, NOT_VALID);
@@ -821,6 +850,20 @@ bool parse_float_config(Dictionary config, FloatConfig *fconfig, bool reconf,
"'focusable' key must be Boolean");
return false;
}
+ } else if (!strcmp(key, "style")) {
+ if (val.type != kObjectTypeString) {
+ api_set_error(err, kErrorTypeValidation,
+ "'style' key must be String");
+ return false;
+ }
+ if (val.data.string.data[0] == NUL) {
+ fconfig->style = kWinStyleUnused;
+ } else if (striequal(val.data.string.data, "minimal")) {
+ fconfig->style = kWinStyleMinimal;
+ } else {
+ api_set_error(err, kErrorTypeValidation,
+ "Invalid value of 'style' key");
+ }
} else {
api_set_error(err, kErrorTypeValidation,
"Invalid key '%s'", key);
@@ -981,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);
}
@@ -1059,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);
}
@@ -1204,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)
@@ -1674,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 */
@@ -1918,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;
}
@@ -1964,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) */
@@ -2039,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;
}
@@ -2085,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) */
@@ -2772,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;
@@ -2894,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;
}
@@ -2931,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. */
@@ -3013,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;
}
@@ -3023,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;
}
@@ -3047,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;
}
@@ -3057,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;
}
@@ -3081,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);
}
}
@@ -3122,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. */
@@ -3192,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;
@@ -3204,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;
@@ -3258,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;
@@ -3266,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;
@@ -3301,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;
@@ -3309,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;
@@ -4787,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);
}
}
@@ -4823,13 +4878,9 @@ void win_setheight_win(int height, win_T *win)
}
if (win->w_floating) {
- if (win->w_float_config.external) {
- win->w_float_config.height = height;
- win_config_float(win, win->w_float_config);
- } else {
- beep_flush();
- return;
- }
+ win->w_float_config.height = height;
+ win_config_float(win, win->w_float_config);
+ redraw_win_later(win, NOT_VALID);
} else {
frame_setheight(win->w_frame, height + win->w_status_height);
@@ -4844,9 +4895,9 @@ void win_setheight_win(int height, win_T *win)
cmdline_row = row;
msg_row = row;
msg_col = 0;
+ redraw_all_later(NOT_VALID);
}
- redraw_all_later(NOT_VALID);
}
@@ -4904,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;
@@ -5029,21 +5081,17 @@ void win_setwidth_win(int width, win_T *wp)
width = 1;
}
if (wp->w_floating) {
- if (wp->w_float_config.external) {
- wp->w_float_config.width = width;
- win_config_float(wp, wp->w_float_config);
- } else {
- beep_flush();
- return;
- }
+ wp->w_float_config.width = width;
+ win_config_float(wp, wp->w_float_config);
+ redraw_win_later(wp, NOT_VALID);
} else {
frame_setwidth(wp->w_frame, width + wp->w_vsep_width);
// recompute the window positions
(void)win_comp_pos();
+ redraw_all_later(NOT_VALID);
}
- redraw_all_later(NOT_VALID);
}
/*
@@ -5089,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)
@@ -5261,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 */
@@ -5364,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);
@@ -5898,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)
@@ -6516,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;
}
@@ -6536,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;
}