[vim/vim] cannot use a {} block in a nested :autocmd (PR #20933)

h_east (Vim Github Repository) <[email protected]> Mon, 03 Aug 2026 13:58:04 -0700
Newsgroups gmane.editors.vim.devel
Message-ID <vim/vim/pull/[email protected]>

----==_mimepart_6a7100dccba85_e911803203c2
Content-Type: text/plain; charset="UTF-8"

```
Problem:  At script level a "{" block is only recognized when it is the
          whole argument of :autocmd or :command, so an :autocmd that is
          the command of another :autocmd cannot use a block.  In a :def
          function a trailing "{" is accepted instead, and there any
          command ending in "{", such as "normal! {", is mistaken for the
          start of a block.
Solution: Locate the block by following the argument of the command,
          descending into a nested :autocmd or :command, and use that
          everywhere a block needs to be recognized.
```

fixes: #20918

---

Two different rules were used to recognize a `{}` block after `:autocmd` and
`:command`, and each is wrong in the opposite direction.

At script level a block is only recognized when the command argument is `{`
and nothing else (patch 8.2.3268).  So an `:autocmd` that is the command of
another `:autocmd` cannot use one:

```vim
vim9script
autocmd FileType fzf autocmd BufWinEnter * ++once {
    echo 'hello'
}
```

The outer argument ends with `{` but does not consist of it, so no block is
read.  The lines after it run as ordinary script lines and the final `}` gives
E1128.

In a `:def` function the check is the reverse (patch 8.2.3271, same day): the
line starts a block when it ends in `{` and begins with `au` or `com`.  Nesting
works there, but a command that merely happens to end in `{` is taken for a
block:

```vim
vim9script
def Setup()
  autocmd BufReadPost * normal! {
  echo 'after'
enddef
```

`normal! {` moves to the previous paragraph.  The rest of the function is
swallowed while looking for `}` and E1171 is given.

Both now use one function, `find_cmd_block_start()`.  It returns the `{` when
the command argument is `{` at the end of the line, and follows the argument of
a nested `:autocmd` or `:command` to look there too.  A trailing `{` belonging
to some other command is not a block start.

`UC_VIM9` is now set only for the command that owns the block, so an `:autocmd`
with one nested in it keeps the syntax of its own script.

Nesting the blocks themselves is still not supported, as documented.
You can view, comment on, or merge this pull request online at:

  https://github.com/vim/vim/pull/20933

-- Commit Summary --

  * cannot use a {} block in a nested :autocmd

-- File Changes --

    M runtime/doc/autocmd.txt (8)
    M src/autocmd.c (50)
    M src/ex_docmd.c (62)
    M src/proto/autocmd.pro (1)
    M src/proto/ex_docmd.pro (1)
    M src/testdir/test_autocmd.vim (86)
    M src/testdir/test_usercommands.vim (36)
    M src/testdir/test_vim9_script.vim (41)
    M src/usercmd.c (11)
    M src/userfunc.c (9)
    M src/vim9cmds.c (34)

-- Patch Links --

https://github.com/vim/vim/pull/20933.patch
https://github.com/vim/vim/pull/20933.diff

-- 
Reply to this email directly or view it on GitHub:
https://github.com/vim/vim/pull/20933
You are receiving this because you are subscribed to this thread.

Message ID: <vim/vim/pull/[email protected]>

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups "vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [email protected].
To view this discussion visit https://groups.google.com/d/msgid/vim_dev/vim/vim/pull/20933%40github.com.

----==_mimepart_6a7100dccba85_e911803203c2
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

<pre class=3D"notranslate"><code class=3D"notranslate">Problem:  At script =
level a "{" block is only recognized when it is the
          whole argument of :autocmd or :command, so an :autocmd that is
          the command of another :autocmd cannot use a block.  In a :def
          function a trailing "{" is accepted instead, and there any
          command ending in "{", such as "normal! {", is mistaken for the
          start of a block.
Solution: Locate the block by following the argument of the command,
          descending into a nested :autocmd or :command, and use that
          everywhere a block needs to be recognized.
</code></pre>
<p dir=3D"auto"><span class=3D"issue-keyword tooltipped tooltipped-se" aria=
-label=3D"This pull request closes issue #20918.">fixes</span>: <a class=3D=
"issue-link js-issue-link" data-error-text=3D"Failed to load title" data-id=
=3D"5042374036" data-permission-text=3D"Title is private" data-url=3D"https=
://github.com/vim/vim/issues/20918" data-hovercard-type=3D"issue" data-hove=
rcard-url=3D"/vim/vim/issues/20918/hovercard" href=3D"https://github.com/vi=
m/vim/issues/20918">#20918</a></p>
<hr>
<p dir=3D"auto">Two different rules were used to recognize a <code class=3D=
"notranslate">{}</code> block after <code class=3D"notranslate">:autocmd</c=
ode> and<br>
<code class=3D"notranslate">:command</code>, and each is wrong in the oppos=
ite direction.</p>
<p dir=3D"auto">At script level a block is only recognized when the command=
 argument is <code class=3D"notranslate">{</code><br>
and nothing else (patch 8.2.3268).  So an <code class=3D"notranslate">:auto=
cmd</code> that is the command of<br>
another <code class=3D"notranslate">:autocmd</code> cannot use one:</p>
<div class=3D"highlight highlight-source-viml" dir=3D"auto"><pre class=3D"n=
otranslate"><span class=3D"pl-c1">vim9script</span>
<span class=3D"pl-k">autocmd</span> <span class=3D"pl-c1">FileType</span> <=
span class=3D"pl-s">fzf</span> <span class=3D"pl-k">autocmd</span> <span cl=
ass=3D"pl-c1">BufWinEnter</span> <span class=3D"pl-s">*</span> <span class=
=3D"pl-k">++once</span> {
    <span class=3D"pl-c1">echo</span> <span class=3D"pl-s"><span class=3D"p=
l-pds">'</span>hello<span class=3D"pl-pds">'</span></span>
}</pre></div>
<p dir=3D"auto">The outer argument ends with <code class=3D"notranslate">{<=
/code> but does not consist of it, so no block is<br>
read.  The lines after it run as ordinary script lines and the final <code =
class=3D"notranslate">}</code> gives<br>
E1128.</p>
<p dir=3D"auto">In a <code class=3D"notranslate">:def</code> function the c=
heck is the reverse (patch 8.2.3271, same day): the<br>
line starts a block when it ends in <code class=3D"notranslate">{</code> an=
d begins with <code class=3D"notranslate">au</code> or <code class=3D"notra=
nslate">com</code>.  Nesting<br>
works there, but a command that merely happens to end in <code class=3D"not=
ranslate">{</code> is taken for a<br>
block:</p>
<div class=3D"highlight highlight-source-viml" dir=3D"auto"><pre class=3D"n=
otranslate"><span class=3D"pl-c1">vim9script</span>
<span class=3D"pl-c1">def</span> <span class=3D"pl-en">Setup</span>()
  <span class=3D"pl-k">autocmd</span> <span class=3D"pl-c1">BufReadPost</sp=
an> <span class=3D"pl-s">*</span> <span class=3D"pl-c1">normal</span><span =
class=3D"pl-k">!</span> {
  <span class=3D"pl-c1">echo</span> <span class=3D"pl-s"><span class=3D"pl-=
pds">'</span>after<span class=3D"pl-pds">'</span></span>
<span class=3D"pl-c1">enddef</span></pre></div>
<p dir=3D"auto"><code class=3D"notranslate">normal! {</code> moves to the p=
revious paragraph.  The rest of the function is<br>
swallowed while looking for <code class=3D"notranslate">}</code> and E1171 =
is given.</p>
<p dir=3D"auto">Both now use one function, <code class=3D"notranslate">find=
_cmd_block_start()</code>.  It returns the <code class=3D"notranslate">{</c=
ode> when<br>
the command argument is <code class=3D"notranslate">{</code> at the end of =
the line, and follows the argument of<br>
a nested <code class=3D"notranslate">:autocmd</code> or <code class=3D"notr=
anslate">:command</code> to look there too.  A trailing <code class=3D"notr=
anslate">{</code> belonging<br>
to some other command is not a block start.</p>
<p dir=3D"auto"><code class=3D"notranslate">UC_VIM9</code> is now set only =
for the command that owns the block, so an <code class=3D"notranslate">:aut=
ocmd</code><br>
with one nested in it keeps the syntax of its own script.</p>
<p dir=3D"auto">Nesting the blocks themselves is still not supported, as do=
cumented.</p>

<hr>

<h4>You can view, comment on, or merge this pull request online at:</h4>
<p>&nbsp;&nbsp;<a href=3D'https://github.com/vim/vim/pull/20933'>https://gi=
thub.com/vim/vim/pull/20933</a></p>

<h4>Commit Summary</h4>
<ul>
  <li><a href=3D"https://github.com/vim/vim/pull/20933/commits/34a9b39cb65b=
ee7231fb04c7346dd162ac5ff134" class=3D"commit-link">34a9b39</a>  cannot use=
 a {} block in a nested :autocmd</li>
</ul>

<h4 style=3D"display: inline-block">File Changes </h4> <p style=3D"display:=
 inline-block">(<a href=3D"https://github.com/vim/vim/pull/20933/files">11&=
nbsp;files</a>)</p>
<ul>
  <li>
    <strong>M</strong>
    <a href=3D"https://github.com/vim/vim/pull/20933/files#diff-7fc4babd126=
f0b22993940da3ae8260a3b82ec20aa3dca54425bc4d27e6d8600">runtime/doc/autocmd.=
txt</a>
    (8)
  </li>
  <li>
    <strong>M</strong>
    <a href=3D"https://github.com/vim/vim/pull/20933/files#diff-65ea201c4b4=
9898f90255b7fd507b702016d46bc657c54346d3828939b13ff7a">src/autocmd.c</a>
    (50)
  </li>
  <li>
    <strong>M</strong>
    <a href=3D"https://github.com/vim/vim/pull/20933/files#diff-8663dec4897=
df405b32c112b236466a2f6190bd32323ab22d161772949103d54">src/ex_docmd.c</a>
    (62)
  </li>
  <li>
    <strong>M</strong>
    <a href=3D"https://github.com/vim/vim/pull/20933/files#diff-827b6530080=
1d2ac596664087226dde1aed25eec61175a0d804b7ae42a6bca5e">src/proto/autocmd.pr=
o</a>
    (1)
  </li>
  <li>
    <strong>M</strong>
    <a href=3D"https://github.com/vim/vim/pull/20933/files#diff-c6bf1026974=
0ca90e853bdcd9a888cc6494570c2009f6dba3e288702b32f0311">src/proto/ex_docmd.p=
ro</a>
    (1)
  </li>
  <li>
    <strong>M</strong>
    <a href=3D"https://github.com/vim/vim/pull/20933/files#diff-12cb333d2b5=
d5ba2753dcb2d58c1ee23cf888269a558caaf91a018246493b363">src/testdir/test_aut=
ocmd.vim</a>
    (86)
  </li>
  <li>
    <strong>M</strong>
    <a href=3D"https://github.com/vim/vim/pull/20933/files#diff-a34c69c71c2=
8bf4f93acdc92ff1a2c5a8ed3e496e935d523fe1c6e50ecb76dc3">src/testdir/test_use=
rcommands.vim</a>
    (36)
  </li>
  <li>
    <strong>M</strong>
    <a href=3D"https://github.com/vim/vim/pull/20933/files#diff-96be1047f3a=
747456150d86f011fb50d37dbb9174799525ac0a291f67cb5c788">src/testdir/test_vim=
9_script.vim</a>
    (41)
  </li>
  <li>
    <strong>M</strong>
    <a href=3D"https://github.com/vim/vim/pull/20933/files#diff-867b39b1728=
92a0c2f57c7c89b70b7f5f8ba59eff76bf00ecd50d1b20d31af1c">src/usercmd.c</a>
    (11)
  </li>
  <li>
    <strong>M</strong>
    <a href=3D"https://github.com/vim/vim/pull/20933/files#diff-62d8f9f3d3b=
07d630f5ca65979eb333b1822f699247cb7637902e6dadbeb10d0">src/userfunc.c</a>
    (9)
  </li>
  <li>
    <strong>M</strong>
    <a href=3D"https://github.com/vim/vim/pull/20933/files#diff-2042d33fd3f=
4181ec50bbaa9945278ef2a8c432789e9eb596381bad0768da6cd">src/vim9cmds.c</a>
    (34)
  </li>
</ul>

<h4>Patch Links:</h4>
<ul>
  <li><a href=3D'https://github.com/vim/vim/pull/20933.patch'>https://githu=
b.com/vim/vim/pull/20933.patch</a></li>
  <li><a href=3D'https://github.com/vim/vim/pull/20933.diff'>https://github=
.com/vim/vim/pull/20933.diff</a></li>
</ul>

<p style=3D"font-size:small;-webkit-text-size-adjust:none;color:#666;">&mda=
sh;<br />Reply to this email directly, <a href=3D"https://github.com/vim/vi=
m/pull/20933">view it on GitHub</a>, or <a href=3D"https://github.com/notif=
ications/unsubscribe-auth/ACY5DGDUON23XXUG2VBUX4D5ID4FZAVCNFSNUABEKJSXA33TN=
F2G64TZHM2DAOJZG42DQMR3JFZXG5LFHM2TANJUGE3DCNBRGGQXMAQ">unsubscribe</a>.<br=
 />Triage notifications, keep track of coding agent tasks and review pull r=
equests on the go with GitHub Mobile for <a href=3D"https://github.com/noti=
fications/mobile/ios/ACY5DGGJXMOC264RMGPGE735ID4FZA5CNFSNUABEM5UWIORPF5TWS5=
BNNB2WEL2QOVWGYUTFOF2WK43UF42DCOJYGAYTIMZTGWTHEZLBONXW5KTTOVRHGY3SNFRGKZFFM=
V3GK3TUVJTG633UMVZF62LPOM">iOS</a> and <a href=3D"https://github.com/notifi=
cations/mobile/android/ACY5DGCZZGJNYO4PFGAHMGD5ID4FZA5CNFSNUABEM5UWIORPF5TW=
S5BNNB2WEL2QOVWGYUTFOF2WK43UF42DCOJYGAYTIMZTGWTHEZLBONXW5KTTOVRHGY3SNFRGKZF=
FMV3GK3TUVZTG633UMVZF6YLOMRZG62LE">Android</a>. Download it today!
<br />You are receiving this because you are subscribed to this thread.<img=
 src=3D"https://github.com/notifications/beacon/ACY5DGEUYDAEJLUUQ5QX4PT5ID4=
FZBFCNFSM6AAAAAC4ZKETQGWGG33NNVSW45C7OR4XAZNFJFZXG5LFVJRW63LNMVXHIX3JMTHQAA=
AAAEWUAYQDUZZGKYLTN5XKU43VMJZWG4TJMJSWI.gif" height=3D"1" width=3D"1" alt=
=3D"" /><span style=3D"color: transparent; font-size: 0; display: none; vis=
ibility: hidden; overflow: hidden; opacity: 0; width: 0; height: 0; max-wid=
th: 0; max-height: 0; mso-hide: all">Message ID: <span>&lt;vim/vim/pull/209=
33</span><span>@</span><span>github</span><span>.</span><span>com&gt;</span=
></span></p>
<script type=3D"application/ld+json">[
{
"@context": "http://schema.org",
"@type": "EmailMessage",
"potentialAction": {
"@type": "ViewAction",
"target": "https://github.com/vim/vim/pull/20933",
"url": "https://github.com/vim/vim/pull/20933",
"name": "View Pull Request"
},
"description": "View this Pull Request on GitHub",
"publisher": {
"@type": "Organization",
"name": "GitHub",
"url": "https://github.com"
}
}
]</script>

<p></p>

-- <br />
-- <br />
You received this message from the &quot;vim_dev&quot; maillist.<br />
Do not top-post! Type your reply below the text you are replying to.<br />
For more information, visit <a href=3D"http://www.vim.org/maillist.php">htt=
p://www.vim.org/maillist.php</a><br />
<br />
--- <br />
You received this message because you are subscribed to the Google Groups &=
quot;vim_dev&quot; group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:[email protected]">vim_dev+uns=
[email protected]</a>.<br />
To view this discussion visit <a href=3D"https://groups.google.com/d/msgid/=
vim_dev/vim/vim/pull/20933%40github.com?utm_medium=3Demail&utm_source=3Dfoo=
ter">https://groups.google.com/d/msgid/vim_dev/vim/vim/pull/20933%40github.=
com</a>.<br />

----==_mimepart_6a7100dccba85_e911803203c2--