aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--runtime/doc/starting.txt3
-rwxr-xr-xscripts/vim-patch.sh6
-rw-r--r--src/nvim/ex_getln.c80
-rw-r--r--src/nvim/tui/tui.c43
-rw-r--r--test/functional/ex_cmds/cmd_map_spec.lua28
5 files changed, 100 insertions, 60 deletions
diff --git a/runtime/doc/starting.txt b/runtime/doc/starting.txt
index 24fb87a6b4..c9ce2b9dc1 100644
--- a/runtime/doc/starting.txt
+++ b/runtime/doc/starting.txt
@@ -408,9 +408,6 @@ accordingly. Vim proceeds in this order:
Windows $XDG_CONFIG_HOME/nvim/init.vim
(default for $XDG_CONFIG_HOME is ~/AppData/Local)
- The files are searched in the order specified above and only the first
- one that is found is read.
-
RECOMMENDATION: Put all your Vim configuration stuff in the
$HOME/.config/nvim/ directory. That makes it easy to copy it to
another system.
diff --git a/scripts/vim-patch.sh b/scripts/vim-patch.sh
index 6dd411a34e..9ea43383b6 100755
--- a/scripts/vim-patch.sh
+++ b/scripts/vim-patch.sh
@@ -85,12 +85,12 @@ get_vim_sources() {
git clone https://github.com/vim/vim.git "${VIM_SOURCE_DIR}"
cd "${VIM_SOURCE_DIR}"
else
- if [[ ! -d "${VIM_SOURCE_DIR}/.git" ]]; then
+ cd "${VIM_SOURCE_DIR}"
+ if [[ "$(git rev-parse --show-toplevel)" != "${VIM_SOURCE_DIR}" ]]; then
msg_err "${VIM_SOURCE_DIR} does not appear to be a git repository."
echo " Please remove it and try again."
exit 1
fi
- cd "${VIM_SOURCE_DIR}"
echo "Updating Vim sources: ${VIM_SOURCE_DIR}"
git pull &&
msg_ok "Updated Vim sources." ||
@@ -202,7 +202,7 @@ get_vimpatch() {
printf "Pre-processing patch...\n"
preprocess_patch "${NVIM_SOURCE_DIR}/${patch_file}"
- msg_ok "Saved patch to '${NVIM_SOURCE_DIR}/${patch_file}'.\n"
+ msg_ok "Saved patch to '${NVIM_SOURCE_DIR}/${patch_file}'."
}
stage_patch() {
diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c
index 1810056a4a..7f40a984d1 100644
--- a/src/nvim/ex_getln.c
+++ b/src/nvim/ex_getln.c
@@ -177,10 +177,6 @@ typedef struct command_line_state {
int break_ctrl_c;
expand_T xpc;
long *b_im_ptr;
- // Everything that may work recursively should save and restore the
- // current command line in save_ccline. That includes update_screen(), a
- // custom status line may invoke ":normal".
- struct cmdline_info save_ccline;
} CommandLineState;
typedef struct cmdline_info CmdlineInfo;
@@ -225,11 +221,19 @@ static bool need_cursor_update = false;
# include "ex_getln.c.generated.h"
#endif
-static int cmd_hkmap = 0; /* Hebrew mapping during command line */
+static int cmd_hkmap = 0; // Hebrew mapping during command line
+static int cmd_fkmap = 0; // Farsi mapping during command line
-static int cmd_fkmap = 0; /* Farsi mapping during command line */
+/// Internal entry point for cmdline mode.
+///
+/// caller must use save_cmdline and restore_cmdline. Best is to use
+/// getcmdline or getcmdline_prompt, instead of calling this directly.
static uint8_t *command_line_enter(int firstc, long count, int indent)
{
+ // can be invoked recursively, identify each level
+ static int cmdline_level = 0;
+ cmdline_level++;
+
CommandLineState state, *s = &state;
memset(s, 0, sizeof(CommandLineState));
s->firstc = firstc;
@@ -257,7 +261,7 @@ static uint8_t *command_line_enter(int firstc, long count, int indent)
}
ccline.prompt_id = last_prompt_id++;
- ccline.level++;
+ ccline.level = cmdline_level;
ccline.overstrike = false; // always start in insert mode
clearpos(&s->match_end);
s->save_cursor = curwin->w_cursor; // may be restored later
@@ -489,19 +493,14 @@ static uint8_t *command_line_enter(int firstc, long count, int indent)
sb_text_end_cmdline();
- {
- char_u *p = ccline.cmdbuff;
-
- // Make ccline empty, getcmdline() may try to use it.
- ccline.cmdbuff = NULL;
+ char_u *p = ccline.cmdbuff;
- if (ui_is_external(kUICmdline)) {
- ccline.redraw_state = kCmdRedrawNone;
- ui_call_cmdline_hide(ccline.level);
- }
- ccline.level--;
- return p;
+ if (ui_is_external(kUICmdline)) {
+ ui_call_cmdline_hide(ccline.level);
}
+
+ cmdline_level--;
+ return p;
}
static int command_line_check(VimState *state)
@@ -641,9 +640,7 @@ static int command_line_execute(VimState *state, int key)
p_ls = save_p_ls;
p_wmh = save_p_wmh;
last_status(false);
- save_cmdline(&s->save_ccline);
update_screen(VALID); // redraw the screen NOW
- restore_cmdline(&s->save_ccline);
redrawcmd();
save_p_ls = -1;
wild_menu_showing = 0;
@@ -818,18 +815,17 @@ static int command_line_execute(VimState *state, int key)
new_cmdpos = ccline.cmdpos;
}
- save_cmdline(&s->save_ccline);
s->c = get_expr_register();
- restore_cmdline(&s->save_ccline);
if (s->c == '=') {
// Need to save and restore ccline. And set "textlock"
// to avoid nasty things like going to another buffer when
// evaluating an expression.
- save_cmdline(&s->save_ccline);
- ++textlock;
+ CmdlineInfo save_ccline;
+ save_cmdline(&save_ccline);
+ textlock++;
p = get_expr_line();
- --textlock;
- restore_cmdline(&s->save_ccline);
+ textlock--;
+ restore_cmdline(&save_ccline);
if (p != NULL) {
len = (int)STRLEN(p);
@@ -1362,9 +1358,10 @@ static int command_line_handle_key(CommandLineState *s)
beep_flush();
s->c = ESC;
} else {
- save_cmdline(&s->save_ccline);
+ CmdlineInfo save_ccline;
+ save_cmdline(&save_ccline);
s->c = get_expr_register();
- restore_cmdline(&s->save_ccline);
+ restore_cmdline(&save_ccline);
}
}
@@ -1899,9 +1896,7 @@ static int command_line_changed(CommandLineState *s)
curwin->w_redr_status = true;
}
- save_cmdline(&s->save_ccline);
update_screen(SOME_VALID);
- restore_cmdline(&s->save_ccline);
restore_last_search_pattern();
// Leave it at the end to make CTRL-R CTRL-W work.
@@ -1996,7 +1991,14 @@ getcmdline (
int indent // indent for inside conditionals
)
{
- return command_line_enter(firstc, count, indent);
+ // Be prepared for situations where cmdline can be invoked recursively.
+ // That includes cmd mappings, event handlers, as well as update_screen()
+ // (custom status line eval), which all may invoke ":normal :".
+ CmdlineInfo save_ccline;
+ save_cmdline(&save_ccline);
+ char_u *retval = command_line_enter(firstc, count, indent);
+ restore_cmdline(&save_ccline);
+ return retval;
}
/// Get a command line with a prompt
@@ -2020,7 +2022,7 @@ char *getcmdline_prompt(const char firstc, const char *const prompt,
{
const int msg_col_save = msg_col;
- struct cmdline_info save_ccline;
+ CmdlineInfo save_ccline;
save_cmdline(&save_ccline);
ccline.prompt_id = last_prompt_id++;
@@ -2034,7 +2036,7 @@ char *getcmdline_prompt(const char firstc, const char *const prompt,
int msg_silent_saved = msg_silent;
msg_silent = 0;
- char *const ret = (char *)getcmdline(firstc, 1L, 0);
+ char *const ret = (char *)command_line_enter(firstc, 1L, 0);
restore_cmdline(&save_ccline);
msg_silent = msg_silent_saved;
@@ -2176,6 +2178,7 @@ getexline (
/* When executing a register, remove ':' that's in front of each line. */
if (exec_from_reg && vpeekc() == ':')
(void)vgetc();
+
return getcmdline(c, 1L, indent);
}
@@ -3019,16 +3022,16 @@ void cmdline_screen_cleared(void)
}
int prev_level = ccline.level-1;
- CmdlineInfo *prev_ccline = ccline.prev_ccline;
- while (prev_level > 0 && prev_ccline) {
- if (prev_ccline->level == prev_level) {
+ CmdlineInfo *line = ccline.prev_ccline;
+ while (prev_level > 0 && line) {
+ if (line->level == prev_level) {
// don't redraw a cmdline already shown in the cmdline window
if (prev_level != cmdwin_level) {
- prev_ccline->redraw_state = kCmdRedrawAll;
+ line->redraw_state = kCmdRedrawAll;
}
prev_level--;
}
- prev_ccline = prev_ccline->prev_ccline;
+ line = line->prev_ccline;
}
need_cursor_update = true;
@@ -3244,6 +3247,7 @@ static void save_cmdline(struct cmdline_info *ccp)
ccline.cmdprompt = NULL;
ccline.xpc = NULL;
ccline.special_char = NUL;
+ ccline.level = 0;
}
/*
diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c
index df14ddf988..0781b03965 100644
--- a/src/nvim/tui/tui.c
+++ b/src/nvim/tui/tui.c
@@ -88,6 +88,7 @@ typedef struct {
bool cont_received;
UGrid grid;
kvec_t(Rect) invalid_regions;
+ bool did_resize;
int row, col;
int out_fd;
bool scroll_region_is_full_screen;
@@ -95,6 +96,7 @@ typedef struct {
bool can_set_lr_margin;
bool can_set_left_right_margin;
bool immediate_wrap_after_last_column;
+ bool bce;
bool mouse_enabled;
bool busy, is_invisible;
bool cork, overflow;
@@ -236,6 +238,7 @@ static void terminfo_start(UI *ui)
data->immediate_wrap_after_last_column =
terminfo_is_term_family(term, "cygwin")
|| terminfo_is_term_family(term, "interix");
+ data->bce = unibi_get_bool(data->ut, unibi_back_color_erase);
data->normlen = unibi_pre_fmt_str(data, unibi_cursor_normal,
data->norm, sizeof data->norm);
data->invislen = unibi_pre_fmt_str(data, unibi_cursor_invisible,
@@ -435,6 +438,12 @@ static bool attrs_differ(HlAttrs a1, HlAttrs a2, bool rgb)
}
}
+static bool no_bg(UI *ui, HlAttrs attrs)
+{
+ return ui->rgb ? attrs.rgb_bg_color == -1
+ : attrs.cterm_bg_color == 0;
+}
+
static void update_attrs(UI *ui, HlAttrs attrs)
{
TUIData *data = ui->data;
@@ -597,8 +606,6 @@ static void cursor_goto(UI *ui, int row, int col)
if (row == grid->row && col == grid->col) {
return;
}
- grid->row = row;
- grid->col = col;
if (0 == row && 0 == col) {
unibi_out(ui, unibi_cursor_home);
ugrid_goto(grid, row, col);
@@ -693,10 +700,11 @@ static void clear_region(UI *ui, int top, int bot, int left, int right,
UGrid *grid = &data->grid;
bool cleared = false;
- // TODO(bfredl): support BCE for non-default background
- bool nobg = ui->rgb ? attrs.rgb_bg_color == -1
- : attrs.cterm_bg_color == 0;
- if (nobg && right == ui->width -1) {
+
+ // non-BCE terminals can't clear with non-default background color
+ bool can_clear = data->bce || no_bg(ui, attrs);
+
+ if (can_clear && right == ui->width -1) {
// Background is set to the default color and the right edge matches the
// screen end, try to use terminal codes for clearing the requested area.
update_attrs(ui, attrs);
@@ -729,6 +737,14 @@ static void clear_region(UI *ui, int top, int bot, int left, int right,
cursor_goto(ui, row, col);
print_cell(ui, cell);
});
+
+ if (data->did_resize && top == 0) {
+ // TODO(bfredl): the first line of the screen doesn't gets properly
+ // cleared after resize by the loop above, so redraw the final state
+ // after the next flush.
+ invalidate(ui, 0, bot, left, right);
+ data->did_resize = false;
+ }
}
// restore cursor
@@ -804,6 +820,7 @@ static void tui_grid_resize(UI *ui, Integer g, Integer width, Integer height)
TUIData *data = ui->data;
UGrid *grid = &data->grid;
ugrid_resize(grid, (int)width, (int)height);
+ data->did_resize = true;
// resize might not always be followed by a clear before flush
// so clip the invalid region
@@ -984,18 +1001,13 @@ static void tui_grid_scroll(UI *ui, Integer g, Integer top, Integer bot,
ugrid_scroll(grid, (int)rows, &clear_top, &clear_bot);
if (can_use_scroll(ui)) {
- bool scroll_clears_to_current_colour =
- unibi_get_bool(data->ut, unibi_back_color_erase);
-
// Change terminal scroll region and move cursor to the top
if (!data->scroll_region_is_full_screen) {
set_scroll_region(ui);
}
cursor_goto(ui, grid->top, grid->left);
// also set default color attributes or some terminals can become funny
- if (scroll_clears_to_current_colour) {
- update_attrs(ui, data->clear_attrs);
- }
+ update_attrs(ui, data->clear_attrs);
if (rows > 0) {
if (rows == 1) {
@@ -1019,7 +1031,7 @@ static void tui_grid_scroll(UI *ui, Integer g, Integer top, Integer bot,
}
cursor_goto(ui, data->row, data->col);
- if (!scroll_clears_to_current_colour) {
+ if (!(data->bce || no_bg(ui, data->clear_attrs))) {
// Scrolling will leave wrong background in the cleared area on non-BCE
// terminals. Update the cleared area.
clear_region(ui, clear_top, clear_bot, grid->left, grid->right,
@@ -1382,6 +1394,7 @@ static void patch_terminfo_bugs(TUIData *data, const char *term,
bool roxterm = !!os_getenv("ROXTERM_ID");
#endif
bool xterm = terminfo_is_term_family(term, "xterm");
+ bool kitty = terminfo_is_term_family(term, "xterm-kitty");
bool linuxvt = terminfo_is_term_family(term, "linux");
bool rxvt = terminfo_is_term_family(term, "rxvt");
bool teraterm = terminfo_is_term_family(term, "teraterm");
@@ -1437,8 +1450,8 @@ static void patch_terminfo_bugs(TUIData *data, const char *term,
}
}
- if (!true_xterm) {
- // Cannot trust terminfo; safer to disable BCE. #7624
+ if (tmux || screen || kitty) {
+ // Disable BCE in some cases we know it is not working. #8806
unibi_set_bool(ut, unibi_back_color_erase, false);
}
diff --git a/test/functional/ex_cmds/cmd_map_spec.lua b/test/functional/ex_cmds/cmd_map_spec.lua
index 77d025dcc7..acb76e382d 100644
--- a/test/functional/ex_cmds/cmd_map_spec.lua
+++ b/test/functional/ex_cmds/cmd_map_spec.lua
@@ -656,7 +656,6 @@ describe('mappings with <Cmd>', function()
end)
it('works in cmdline mode', function()
- cmdmap('<F2>', 'call setcmdpos(2)')
feed(':text<F3>')
eq('c', eval('m'))
-- didn't leave cmdline mode
@@ -768,5 +767,32 @@ describe('mappings with <Cmd>', function()
end)
+ it("doesn't crash when invoking cmdline mode recursively #8859", function()
+ cmdmap('<F2>', 'norm! :foo')
+ feed(':bar')
+ screen:expect([[
+ some short lines |
+ of test text |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ :bar^ |
+ ]])
+
+ feed('<f2>x')
+ screen:expect([[
+ some short lines |
+ of test text |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ :barx^ |
+ ]])
+ end)
+
end)