aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/nvim/CMakeLists.txt1
-rw-r--r--src/nvim/api/autocmd.c112
-rw-r--r--src/nvim/autocmd.c59
-rw-r--r--src/nvim/eval.c3
-rw-r--r--src/nvim/eval/funcs.c2
-rw-r--r--src/nvim/ex_cmds2.c4
-rw-r--r--src/nvim/lua/executor.c3
-rw-r--r--src/nvim/map.c1
-rw-r--r--src/nvim/map.h1
-rw-r--r--src/nvim/ops.c70
-rw-r--r--src/nvim/screen.c6
-rw-r--r--src/nvim/testdir/test_autochdir.vim61
-rw-r--r--src/nvim/testdir/test_diffmode.vim26
-rw-r--r--src/nvim/testdir/test_registers.vim76
-rw-r--r--src/nvim/window.c3
-rw-r--r--src/nvim/window.h25
16 files changed, 370 insertions, 83 deletions
diff --git a/src/nvim/CMakeLists.txt b/src/nvim/CMakeLists.txt
index 9abefbe02a..9f29cae29d 100644
--- a/src/nvim/CMakeLists.txt
+++ b/src/nvim/CMakeLists.txt
@@ -342,6 +342,7 @@ add_custom_command(
${LUA_KEYMAP_MODULE_SOURCE} "vim.keymap"
DEPENDS
${CHAR_BLOB_GENERATOR}
+ ${LUA_INIT_PACKAGES_MODULE_SOURCE}
${LUA_EDITOR_MODULE_SOURCE}
${LUA_SHARED_MODULE_SOURCE}
${LUA_INSPECT_MODULE_SOURCE}
diff --git a/src/nvim/api/autocmd.c b/src/nvim/api/autocmd.c
index 685667ac64..5ede0e5265 100644
--- a/src/nvim/api/autocmd.c
+++ b/src/nvim/api/autocmd.c
@@ -40,7 +40,7 @@ static int64_t next_autocmd_id = 1;
///
/// @param opts Optional Parameters:
/// - event : Name or list of name of events to match against
-/// - group (string): Name of group to match against
+/// - group (string|int): Name or id of group to match against
/// - pattern: Pattern or list of patterns to match against. Cannot be used with {buffer}
/// - buffer: Buffer number or list of buffer numbers for buffer local autocommands
/// |autocmd-buflocal|. Cannot be used with {pattern}
@@ -62,19 +62,27 @@ Array nvim_get_autocmds(Dict(get_autocmds) *opts, Error *err)
int group = 0;
- if (opts->group.type != kObjectTypeNil) {
- Object v = opts->group;
- if (v.type != kObjectTypeString) {
- api_set_error(err, kErrorTypeValidation, "group must be a string.");
- goto cleanup;
- }
-
- group = augroup_find(v.data.string.data);
-
- if (group < 0) {
- api_set_error(err, kErrorTypeValidation, "invalid augroup passed.");
+ switch (opts->group.type) {
+ case kObjectTypeNil:
+ break;
+ case kObjectTypeString:
+ group = augroup_find(opts->group.data.string.data);
+ if (group < 0) {
+ api_set_error(err, kErrorTypeValidation, "invalid augroup passed.");
+ goto cleanup;
+ }
+ break;
+ case kObjectTypeInteger:
+ group = (int)opts->group.data.integer;
+ char *name = augroup_name(group);
+ if (!augroup_exists(name)) {
+ api_set_error(err, kErrorTypeValidation, "invalid augroup passed.");
+ goto cleanup;
+ }
+ break;
+ default:
+ api_set_error(err, kErrorTypeValidation, "group must be a string or an integer.");
goto cleanup;
- }
}
if (opts->event.type != kObjectTypeNil) {
@@ -321,7 +329,7 @@ cleanup:
/// - buffer: (bufnr)
/// - create a |autocmd-buflocal| autocmd.
/// - NOTE: Cannot be used with {pattern}
-/// - group: (string) The augroup name
+/// - group: (string|int) The augroup name or id
/// - once: (boolean) - See |autocmd-once|
/// - nested: (boolean) - See |autocmd-nested|
/// - desc: (string) - Description of the autocmd
@@ -406,23 +414,29 @@ Integer nvim_create_autocmd(uint64_t channel_id, Object event, Dict(create_autoc
bool is_once = api_object_to_bool(opts->once, "once", false, err);
bool is_nested = api_object_to_bool(opts->nested, "nested", false, err);
- // TODO(tjdevries): accept number for namespace instead
- if (opts->group.type != kObjectTypeNil) {
- Object *v = &opts->group;
- if (v->type != kObjectTypeString) {
- api_set_error(err, kErrorTypeValidation, "'group' must be a string");
- goto cleanup;
- }
-
- au_group = augroup_find(v->data.string.data);
-
- if (au_group == AUGROUP_ERROR) {
- api_set_error(err,
- kErrorTypeException,
- "invalid augroup: %s", v->data.string.data);
-
+ switch (opts->group.type) {
+ case kObjectTypeNil:
+ break;
+ case kObjectTypeString:
+ au_group = augroup_find(opts->group.data.string.data);
+ if (au_group == AUGROUP_ERROR) {
+ api_set_error(err,
+ kErrorTypeValidation,
+ "invalid augroup: %s", opts->group.data.string.data);
+ goto cleanup;
+ }
+ break;
+ case kObjectTypeInteger:
+ au_group = (int)opts->group.data.integer;
+ char *name = augroup_name(au_group);
+ if (!augroup_exists(name)) {
+ api_set_error(err, kErrorTypeValidation, "invalid augroup: %d", au_group);
+ goto cleanup;
+ }
+ break;
+ default:
+ api_set_error(err, kErrorTypeValidation, "'group' must be a string or an integer.");
goto cleanup;
- }
}
if (opts->pattern.type != kObjectTypeNil && opts->buffer.type != kObjectTypeNil) {
@@ -624,7 +638,7 @@ void nvim_del_augroup_by_name(String name)
/// - NOTE: Cannot be used with {pattern}
/// - pattern (string|table) - optional, defaults to "*".
/// - NOTE: Cannot be used with {buffer}
-/// - group (string) - autocmd group name
+/// - group (string|int) - autocmd group name or id
/// - modeline (boolean) - Default true, see |<nomodeline>|
void nvim_do_autocmd(Object event, Dict(do_autocmd) *opts, Error *err)
FUNC_API_SINCE(9)
@@ -644,21 +658,29 @@ void nvim_do_autocmd(Object event, Dict(do_autocmd) *opts, Error *err)
goto cleanup;
}
- if (opts->group.type != kObjectTypeNil) {
- if (opts->group.type != kObjectTypeString) {
- api_set_error(err, kErrorTypeValidation, "'group' must be a string");
- goto cleanup;
- }
-
- au_group = augroup_find(opts->group.data.string.data);
-
- if (au_group == AUGROUP_ERROR) {
- api_set_error(err,
- kErrorTypeException,
- "invalid augroup: %s", opts->group.data.string.data);
-
+ switch (opts->group.type) {
+ case kObjectTypeNil:
+ break;
+ case kObjectTypeString:
+ au_group = augroup_find(opts->group.data.string.data);
+ if (au_group == AUGROUP_ERROR) {
+ api_set_error(err,
+ kErrorTypeValidation,
+ "invalid augroup: %s", opts->group.data.string.data);
+ goto cleanup;
+ }
+ break;
+ case kObjectTypeInteger:
+ au_group = (int)opts->group.data.integer;
+ char *name = augroup_name(au_group);
+ if (!augroup_exists(name)) {
+ api_set_error(err, kErrorTypeValidation, "invalid augroup: %d", au_group);
+ goto cleanup;
+ }
+ break;
+ default:
+ api_set_error(err, kErrorTypeValidation, "'group' must be a string or an integer.");
goto cleanup;
- }
}
if (opts->buffer.type != kObjectTypeNil) {
diff --git a/src/nvim/autocmd.c b/src/nvim/autocmd.c
index 7cb493f57d..a850e5c1a0 100644
--- a/src/nvim/autocmd.c
+++ b/src/nvim/autocmd.c
@@ -105,15 +105,24 @@ static char_u *old_termresponse = NULL;
#define FOR_ALL_AUPATS_IN_EVENT(event, ap) \
for (AutoPat *ap = first_autopat[event]; ap != NULL; ap = ap->next) // NOLINT
-// Map of autocmd group names.
+// Map of autocmd group names and ids.
// name -> ID
-static Map(String, int) augroup_map = MAP_INIT;
+// ID -> name
+static Map(String, int) map_augroup_name_to_id = MAP_INIT;
+static Map(int, String) map_augroup_id_to_name = MAP_INIT;
-static void augroup_map_del(char *name)
+static void augroup_map_del(int id, char *name)
{
- String key = map_key(String, int)(&augroup_map, cstr_as_string(name));
- map_del(String, int)(&augroup_map, key);
- api_free_string(key);
+ if (name != NULL) {
+ String key = map_key(String, int)(&map_augroup_name_to_id, cstr_as_string(name));
+ map_del(String, int)(&map_augroup_name_to_id, key);
+ api_free_string(key);
+ }
+ if (id > 0) {
+ String mapped = map_get(int, String)(&map_augroup_id_to_name, id);
+ api_free_string(mapped);
+ map_del(int, String)(&map_augroup_id_to_name, id);
+ }
}
@@ -382,12 +391,14 @@ int augroup_add(char *name)
}
if (existing_id == AUGROUP_DELETED) {
- augroup_map_del(name);
+ augroup_map_del(existing_id, name);
}
int next_id = next_augroup_id++;
- String name_copy = cstr_to_string(name);
- map_put(String, int)(&augroup_map, name_copy, next_id);
+ String name_key = cstr_to_string(name);
+ String name_val = cstr_to_string(name);
+ map_put(String, int)(&map_augroup_name_to_id, name_key, next_id);
+ map_put(int, String)(&map_augroup_id_to_name, next_id, name_val);
return next_id;
}
@@ -416,7 +427,8 @@ void augroup_del(char *name, bool stupid_legacy_mode)
FOR_ALL_AUPATS_IN_EVENT(event, ap) {
if (ap->group == i && ap->pat != NULL) {
give_warning((char_u *)_("W19: Deleting augroup that is still in use"), true);
- map_put(String, int)(&augroup_map, cstr_as_string(name), AUGROUP_DELETED);
+ map_put(String, int)(&map_augroup_name_to_id, cstr_as_string(name), AUGROUP_DELETED);
+ augroup_map_del(ap->group, NULL);
return;
}
}
@@ -432,7 +444,7 @@ void augroup_del(char *name, bool stupid_legacy_mode)
}
// Remove the group because it's not currently in use.
- augroup_map_del(name);
+ augroup_map_del(i, name);
au_cleanup();
}
}
@@ -445,7 +457,7 @@ void augroup_del(char *name, bool stupid_legacy_mode)
int augroup_find(const char *name)
FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
{
- int existing_id = map_get(String, int)(&augroup_map, cstr_as_string((char *)name));
+ int existing_id = map_get(String, int)(&map_augroup_name_to_id, cstr_as_string((char *)name));
if (existing_id == AUGROUP_DELETED) {
return existing_id;
}
@@ -487,13 +499,10 @@ char *augroup_name(int group)
return NULL;
}
- String key;
- int value;
- map_foreach(&augroup_map, key, value, {
- if (value == group) {
- return key.data;
- }
- });
+ String key = map_get(int, String)(&map_augroup_id_to_name, group);
+ if (key.data != NULL) {
+ return key.data;
+ }
// If it's not in the map anymore, then it must have been deleted.
return (char *)get_deleted_augroup();
@@ -526,7 +535,7 @@ void do_augroup(char_u *arg, int del_group)
String name;
int value;
- map_foreach(&augroup_map, name, value, {
+ map_foreach(&map_augroup_name_to_id, name, value, {
if (value > 0) {
msg_puts(name.data);
} else {
@@ -556,11 +565,17 @@ void free_all_autocmds(void)
// Delete the augroup_map, including free the data
String name;
int id;
- map_foreach(&augroup_map, name, id, {
+ map_foreach(&map_augroup_name_to_id, name, id, {
+ (void)id;
+ api_free_string(name);
+ })
+ map_destroy(String, int)(&map_augroup_name_to_id);
+
+ map_foreach(&map_augroup_id_to_name, id, name, {
(void)id;
api_free_string(name);
})
- map_destroy(String, int)(&augroup_map);
+ map_destroy(int, String)(&map_augroup_id_to_name);
}
#endif
diff --git a/src/nvim/eval.c b/src/nvim/eval.c
index aa7b9e80a4..8cdb03c341 100644
--- a/src/nvim/eval.c
+++ b/src/nvim/eval.c
@@ -7789,8 +7789,7 @@ bool callback_call(Callback *const callback, const int argcount_in, typval_T *co
break;
case kCallbackLua:
- ILOG(" We tryin to call dat dang lua ref ");
- nlua_call_ref(callback->data.luaref, "aucmd", args, false, NULL);
+ nlua_call_ref(callback->data.luaref, NULL, args, false, NULL);
return false;
break;
diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c
index d207dcb527..f47c9c482b 100644
--- a/src/nvim/eval/funcs.c
+++ b/src/nvim/eval/funcs.c
@@ -11411,7 +11411,7 @@ static void f_synIDattr(typval_T *argvars, typval_T *rettv, FunPtr fptr)
case 'u': {
const size_t len = STRLEN(what);
if (len <= 5 || (TOLOWER_ASC(what[5]) == 'l' && len <= 9)) { // underline
- p = highlight_has_attr(id, HL_UNDERCURL, modec);
+ p = highlight_has_attr(id, HL_UNDERLINE, modec);
} else if (TOLOWER_ASC(what[5]) == 'c') { // undercurl
p = highlight_has_attr(id, HL_UNDERCURL, modec);
} else if (len > 9 && TOLOWER_ASC(what[9]) == 'l') { // underlineline
diff --git a/src/nvim/ex_cmds2.c b/src/nvim/ex_cmds2.c
index 2a40e50014..5c040adc1c 100644
--- a/src/nvim/ex_cmds2.c
+++ b/src/nvim/ex_cmds2.c
@@ -1698,7 +1698,7 @@ static bool concat_continued_line(garray_T *const ga, const int init_growsize,
return false;
}
if (ga->ga_len > init_growsize) {
- ga_set_growsize(ga, MAX(ga->ga_len, 8000));
+ ga_set_growsize(ga, MIN(ga->ga_len, 8000));
}
ga_concat_len(ga, (const char *)line + 1, len - 1);
return true;
@@ -1852,7 +1852,7 @@ static void cmd_source_buffer(const exarg_T *const eap)
for (linenr_T curr_lnum = eap->line1; curr_lnum <= final_lnum; curr_lnum++) {
// Adjust growsize to current length to speed up concatenating many lines.
if (ga.ga_len > 400) {
- ga_set_growsize(&ga, MAX(ga.ga_len, 8000));
+ ga_set_growsize(&ga, MIN(ga.ga_len, 8000));
}
ga_concat(&ga, (char *)ml_get(curr_lnum));
ga_append(&ga, NL);
diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c
index 29a3c515c2..6aaff100ca 100644
--- a/src/nvim/lua/executor.c
+++ b/src/nvim/lua/executor.c
@@ -565,7 +565,8 @@ static bool nlua_init_packages(lua_State *lstate)
lua_getglobal(lstate, "require");
lua_pushstring(lstate, "vim._init_packages");
if (nlua_pcall(lstate, 1, 0)) {
- nlua_error(lstate, _("E5106: Error while loading packages: %.*s\n"));
+ mch_errmsg(lua_tostring(lstate, -1));
+ mch_errmsg("\n");
return false;
}
diff --git a/src/nvim/map.c b/src/nvim/map.c
index 091d653046..4e39eb8c07 100644
--- a/src/nvim/map.c
+++ b/src/nvim/map.c
@@ -178,6 +178,7 @@ MAP_IMPL(String, MsgpackRpcRequestHandler, MSGPACK_HANDLER_INITIALIZER)
MAP_IMPL(HlEntry, int, DEFAULT_INITIALIZER)
MAP_IMPL(String, handle_T, 0)
MAP_IMPL(String, int, DEFAULT_INITIALIZER)
+MAP_IMPL(int, String, DEFAULT_INITIALIZER)
MAP_IMPL(ColorKey, ColorItem, COLOR_ITEM_INITIALIZER)
diff --git a/src/nvim/map.h b/src/nvim/map.h
index c9c89bf2fd..00f72386a7 100644
--- a/src/nvim/map.h
+++ b/src/nvim/map.h
@@ -47,6 +47,7 @@ MAP_DECLS(String, MsgpackRpcRequestHandler)
MAP_DECLS(HlEntry, int)
MAP_DECLS(String, handle_T)
MAP_DECLS(String, int)
+MAP_DECLS(int, String)
MAP_DECLS(ColorKey, ColorItem)
diff --git a/src/nvim/ops.c b/src/nvim/ops.c
index b5c7020dee..3f51210781 100644
--- a/src/nvim/ops.c
+++ b/src/nvim/ops.c
@@ -1023,6 +1023,60 @@ static int stuff_yank(int regname, char_u *p)
static int execreg_lastc = NUL;
+/// When executing a register as a series of ex-commands, if the
+/// line-continuation character is used for a line, then join it with one or
+/// more previous lines. Note that lines are processed backwards starting from
+/// the last line in the register.
+///
+/// @param lines list of lines in the register
+/// @param idx index of the line starting with \ or "\. Join this line with all the immediate
+/// predecessor lines that start with a \ and the first line that doesn't start
+/// with a \. Lines that start with a comment "\ character are ignored.
+/// @returns the concatenated line. The index of the line that should be
+/// processed next is returned in idx.
+static char_u *execreg_line_continuation(char_u **lines, size_t *idx)
+{
+ size_t i = *idx;
+ assert(i > 0);
+ const size_t cmd_end = i;
+
+ garray_T ga;
+ ga_init(&ga, (int)sizeof(char_u), 400);
+
+ char_u *p;
+
+ // search backwards to find the first line of this command.
+ // Any line not starting with \ or "\ is the start of the
+ // command.
+ while (--i > 0) {
+ p = skipwhite(lines[i]);
+ if (*p != '\\' && (p[0] != '"' || p[1] != '\\' || p[2] != ' ')) {
+ break;
+ }
+ }
+ const size_t cmd_start = i;
+
+ // join all the lines
+ ga_concat(&ga, (char *)lines[cmd_start]);
+ for (size_t j = cmd_start + 1; j <= cmd_end; j++) {
+ p = skipwhite(lines[j]);
+ if (*p == '\\') {
+ // Adjust the growsize to the current length to
+ // speed up concatenating many lines.
+ if (ga.ga_len > 400) {
+ ga_set_growsize(&ga, MIN(ga.ga_len, 8000));
+ }
+ ga_concat(&ga, (char *)(p + 1));
+ }
+ }
+ ga_append(&ga, NUL);
+ char_u *str = vim_strsave(ga.ga_data);
+ ga_clear(&ga);
+
+ *idx = i;
+ return str;
+}
+
/// Execute a yank register: copy it into the stuff buffer
///
/// @param colon insert ':' before each line
@@ -1111,7 +1165,21 @@ int do_execreg(int regname, int colon, int addcr, int silent)
return FAIL;
}
}
- escaped = vim_strsave_escape_ks(reg->y_array[i]);
+
+ // Handle line-continuation for :@<register>
+ char_u *str = reg->y_array[i];
+ bool free_str = false;
+ if (colon && i > 0) {
+ p = skipwhite(str);
+ if (*p == '\\' || (p[0] == '"' && p[1] == '\\' && p[2] == ' ')) {
+ str = execreg_line_continuation(reg->y_array, &i);
+ free_str = true;
+ }
+ }
+ escaped = vim_strsave_escape_ks(str);
+ if (free_str) {
+ xfree(str);
+ }
retval = ins_typebuf(escaped, remap, 0, true, silent);
xfree(escaped);
if (retval == FAIL) {
diff --git a/src/nvim/screen.c b/src/nvim/screen.c
index ee1acd8d03..1cdee7c972 100644
--- a/src/nvim/screen.c
+++ b/src/nvim/screen.c
@@ -2890,9 +2890,9 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
} else if (wp->w_p_cul
&& lnum == wp->w_cursor.lnum
&& (wp->w_p_culopt_flags & CULOPT_NBR)
- && (row == startrow
- || wp->w_p_culopt_flags & CULOPT_LINE)
- && filler_todo == 0) {
+ && (row == startrow + filler_lines
+ || (row > startrow + filler_lines
+ && wp->w_p_culopt_flags & CULOPT_LINE))) {
// When 'cursorline' is set highlight the line number of
// the current line differently.
// When 'cursorlineopt' has "screenline" only highlight
diff --git a/src/nvim/testdir/test_autochdir.vim b/src/nvim/testdir/test_autochdir.vim
index 53ed4617f7..4229095f9f 100644
--- a/src/nvim/testdir/test_autochdir.vim
+++ b/src/nvim/testdir/test_autochdir.vim
@@ -26,6 +26,54 @@ func Test_set_filename()
call delete('samples/Xtest')
endfunc
+func Test_set_filename_other_window()
+ CheckFunction test_autochdir
+ let cwd = getcwd()
+ call test_autochdir()
+ call mkdir('Xa')
+ call mkdir('Xb')
+ call mkdir('Xc')
+ try
+ args Xa/aaa.txt Xb/bbb.txt
+ set acd
+ let winid = win_getid()
+ snext
+ call assert_equal('Xb', substitute(getcwd(), '.*/\([^/]*\)$', '\1', ''))
+ call win_execute(winid, 'file ' .. cwd .. '/Xc/ccc.txt')
+ call assert_equal('Xb', substitute(getcwd(), '.*/\([^/]*\)$', '\1', ''))
+ finally
+ set noacd
+ call chdir(cwd)
+ call delete('Xa', 'rf')
+ call delete('Xb', 'rf')
+ call delete('Xc', 'rf')
+ bwipe! aaa.txt
+ bwipe! bbb.txt
+ bwipe! ccc.txt
+ endtry
+endfunc
+
+func Test_acd_win_execute()
+ CheckFunction test_autochdir
+ let cwd = getcwd()
+ set acd
+ call test_autochdir()
+
+ call mkdir('Xfile')
+ let winid = win_getid()
+ new Xfile/file
+ call assert_match('testdir.Xfile$', getcwd())
+ cd ..
+ call assert_match('testdir$', getcwd())
+ call win_execute(winid, 'echo')
+ call assert_match('testdir$', getcwd())
+
+ bwipe!
+ set noacd
+ call chdir(cwd)
+ call delete('Xfile', 'rf')
+endfunc
+
func Test_verbose_pwd()
CheckFunction test_autochdir
let cwd = getcwd()
@@ -42,20 +90,27 @@ func Test_verbose_pwd()
set acd
wincmd w
call assert_match('\[autochdir\].*testdir$', execute('verbose pwd'))
- execute 'lcd' cwd
- call assert_match('\[window\].*testdir$', execute('verbose pwd'))
execute 'tcd' cwd
call assert_match('\[tabpage\].*testdir$', execute('verbose pwd'))
execute 'cd' cwd
call assert_match('\[global\].*testdir$', execute('verbose pwd'))
+ execute 'lcd' cwd
+ call assert_match('\[window\].*testdir$', execute('verbose pwd'))
edit
call assert_match('\[autochdir\].*testdir$', execute('verbose pwd'))
+ enew
+ wincmd w
+ call assert_match('\[autochdir\].*testdir[/\\]Xautodir', execute('verbose pwd'))
+ wincmd w
+ call assert_match('\[window\].*testdir$', execute('verbose pwd'))
wincmd w
call assert_match('\[autochdir\].*testdir[/\\]Xautodir', execute('verbose pwd'))
set noacd
call assert_match('\[autochdir\].*testdir[/\\]Xautodir', execute('verbose pwd'))
wincmd w
- call assert_match('\[global\].*testdir', execute('verbose pwd'))
+ call assert_match('\[window\].*testdir$', execute('verbose pwd'))
+ execute 'cd' cwd
+ call assert_match('\[global\].*testdir$', execute('verbose pwd'))
wincmd w
call assert_match('\[window\].*testdir[/\\]Xautodir', execute('verbose pwd'))
diff --git a/src/nvim/testdir/test_diffmode.vim b/src/nvim/testdir/test_diffmode.vim
index 482d39056f..10eb979b45 100644
--- a/src/nvim/testdir/test_diffmode.vim
+++ b/src/nvim/testdir/test_diffmode.vim
@@ -1017,6 +1017,32 @@ func Test_diff_with_cursorline()
call delete('Xtest_diff_cursorline')
endfunc
+func Test_diff_with_cursorline_number()
+ CheckScreendump
+
+ let lines =<< trim END
+ hi CursorLine ctermbg=red ctermfg=white
+ hi CursorLineNr ctermbg=white ctermfg=black cterm=underline
+ set cursorline number
+ call setline(1, ["baz", "foo", "foo", "bar"])
+ 2
+ vnew
+ call setline(1, ["foo", "foo", "bar"])
+ windo diffthis
+ 1wincmd w
+ END
+ call writefile(lines, 'Xtest_diff_cursorline_number')
+ let buf = RunVimInTerminal('-S Xtest_diff_cursorline_number', {})
+
+ call VerifyScreenDump(buf, 'Test_diff_with_cursorline_number_01', {})
+ call term_sendkeys(buf, ":set cursorlineopt=number\r")
+ call VerifyScreenDump(buf, 'Test_diff_with_cursorline_number_02', {})
+
+ " clean up
+ call StopVimInTerminal(buf)
+ call delete('Xtest_diff_cursorline_number')
+endfunc
+
func Test_diff_with_cursorline_breakindent()
CheckScreendump
diff --git a/src/nvim/testdir/test_registers.vim b/src/nvim/testdir/test_registers.vim
index 23e39eba35..ecc65b240b 100644
--- a/src/nvim/testdir/test_registers.vim
+++ b/src/nvim/testdir/test_registers.vim
@@ -482,6 +482,82 @@ func Test_v_register()
bwipe!
endfunc
+" Test for executing the contents of a register as an Ex command with line
+" continuation.
+func Test_execute_reg_as_ex_cmd()
+ " Line continuation with just two lines
+ let code =<< trim END
+ let l = [
+ \ 1]
+ END
+ let @r = code->join("\n")
+ let l = []
+ @r
+ call assert_equal([1], l)
+
+ " Line continuation with more than two lines
+ let code =<< trim END
+ let l = [
+ \ 1,
+ \ 2,
+ \ 3]
+ END
+ let @r = code->join("\n")
+ let l = []
+ @r
+ call assert_equal([1, 2, 3], l)
+
+ " use comments interspersed with code
+ let code =<< trim END
+ let l = [
+ "\ one
+ \ 1,
+ "\ two
+ \ 2,
+ "\ three
+ \ 3]
+ END
+ let @r = code->join("\n")
+ let l = []
+ @r
+ call assert_equal([1, 2, 3], l)
+
+ " use line continuation in the middle
+ let code =<< trim END
+ let a = "one"
+ let l = [
+ \ 1,
+ \ 2]
+ let b = "two"
+ END
+ let @r = code->join("\n")
+ let l = []
+ @r
+ call assert_equal([1, 2], l)
+ call assert_equal("one", a)
+ call assert_equal("two", b)
+
+ " only one line with a \
+ let @r = "\\let l = 1"
+ call assert_fails('@r', 'E10:')
+
+ " only one line with a "\
+ let @r = ' "\ let i = 1'
+ @r
+ call assert_false(exists('i'))
+
+ " first line also begins with a \
+ let @r = "\\let l = [\n\\ 1]"
+ call assert_fails('@r', 'E10:')
+
+ " Test with a large number of lines
+ let @r = "let str = \n"
+ let @r ..= repeat(" \\ 'abcdefghijklmnopqrstuvwxyz' ..\n", 312)
+ let @r ..= ' \ ""'
+ @r
+ call assert_equal(repeat('abcdefghijklmnopqrstuvwxyz', 312), str)
+endfunc
+
func Test_ve_blockpaste()
new
set ve=all
diff --git a/src/nvim/window.c b/src/nvim/window.c
index 83048d911f..d5299202b0 100644
--- a/src/nvim/window.c
+++ b/src/nvim/window.c
@@ -6763,9 +6763,6 @@ void restore_win_noblock(switchwin_T *switchwin, bool no_display)
curwin = switchwin->sw_curwin;
curbuf = curwin->w_buffer;
}
- // If called by win_execute() and executing the command changed the
- // directory, it now has to be restored.
- fix_current_dir();
}
/// Make "buf" the current buffer.
diff --git a/src/nvim/window.h b/src/nvim/window.h
index e2fd2c515d..42701f72b4 100644
--- a/src/nvim/window.h
+++ b/src/nvim/window.h
@@ -5,6 +5,7 @@
#include "nvim/buffer_defs.h"
#include "nvim/mark.h"
+#include "nvim/os/os.h"
// Values for file_name_in_line()
#define FNAME_MESS 1 // give error message
@@ -47,12 +48,36 @@ typedef struct {
do { \
win_T *const wp_ = (wp); \
const pos_T curpos_ = wp_->w_cursor; \
+ char_u cwd_[MAXPATHL]; \
+ char_u autocwd_[MAXPATHL]; \
+ bool apply_acd_ = false; \
+ int cwd_status_ = FAIL; \
+ /* Getting and setting directory can be slow on some systems, only do */ \
+ /* this when the current or target window/tab have a local directory or */ \
+ /* 'acd' is set. */ \
+ if (curwin != wp \
+ && (curwin->w_localdir != NULL || wp->w_localdir != NULL \
+ || (curtab != tp && (curtab->tp_localdir != NULL || tp->tp_localdir != NULL)) \
+ || p_acd)) { \
+ cwd_status_ = os_dirname(cwd_, MAXPATHL); \
+ } \
+ /* If 'acd' is set, check we are using that directory. If yes, then */ \
+ /* apply 'acd' afterwards, otherwise restore the current directory. */ \
+ if (cwd_status_ == OK && p_acd) { \
+ do_autochdir(); \
+ apply_acd_ = os_dirname(autocwd_, MAXPATHL) == OK && STRCMP(cwd_, autocwd_) == 0; \
+ } \
switchwin_T switchwin_; \
if (switch_win_noblock(&switchwin_, wp_, (tp), true) == OK) { \
check_cursor(); \
block; \
} \
restore_win_noblock(&switchwin_, true); \
+ if (apply_acd_) { \
+ do_autochdir(); \
+ } else if (cwd_status_ == OK) { \
+ os_chdir((char *)cwd_); \
+ } \
/* Update the status line if the cursor moved. */ \
if (win_valid(wp_) && !equalpos(curpos_, wp_->w_cursor)) { \
wp_->w_redr_status = true; \