aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/nvim/api/vimscript.c12
-rw-r--r--src/nvim/change.c4
-rw-r--r--src/nvim/cursor.c18
-rw-r--r--src/nvim/edit.c9
-rw-r--r--src/nvim/event/loop.c2
-rw-r--r--src/nvim/ex_docmd.c15
-rw-r--r--src/nvim/ex_getln.c11
-rw-r--r--src/nvim/globals.h3
-rw-r--r--src/nvim/grid.c2
-rw-r--r--src/nvim/indent_c.c2
-rw-r--r--src/nvim/strings.c8
-rw-r--r--src/nvim/terminal.c17
-rw-r--r--src/nvim/testdir/test_cindent.vim7
-rw-r--r--src/nvim/testdir/test_cmdline.vim12
-rw-r--r--src/nvim/testdir/test_visual.vim12
15 files changed, 93 insertions, 41 deletions
diff --git a/src/nvim/api/vimscript.c b/src/nvim/api/vimscript.c
index 42101af7f0..b8f7b33cd5 100644
--- a/src/nvim/api/vimscript.c
+++ b/src/nvim/api/vimscript.c
@@ -34,7 +34,7 @@
/// Unlike |nvim_command()| this function supports heredocs, script-scope (s:),
/// etc.
///
-/// On execution error: fails with VimL error, does not update v:errmsg.
+/// On execution error: fails with VimL error, updates v:errmsg.
///
/// @see |execute()|
/// @see |nvim_command()|
@@ -98,7 +98,7 @@ theend:
/// Executes an Ex command.
///
-/// On execution error: fails with VimL error, does not update v:errmsg.
+/// On execution error: fails with VimL error, updates v:errmsg.
///
/// Prefer using |nvim_cmd()| or |nvim_exec()| over this. To evaluate multiple lines of Vim script
/// or an Ex command directly, use |nvim_exec()|. To construct an Ex command using a structured
@@ -118,7 +118,7 @@ void nvim_command(String command, Error *err)
/// Evaluates a VimL |expression|.
/// Dictionaries and Lists are recursively expanded.
///
-/// On execution error: fails with VimL error, does not update v:errmsg.
+/// On execution error: fails with VimL error, updates v:errmsg.
///
/// @param expr VimL expression string
/// @param[out] err Error details, if any
@@ -226,7 +226,7 @@ free_vim_args:
/// Calls a VimL function with the given arguments.
///
-/// On execution error: fails with VimL error, does not update v:errmsg.
+/// On execution error: fails with VimL error, updates v:errmsg.
///
/// @param fn Function to call
/// @param args Function arguments packed in an Array
@@ -240,7 +240,7 @@ Object nvim_call_function(String fn, Array args, Error *err)
/// Calls a VimL |Dictionary-function| with the given arguments.
///
-/// On execution error: fails with VimL error, does not update v:errmsg.
+/// On execution error: fails with VimL error, updates v:errmsg.
///
/// @param dict Dictionary, or String evaluating to a VimL |self| dict
/// @param fn Name of the function defined on the VimL dict
@@ -996,6 +996,8 @@ end:
/// such as having spaces inside a command argument, expanding filenames in a command that otherwise
/// doesn't expand filenames, etc.
///
+/// On execution error: fails with VimL error, updates v:errmsg.
+///
/// @see |nvim_exec()|
/// @see |nvim_command()|
///
diff --git a/src/nvim/change.c b/src/nvim/change.c
index a21665dc23..94e5a19edc 100644
--- a/src/nvim/change.c
+++ b/src/nvim/change.c
@@ -209,6 +209,10 @@ static void changed_common(linenr_T lnum, colnr_T col, linenr_T lnume, long xtra
curwin->w_changelistidx = curbuf->b_changelistlen;
}
+ if (VIsual_active) {
+ check_visual_pos();
+ }
+
FOR_ALL_TAB_WINDOWS(tp, wp) {
if (wp->w_buffer == curbuf) {
// Mark this window to be redrawn later.
diff --git a/src/nvim/cursor.c b/src/nvim/cursor.c
index 11c734479c..1446257f7e 100644
--- a/src/nvim/cursor.c
+++ b/src/nvim/cursor.c
@@ -399,6 +399,24 @@ void check_cursor(void)
check_cursor_col();
}
+/// Check if VIsual position is valid, correct it if not.
+/// Can be called when in Visual mode and a change has been made.
+void check_visual_pos(void)
+{
+ if (VIsual.lnum > curbuf->b_ml.ml_line_count) {
+ VIsual.lnum = curbuf->b_ml.ml_line_count;
+ VIsual.col = 0;
+ VIsual.coladd = 0;
+ } else {
+ int len = (int)STRLEN(ml_get(VIsual.lnum));
+
+ if (VIsual.col > len) {
+ VIsual.col = len;
+ VIsual.coladd = 0;
+ }
+ }
+}
+
/// Make sure curwin->w_cursor is not on the NUL at the end of the line.
/// Allow it when in Visual mode and 'selection' is not "old".
void adjust_cursor_col(void)
diff --git a/src/nvim/edit.c b/src/nvim/edit.c
index 357e9184d7..aa77c03b48 100644
--- a/src/nvim/edit.c
+++ b/src/nvim/edit.c
@@ -6770,13 +6770,8 @@ static void stop_insert(pos_T *end_insert_pos, int esc, int nomove)
// <C-S-Right> may have started Visual mode, adjust the position for
// deleted characters.
- if (VIsual_active && VIsual.lnum == curwin->w_cursor.lnum) {
- int len = (int)STRLEN(get_cursor_line_ptr());
-
- if (VIsual.col > len) {
- VIsual.col = len;
- VIsual.coladd = 0;
- }
+ if (VIsual_active) {
+ check_visual_pos();
}
}
}
diff --git a/src/nvim/event/loop.c b/src/nvim/event/loop.c
index 89fced59c5..d4e20e2f66 100644
--- a/src/nvim/event/loop.c
+++ b/src/nvim/event/loop.c
@@ -143,7 +143,7 @@ bool loop_close(Loop *loop, bool wait)
while (true) {
// Run the loop to tickle close-callbacks (which should then free memory).
// Use UV_RUN_NOWAIT to avoid a hang. #11820
- uv_run(&loop->uv, didstop ? UV_RUN_DEFAULT : UV_RUN_NOWAIT);
+ uv_run(&loop->uv, didstop ? UV_RUN_DEFAULT : UV_RUN_NOWAIT); // -V547
if ((uv_loop_close(&loop->uv) != UV_EBUSY) || !wait) {
break;
}
diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c
index 0510faa57d..7506c353dd 100644
--- a/src/nvim/ex_docmd.c
+++ b/src/nvim/ex_docmd.c
@@ -345,7 +345,7 @@ int do_cmdline(char *cmdline, LineGetter fgetline, void *cookie, int flags)
// here. The value of 200 allows nested function calls, ":source", etc.
// Allow 200 or 'maxfuncdepth', whatever is larger.
if (call_depth >= 200 && call_depth >= p_mfd) {
- emsg(_("E169: Command too recursive"));
+ emsg(_(e_command_too_recursive));
// When converting to an exception, we do not include the command name
// since this is not an error of the specific command.
do_errthrow((cstack_T *)NULL, NULL);
@@ -1683,14 +1683,13 @@ void execute_cmd(exarg_T *eap, CmdParseInfo *cmdinfo)
(eap->argt & EX_BUFUNL) != 0, false, false);
eap->addr_count = 1;
// Shift each argument by 1
- if (eap->args != NULL) {
- for (size_t i = 0; i < eap->argc - 1; i++) {
- eap->args[i] = eap->args[i + 1];
- }
- // Make the last argument point to the NUL terminator at the end of string
- eap->args[eap->argc - 1] = eap->args[eap->argc - 1] + eap->arglens[eap->argc - 1];
- eap->argc -= 1;
+ for (size_t i = 0; i < eap->argc - 1; i++) {
+ eap->args[i] = eap->args[i + 1];
}
+ // Make the last argument point to the NUL terminator at the end of string
+ eap->args[eap->argc - 1] = eap->args[eap->argc - 1] + eap->arglens[eap->argc - 1];
+ eap->argc -= 1;
+
eap->arg = eap->args[0];
}
if (eap->line2 < 0) { // failed
diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c
index 114f1e2ae5..1d496cbf25 100644
--- a/src/nvim/ex_getln.c
+++ b/src/nvim/ex_getln.c
@@ -804,6 +804,12 @@ static uint8_t *command_line_enter(int firstc, long count, int indent, bool init
ccline.cmdlen = s->indent;
}
+ if (cmdline_level == 50) {
+ // Somehow got into a loop recursively calling getcmdline(), bail out.
+ emsg(_(e_command_too_recursive));
+ goto theend;
+ }
+
ExpandInit(&s->xpc);
ccline.xpc = &s->xpc;
@@ -995,12 +1001,13 @@ static uint8_t *command_line_enter(int firstc, long count, int indent, bool init
State = s->save_State;
setmouse();
ui_cursor_shape(); // may show different cursor shape
+ sb_text_end_cmdline();
+
+theend:
xfree(s->save_p_icm);
xfree(ccline.last_colors.cmdbuff);
kv_destroy(ccline.last_colors.colors);
- sb_text_end_cmdline();
-
char_u *p = ccline.cmdbuff;
if (ui_has(kUICmdline)) {
diff --git a/src/nvim/globals.h b/src/nvim/globals.h
index e34e3983db..3231ac011a 100644
--- a/src/nvim/globals.h
+++ b/src/nvim/globals.h
@@ -877,7 +877,8 @@ EXTERN char e_api_spawn_failed[] INIT(= N_("E903: Could not spawn API job"));
EXTERN char e_argreq[] INIT(= N_("E471: Argument required"));
EXTERN char e_backslash[] INIT(= N_("E10: \\ should be followed by /, ? or &"));
EXTERN char e_cmdwin[] INIT(= N_("E11: Invalid in command-line window; <CR> executes, CTRL-C quits"));
-EXTERN char e_curdir[] INIT(= N_( "E12: Command not allowed from exrc/vimrc in current dir or tag search"));
+EXTERN char e_curdir[] INIT(= N_("E12: Command not allowed from exrc/vimrc in current dir or tag search"));
+EXTERN char e_command_too_recursive[] INIT(= N_("E169: Command too recursive"));
EXTERN char e_endif[] INIT(= N_("E171: Missing :endif"));
EXTERN char e_endtry[] INIT(= N_("E600: Missing :endtry"));
EXTERN char e_endwhile[] INIT(= N_("E170: Missing :endwhile"));
diff --git a/src/nvim/grid.c b/src/nvim/grid.c
index 8a5d8081c0..13429994de 100644
--- a/src/nvim/grid.c
+++ b/src/nvim/grid.c
@@ -63,7 +63,7 @@ void grid_clear_line(ScreenGrid *grid, size_t off, int width, bool valid)
void grid_invalidate(ScreenGrid *grid)
{
- (void)memset(grid->attrs, -1, sizeof(sattr_T) * (size_t)(grid->Rows * grid->Columns));
+ (void)memset(grid->attrs, -1, sizeof(sattr_T) * (size_t)grid->Rows * (size_t)grid->Columns);
}
bool grid_invalid_row(ScreenGrid *grid, int row)
diff --git a/src/nvim/indent_c.c b/src/nvim/indent_c.c
index 6f75183a5a..e6dc985726 100644
--- a/src/nvim/indent_c.c
+++ b/src/nvim/indent_c.c
@@ -150,7 +150,7 @@ static const char_u *skip_string(const char_u *p)
i++;
}
}
- if (p[i] == '\'') { // check for trailing '
+ if (p[i - 1] != NUL && p[i] == '\'') { // check for trailing '
p += i;
continue;
}
diff --git a/src/nvim/strings.c b/src/nvim/strings.c
index c0c942ffd2..cde2059a9d 100644
--- a/src/nvim/strings.c
+++ b/src/nvim/strings.c
@@ -634,12 +634,12 @@ static const void *tv_ptr(const typval_T *const tvs, int *const idxp)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
{
#define OFF(attr) offsetof(union typval_vval_union, attr)
- STATIC_ASSERT(OFF(v_string) == OFF(v_list)
+ STATIC_ASSERT(OFF(v_string) == OFF(v_list) // -V568
&& OFF(v_string) == OFF(v_dict)
&& OFF(v_string) == OFF(v_partial)
- && sizeof(tvs[0].vval.v_string) == sizeof(tvs[0].vval.v_list) // -V568
- && sizeof(tvs[0].vval.v_string) == sizeof(tvs[0].vval.v_dict) // -V568
- && sizeof(tvs[0].vval.v_string) == sizeof(tvs[0].vval.v_partial), // -V568
+ && sizeof(tvs[0].vval.v_string) == sizeof(tvs[0].vval.v_list)
+ && sizeof(tvs[0].vval.v_string) == sizeof(tvs[0].vval.v_dict)
+ && sizeof(tvs[0].vval.v_string) == sizeof(tvs[0].vval.v_partial),
"Strings, dictionaries, lists and partials are expected to be pointers, "
"so that all three of them can be accessed via v_string");
#undef OFF
diff --git a/src/nvim/terminal.c b/src/nvim/terminal.c
index 2d3102707c..c8f70d4afd 100644
--- a/src/nvim/terminal.c
+++ b/src/nvim/terminal.c
@@ -1374,26 +1374,21 @@ static void fetch_row(Terminal *term, int row, int end_col)
while (col < end_col) {
VTermScreenCell cell;
fetch_cell(term, row, col, &cell);
- int cell_len = 0;
if (cell.chars[0]) {
+ int cell_len = 0;
for (int i = 0; cell.chars[i]; i++) {
cell_len += utf_char2bytes((int)cell.chars[i], ptr + cell_len);
}
- } else {
- *ptr = ' ';
- cell_len = 1;
- }
- char c = *ptr;
- ptr += cell_len;
- if (c != ' ') {
- // only increase the line length if the last character is not whitespace
+ ptr += cell_len;
line_len = (size_t)(ptr - term->textbuf);
+ } else {
+ *ptr++ = ' ';
}
col += cell.width;
}
- // trim trailing whitespace
- term->textbuf[line_len] = 0;
+ // end of line
+ term->textbuf[line_len] = NUL;
}
static bool fetch_cell(Terminal *term, int row, int col, VTermScreenCell *cell)
diff --git a/src/nvim/testdir/test_cindent.vim b/src/nvim/testdir/test_cindent.vim
index 4d69aed96c..7ba8ef3397 100644
--- a/src/nvim/testdir/test_cindent.vim
+++ b/src/nvim/testdir/test_cindent.vim
@@ -5311,6 +5311,13 @@ func Test_cindent_case()
bwipe!
endfunc
+" This was reading past the end of the line
+func Test_cindent_check_funcdecl()
+ new
+ sil norm o0('\0=L
+ bwipe!
+endfunc
+
func Test_cindent_scopedecls()
new
setl cindent ts=4 sw=4
diff --git a/src/nvim/testdir/test_cmdline.vim b/src/nvim/testdir/test_cmdline.vim
index 759caac878..b2c752376f 100644
--- a/src/nvim/testdir/test_cmdline.vim
+++ b/src/nvim/testdir/test_cmdline.vim
@@ -1224,4 +1224,16 @@ func Test_screenpos_and_completion()
call feedkeys(":let a\<C-R>=Check_completion()\<CR>\<Esc>", "xt")
endfunc
+func Test_recursive_register()
+ let @= = ''
+ silent! ?e/
+ let caught = 'no'
+ try
+ normal //
+ catch /E169:/
+ let caught = 'yes'
+ endtry
+ call assert_equal('yes', caught)
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_visual.vim b/src/nvim/testdir/test_visual.vim
index 2b88deb813..41c29c5bb0 100644
--- a/src/nvim/testdir/test_visual.vim
+++ b/src/nvim/testdir/test_visual.vim
@@ -1249,11 +1249,23 @@ endfunc
func Test_visual_block_append_invalid_char()
" this was going over the end of the line
+ set isprint=@,161-255
new
call setline(1, [' let xxx', 'xxxxxˆ', 'xxxxxxxxxxx'])
exe "normal 0\<C-V>jjA-\<Esc>"
call assert_equal([' - let xxx', 'xxxxx -ˆ', 'xxxxxxxx-xxx'], getline(1, 3))
bwipe!
+ set isprint&
+endfunc
+
+func Test_visual_block_with_substitute()
+ " this was reading beyond the end of the line
+ new
+ norm a0)
+ sil! norm  O
+ s/)
+ sil! norm 
+ bwipe!
endfunc
func Test_visual_reselect_with_count()