Add autocmd_get() and autocmd_set() functions to get and set autocmds#10291
Add autocmd_get() and autocmd_set() functions to get and set autocmds#10291yegappan wants to merge 1 commit intovim:masterfrom
Conversation
Codecov Report
@@ Coverage Diff @@
## master #10291 +/- ##
==========================================
- Coverage 81.62% 81.62% -0.01%
==========================================
Files 158 158
Lines 184737 184912 +175
Branches 41768 41822 +54
==========================================
+ Hits 150797 150938 +141
- Misses 21452 21463 +11
- Partials 12488 12511 +23
Flags with carried forward coverage won't be shown. Click here to find out more.
Continue to review full report at Codecov.
|
|
Is there a way to set a callback function directly instead of a command, just like we can set callbacks for jobs, timers or popups? |
Currently you can use only an Ex command to handle an autocmd event. |
|
What does autocmd_set() do when there already is an autocommand with the same group? When using ":autocmd" it would get added, which probably works best. Having a "delete" flag for autocmd_set() seems strange. Perhaps it's better to use autocmd_add() and autocmd_delete(). |
|
Hi Bram,
On Tue, Apr 26, 2022 at 2:00 PM Bram Moolenaar ***@***.***> wrote:
What does autocmd_set() do when there already is an autocommand with the
same group? When using ":autocmd" it would get added, which probably works
best.
Yes. The behavior of autocmd_set() is the same as the ":autocmd" command.
If an autocommand already exists for a given group, event and pattern,
then the new command is added to the list.
Having a "delete" flag for autocmd_set() seems strange. Perhaps it's
better to use autocmd_add() and autocmd_delete().
I will add a separate function for deleting autocmds.
Regards,
Yegappan
|
|
@yegappan Currently it is not documented how |
|
I think this PR also addresses #6339. |
I have updated the help text to describe how buffer-local autocmds can be added and deleted. |
|
Personally I preferred the previous version where a buffer number could be specified directly without doing any string concatenation like The documentation just wasn't clear enough whether the I think it would be a lot more readable if we could set the buffer number directly, especially in |
e8884c2 to
8369e9b
Compare
I have updated the PR to support specifying the buffer number and updated the doc. |
|
I'll leave this open for comments a couple of days. Nit: "automatic commands" isn't used in the help, only "autocmds" and "autocommands". It's a weird name anyway, but we're stuck with it. |
7ea27d4 to
0517c44
Compare
|
I think the documentation in In the examples of And what is the purpose of |
|
The documentation uses |
|
Hi,
On Sat, Apr 30, 2022 at 3:24 AM bfrg ***@***.***> wrote:
I think the documentation in :h autocmd_delete() is outdated.
In the examples of autocmd_delete() the function is called with the entry
'delete' which doesn't exist.
I have updated the examples for autocmd_delete() to remove the 'delete"
item.
And what is the purpose of nested or once in autocmd_delete()? Aren't
these options only useful for autocmd_add()?
These are optional items. You can get a list of autocmds using the
autocmd_get() function
and pass the list to autocmd_delete() to remove the autocmds. In this case,
these items
will be present.
- Yegappan
|
|
One common pitfall when adding an autocmd is to forget to wrap it inside a self-clearing augroup. Bad: autocmd CursorHold * echomsg 'do something'Good: augroup MyGroup
autocmd!
autocmd CursorHold * echomsg 'do something'
augroup ENDThe first snippet is bad, because if for some reason the script is sourced multiple times, there will be a duplicate autocmd: vim9script
var code = 'autocmd CursorHold * echomsg "do something"'
[code]->writefile('/tmp/script.vim')
source /tmp/script.vim
source /tmp/script.vim
autocmd CursorHoldDepending on the cost of the executed command and/or the frequency of the event, this might slow Vim down noticeably, or even cause errors. Now, here is how we can rewrite the good snippet with the new functions: vim9script
if exists('#MyGroup')
autocmd_delete([{group: 'MyGroup', event: '*'}])
endif
autocmd_add([{group: 'MyGroup', event: 'CursorHold', pattern: '*', cmd: "echomsg 'do something'"}])The whole When |
|
@brammool's comment from the mailing list, which hasn't come through to github:
Using "silent!" helps though. Here you don't care about errors.
It's probably better to add a "replace" argument: If an autocommand for this group and event already exists, replace it with this one. This works better when someone edits the .vimrc to change the command, sourcing the file again should use the new one, not keep the old one. |
I think either |
|
Hi,
On Mon, May 23, 2022 at 1:40 PM Nick Jensen ***@***.***> wrote:
It's probably better to add a "replace" argument: If an autocommand for
this group and event already exists, replace it with this one.
I think either unique or replace are both fine (although unique is more
descriptive in my mind), as long as the default value is true so we
normally don't need to use it, or even know about it! It is very rare that
an autocmd should *not* replace an existing one with the same group and
event.
If the 'replace' item is specified, then autocmd_add() will remove all the
commands
associated with an autocmd event in the group and add the new command. If a
group is not specified, then the default group will be used. This is same
as running
the following command:
autocmd! {group} {event} {pat} {cmd}
If we make 'replace' the default, then a call to autocmd_add() in a .vimrc
file will
remove commands added by a plugin (in the default group) for that event.
A user may not expect this. So we should not make 'replace' as the default.
- Yegappan
|
IMO, an autocmd should always be added in a named augroup; not in the default one. Unless we're quickly testing some feature. I was not clear enough in the previous post, sorry. My idea was for And if The only counter-argument I can find is that it would make
Anyway, the mere introduction of Thank you very much for working on these functions, they're very useful. |
|
Hi,
On Mon, May 23, 2022 at 5:58 PM lacygoill ***@***.***> wrote:
If a group is not specified, then the default group will be used.
[...]
If we make 'replace' the default, then a call to autocmd_add() in a .vimrc
file will remove commands added by a plugin (in the default group) for
that event.
A user may not expect this.
IMO, an autocmd should always be added in a named augroup; not in the
default one. Unless we're quickly testing some feature.
I was not clear enough in the previous post, sorry. My idea was for unique
/replace to be considered only when the autocmd was placed in a named
augroup. Because AFAIK the default augroup can't be cleared specifically
(right?). So, it wouldn't make sense for autocmd_add() to provide a
feature which was not also provided by :autocmd.
And if replace is ignored for the default augroup, then there would be no
issue (right?).
You can use ":autocmd!" to remove the commands associated with an event
in the default group and add a new command. e.g.
autocmd CursorHold * echo "cmd1"
autocmd CursorHold * echo "cmd2"
autocmd! CursorHold * echo "cmd3"
Currently autocmd_add() doesn't support this feature. I have created
PR 10473
to add this.
Regards,
Yegappan
… The only counter-argument I can find is that it would make replace more
complicated to understand. But IMO, doing what the user expects is more
important. And to quote :help local-options
<https://vimhelp.org/options.txt.html#local-options>:
Unfortunately, doing what the user expects is a bit complicated...
Anyway, the mere introduction of replace would already be a big
improvement. Making it default for *named* augroups would be even better,
but not that important.
Thank you very much for working on these functions, they're very useful.
|
|
Yegappan wrote:
On Mon, May 23, 2022 at 1:40 PM Nick Jensen ***@***.***>
wrote:
> It's probably better to add a "replace" argument: If an autocommand for
> this group and event already exists, replace it with this one.
>
> I think either unique or replace are both fine (although unique is more
> descriptive in my mind), as long as the default value is true so we
> normally don't need to use it, or even know about it! It is very rare that
> an autocmd should *not* replace an existing one with the same group and
> event.
>
>
> If the 'replace' item is specified, then autocmd_add() will remove all the
commands
associated with an autocmd event in the group and add the new command. If a
group is not specified, then the default group will be used. This is same
as running
the following command:
autocmd! {group} {event} {pat} {cmd}
If we make 'replace' the default, then a call to autocmd_add() in a .vimrc
file will
remove commands added by a plugin (in the default group) for that event.
A user may not expect this. So we should not make 'replace' as the default.
Right, having "replace" be the default goes against what would normally
be expected. For example:
autocmd_add( ... some group and event ..., command one)
autocmd_add( ... some group and event ..., command two)
Here the user adds two commands for the same group and event. Both
should be added. Having the second one remove the first one is very
unexpected. Note that the two commands could be far apart.
…--
Facepalm statement #4: "3000 year old graves? That's not possible, it's only
2014!"
/// Bram Moolenaar -- ***@***.*** -- http://www.Moolenaar.net \\\
/// \\\
\\\ sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ ///
\\\ help me help AIDS victims -- http://ICCF-Holland.org ///
|
I was thinking that the comparison would not be based only on the group and event, but also on the actual command. But maybe that would have been too tricky to implement. Anyway, I'm fine with |
|
There is another issue: it's not easy to use vim9script
autocmd_add([{group: 'SomeGroup', event: 'BufEnter,WinEnter,VimEnter', pattern: '*', cmd: 'echomsg "do something"'}])
autocmdNotice that It would be useful for the vim9script
autocmd_add([{group: 'SomeGroup', event: ['BufEnter', 'WinEnter', 'VimEnter'], pattern: '*', cmd: 'echomsg "do something"'}]) |
|
And I guess the same limitation applies to a comma-separated list of patterns. |
|
There is another issue: it's not easy to use `autocmd_add()` to install an autocmd listening to several events.
```vim
vim9script
autocmd_add([{group: 'SomeGroup', event: 'BufEnter,WinEnter,VimEnter', pattern: '*', cmd: 'echomsg "do something"'}])
autocmd
```
--- Autocommands ---
SomeGroup BufEnter
* echomsg "do something"
Notice that `autocmd_add()` has ignored everything after the comma
(i.e. `WinEnter` and `VimEnter`).
This should at least give an error.
It would be useful for the `event` key to either accept a
comma-separated list of events, or better yet a list of strings.
Trying the latter currently gives `E730`:
```vim
vim9script
autocmd_add([{group: 'SomeGroup', event: ['BufEnter', 'WinEnter', 'VimEnter'], pattern: '*', cmd: 'echomsg "do something"'}])
```
E730: Using a List as a String
Comparing the alternatives:
event: 'BufEnter,WinEnter,VimEnter',
event: ['BufEnter', 'WinEnter', 'VimEnter']
Just using a string with commas is shorter and has less puncutation.
Is there a reason to use a list?
…--
You cannot propel yourself forward by patting yourself on the back.
/// Bram Moolenaar -- ***@***.*** -- http://www.Moolenaar.net \\\
/// \\\
\\\ sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ ///
\\\ help me help AIDS victims -- http://ICCF-Holland.org ///
|
I'm not sure. While it's more verbose, it seems that an explicit list data structure is a better fit for a list of events/patterns than a string, where the list is implicit (we have to mentally split the string when reading the code). It might also help in some corner cases. For example, in the middle of a comma-separated list of patterns, if one of them starts with a comma, then it needs to be escaped to not be confused with a delimiter: Here the pattern is meant to match a file whose extension is Also, the first autocmd in my vimrc listens to a list of events which is specified by a heredoc (i.e. a list of strings, not a string): With a string, I would probably write: With a list: In the latter, there is no need for Although, I admit that these are corner cases. Ideally, Just a comma-separated list would be fine too, I guess. And at least an error, instead of silently ignoring everything after the first comma. |
|
+1 for using lists for lists of things, otherwise there would be no point in having types other than strings (and reinvent a poor man's TCL). |
|
+1 for using lists for lists of things, otherwise there would be no
point in having types other than strings (and reinvent a poor man's
TCL).
Conceptually using a list for what is a list of words makes a lot of
sense.
You could even avoid writing the list by doing:
'OneEvent,TwoEvent,ThreeEvent'->split(',')
If you are allergic to square brackets ...
…--
"My particular problem is with registry entries, which seem to just
accumulate like plastic coffee cups..." -- Paul Moore
/// Bram Moolenaar -- ***@***.*** -- http://www.Moolenaar.net \\\
/// \\\
\\\ sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ ///
\\\ help me help AIDS victims -- http://ICCF-Holland.org ///
|
No description provided.