aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rwxr-xr-xsrc/clint.py4
-rw-r--r--src/nvim/api/autocmd.c112
-rw-r--r--src/nvim/autocmd.c59
-rw-r--r--src/nvim/eval.c5
-rw-r--r--src/nvim/eval/funcs.c8
-rw-r--r--src/nvim/eval/userfunc.c8
-rw-r--r--src/nvim/ex_cmds2.c7
-rw-r--r--src/nvim/ex_docmd.c2
-rw-r--r--src/nvim/ex_eval.c2
-rw-r--r--src/nvim/fileio.c6
-rw-r--r--src/nvim/getchar.c2
-rw-r--r--src/nvim/highlight.c2
-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/marktree.c4
-rw-r--r--src/nvim/memline.c4
-rw-r--r--src/nvim/ops.c103
-rw-r--r--src/nvim/option.c8
-rw-r--r--src/nvim/regexp.c27
-rw-r--r--src/nvim/screen.c6
-rw-r--r--src/nvim/spell.c2
-rw-r--r--src/nvim/testdir/test_diffmode.vim26
-rw-r--r--src/nvim/testdir/test_registers.vim161
-rw-r--r--src/nvim/ui.c4
25 files changed, 423 insertions, 144 deletions
diff --git a/src/clint.py b/src/clint.py
index 4b7bf002e6..37b44920af 100755
--- a/src/clint.py
+++ b/src/clint.py
@@ -191,7 +191,6 @@ _ERROR_CATEGORIES = [
'readability/fn_size',
'readability/multiline_comment',
'readability/multiline_string',
- 'readability/nolint',
'readability/nul',
'readability/todo',
'readability/utf8',
@@ -298,9 +297,6 @@ def ParseNolintSuppressions(filename, raw_line, linenum, error):
if category in _ERROR_CATEGORIES:
_error_suppressions.setdefault(
category, set()).add(linenum)
- else:
- error(filename, linenum, 'readability/nolint', 5,
- 'Unknown NOLINT error category: %s' % category)
def ParseKnownErrorSuppressions(filename, raw_lines, linenum):
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 c5c03455b7..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;
@@ -9441,7 +9440,7 @@ void new_script_vars(scid_T id)
hashtab_T *ht;
scriptvar_T *sv;
- ga_grow(&ga_scripts, (int)(id - ga_scripts.ga_len));
+ ga_grow(&ga_scripts, id - ga_scripts.ga_len);
{
/* Re-allocating ga_data means that an ht_array pointing to
* ht_smallarray becomes invalid. We can recognize this: ht_mask is
diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c
index 7da4fe62e8..f47c9c482b 100644
--- a/src/nvim/eval/funcs.c
+++ b/src/nvim/eval/funcs.c
@@ -11413,13 +11413,13 @@ static void f_synIDattr(typval_T *argvars, typval_T *rettv, FunPtr fptr)
if (len <= 5 || (TOLOWER_ASC(what[5]) == 'l' && len <= 9)) { // underline
p = highlight_has_attr(id, HL_UNDERLINE, modec);
} else if (TOLOWER_ASC(what[5]) == 'c') { // undercurl
- p = highlight_has_attr(id, HL_UNDERCURL, modec);
+ p = highlight_has_attr(id, HL_UNDERCURL, modec);
} else if (len > 9 && TOLOWER_ASC(what[9]) == 'l') { // underlineline
- p = highlight_has_attr(id, HL_UNDERLINELINE, modec);
+ p = highlight_has_attr(id, HL_UNDERLINELINE, modec);
} else if (len > 6 && TOLOWER_ASC(what[6]) == 'o') { // underdot
- p = highlight_has_attr(id, HL_UNDERDOT, modec);
+ p = highlight_has_attr(id, HL_UNDERDOT, modec);
} else { // underdash
- p = highlight_has_attr(id, HL_UNDERDASH, modec);
+ p = highlight_has_attr(id, HL_UNDERDASH, modec);
}
break;
}
diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c
index 5764f9fbd4..471c4092fe 100644
--- a/src/nvim/eval/userfunc.c
+++ b/src/nvim/eval/userfunc.c
@@ -516,7 +516,7 @@ static char_u *fname_trans_sid(const char_u *const name, char_u *const fname_buf
if (llen > 0) {
fname_buf[0] = K_SPECIAL;
fname_buf[1] = KS_EXTRA;
- fname_buf[2] = (int)KE_SNR;
+ fname_buf[2] = KE_SNR;
int i = 3;
if (eval_fname_sid((const char *)name)) { // "<SID>" or "s:"
if (current_sctx.sc_sid <= 0) {
@@ -1713,7 +1713,7 @@ char_u *trans_function_name(char_u **pp, bool skip, int flags, funcdict_T *fdp,
// Check for hard coded <SNR>: already translated function ID (from a user
// command).
if ((*pp)[0] == K_SPECIAL && (*pp)[1] == KS_EXTRA
- && (*pp)[2] == (int)KE_SNR) {
+ && (*pp)[2] == KE_SNR) {
*pp += 3;
len = get_id_len((const char **)pp) + 3;
return (char_u *)xmemdupz(start, len);
@@ -1821,7 +1821,7 @@ char_u *trans_function_name(char_u **pp, bool skip, int flags, funcdict_T *fdp,
// Change "<SNR>" to the byte sequence.
name[0] = K_SPECIAL;
name[1] = KS_EXTRA;
- name[2] = (int)KE_SNR;
+ name[2] = KE_SNR;
memmove(name + 3, name + 5, strlen((char *)name + 5) + 1);
}
goto theend;
@@ -1888,7 +1888,7 @@ char_u *trans_function_name(char_u **pp, bool skip, int flags, funcdict_T *fdp,
if (!skip && lead > 0) {
name[0] = K_SPECIAL;
name[1] = KS_EXTRA;
- name[2] = (int)KE_SNR;
+ name[2] = KE_SNR;
if (sid_buf_len > 0) { // If it's "<SID>"
memcpy(name + 3, sid_buf, sid_buf_len);
}
diff --git a/src/nvim/ex_cmds2.c b/src/nvim/ex_cmds2.c
index 8666c7e33a..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;
@@ -1796,7 +1796,7 @@ scriptitem_T *new_script_item(char_u *const name, scid_T *const sid_out)
if (sid_out != NULL) {
*sid_out = sid;
}
- ga_grow(&script_items, (int)(sid - script_items.ga_len));
+ ga_grow(&script_items, sid - script_items.ga_len);
while (script_items.ga_len < sid) {
script_items.ga_len++;
SCRIPT_ITEM(script_items.ga_len).sn_name = NULL;
@@ -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);
@@ -2188,7 +2188,6 @@ scriptitem_T *get_current_script_id(char_u *fname, sctx_T *ret_sctx)
}
-
/// ":scriptnames"
void ex_scriptnames(exarg_T *eap)
{
diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c
index 6e915d98dc..a140d76858 100644
--- a/src/nvim/ex_docmd.c
+++ b/src/nvim/ex_docmd.c
@@ -8160,7 +8160,7 @@ static void ex_operators(exarg_T *eap)
case CMD_yank:
oa.op_type = OP_YANK;
- (void)op_yank(&oa, true, false);
+ (void)op_yank(&oa, true);
break;
default: // CMD_rshift or CMD_lshift
diff --git a/src/nvim/ex_eval.c b/src/nvim/ex_eval.c
index 6395bbc70b..25b6aa7d8a 100644
--- a/src/nvim/ex_eval.c
+++ b/src/nvim/ex_eval.c
@@ -430,7 +430,7 @@ char *get_exception_string(void *value, except_type_T type, char_u *cmdname, int
STRCAT(val, p);
p[-2] = NUL;
- sprintf((char *)(val + STRLEN(p)), " (%s)", &mesg[1]);
+ snprintf(val + STRLEN(p), strlen(" (%s)"), " (%s)", &mesg[1]);
p[-2] = '"';
}
break;
diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c
index 965aa8749d..c5a89d3371 100644
--- a/src/nvim/fileio.c
+++ b/src/nvim/fileio.c
@@ -3911,13 +3911,13 @@ static int check_mtime(buf_T *buf, FileInfo *file_info)
static bool time_differs(const FileInfo *file_info, long mtime, long mtime_ns) FUNC_ATTR_CONST
{
- return (long)file_info->stat.st_mtim.tv_nsec != mtime_ns
+ return file_info->stat.st_mtim.tv_nsec != mtime_ns
#if defined(__linux__) || defined(MSWIN)
// On a FAT filesystem, esp. under Linux, there are only 5 bits to store
// the seconds. Since the roundoff is done when flushing the inode, the
// time may change unexpectedly by one second!!!
- || (long)file_info->stat.st_mtim.tv_sec - mtime > 1
- || mtime - (long)file_info->stat.st_mtim.tv_sec > 1;
+ || file_info->stat.st_mtim.tv_sec - mtime > 1
+ || mtime - file_info->stat.st_mtim.tv_sec > 1;
#else
|| (long)file_info->stat.st_mtim.tv_sec != mtime;
#endif
diff --git a/src/nvim/getchar.c b/src/nvim/getchar.c
index 22d957d03d..299456f688 100644
--- a/src/nvim/getchar.c
+++ b/src/nvim/getchar.c
@@ -4140,7 +4140,7 @@ int makemap(FILE *fd, buf_T *buf)
}
for (p = mp->m_str; *p != NUL; p++) {
if (p[0] == K_SPECIAL && p[1] == KS_EXTRA
- && p[2] == (int)KE_SNR) {
+ && p[2] == KE_SNR) {
break;
}
}
diff --git a/src/nvim/highlight.c b/src/nvim/highlight.c
index a01d8369ba..a1fd0d0d66 100644
--- a/src/nvim/highlight.c
+++ b/src/nvim/highlight.c
@@ -327,7 +327,7 @@ void update_window_hl(win_T *wp, bool invalid)
wp->w_hl_attr_normal);
}
- for (int hlf = 0; hlf < (int)HLF_COUNT; hlf++) {
+ for (int hlf = 0; hlf < HLF_COUNT; hlf++) {
int attr;
if (wp->w_hl_ids[hlf] != 0) {
attr = hl_get_ui_attr(hlf, wp->w_hl_ids[hlf], false);
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/marktree.c b/src/nvim/marktree.c
index 918db8b76c..d2354dbf6b 100644
--- a/src/nvim/marktree.c
+++ b/src/nvim/marktree.c
@@ -558,8 +558,8 @@ void marktree_revise(MarkTree *b, MarkTreeIter *itr, uint8_t decor_level, mtkey_
{
// TODO(bfredl): clean up this mess and re-instantiate &= and |= forms
// once we upgrade to a non-broken version of gcc in functionaltest-lua CI
- rawkey(itr).flags = (uint16_t)((uint16_t)rawkey(itr).flags & (uint16_t)~MT_FLAG_DECOR_MASK);
- rawkey(itr).flags = (uint16_t)((uint16_t)rawkey(itr).flags
+ rawkey(itr).flags = (uint16_t)(rawkey(itr).flags & (uint16_t)~MT_FLAG_DECOR_MASK);
+ rawkey(itr).flags = (uint16_t)(rawkey(itr).flags
| (uint16_t)(decor_level << MT_FLAG_DECOR_OFFSET)
| (uint16_t)(key.flags & MT_FLAG_DECOR_MASK));
rawkey(itr).decor_full = key.decor_full;
diff --git a/src/nvim/memline.c b/src/nvim/memline.c
index 004ef36b36..59f57aa667 100644
--- a/src/nvim/memline.c
+++ b/src/nvim/memline.c
@@ -303,7 +303,7 @@ int ml_open(buf_T *buf)
b0p->b0_id[0] = BLOCK0_ID0;
b0p->b0_id[1] = BLOCK0_ID1;
- b0p->b0_magic_long = (long)B0_MAGIC_LONG;
+ b0p->b0_magic_long = B0_MAGIC_LONG;
b0p->b0_magic_int = (int)B0_MAGIC_INT;
b0p->b0_magic_short = (short)B0_MAGIC_SHORT;
b0p->b0_magic_char = B0_MAGIC_CHAR;
@@ -3709,7 +3709,7 @@ static char *findswapname(buf_T *buf, char **dirp, char *old_fname, bool *found_
static int b0_magic_wrong(ZERO_BL *b0p)
{
- return b0p->b0_magic_long != (long)B0_MAGIC_LONG
+ return b0p->b0_magic_long != B0_MAGIC_LONG
|| b0p->b0_magic_int != (int)B0_MAGIC_INT
|| b0p->b0_magic_short != (short)B0_MAGIC_SHORT
|| b0p->b0_magic_char != B0_MAGIC_CHAR;
diff --git a/src/nvim/ops.c b/src/nvim/ops.c
index b5c7020dee..23db7fe5a3 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) {
@@ -1504,20 +1572,20 @@ int op_delete(oparg_T *oap)
yankreg_T *reg = NULL;
int did_yank = false;
if (oap->regname != 0) {
- // yank without message
- did_yank = op_yank(oap, false, true);
- if (!did_yank) {
- // op_yank failed, don't do anything
+ // check for read-only register
+ if (!valid_yank_reg(oap->regname, true)) {
+ beep_flush();
return OK;
}
+ reg = get_yank_register(oap->regname, YREG_YANK); // yank into specif'd reg
+ op_yank_reg(oap, false, reg, is_append_register(oap->regname)); // yank without message
+ did_yank = true;
}
- /*
- * Put deleted text into register 1 and shift number registers if the
- * delete contains a line break, or when a regname has been specified.
- */
- if (oap->regname != 0 || oap->motion_type == kMTLineWise
- || oap->line_count > 1 || oap->use_reg_one) {
+ // Put deleted text into register 1 and shift number registers if the
+ // delete contains a line break, or when using a specific operator (Vi
+ // compatible)
+ if (oap->motion_type == kMTLineWise || oap->line_count > 1 || oap->use_reg_one) {
shift_delete_registers(is_append_register(oap->regname));
reg = &y_regs[1];
op_yank_reg(oap, false, reg, false);
@@ -2579,12 +2647,12 @@ void free_register(yankreg_T *reg)
/// Yanks the text between "oap->start" and "oap->end" into a yank register.
/// If we are to append (uppercase register), we first yank into a new yank
/// register and then concatenate the old and the new one.
+/// Do not call this from a delete operation. Use op_yank_reg() instead.
///
/// @param oap operator arguments
/// @param message show message when more than `&report` lines are yanked.
-/// @param deleting whether the function was called from a delete operation.
/// @returns whether the operation register was writable.
-bool op_yank(oparg_T *oap, bool message, int deleting)
+bool op_yank(oparg_T *oap, bool message)
FUNC_ATTR_NONNULL_ALL
{
// check for read-only register
@@ -2598,11 +2666,8 @@ bool op_yank(oparg_T *oap, bool message, int deleting)
yankreg_T *reg = get_yank_register(oap->regname, YREG_YANK);
op_yank_reg(oap, message, reg, is_append_register(oap->regname));
- // op_delete will set_clipboard and do_autocmd
- if (!deleting) {
- set_clipboard(oap->regname, reg);
- do_autocmd_textyankpost(oap, reg);
- }
+ set_clipboard(oap->regname, reg);
+ do_autocmd_textyankpost(oap, reg);
return true;
}
@@ -6630,7 +6695,7 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank)
} else {
curwin->w_p_lbr = lbr_saved;
oap->excl_tr_ws = cap->cmdchar == 'z';
- (void)op_yank(oap, !gui_yank, false);
+ (void)op_yank(oap, !gui_yank);
}
check_cursor_col();
break;
diff --git a/src/nvim/option.c b/src/nvim/option.c
index 9068c90dd1..a0706dfa14 100644
--- a/src/nvim/option.c
+++ b/src/nvim/option.c
@@ -3851,7 +3851,7 @@ static bool parse_winhl_opt(win_T *wp)
if (strncmp("Normal", p, nlen) == 0) {
w_hl_id_normal = hl_id;
} else {
- for (hlf = 0; hlf < (int)HLF_COUNT; hlf++) {
+ for (hlf = 0; hlf < HLF_COUNT; hlf++) {
if (strlen(hlf_names[hlf]) == nlen
&& strncmp(hlf_names[hlf], p, nlen) == 0) {
w_hl_ids[hlf] = hl_id;
@@ -5267,7 +5267,7 @@ static void showoptions(int all, int opt_flags)
&& Columns + GAP >= INT_MIN + 3
&& (Columns + GAP - 3) / INC >= INT_MIN
&& (Columns + GAP - 3) / INC <= INT_MAX);
- cols = (int)((Columns + GAP - 3) / INC);
+ cols = (Columns + GAP - 3) / INC;
if (cols == 0) {
cols = 1;
}
@@ -5666,11 +5666,11 @@ void comp_col(void)
assert(sc_col >= 0
&& INT_MIN + sc_col <= Columns
&& Columns - sc_col <= INT_MAX);
- sc_col = (int)(Columns - sc_col);
+ sc_col = Columns - sc_col;
assert(ru_col >= 0
&& INT_MIN + ru_col <= Columns
&& Columns - ru_col <= INT_MAX);
- ru_col = (int)(Columns - ru_col);
+ ru_col = Columns - ru_col;
if (sc_col <= 0) { // screen too narrow, will become a mess
sc_col = 1;
}
diff --git a/src/nvim/regexp.c b/src/nvim/regexp.c
index 6a6c915094..b7f11b2de0 100644
--- a/src/nvim/regexp.c
+++ b/src/nvim/regexp.c
@@ -468,6 +468,8 @@ static int toggle_Magic(int x)
#define EMSG_RET_FAIL(m) return (emsg(m), rc_did_emsg = true, FAIL)
#define EMSG2_RET_NULL(m, c) \
return (semsg((m), (c) ? "" : "\\"), rc_did_emsg = true, (void *)NULL)
+#define EMSG3_RET_NULL(m, c, a) \
+ return (semsg((const char *)(m), (c) ? "" : "\\", (a)), rc_did_emsg = true, (void *)NULL)
#define EMSG2_RET_FAIL(m, c) \
return (semsg((m), (c) ? "" : "\\"), rc_did_emsg = true, FAIL)
#define EMSG_ONE_RET_NULL EMSG2_RET_NULL(_( \
@@ -1762,13 +1764,9 @@ static char_u *regpiece(int *flagp)
if (re_multi_type(peekchr()) != NOT_MULTI) {
// Can't have a multi follow a multi.
if (peekchr() == Magic('*')) {
- snprintf((char *)IObuff, IOSIZE, _("E61: Nested %s*"),
- reg_magic >= MAGIC_ON ? "" : "\\");
- } else {
- snprintf((char *)IObuff, IOSIZE, _("E62: Nested %s%c"),
- reg_magic == MAGIC_ALL ? "" : "\\", no_Magic(peekchr()));
+ EMSG2_RET_NULL(_("E61: Nested %s*"), reg_magic >= MAGIC_ON);
}
- EMSG_RET_NULL((char *)IObuff);
+ EMSG3_RET_NULL(_("E62: Nested %s%c"), reg_magic == MAGIC_ALL, no_Magic(peekchr()));
}
return ret;
@@ -1927,10 +1925,8 @@ static char_u *regatom(int *flagp)
case Magic('{'):
case Magic('*'):
c = no_Magic(c);
- snprintf((char *)IObuff, IOSIZE, _("E64: %s%c follows nothing"),
- (c == '*' ? reg_magic >= MAGIC_ON : reg_magic == MAGIC_ALL)
- ? "" : "\\", c);
- EMSG_RET_NULL((char *)IObuff);
+ EMSG3_RET_NULL(_("E64: %s%c follows nothing"),
+ (c == '*' ? reg_magic >= MAGIC_ON : reg_magic == MAGIC_ALL), c);
// NOTREACHED
case Magic('~'): /* previous substitute pattern */
@@ -2537,7 +2533,9 @@ do_multibyte:
static bool re_mult_next(char *what)
{
if (re_multi_type(peekchr()) == MULTI_MULT) {
- EMSG2_RET_FAIL(_("E888: (NFA regexp) cannot repeat %s"), what);
+ semsg(_("E888: (NFA regexp) cannot repeat %s"), what);
+ rc_did_emsg = true;
+ return false;
}
return true;
}
@@ -3149,9 +3147,7 @@ static int read_limits(long *minval, long *maxval)
regparse++; // Allow either \{...} or \{...\}
}
if (*regparse != '}') {
- snprintf((char *)IObuff, IOSIZE, _("E554: Syntax error in %s{...}"),
- reg_magic == MAGIC_ALL ? "" : "\\");
- EMSG_RET_FAIL((char *)IObuff);
+ EMSG2_RET_FAIL(_("E554: Syntax error in %s{...}"), reg_magic == MAGIC_ALL);
}
/*
@@ -5043,8 +5039,7 @@ static bool regmatch(
} else {
MB_PTR_BACK(rex.line, rp->rs_un.regsave.rs_u.ptr);
if (limit > 0
- && (long)(behind_pos.rs_u.ptr
- - rp->rs_un.regsave.rs_u.ptr) > limit) {
+ && (behind_pos.rs_u.ptr - rp->rs_un.regsave.rs_u.ptr) > (ptrdiff_t)limit) {
no = FAIL;
}
}
diff --git a/src/nvim/screen.c b/src/nvim/screen.c
index 1498d1c9b3..3a87cba7f9 100644
--- a/src/nvim/screen.c
+++ b/src/nvim/screen.c
@@ -2888,9 +2888,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/spell.c b/src/nvim/spell.c
index 1296d410f6..fb644daa39 100644
--- a/src/nvim/spell.c
+++ b/src/nvim/spell.c
@@ -3824,7 +3824,7 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so
// At end of a prefix or at start of prefixtree: check for
// following word.
- if (byts[arridx] == 0 || n == (int)STATE_NOPREFIX) {
+ if (byts[arridx] == 0 || n == STATE_NOPREFIX) {
// Set su->su_badflags to the caps type at this position.
// Use the caps type until here for the prefix itself.
n = nofold_len(fword, sp->ts_fidx, su->su_badptr);
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..f78b748d71 100644
--- a/src/nvim/testdir/test_registers.vim
+++ b/src/nvim/testdir/test_registers.vim
@@ -62,7 +62,6 @@ func Test_display_registers()
call assert_match('^\nType Name Content\n'
\ . ' c "" a\n'
\ . ' c "0 ba\n'
- \ . ' c "1 b\n'
\ . ' c "a b\n'
\ . '.*'
\ . ' c "- a\n'
@@ -85,6 +84,90 @@ func Test_display_registers()
let g:clipboard = save_clipboard
endfunc
+func Test_register_one()
+ " delete a line goes into register one
+ new
+ call setline(1, "one")
+ normal dd
+ call assert_equal("one\n", @1)
+
+ " delete a word does not change register one, does change "-
+ call setline(1, "two")
+ normal de
+ call assert_equal("one\n", @1)
+ call assert_equal("two", @-)
+
+ " delete a word with a register does not change register one
+ call setline(1, "three")
+ normal "ade
+ call assert_equal("three", @a)
+ call assert_equal("one\n", @1)
+
+ " delete a word with register DOES change register one with one of a list of
+ " operators
+ " %
+ call setline(1, ["(12)3"])
+ normal "ad%
+ call assert_equal("(12)", @a)
+ call assert_equal("(12)", @1)
+
+ " (
+ call setline(1, ["first second"])
+ normal $"ad(
+ call assert_equal("first secon", @a)
+ call assert_equal("first secon", @1)
+
+ " )
+ call setline(1, ["First Second."])
+ normal gg0"ad)
+ call assert_equal("First Second.", @a)
+ call assert_equal("First Second.", @1)
+
+ " `
+ call setline(1, ["start here."])
+ normal gg0fhmx0"ad`x
+ call assert_equal("start ", @a)
+ call assert_equal("start ", @1)
+
+ " /
+ call setline(1, ["searchX"])
+ exe "normal gg0\"ad/X\<CR>"
+ call assert_equal("search", @a)
+ call assert_equal("search", @1)
+
+ " ?
+ call setline(1, ["Ysearch"])
+ exe "normal gg$\"ad?Y\<CR>"
+ call assert_equal("Ysearc", @a)
+ call assert_equal("Ysearc", @1)
+
+ " n
+ call setline(1, ["Ynext"])
+ normal gg$"adn
+ call assert_equal("Ynex", @a)
+ call assert_equal("Ynex", @1)
+
+ " N
+ call setline(1, ["prevY"])
+ normal gg0"adN
+ call assert_equal("prev", @a)
+ call assert_equal("prev", @1)
+
+ " }
+ call setline(1, ["one", ""])
+ normal gg0"ad}
+ call assert_equal("one\n", @a)
+ call assert_equal("one\n", @1)
+
+ " {
+ call setline(1, ["", "two"])
+ normal 2G$"ad{
+ call assert_equal("\ntw", @a)
+ call assert_equal("\ntw", @1)
+
+ bwipe!
+endfunc
+
func Test_recording_status_in_ex_line()
norm qx
redraw!
@@ -482,6 +565,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/ui.c b/src/nvim/ui.c
index 31b9614c34..7c67c058b0 100644
--- a/src/nvim/ui.c
+++ b/src/nvim/ui.c
@@ -639,8 +639,8 @@ void ui_grid_resize(handle_T grid_handle, int width, int height, Error *error)
}
} else {
// non-positive indicates no request
- wp->w_height_request = (int)MAX(height, 0);
- wp->w_width_request = (int)MAX(width, 0);
+ wp->w_height_request = MAX(height, 0);
+ wp->w_width_request = MAX(width, 0);
win_set_inner_size(wp);
}
}