mirror of
https://github.com/neovim/neovim.git
synced 2026-05-06 08:26:45 -04:00
backport: feat(events): trigger MarkSet autocmd in :delmarks (#39218)
Problem: `api.nvim_buf_del_mark` already emits a `MarkSet` event with `col` and `line` set to 0. However, `:delmarks` currently emits no events. Solution: Change `:delmarks` to emit the same `col==line==0` event.
This commit is contained in:
@@ -785,11 +785,13 @@ LspRequest See |LspRequest|
|
||||
LspTokenUpdate See |LspTokenUpdate|
|
||||
*MarkSet*
|
||||
MarkSet After a |mark| is set by |m|, |:mark|, and
|
||||
|nvim_buf_set_mark()|. Supports `[a-zA-Z]`
|
||||
|nvim_buf_set_mark()|, or deleted by |:delmarks|
|
||||
and |nvim_buf_del_mark()|. Supports `[a-zA-Z]`
|
||||
marks (may support more in the future).
|
||||
The |autocmd-pattern| is matched against the
|
||||
mark name (e.g. `[ab]` matches `a` or `b`, `*`
|
||||
matches all).
|
||||
matches all). If line is 0, the mark has been
|
||||
deleted.
|
||||
|
||||
The |event-data| has these keys (type: `vim.event.markset.data`):
|
||||
- name: Mark name (e.g. "a")
|
||||
|
||||
@@ -199,6 +199,8 @@ EVENTS
|
||||
• |SessionLoadPre| is triggered before loading a |Session| file.
|
||||
• |TabClosedPre| is triggered before closing a |tabpage|.
|
||||
• |TermRequest| event gained a `terminator` parameter.
|
||||
• |:delmarks| now triggers the |MarkSet| autocommand with line==col==0, same
|
||||
as |nvim_buf_del_mark()|
|
||||
|
||||
HIGHLIGHTS
|
||||
|
||||
|
||||
+65
-5
@@ -81,7 +81,9 @@ void free_xfmark(xfmark_T fm)
|
||||
free_fmark(fm.fmark);
|
||||
}
|
||||
|
||||
/// Free and clear fmark_T item
|
||||
/// Free and clear fmark_T item.
|
||||
///
|
||||
/// Does not trigger "MarkSet" event.
|
||||
void clear_fmark(fmark_T *const fm, const Timestamp timestamp)
|
||||
FUNC_ATTR_NONNULL_ALL
|
||||
{
|
||||
@@ -849,6 +851,8 @@ bool mark_check_line_bounds(buf_T *buf, fmark_T *fm, const char **errormsg)
|
||||
///
|
||||
/// Used mainly when trashing the entire buffer during ":e" type commands.
|
||||
///
|
||||
/// Does not trigger "MarkSet" event.
|
||||
///
|
||||
/// @param[out] buf Buffer to clear marks in.
|
||||
void clrallmarks(buf_T *const buf, const Timestamp timestamp)
|
||||
FUNC_ATTR_NONNULL_ALL
|
||||
@@ -1010,9 +1014,30 @@ void ex_delmarks(exarg_T *eap)
|
||||
{
|
||||
int from, to;
|
||||
int n;
|
||||
pos_T pos = { 0, 0, 0 };
|
||||
|
||||
if (*eap->arg == NUL && eap->forceit) {
|
||||
// clear all marks
|
||||
for (size_t i = 0; i < NMARKS; i++) {
|
||||
if (curbuf->b_namedm[i].mark.lnum != 0) {
|
||||
do_markset_autocmd((char)(i + 'a'), &pos, curbuf);
|
||||
}
|
||||
}
|
||||
if (curbuf->b_last_cursor.mark.lnum != 0) {
|
||||
do_markset_autocmd('"', &pos, curbuf);
|
||||
}
|
||||
if (curbuf->b_last_insert.mark.lnum != 0) {
|
||||
do_markset_autocmd('^', &pos, curbuf);
|
||||
}
|
||||
if (curbuf->b_last_change.mark.lnum != 0) {
|
||||
do_markset_autocmd('.', &pos, curbuf);
|
||||
}
|
||||
if (curbuf->b_op_start.lnum != 0) {
|
||||
do_markset_autocmd('[', &pos, curbuf);
|
||||
}
|
||||
if (curbuf->b_op_end.lnum != 0) {
|
||||
do_markset_autocmd(']', &pos, curbuf);
|
||||
}
|
||||
clrallmarks(curbuf, os_time());
|
||||
} else if (eap->forceit) {
|
||||
emsg(_(e_invarg));
|
||||
@@ -1044,6 +1069,9 @@ void ex_delmarks(exarg_T *eap)
|
||||
|
||||
for (int i = from; i <= to; i++) {
|
||||
if (lower) {
|
||||
if (curbuf->b_namedm[i - 'a'].mark.lnum != 0) {
|
||||
do_markset_autocmd((char)i, &pos, curbuf);
|
||||
}
|
||||
curbuf->b_namedm[i - 'a'].mark.lnum = 0;
|
||||
curbuf->b_namedm[i - 'a'].timestamp = timestamp;
|
||||
} else {
|
||||
@@ -1052,6 +1080,13 @@ void ex_delmarks(exarg_T *eap)
|
||||
} else {
|
||||
n = i - 'A';
|
||||
}
|
||||
if (namedfm[n].fmark.mark.lnum != 0) {
|
||||
buf_T *buf = buflist_findnr(namedfm[n].fmark.fnum);
|
||||
if (buf == NULL) {
|
||||
buf = curbuf;
|
||||
}
|
||||
do_markset_autocmd((char)i, &pos, buf);
|
||||
}
|
||||
namedfm[n].fmark.mark.lnum = 0;
|
||||
namedfm[n].fmark.fnum = 0;
|
||||
namedfm[n].fmark.timestamp = timestamp;
|
||||
@@ -1061,25 +1096,50 @@ void ex_delmarks(exarg_T *eap)
|
||||
} else {
|
||||
switch (*p) {
|
||||
case '"':
|
||||
if (curbuf->b_last_cursor.mark.lnum != 0) {
|
||||
do_markset_autocmd(*p, &pos, curbuf);
|
||||
}
|
||||
clear_fmark(&curbuf->b_last_cursor, timestamp);
|
||||
break;
|
||||
case '^':
|
||||
if (curbuf->b_last_insert.mark.lnum != 0) {
|
||||
do_markset_autocmd(*p, &pos, curbuf);
|
||||
}
|
||||
clear_fmark(&curbuf->b_last_insert, timestamp);
|
||||
break;
|
||||
case ':':
|
||||
// Readonly mark. No deletion allowed.
|
||||
break;
|
||||
case '.':
|
||||
if (curbuf->b_last_change.mark.lnum != 0) {
|
||||
do_markset_autocmd(*p, &pos, curbuf);
|
||||
}
|
||||
clear_fmark(&curbuf->b_last_change, timestamp);
|
||||
break;
|
||||
case '[':
|
||||
curbuf->b_op_start.lnum = 0; break;
|
||||
if (curbuf->b_op_start.lnum != 0) {
|
||||
do_markset_autocmd(*p, &pos, curbuf);
|
||||
}
|
||||
curbuf->b_op_start.lnum = 0;
|
||||
break;
|
||||
case ']':
|
||||
curbuf->b_op_end.lnum = 0; break;
|
||||
if (curbuf->b_op_end.lnum != 0) {
|
||||
do_markset_autocmd(*p, &pos, curbuf);
|
||||
}
|
||||
curbuf->b_op_end.lnum = 0;
|
||||
break;
|
||||
case '<':
|
||||
curbuf->b_visual.vi_start.lnum = 0; break;
|
||||
if (curbuf->b_visual.vi_start.lnum != 0) {
|
||||
do_markset_autocmd(*p, &pos, curbuf);
|
||||
}
|
||||
curbuf->b_visual.vi_start.lnum = 0;
|
||||
break;
|
||||
case '>':
|
||||
curbuf->b_visual.vi_end.lnum = 0; break;
|
||||
if (curbuf->b_visual.vi_end.lnum != 0) {
|
||||
do_markset_autocmd(*p, &pos, curbuf);
|
||||
}
|
||||
curbuf->b_visual.vi_end.lnum = 0;
|
||||
break;
|
||||
case ' ':
|
||||
break;
|
||||
default:
|
||||
|
||||
@@ -151,6 +151,8 @@ describe('MarkSet', function()
|
||||
command('tabclose')
|
||||
|
||||
feed('mD')
|
||||
-- delmarks should signal on the buf the mark is set on, not the current buf
|
||||
command('delmarks A')
|
||||
|
||||
poke_eventloop()
|
||||
eq({
|
||||
@@ -186,6 +188,14 @@ describe('MarkSet', function()
|
||||
name = 'D',
|
||||
},
|
||||
},
|
||||
{
|
||||
buf = 1,
|
||||
event = {
|
||||
col = 0,
|
||||
line = 0,
|
||||
name = 'A',
|
||||
},
|
||||
},
|
||||
}, eval('g:markset_events'))
|
||||
end)
|
||||
|
||||
@@ -283,4 +293,57 @@ describe('MarkSet', function()
|
||||
eq({ 1, 1 }, api.nvim_buf_get_mark(third_bufnr, 'B'))
|
||||
eq({ 3, 0 }, api.nvim_buf_get_mark(first_bufnr, 'C'))
|
||||
end)
|
||||
|
||||
it('emits when marks are deleted', function()
|
||||
command([[
|
||||
let g:mark_events = []
|
||||
autocmd MarkSet * call add(g:mark_events, {'event': deepcopy(v:event)})
|
||||
]])
|
||||
|
||||
api.nvim_buf_set_lines(0, 0, -1, true, {
|
||||
'line 1',
|
||||
'line 2',
|
||||
})
|
||||
|
||||
feed('ma')
|
||||
feed('mb')
|
||||
command('delmarks a')
|
||||
-- deleting a second time should not trigger an event
|
||||
command('delmarks a')
|
||||
api.nvim_buf_del_mark(0, 'b')
|
||||
api.nvim_buf_del_mark(0, 'b')
|
||||
|
||||
poke_eventloop()
|
||||
|
||||
eq({
|
||||
{
|
||||
event = {
|
||||
col = 0,
|
||||
line = 1,
|
||||
name = 'a',
|
||||
},
|
||||
},
|
||||
{
|
||||
event = {
|
||||
col = 0,
|
||||
line = 1,
|
||||
name = 'b',
|
||||
},
|
||||
},
|
||||
{
|
||||
event = {
|
||||
col = 0,
|
||||
line = 0,
|
||||
name = 'a',
|
||||
},
|
||||
},
|
||||
{
|
||||
event = {
|
||||
col = 0,
|
||||
line = 0,
|
||||
name = 'b',
|
||||
},
|
||||
},
|
||||
}, eval('g:mark_events'))
|
||||
end)
|
||||
end)
|
||||
|
||||
Reference in New Issue
Block a user