aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--runtime/doc/api.txt32
-rw-r--r--runtime/ftplugin/query.lua6
-rw-r--r--runtime/indent/query.lua6
-rw-r--r--runtime/lua/vim/filetype.lua2
-rw-r--r--src/nvim/api/autocmd.c291
-rw-r--r--src/nvim/api/extmark.c4
-rw-r--r--src/nvim/api/keysets.lua8
-rw-r--r--src/nvim/api/private/helpers.h5
-rw-r--r--src/nvim/edit.c8
-rw-r--r--src/nvim/move.c13
-rw-r--r--src/nvim/normal.c7
-rw-r--r--src/nvim/screen.c8
-rw-r--r--test/functional/api/autocmd_spec.lua91
-rw-r--r--test/functional/ui/syntax_conceal_spec.lua53
14 files changed, 418 insertions, 116 deletions
diff --git a/runtime/doc/api.txt b/runtime/doc/api.txt
index 0a8a3e9a2c..2b9aef2d77 100644
--- a/runtime/doc/api.txt
+++ b/runtime/doc/api.txt
@@ -2453,9 +2453,9 @@ nvim_buf_get_extmarks({buffer}, {ns_id}, {start}, {end}, {opts})
local pos = a.nvim_win_get_cursor(0)
local ns = a.nvim_create_namespace('my-plugin')
-- Create new extmark at line 1, column 1.
- local m1 = a.nvim_buf_set_extmark(0, ns, 0, 0, 0, {})
+ local m1 = a.nvim_buf_set_extmark(0, ns, 0, 0, {})
-- Create new extmark at line 3, column 1.
- local m2 = a.nvim_buf_set_extmark(0, ns, 0, 2, 0, {})
+ local m2 = a.nvim_buf_set_extmark(0, ns, 0, 2, {})
-- Get extmarks only from line 3.
local ms = a.nvim_buf_get_extmarks(0, ns, {2,0}, {2,0}, {})
-- Get all marks in this buffer + namespace.
@@ -3151,6 +3151,34 @@ nvim_tabpage_set_var({tabpage}, {name}, {value})
==============================================================================
Autocmd Functions *api-autocmd*
+nvim_clear_autocmd({*opts}) *nvim_clear_autocmd()*
+ Clear all autocommands that match the corresponding {opts}. To
+ delete a particular autocmd, see |nvim_del_autocmd|.
+
+ Parameters: ~
+ {opts} Parameters
+ • event: (string|table) Examples:
+ • event: "pat1"
+ • event: { "pat1" }
+ • event: { "pat1", "pat2", "pat3" }
+
+ • pattern: (string|table)
+ • pattern or patterns to match exactly.
+ • For example, if you have `*.py` as that
+ pattern for the autocmd, you must pass
+ `*.py` exactly to clear it. `test.py` will
+ not match the pattern.
+
+ • defaults to clearing all patterns.
+ • NOTE: Cannot be used with {buffer}
+
+ • buffer: (bufnr)
+ • clear only |autocmd-buflocal| autocommands.
+ • NOTE: Cannot be used with {pattern}
+
+ • group: (string|int) The augroup name or id.
+ • NOTE: If not passed, will only delete autocmds not in any group.
+
nvim_create_augroup({name}, {*opts}) *nvim_create_augroup()*
Create or get an autocommand group |autocmd-groups|.
diff --git a/runtime/ftplugin/query.lua b/runtime/ftplugin/query.lua
new file mode 100644
index 0000000000..c1694961af
--- /dev/null
+++ b/runtime/ftplugin/query.lua
@@ -0,0 +1,6 @@
+-- Neovim filetype plugin file
+-- Language: Tree-sitter query
+-- Last Change: 2022 Mar 29
+
+-- it's a lisp!
+vim.cmd [[ runtime! ftplugin/lisp.vim ]]
diff --git a/runtime/indent/query.lua b/runtime/indent/query.lua
new file mode 100644
index 0000000000..55cb73e62b
--- /dev/null
+++ b/runtime/indent/query.lua
@@ -0,0 +1,6 @@
+-- Neovim indent file
+-- Language: Tree-sitter query
+-- Last Change: 2022 Mar 29
+
+-- it's a lisp!
+vim.cmd [[ runtime! indent/lisp.vim ]]
diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua
index ab71de54f8..2194db95a9 100644
--- a/runtime/lua/vim/filetype.lua
+++ b/runtime/lua/vim/filetype.lua
@@ -1424,6 +1424,8 @@ local pattern = {
return "git"
end
end,
+ -- Neovim only
+ [".*/queries/.*%.scm"] = "query", -- tree-sitter queries
-- END PATTERN
}
-- luacheck: pop
diff --git a/src/nvim/api/autocmd.c b/src/nvim/api/autocmd.c
index 66ac394498..f896671287 100644
--- a/src/nvim/api/autocmd.c
+++ b/src/nvim/api/autocmd.c
@@ -392,9 +392,6 @@ Integer nvim_create_autocmd(uint64_t channel_id, Object event, Dict(create_autoc
FUNC_API_SINCE(9)
{
int64_t autocmd_id = -1;
-
- const char_u pattern_buflocal[BUFLOCAL_PAT_LEN];
- int au_group = AUGROUP_DEFAULT;
char *desc = NULL;
Array patterns = ARRAY_DICT_INIT;
@@ -404,7 +401,7 @@ Integer nvim_create_autocmd(uint64_t channel_id, Object event, Dict(create_autoc
Callback cb = CALLBACK_NONE;
- if (!unpack_string_or_array(&event_array, &event, "event", err)) {
+ if (!unpack_string_or_array(&event_array, &event, "event", true, err)) {
goto cleanup;
}
@@ -466,84 +463,13 @@ 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);
- 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.");
+ int au_group = get_augroup_from_object(opts->group, err);
+ if (au_group == AUGROUP_ERROR) {
goto cleanup;
}
- if (opts->pattern.type != kObjectTypeNil && opts->buffer.type != kObjectTypeNil) {
- api_set_error(err, kErrorTypeValidation,
- "cannot pass both: 'pattern' and 'buffer' for the same autocmd");
+ if (!get_patterns_from_pattern_or_buf(&patterns, opts->pattern, opts->buffer, err)) {
goto cleanup;
- } else if (opts->pattern.type != kObjectTypeNil) {
- Object *v = &opts->pattern;
-
- if (v->type == kObjectTypeString) {
- char_u *pat = (char_u *)v->data.string.data;
- size_t patlen = aucmd_pattern_length(pat);
- while (patlen) {
- ADD(patterns, STRING_OBJ(cbuf_to_string((char *)pat, patlen)));
-
- pat = aucmd_next_pattern(pat, patlen);
- patlen = aucmd_pattern_length(pat);
- }
- } else if (v->type == kObjectTypeArray) {
- if (!check_autocmd_string_array(patterns, "pattern", err)) {
- goto cleanup;
- }
-
- Array array = v->data.array;
- for (size_t i = 0; i < array.size; i++) {
- char_u *pat = (char_u *)array.items[i].data.string.data;
- size_t patlen = aucmd_pattern_length(pat);
- while (patlen) {
- ADD(patterns, STRING_OBJ(cbuf_to_string((char *)pat, patlen)));
-
- pat = aucmd_next_pattern(pat, patlen);
- patlen = aucmd_pattern_length(pat);
- }
- }
- } else {
- api_set_error(err,
- kErrorTypeValidation,
- "'pattern' must be a string");
- goto cleanup;
- }
- } else if (opts->buffer.type != kObjectTypeNil) {
- if (opts->buffer.type != kObjectTypeInteger) {
- api_set_error(err,
- kErrorTypeValidation,
- "'buffer' must be an integer");
- goto cleanup;
- }
-
- buf_T *buf = find_buffer_by_handle((Buffer)opts->buffer.data.integer, err);
- if (ERROR_SET(err)) {
- goto cleanup;
- }
-
- snprintf((char *)pattern_buflocal, BUFLOCAL_PAT_LEN, "<buffer=%d>", (int)buf->handle);
- ADD(patterns, STRING_OBJ(cstr_to_string((char *)pattern_buflocal)));
}
if (opts->desc.type != kObjectTypeNil) {
@@ -621,6 +547,94 @@ void nvim_del_autocmd(Integer id, Error *err)
}
}
+/// Clear all autocommands that match the corresponding {opts}. To delete
+/// a particular autocmd, see |nvim_del_autocmd|.
+/// @param opts Parameters
+/// - event: (string|table)
+/// Examples:
+/// - event: "pat1"
+/// - event: { "pat1" }
+/// - event: { "pat1", "pat2", "pat3" }
+/// - pattern: (string|table)
+/// - pattern or patterns to match exactly.
+/// - For example, if you have `*.py` as that pattern for the autocmd,
+/// you must pass `*.py` exactly to clear it. `test.py` will not
+/// match the pattern.
+/// - defaults to clearing all patterns.
+/// - NOTE: Cannot be used with {buffer}
+/// - buffer: (bufnr)
+/// - clear only |autocmd-buflocal| autocommands.
+/// - NOTE: Cannot be used with {pattern}
+/// - group: (string|int) The augroup name or id.
+/// - NOTE: If not passed, will only delete autocmds *not* in any group.
+///
+void nvim_clear_autocmd(Dict(clear_autocmd) *opts, Error *err)
+ FUNC_API_SINCE(9)
+{
+ // TODO(tjdevries): Future improvements:
+ // - once: (boolean) - Only clear autocmds with once. See |autocmd-once|
+ // - nested: (boolean) - Only clear autocmds with nested. See |autocmd-nested|
+ // - group: Allow passing "*" or true or something like that to force doing all
+ // autocmds, regardless of their group.
+
+ Array patterns = ARRAY_DICT_INIT;
+ Array event_array = ARRAY_DICT_INIT;
+
+ if (!unpack_string_or_array(&event_array, &opts->event, "event", false, err)) {
+ goto cleanup;
+ }
+
+ if (opts->pattern.type != kObjectTypeNil && opts->buffer.type != kObjectTypeNil) {
+ api_set_error(err, kErrorTypeValidation,
+ "Cannot use both 'pattern' and 'buffer'");
+ goto cleanup;
+ }
+
+ int au_group = get_augroup_from_object(opts->group, err);
+ if (au_group == AUGROUP_ERROR) {
+ goto cleanup;
+ }
+
+ if (!get_patterns_from_pattern_or_buf(&patterns, opts->pattern, opts->buffer, err)) {
+ goto cleanup;
+ }
+
+ // When we create the autocmds, we want to say that they are all matched, so that's *
+ // but when we clear them, we want to say that we didn't pass a pattern, so that's NUL
+ if (patterns.size == 0) {
+ ADD(patterns, STRING_OBJ(STATIC_CSTR_TO_STRING("")));
+ }
+
+ // If we didn't pass any events, that means clear all events.
+ if (event_array.size == 0) {
+ FOR_ALL_AUEVENTS(event) {
+ FOREACH_ITEM(patterns, pat_object, {
+ char_u *pat = (char_u *)pat_object.data.string.data;
+ if (!clear_autocmd(event, pat, au_group, err)) {
+ goto cleanup;
+ }
+ });
+ }
+ } else {
+ FOREACH_ITEM(event_array, event_str, {
+ GET_ONE_EVENT(event_nr, event_str, cleanup);
+
+ FOREACH_ITEM(patterns, pat_object, {
+ char_u *pat = (char_u *)pat_object.data.string.data;
+ if (!clear_autocmd(event_nr, pat, au_group, err)) {
+ goto cleanup;
+ }
+ });
+ });
+ }
+
+cleanup:
+ api_free_array(event_array);
+ api_free_array(patterns);
+
+ return;
+}
+
/// Create or get an autocommand group |autocmd-groups|.
///
/// To get an existing group id, do:
@@ -723,7 +737,7 @@ void nvim_exec_autocmd(Object event, Dict(exec_autocmd) *opts, Error *err)
Array event_array = ARRAY_DICT_INIT;
- if (!unpack_string_or_array(&event_array, &event, "event", err)) {
+ if (!unpack_string_or_array(&event_array, &event, "event", true, err)) {
goto cleanup;
}
@@ -822,7 +836,7 @@ static bool check_autocmd_string_array(Array arr, char *k, Error *err)
return true;
}
-static bool unpack_string_or_array(Array *array, Object *v, char *k, Error *err)
+static bool unpack_string_or_array(Array *array, Object *v, char *k, bool required, Error *err)
{
if (v->type == kObjectTypeString) {
ADD(*array, copy_object(*v));
@@ -832,10 +846,119 @@ static bool unpack_string_or_array(Array *array, Object *v, char *k, Error *err)
}
*array = copy_array(v->data.array);
} else {
- api_set_error(err,
- kErrorTypeValidation,
- "'%s' must be an array or a string.",
- k);
+ if (required) {
+ api_set_error(err,
+ kErrorTypeValidation,
+ "'%s' must be an array or a string.",
+ k);
+ return false;
+ }
+ }
+
+ return true;
+}
+
+// Returns AUGROUP_ERROR if there was a problem with {group}
+static int get_augroup_from_object(Object group, Error *err)
+{
+ int au_group = AUGROUP_ERROR;
+
+ switch (group.type) {
+ case kObjectTypeNil:
+ return AUGROUP_DEFAULT;
+ case kObjectTypeString:
+ au_group = augroup_find(group.data.string.data);
+ if (au_group == AUGROUP_ERROR) {
+ api_set_error(err,
+ kErrorTypeValidation,
+ "invalid augroup: %s", group.data.string.data);
+
+ return AUGROUP_ERROR;
+ }
+
+ return au_group;
+ case kObjectTypeInteger:
+ au_group = (int)group.data.integer;
+ char *name = augroup_name(au_group);
+ if (!augroup_exists(name)) {
+ api_set_error(err, kErrorTypeValidation, "invalid augroup: %d", au_group);
+ return AUGROUP_ERROR;
+ }
+
+ return au_group;
+ default:
+ api_set_error(err, kErrorTypeValidation, "'group' must be a string or an integer.");
+ return AUGROUP_ERROR;
+ }
+}
+
+static bool get_patterns_from_pattern_or_buf(Array *patterns, Object pattern, Object buffer,
+ Error *err)
+{
+ const char_u pattern_buflocal[BUFLOCAL_PAT_LEN];
+
+ if (pattern.type != kObjectTypeNil && buffer.type != kObjectTypeNil) {
+ api_set_error(err, kErrorTypeValidation,
+ "cannot pass both: 'pattern' and 'buffer' for the same autocmd");
+ return false;
+ } else if (pattern.type != kObjectTypeNil) {
+ Object *v = &pattern;
+
+ if (v->type == kObjectTypeString) {
+ char_u *pat = (char_u *)v->data.string.data;
+ size_t patlen = aucmd_pattern_length(pat);
+ while (patlen) {
+ ADD(*patterns, STRING_OBJ(cbuf_to_string((char *)pat, patlen)));
+
+ pat = aucmd_next_pattern(pat, patlen);
+ patlen = aucmd_pattern_length(pat);
+ }
+ } else if (v->type == kObjectTypeArray) {
+ if (!check_autocmd_string_array(*patterns, "pattern", err)) {
+ return false;
+ }
+
+ Array array = v->data.array;
+ for (size_t i = 0; i < array.size; i++) {
+ char_u *pat = (char_u *)array.items[i].data.string.data;
+ size_t patlen = aucmd_pattern_length(pat);
+ while (patlen) {
+ ADD(*patterns, STRING_OBJ(cbuf_to_string((char *)pat, patlen)));
+
+ pat = aucmd_next_pattern(pat, patlen);
+ patlen = aucmd_pattern_length(pat);
+ }
+ }
+ } else {
+ api_set_error(err,
+ kErrorTypeValidation,
+ "'pattern' must be a string");
+ return false;
+ }
+ } else if (buffer.type != kObjectTypeNil) {
+ if (buffer.type != kObjectTypeInteger) {
+ api_set_error(err,
+ kErrorTypeValidation,
+ "'buffer' must be an integer");
+ return false;
+ }
+
+ buf_T *buf = find_buffer_by_handle((Buffer)buffer.data.integer, err);
+ if (ERROR_SET(err)) {
+ return false;
+ }
+
+ snprintf((char *)pattern_buflocal, BUFLOCAL_PAT_LEN, "<buffer=%d>", (int)buf->handle);
+ ADD(*patterns, STRING_OBJ(cstr_to_string((char *)pattern_buflocal)));
+ }
+
+ return true;
+}
+
+static bool clear_autocmd(event_T event, char_u *pat, int au_group, Error *err)
+{
+ if (do_autocmd_event(event, pat, false, false, (char_u *)"", true, au_group) == FAIL) {
+ api_set_error(err, kErrorTypeException, "Failed to clear autocmd");
return false;
}
diff --git a/src/nvim/api/extmark.c b/src/nvim/api/extmark.c
index 797b64e2af..8dca37a321 100644
--- a/src/nvim/api/extmark.c
+++ b/src/nvim/api/extmark.c
@@ -259,9 +259,9 @@ ArrayOf(Integer) nvim_buf_get_extmark_by_id(Buffer buffer, Integer ns_id,
/// local pos = a.nvim_win_get_cursor(0)
/// local ns = a.nvim_create_namespace('my-plugin')
/// -- Create new extmark at line 1, column 1.
-/// local m1 = a.nvim_buf_set_extmark(0, ns, 0, 0, 0, {})
+/// local m1 = a.nvim_buf_set_extmark(0, ns, 0, 0, {})
/// -- Create new extmark at line 3, column 1.
-/// local m2 = a.nvim_buf_set_extmark(0, ns, 0, 2, 0, {})
+/// local m2 = a.nvim_buf_set_extmark(0, ns, 0, 2, {})
/// -- Get extmarks only from line 3.
/// local ms = a.nvim_buf_get_extmarks(0, ns, {2,0}, {2,0}, {})
/// -- Get all marks in this buffer + namespace.
diff --git a/src/nvim/api/keysets.lua b/src/nvim/api/keysets.lua
index 6a29b0fb59..520bb7fbc6 100644
--- a/src/nvim/api/keysets.lua
+++ b/src/nvim/api/keysets.lua
@@ -123,14 +123,20 @@ return {
"nocombine";
};
-- Autocmds
+ clear_autocmd = {
+ "buffer";
+ "event";
+ "group";
+ "pattern";
+ };
create_autocmd = {
"buffer";
"callback";
"command";
"desc";
"group";
- "once";
"nested";
+ "once";
"pattern";
};
exec_autocmd = {
diff --git a/src/nvim/api/private/helpers.h b/src/nvim/api/private/helpers.h
index bc7c2e6a60..650349cde7 100644
--- a/src/nvim/api/private/helpers.h
+++ b/src/nvim/api/private/helpers.h
@@ -140,8 +140,9 @@ typedef struct {
// Useful macro for executing some `code` for each item in an array.
#define FOREACH_ITEM(a, __foreach_item, code) \
- for (size_t __foreach_i = 0; __foreach_i < (a).size; __foreach_i++) { \
- Object __foreach_item = (a).items[__foreach_i]; \
+ for (size_t (__foreach_item ## _index) = 0; (__foreach_item ## _index) < (a).size; \
+ (__foreach_item ## _index)++) { \
+ Object __foreach_item = (a).items[__foreach_item ## _index]; \
code; \
}
diff --git a/src/nvim/edit.c b/src/nvim/edit.c
index c087948810..815d57121b 100644
--- a/src/nvim/edit.c
+++ b/src/nvim/edit.c
@@ -1480,8 +1480,6 @@ bool edit(int cmdchar, bool startln, long count)
/// @param ready not busy with something
static void ins_redraw(bool ready)
{
- bool conceal_cursor_moved = false;
-
if (char_avail()) {
return;
}
@@ -1504,7 +1502,6 @@ static void ins_redraw(bool ready)
update_curswant();
ins_apply_autocmds(EVENT_CURSORMOVEDI);
}
- conceal_cursor_moved = true;
curwin->w_last_cursormoved = curwin->w_cursor;
}
@@ -1560,11 +1557,6 @@ static void ins_redraw(bool ready)
curbuf->b_changed_invalid = false;
}
- if (curwin->w_p_cole > 0 && conceal_cursor_line(curwin)
- && conceal_cursor_moved) {
- redrawWinline(curwin, curwin->w_cursor.lnum);
- }
-
pum_check_clear();
if (must_redraw) {
update_screen(0);
diff --git a/src/nvim/move.c b/src/nvim/move.c
index 9b35a7da0a..5e02e355bf 100644
--- a/src/nvim/move.c
+++ b/src/nvim/move.c
@@ -96,12 +96,12 @@ static void comp_botline(win_T *wp)
}
/// Redraw when w_cline_row changes and 'relativenumber' or 'cursorline' is set.
+/// Also when concealing is on and 'concealcursor' is not active.
void redraw_for_cursorline(win_T *wp)
FUNC_ATTR_NONNULL_ALL
{
- if ((wp->w_p_rnu || win_cursorline_standout(wp))
- && (wp->w_valid & VALID_CROW) == 0
- && !pum_visible()) {
+ if ((wp->w_valid & VALID_CROW) == 0 && !pum_visible()
+ && (wp->w_p_rnu || win_cursorline_standout(wp))) {
// win_line() will redraw the number column and cursorline only.
redraw_later(wp, VALID);
}
@@ -109,6 +109,7 @@ void redraw_for_cursorline(win_T *wp)
/// Redraw when w_virtcol changes and 'cursorcolumn' is set or 'cursorlineopt'
/// contains "screenline".
+/// Also when concealing is on and 'concealcursor' is active.
static void redraw_for_cursorcolumn(win_T *wp)
FUNC_ATTR_NONNULL_ALL
{
@@ -121,6 +122,12 @@ static void redraw_for_cursorcolumn(win_T *wp)
redraw_later(wp, VALID);
}
}
+ // If the cursor moves horizontally when 'concealcursor' is active, then the
+ // current line needs to be redrawn in order to calculate the correct
+ // cursor position.
+ if ((wp->w_valid & VALID_VIRTCOL) == 0 && wp->w_p_cole > 0 && conceal_cursor_line(wp)) {
+ redrawWinline(wp, wp->w_cursor.lnum);
+ }
}
/*
diff --git a/src/nvim/normal.c b/src/nvim/normal.c
index 6c7595d1a4..72e80952ff 100644
--- a/src/nvim/normal.c
+++ b/src/nvim/normal.c
@@ -1288,13 +1288,6 @@ static void normal_redraw(NormalState *s)
update_topline(curwin);
validate_cursor();
- // If the cursor moves horizontally when 'concealcursor' is active, then the
- // current line needs to be redrawn in order to calculate the correct
- // cursor position.
- if (curwin->w_p_cole > 0 && conceal_cursor_line(curwin)) {
- redrawWinline(curwin, curwin->w_cursor.lnum);
- }
-
if (VIsual_active) {
update_curbuf(INVERTED); // update inverted part
} else if (must_redraw) {
diff --git a/src/nvim/screen.c b/src/nvim/screen.c
index 262f17cd21..f922a50260 100644
--- a/src/nvim/screen.c
+++ b/src/nvim/screen.c
@@ -667,15 +667,11 @@ void conceal_check_cursor_line(void)
/// Whether cursorline is drawn in a special way
///
-/// If true, both old and new cursorline will need
-/// to be redrawn when moving cursor within windows.
-/// TODO(bfredl): VIsual_active shouldn't be needed, but is used to fix a glitch
-/// caused by scrolling.
+/// If true, both old and new cursorline will need to be redrawn when moving cursor within windows.
bool win_cursorline_standout(const win_T *wp)
FUNC_ATTR_NONNULL_ALL
{
- return wp->w_p_cul
- || (wp->w_p_cole > 0 && (VIsual_active || !conceal_cursor_line(wp)));
+ return wp->w_p_cul || (wp->w_p_cole > 0 && !conceal_cursor_line(wp));
}
/*
diff --git a/test/functional/api/autocmd_spec.lua b/test/functional/api/autocmd_spec.lua
index 25220f7e74..9fc0066819 100644
--- a/test/functional/api/autocmd_spec.lua
+++ b/test/functional/api/autocmd_spec.lua
@@ -980,4 +980,95 @@ describe('autocmd api', function()
eq(0, #meths.get_autocmds { event = 'BufReadPost' })
end)
end)
+
+ describe('nvim_clear_autocmd', function()
+ it('should clear based on event + pattern', function()
+ command('autocmd InsertEnter *.py :echo "Python can be cool sometimes"')
+ command('autocmd InsertEnter *.txt :echo "Text Files Are Cool"')
+
+ local search = { event = "InsertEnter", pattern = "*.txt" }
+ local before_delete = meths.get_autocmds(search)
+ eq(1, #before_delete)
+
+ local before_delete_all = meths.get_autocmds { event = search.event }
+ eq(2, #before_delete_all)
+
+ meths.clear_autocmd(search)
+ local after_delete = meths.get_autocmds(search)
+ eq(0, #after_delete)
+
+ local after_delete_all = meths.get_autocmds { event = search.event }
+ eq(1, #after_delete_all)
+ end)
+
+ it('should clear based on event', function()
+ command('autocmd InsertEnter *.py :echo "Python can be cool sometimes"')
+ command('autocmd InsertEnter *.txt :echo "Text Files Are Cool"')
+
+ local search = { event = "InsertEnter"}
+ local before_delete = meths.get_autocmds(search)
+ eq(2, #before_delete)
+
+ meths.clear_autocmd(search)
+ local after_delete = meths.get_autocmds(search)
+ eq(0, #after_delete)
+ end)
+
+ it('should clear based on pattern', function()
+ command('autocmd InsertEnter *.TestPat1 :echo "Enter 1"')
+ command('autocmd InsertLeave *.TestPat1 :echo "Leave 1"')
+ command('autocmd InsertEnter *.TestPat2 :echo "Enter 2"')
+ command('autocmd InsertLeave *.TestPat2 :echo "Leave 2"')
+
+ local search = { pattern = "*.TestPat1"}
+ local before_delete = meths.get_autocmds(search)
+ eq(2, #before_delete)
+ local before_delete_events = meths.get_autocmds { event = { "InsertEnter", "InsertLeave" } }
+ eq(4, #before_delete_events)
+
+ meths.clear_autocmd(search)
+ local after_delete = meths.get_autocmds(search)
+ eq(0, #after_delete)
+
+ local after_delete_events = meths.get_autocmds { event = { "InsertEnter", "InsertLeave" } }
+ eq(2, #after_delete_events)
+ end)
+
+ it('should allow clearing by buffer', function()
+ command('autocmd! InsertEnter')
+ command('autocmd InsertEnter <buffer> :echo "Enter Buffer"')
+ command('autocmd InsertEnter *.TestPat1 :echo "Enter Pattern"')
+
+ local search = { event = "InsertEnter" }
+ local before_delete = meths.get_autocmds(search)
+ eq(2, #before_delete)
+
+ meths.clear_autocmd { buffer = 0 }
+ local after_delete = meths.get_autocmds(search)
+ eq(1, #after_delete)
+ eq("*.TestPat1", after_delete[1].pattern)
+ end)
+
+ it('should allow clearing by buffer and group', function()
+ command('augroup TestNvimClearAutocmds')
+ command(' au!')
+ command(' autocmd InsertEnter <buffer> :echo "Enter Buffer"')
+ command(' autocmd InsertEnter *.TestPat1 :echo "Enter Pattern"')
+ command('augroup END')
+
+ local search = { event = "InsertEnter", group = "TestNvimClearAutocmds" }
+ local before_delete = meths.get_autocmds(search)
+ eq(2, #before_delete)
+
+ -- Doesn't clear without passing group.
+ meths.clear_autocmd { buffer = 0 }
+ local without_group = meths.get_autocmds(search)
+ eq(2, #without_group)
+
+ -- Doest clear with passing group.
+ meths.clear_autocmd { buffer = 0, group = search.group }
+ local with_group = meths.get_autocmds(search)
+ eq(1, #with_group)
+ end)
+ end)
end)
diff --git a/test/functional/ui/syntax_conceal_spec.lua b/test/functional/ui/syntax_conceal_spec.lua
index 4e1852162f..92e5a5dd94 100644
--- a/test/functional/ui/syntax_conceal_spec.lua
+++ b/test/functional/ui/syntax_conceal_spec.lua
@@ -3,6 +3,7 @@ local Screen = require('test.functional.ui.screen')
local clear, feed, command = helpers.clear, helpers.feed, helpers.command
local eq = helpers.eq
local insert = helpers.insert
+local poke_eventloop = helpers.poke_eventloop
describe('Screen', function()
local screen
@@ -911,7 +912,57 @@ describe('Screen', function()
{0:~ }|
|
]]}
- eq(grid_lines, {{2, 0, {{'c', 0, 3}}}})
+ eq({{2, 0, {{'c', 0, 3}}}}, grid_lines)
+ end)
+
+ it('K_EVENT should not cause extra redraws with concealcursor #13196', function()
+ command('set conceallevel=1')
+ command('set concealcursor=nv')
+ command('set redrawdebug+=nodelta')
+
+ insert([[
+ aaa
+ bbb
+ ccc
+ ]])
+ screen:expect{grid=[[
+ aaa |
+ bbb |
+ ccc |
+ ^ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ |
+ ]]}
+
+ -- XXX: hack to get notifications, and check only a single line is
+ -- updated. Could use next_msg() also.
+ local orig_handle_grid_line = screen._handle_grid_line
+ local grid_lines = {}
+ function screen._handle_grid_line(self, grid, row, col, items)
+ table.insert(grid_lines, {row, col, items})
+ orig_handle_grid_line(self, grid, row, col, items)
+ end
+ feed('k')
+ screen:expect{grid=[[
+ aaa |
+ bbb |
+ ^ccc |
+ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ |
+ ]]}
+ eq({{2, 0, {{'c', 0, 3}}}}, grid_lines)
+ poke_eventloop() -- causes K_EVENT key
+ screen:expect_unchanged()
+ eq({{2, 0, {{'c', 0, 3}}}}, grid_lines)
end)
-- Copy of Test_cursor_column_in_concealed_line_after_window_scroll in