aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.git-blame-ignore-revs13
-rw-r--r--.github/labeler.yml1
-rw-r--r--.github/scripts/remove-reviewers.js16
-rw-r--r--.github/workflows/api-docs-check.yml2
-rw-r--r--.github/workflows/api-docs.yml8
-rw-r--r--.github/workflows/labeler.yml2
-rw-r--r--.github/workflows/remove-reviewers-on-draft.yml17
-rw-r--r--.mailmap134
-rw-r--r--Makefile2
-rw-r--r--README.md4
-rwxr-xr-xci/snap/deploy.sh4
-rw-r--r--runtime/autoload/clojurecomplete.vim8
-rw-r--r--runtime/autoload/health.vim2
-rw-r--r--runtime/autoload/health/provider.vim2
-rw-r--r--runtime/autoload/python3complete.vim5
-rw-r--r--runtime/doc/api.txt286
-rw-r--r--runtime/doc/autocmd.txt8
-rw-r--r--runtime/doc/builtin.txt17
-rw-r--r--runtime/doc/insert.txt2
-rw-r--r--runtime/doc/lsp.txt3
-rw-r--r--runtime/doc/lua.txt16
-rw-r--r--runtime/doc/message.txt2
-rw-r--r--runtime/doc/options.txt6
-rw-r--r--runtime/doc/pattern.txt46
-rw-r--r--runtime/doc/repeat.txt3
-rw-r--r--runtime/doc/syntax.txt3
-rw-r--r--runtime/doc/vim_diff.txt1
-rw-r--r--runtime/filetype.vim5
-rw-r--r--runtime/ftplugin/clojure.vim12
-rw-r--r--runtime/ftplugin/cpp.vim1
-rw-r--r--runtime/ftplugin/query.lua6
-rw-r--r--runtime/ftplugin/ruby.vim44
-rw-r--r--runtime/indent/clojure.vim2
-rw-r--r--runtime/indent/query.lua6
-rw-r--r--runtime/indent/ruby.vim48
-rw-r--r--runtime/lua/vim/diagnostic.lua23
-rw-r--r--runtime/lua/vim/filetype.lua6
-rw-r--r--runtime/lua/vim/lsp/util.lua4
-rw-r--r--runtime/lua/vim/shared.lua27
-rw-r--r--runtime/lua/vim/treesitter/highlighter.lua10
-rw-r--r--runtime/syntax/clojure.vim42
-rw-r--r--runtime/syntax/debchangelog.vim6
-rw-r--r--runtime/syntax/debsources.vim6
-rw-r--r--runtime/syntax/eruby.vim12
-rw-r--r--runtime/syntax/ruby.vim16
-rw-r--r--runtime/syntax/tmux.vim127
-rwxr-xr-xsrc/clint.py4
-rw-r--r--src/nvim/api/autocmd.c521
-rw-r--r--src/nvim/api/extmark.c4
-rw-r--r--src/nvim/api/keysets.lua10
-rw-r--r--src/nvim/api/private/helpers.h5
-rw-r--r--src/nvim/autocmd.c12
-rw-r--r--src/nvim/buffer.c28
-rw-r--r--src/nvim/buffer_defs.h2
-rw-r--r--src/nvim/change.c2
-rw-r--r--src/nvim/diff.c2
-rw-r--r--src/nvim/edit.c8
-rw-r--r--src/nvim/eval.c3
-rw-r--r--src/nvim/eval/funcs.c5
-rw-r--r--src/nvim/ex_docmd.c2
-rw-r--r--src/nvim/ex_getln.c144
-rw-r--r--src/nvim/ex_session.c32
-rw-r--r--src/nvim/fileio.c2
-rw-r--r--src/nvim/getchar.c5
-rw-r--r--src/nvim/main.c2
-rw-r--r--src/nvim/message.c25
-rw-r--r--src/nvim/move.c42
-rw-r--r--src/nvim/normal.c10
-rw-r--r--src/nvim/ops.c2
-rw-r--r--src/nvim/option_defs.h4
-rw-r--r--src/nvim/path.c2
-rw-r--r--src/nvim/quickfix.c1
-rw-r--r--src/nvim/regexp.c6
-rw-r--r--src/nvim/regexp_bt.c38
-rw-r--r--src/nvim/regexp_nfa.c30
-rw-r--r--src/nvim/screen.c34
-rw-r--r--src/nvim/spellfile.c3
-rw-r--r--src/nvim/state.c7
-rw-r--r--src/nvim/testdir/test_autocmd.vim30
-rw-r--r--src/nvim/testdir/test_cursorline.vim21
-rw-r--r--src/nvim/testdir/test_display.vim21
-rw-r--r--src/nvim/testdir/test_filechanged.vim1
-rw-r--r--src/nvim/testdir/test_filetype.vim1
-rw-r--r--src/nvim/testdir/test_highlight.vim25
-rw-r--r--src/nvim/testdir/test_messages.vim53
-rw-r--r--src/nvim/testdir/test_mksession.vim43
-rw-r--r--src/nvim/testdir/test_number.vim25
-rw-r--r--src/nvim/testdir/test_quickfix.vim202
-rw-r--r--src/nvim/testdir/test_regexp_latin.vim97
-rw-r--r--src/nvim/testdir/test_sort.vim1
-rw-r--r--src/nvim/tui/tui.c28
-rw-r--r--src/nvim/ui_client.c8
-rw-r--r--src/nvim/window.c130
-rw-r--r--test/busted/outputHandlers/nvim.lua2
-rw-r--r--test/functional/api/autocmd_spec.lua156
-rw-r--r--test/functional/api/command_spec.lua7
-rw-r--r--test/functional/api/vim_spec.lua12
-rw-r--r--test/functional/editor/tabpage_spec.lua17
-rw-r--r--test/functional/ex_cmds/cmd_map_spec.lua58
-rw-r--r--test/functional/ex_cmds/echo_spec.lua14
-rw-r--r--test/functional/ex_cmds/script_spec.lua14
-rw-r--r--test/functional/helpers.lua26
-rw-r--r--test/functional/legacy/assert_spec.lua12
-rw-r--r--test/functional/legacy/display_spec.lua36
-rw-r--r--test/functional/legacy/memory_usage_spec.lua17
-rw-r--r--test/functional/legacy/messages_spec.lua71
-rw-r--r--test/functional/lua/vim_spec.lua6
-rw-r--r--test/functional/plugin/matchparen_spec.lua2
-rw-r--r--test/functional/ui/decorations_spec.lua32
-rw-r--r--test/functional/ui/fold_spec.lua2
-rw-r--r--test/functional/ui/global_statusline_spec.lua27
-rw-r--r--test/functional/ui/highlight_spec.lua142
-rw-r--r--test/functional/ui/input_spec.lua44
-rw-r--r--test/functional/ui/syntax_conceal_spec.lua53
-rw-r--r--test/functional/vimscript/lang_spec.lua1
-rw-r--r--test/functional/vimscript/timer_spec.lua2
-rw-r--r--third-party/CMakeLists.txt4
117 files changed, 2558 insertions, 898 deletions
diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs
index bbca6b3339..737a9a249e 100644
--- a/.git-blame-ignore-revs
+++ b/.git-blame-ignore-revs
@@ -36,3 +36,16 @@ d90fb1c0bfc1e64c783c385a79e7de87013dadba
9c268263b1792d00b3ffdfd7495af2575862656e
8c74c895b300bcee5fa937a2329d1d4756567b42
40be47e0faef7aa015eb4ba44ceb1ee1a03e97cf
+4472c56d54f447040f6e8610b261b7efa0d04eb6
+a68faed02dc8e37b8f10da14dc02e33e6ed93947
+725cbe7d414f609e769081276f2a034e32a4337b
+7e3bdc75e44b9139d8afaea4381b53ae78b15746
+4ba12b3dda34472c193c9fa8ffd7d3bd5b6c04d6
+849f104c2789c884428fd45501912c6591a78e12
+38dd53c525054daf83dba27d7d46e90e8b41fa50
+6059784770c4c88fb6fe528b9f7634192fa1164e
+ee031eb5256bb83e0d6add2bae6fd943a4186ffe
+
+# typos
+d238b8f6003d34cae7f65ff7585b48a2cd9449fb
+4547137aaff32b20172870a549d3a28a3c7adf1c
diff --git a/.github/labeler.yml b/.github/labeler.yml
index e20a2577cd..2e3aa8f875 100644
--- a/.github/labeler.yml
+++ b/.github/labeler.yml
@@ -49,6 +49,7 @@
"build":
- CMakeLists.txt
- "**/CMakeLists.txt"
+ - "**/Makefile"
- "**/*.cmake"
"test":
diff --git a/.github/scripts/remove-reviewers.js b/.github/scripts/remove-reviewers.js
new file mode 100644
index 0000000000..631f08e57d
--- /dev/null
+++ b/.github/scripts/remove-reviewers.js
@@ -0,0 +1,16 @@
+module.exports = async ({github, context}) => {
+ const requestedReviewers = await github.rest.pulls.listRequestedReviewers({
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ pull_number: context.issue.number
+ });
+
+ const reviewers = requestedReviewers.data.users.map(e => e.login)
+
+ github.rest.pulls.removeRequestedReviewers({
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ pull_number: context.issue.number,
+ reviewers: reviewers
+ });
+}
diff --git a/.github/workflows/api-docs-check.yml b/.github/workflows/api-docs-check.yml
index bcbc631172..f76c035de4 100644
--- a/.github/workflows/api-docs-check.yml
+++ b/.github/workflows/api-docs-check.yml
@@ -6,8 +6,8 @@ on:
- 'marvim/api-doc-update**'
paths:
- 'src/nvim/api/*.[ch]'
- - 'src/nvim/**.lua'
- 'runtime/lua/**.lua'
+ - 'runtime/doc/**'
jobs:
call-regen-api-docs:
diff --git a/.github/workflows/api-docs.yml b/.github/workflows/api-docs.yml
index 7550af6fef..ce8ed7996a 100644
--- a/.github/workflows/api-docs.yml
+++ b/.github/workflows/api-docs.yml
@@ -1,13 +1,13 @@
# Autogenerate the API docs on new commit to important branches
-# Also work as a check for PR's to not forget commiting their doc changes
+# Also work as a check for PR's to not forget committing their doc changes
# called from api-docs-check.yml
name: Autogenerate API docs
on:
push:
paths:
- 'src/nvim/api/*.[ch]'
- - 'src/nvim/**.lua'
- 'runtime/lua/**.lua'
+ - 'runtime/doc/**'
branches:
- 'master'
- 'release-[0-9]+.[0-9]+'
@@ -53,10 +53,12 @@ jobs:
python3 scripts/gen_vimdoc.py
printf '::set-output name=UPDATED_DOCS::%s\n' $([ -z "$(git diff)" ]; echo $?)
- - name: FAIL, PR has not commited doc changes
+ - name: FAIL, PR has not committed doc changes
if: ${{ steps.docs.outputs.UPDATED_DOCS != 0 && inputs.check_only }}
run: |
echo "Job failed, run ./scripts/gen_vimdoc.py and commit your doc changes"
+ echo "The doc generation produces the following changes:"
+ git --no-pager diff
exit 1
- name: Automatic PR
diff --git a/.github/workflows/labeler.yml b/.github/workflows/labeler.yml
index d50e0c1f92..7845ae92a3 100644
--- a/.github/workflows/labeler.yml
+++ b/.github/workflows/labeler.yml
@@ -30,6 +30,8 @@ jobs:
run: gh pr edit "$PR_NUMBER" --add-label "$(echo "$PR_TITLE" | sed -E 's|([[:alpha:]]+)(\(.*\))?!?:.*|\1|')" || true
- name: "Extract commit scope and add as label"
run: gh pr edit "$PR_NUMBER" --add-label "$(echo "$PR_TITLE" | sed -E 's|[[:alpha:]]+\((.+)\)!?:.*|\1|')" || true
+ - name: "Extract if the PR is a breaking change and add it as label"
+ run: gh pr edit "$PR_NUMBER" --add-label "$(echo "$PR_TITLE" | sed -E 's|[[:alpha:]]+(\(.*\))?!:.*|breaking-change|')" || true
request-reviewer:
if: github.event.pull_request.state == 'open' && github.event.pull_request.draft == false
diff --git a/.github/workflows/remove-reviewers-on-draft.yml b/.github/workflows/remove-reviewers-on-draft.yml
new file mode 100644
index 0000000000..64474618b8
--- /dev/null
+++ b/.github/workflows/remove-reviewers-on-draft.yml
@@ -0,0 +1,17 @@
+name: "Remove reviewers"
+on:
+ pull_request_target:
+ types: [converted_to_draft, closed]
+jobs:
+ remove-reviewers:
+ runs-on: ubuntu-latest
+ permissions:
+ pull-requests: write
+ steps:
+ - uses: actions/checkout@v2
+ - name: 'Remove reviewers'
+ uses: actions/github-script@v6
+ with:
+ script: |
+ const script = require('./.github/scripts/remove-reviewers.js')
+ await script({github, context})
diff --git a/.mailmap b/.mailmap
new file mode 100644
index 0000000000..1aa9aa36d8
--- /dev/null
+++ b/.mailmap
@@ -0,0 +1,134 @@
+Abdelhakeem <abdelhakeem.osama@hotmail.com> Abdelhakeem Osama
+Alvaro Muñoz <alvaro@pwntester.com> Alvaro Muñoz
+Andreas Johansson <andreas@ndrs.xyz> <ndreas@users.noreply.github.com>
+Andrew Pyatkov <mrbiggfoot@gmail.com> <mrbiggfoot@users.noreply.github.com>
+Anmol Sethi <hi@nhooyr.io> <anmol@aubble.com>
+Anmol Sethi <hi@nhooyr.io> <me@anmol.io>
+Anmol Sethi <hi@nhooyr.io> <nhooyr@users.noreply.github.com>
+BK1603 <chouhan.shreyansh2702@gmail.com> Shreyansh Chouhan
+Billy Su <g4691821@gmail.com> Billy SU
+Billy Vong <billyvg@gmail.com> <billyvg@users.noreply.github.com>
+Björn Linse <bjorn.linse@gmail.com> bfredl
+Carlos Hernandez <carlos@techbyte.ca> <hurricanehrndz@users.noreply.github.com>
+Chris Kipp <ckipp@pm.me> ckipp01
+Christian Clason <c.clason@uni-graz.at> <christian.clason@uni-due.de>
+Cédric Barreteau <> <cbarrete@users.noreply.github.com>
+Dan Aloni <alonid@gmail.com> <dan@kernelim.com>
+Daniel Hahler <git@thequod.de> <github@thequod.de>
+Eisuke Kawashima <e-kwsm@users.noreply.github.com> E Kawashima
+ElPiloto <luis.r.piloto@gmail.com> Luis Piloto
+Eliseo Martínez <eliseomarmol@gmail.com> Eliseo Martínez
+Fabian Viöl <f.vioel@googlemail.com> Fabian
+Florian Walch <florian@fwalch.com> <fwalch@users.noreply.github.com>
+Gabriel Cruz <gabs.oficial98@gmail.com> <LTKills@users.noreply.github.com>
+Gaelan Steele <gbs@canishe.com> Gaelan
+Gavin D. Howard <gavin@schedmd.com> <yzena.tech@gmail.com>
+George Zhao <zhaozg@gmail.com> <zhaozg@aliyun.com>
+George Zhao <zhaozg@gmail.com> George Zhao
+Gregory Anders <greg@gpanders.com> <8965202+gpanders@users.noreply.github.com>
+Gregory Anders <greg@gpanders.com> Greg Anders
+Grzegorz Milka <grzegorzmilka@gmail.com> Grzegorz
+Harm te Hennepe <dhtehennepe@gmail.com> <d.h.tehennepe@student.utwente.nl>
+Harm te Hennepe <dhtehennepe@gmail.com> <harm@tehennepe.org>
+Hirokazu Hata <h.hata.ai.t@gmail.com> <h-michael@users.noreply.github.com>
+Ihor Antonov <ngortheone@gmail.com> <ngortheone@users.noreply.github.com>
+J Phani Mahesh <phanimahesh@gmail.com> <github@phanimahesh.me>
+Jack Bracewell <FriedSock@users.noreply.github.com> <jack.bracewell@unboxedconsulting.com>
+Jack Bracewell <FriedSock@users.noreply.github.com> <jbtwentythree@gmail.com>
+Jacques Germishuys <jacquesg@striata.com> <jacquesg@users.noreply.github.com>
+Jakub Łuczyński <doubleloop@o2.pl> <doubleloop@users.noreply.github.com>
+James McCoy <jamessan@jamessan.com> <vega.james@gmail.com>
+Jan Edmund Lazo <jan.lazo@mail.utoronto.ca> <janedmundlazo@hotmail.com>
+Jan Viljanen <jan.a.viljanen@gmail.com> <jan.viljanen@greenpeace.org>
+Javier Lopez <graulopezjavier@gmail.com> Javier López
+Jit Yao Yap <jityao@gmail.com> <jityao+github@gmail.com>
+Jit Yao Yap <jityao@gmail.com> Jit
+John Gehrig <jdg.gehrig@gmail.com> <jgehrig@users.noreply.github.com>
+John Schmidt <john.schmidt.h@gmail.com> John
+John Szakmeister <john@szakmeister.net> <jszakmeister@users.noreply.github.com>
+Jonathan de Boyne Pollard <J.deBoynePollard-newsgroups@NTLWorld.com> <jdebp@users.noreply.github.com>
+Jonathan de Boyne Pollard <J.deBoynePollard-newsgroups@NTLWorld.com> <postmaster@localhost>
+Jurica Bradaric <jbradaric@gmail.com> <jbradaric@users.noreply.github.com>
+Jurica Bradaric <jbradaric@gmail.com> <jurica.bradaric@avl.com>
+KillTheMule <KillTheMule@users.noreply.github.com> <github@pipsfrank.de>
+Kwon-Young Choi <kwon-young.choi@hotmail.fr> Kwon-Young
+Lucas Hoffmann <l-m-h@web.de> <lucc@posteo.de>
+Lucas Hoffmann <l-m-h@web.de> <lucc@users.noreply.github.com>
+Marco Hinz <mh.codebro@gmail.com> <mh.codebro+github@gmail.com>
+Marvim the Paranoid Android <marvim@users.noreply.github.com> marvim
+Mateusz Czapliński <czapkofan@gmail.com> Mateusz Czaplinski
+Mathias Fussenegger <f.mathias@zignar.net> <mfussenegger@users.noreply.github.com>
+Mathias Fussenegger <f.mathias@zignar.net> Mathias Fußenegger
+Matt Wozniski <godlygeek@gmail.com> <godlygeek+git@gmail.com>
+Matthieu Coudron <mattator@gmail.com> <coudron@iij.ad.jp>
+Matthieu Coudron <mattator@gmail.com> <matthieu.coudron@upmc.fr>
+Matthieu Coudron <mattator@gmail.com> <mcoudron@hotmail.com>
+Matthieu Coudron <mattator@gmail.com> <teto@users.noreply.github.com>
+MichaHoffmann <michoffmann.potsdam@gmail.com> Michael Hoffmann
+MichaHoffmann <michoffmann.potsdam@gmail.com> micha
+Michael Ennen <mike.ennen@gmail.com> <brcolow@users.noreply.github.com>
+Michael Ennen <mike.ennen@gmail.com> brcolow
+Michael Reed <m.reed@mykolab.com> <Pyrohh@users.noreply.github.com>
+Michael Schupikov <michael@schupikov.de> <DarkDeepBlue@users.noreply.github.com>
+Nicolas Hillegeer <nicolas@hillegeer.com> <nicolashillegeer@gmail.com>
+Panashe M. Fundira <fundirap@gmail.com> Panashe Fundira
+Patrice Peterson <patrice.peterson@mailbox.org> runiq
+Pavel Platto <hinidu@gmail.com> Hinidu
+Petter Wahlman <petter@wahlman.no> <pwahlman@cisco.com>
+Poh Zi How <poh.zihow@gmail.com> pohzipohzi
+Rich Wareham <rjw57@cam.ac.uk> <rjw57@cantab.net>
+Rui Abreu Ferreira <equalsraf@users.noreply.github.com> @equalsraf
+Rui Abreu Ferreira <raf-ep@gmx.com> <equalsraf@users.noreply.github.com>
+Rui Abreu Ferreira <raf-ep@gmx.com> <rap-ep@gmx.com>
+Sam Wilson <tecywiz121@hotmail.com> <sawilson@akamai.com>
+Sander Bosma <sanderbosma@gmail.com> sander2
+Santos Gallegos <stsewd@protonmail.com> <santos_g@outlook.com>
+Sebastian Parborg <darkdefende@gmail.com> DarkDefender
+Shirasaka <tk.shirasaka@gmail.com> tk-shirasaka
+Shota <shotat@users.noreply.github.com> shotat
+Shougo Matsushita <Shougo.Matsu@gmail.com> Shougo
+Stephan Seitz <stephan.seitz@fau.de> <stephan.lauf@yahoo.de>
+Steven Sojka <Steven.Sojka@tdameritrade.com> <steelsojka@gmail.com>
+Steven Sojka <steelsojka@gmail.com> <steelsojka@users.noreply.github.com>
+TJ DeVries <devries.timothyj@gmail.com> <timothydvrs1234@gmail.com>
+Thomas Fehér <thomas.feher@yahoo.de> <thomasfeher@web.de>
+Thomas Vigouroux <tomvig38@gmail.com> <39092278+vigoux@users.noreply.github.com>
+Utkarsh Maheshwari <UtkarshME96@gmail.com> UTkarsh Maheshwari
+Utkarsh Maheshwari <utkarshme96@gmail.com> <UtkarshME96@gmail.com>
+VVKot <volodymyr.kot.ua@gmail.com> Volodymyr Kot
+Victor Adam <victor.adam@cofelyineo-gdfsuez.com> <Victor.Adam@derpymail.org>
+Wang Shidong <wsdjeg@outlook.com> <wsdjeg@users.noreply.github.com>
+Wei Huang <daviseago@gmail.com> davix
+Xu Cheng <xucheng@me.com> <xu-cheng@users.noreply.github.com>
+Yamakaky <yamakaky@gmail.com> <yamakaky@yamaworld.fr>
+Yegappan Lakshmanan <yegappan@yahoo.com> <4298407+yegappan@users.noreply.github.com>
+Yichao Zhou <broken.zhoug@gmail.com> Yichao Zhou <broken.zhou@gmail.com>
+Yichao Zhou <broken.zhoug@gmail.com> zhou13 <broken.zhou@gmail.com>
+Yorick Peterse <git@yorickpeterse.com> <yorick@yorickpeterse.com>
+ZyX <kp-pav@yandex.ru> <kp-pav@ya.ru>
+ZyX <kp-pav@yandex.ru> Nikolai Aleksandrovich Pavlov
+aph <a.hewson@gmail.com> Ashley Hewson
+butwerenotthereyet <58348703+butwerenotthereyet@users.noreply.github.com> We're Yet
+chemzqm <chemzqm@gmail.com> Qiming zhao
+chentau <tchen1998@gmail.com> Tony Chen
+dedmass <carlo.abelli@gmail.com> Carlo Abelli
+equal-l2 <eng.equall2@gmail.com> <equal-l2@users.noreply.github.com>
+francisco souza <fsouza@users.noreply.github.com> <108725+fsouza@users.noreply.github.com>
+glacambre <code@lacamb.re> <me@r4>
+glacambre <code@lacamb.re> Ghjuvan Lacambre
+ii14 <ii14@users.noreply.github.com> <59243201+ii14@users.noreply.github.com>
+jdrouhard <john@jmdtech.org> <github@jmdtech.org>
+kuuote <znmxodq1@gmail.com> <36663503+kuuote@users.noreply.github.com>
+matveyt <matthewtarasov@gmail.com> <35012635+matveyt@users.noreply.github.com>
+nate <nateozemon@gmail.com> nateozem
+ray-x <rayx.cn@gmail.com> rayx
+relnod <mail@paul-schiffers.de> <relnod@users.noreply.github.com>
+rockerBOO <rockerboo@gmail.com> Dave Lage
+rpigott <rpigott@berkeley.edu> Ronan Pigott
+sach1t <sach0010t@gmail.com> <sach1t@users.noreply.github.com>
+shade-of-noon <73705427+shade-of-noon@users.noreply.github.com> Edwin Pujols
+shadmansaleh <shadmansaleh3@gmail.com> <13149513+shadmansaleh@users.noreply.github.com>
+shadmansaleh <shadmansaleh3@gmail.com> Shadman
+sohnryang <loop.infinitely@gmail.com> 손량
+timeyyy <timeyyy_da_man@hotmail.com> Timothy C Eichler
+timeyyy <timeyyy_da_man@hotmail.com> timothy eichler
diff --git a/Makefile b/Makefile
index 86e723df67..df4f2995d8 100644
--- a/Makefile
+++ b/Makefile
@@ -166,7 +166,7 @@ _opt_pylint:
|| echo "SKIP: pylint (flake8 not found)"
commitlint:
- $(NVIM_PRG) --clean -es +"lua require('scripts.lintcommit').main({trace=false})"
+ $(NVIM_PRG) -u NONE -es +"lua require('scripts.lintcommit').main({trace=false})"
_opt_commitlint:
@test -x build/bin/nvim && { $(MAKE) commitlint; exit $$?; } \
diff --git a/README.md b/README.md
index 4ec5cf2be3..b5a469b32d 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,6 @@
-[![Neovim](https://raw.githubusercontent.com/neovim/neovim.github.io/master/logos/neovim-logo-300x87.png)](https://neovim.io)
+<h1 align="center">
+ <img src="https://raw.githubusercontent.com/neovim/neovim.github.io/master/logos/neovim-logo-300x87.png" alt="Neovim">
+</h1>
[Documentation](https://neovim.io/doc/general/) |
[Chat](https://app.element.io/#/room/#neovim:matrix.org) |
diff --git a/ci/snap/deploy.sh b/ci/snap/deploy.sh
index 8429059e22..1794fc61d9 100755
--- a/ci/snap/deploy.sh
+++ b/ci/snap/deploy.sh
@@ -8,7 +8,7 @@ WEBHOOK_PAYLOAD="$(cat "${SNAP_DIR}/.snapcraft_payload")"
PAYLOAD_SIG="${SECRET_SNAP_SIG}"
-snap_realease_needed() {
+snap_release_needed() {
last_committed_tag="$(git tag -l --sort=refname|head -1)"
last_snap_release="$(snap info nvim | awk '$1 == "latest/edge:" { print $2 }' | perl -lpe 's/v\d.\d.\d-//g')"
git fetch -f --tags
@@ -33,7 +33,7 @@ trigger_snapcraft_webhook() {
}
-if $(snap_realease_needed); then
+if $(snap_release_needed); then
echo "New snap release required"
trigger_snapcraft_webhook
fi
diff --git a/runtime/autoload/clojurecomplete.vim b/runtime/autoload/clojurecomplete.vim
index 9f2c39081a..02262a6f91 100644
--- a/runtime/autoload/clojurecomplete.vim
+++ b/runtime/autoload/clojurecomplete.vim
@@ -4,12 +4,12 @@
" Former Maintainers: Sung Pae <self@sungpae.com>
" URL: https://github.com/clojure-vim/clojure.vim
" License: Vim (see :h license)
-" Last Change: 2021-10-26
+" Last Change: 2022-03-24
" -*- COMPLETION WORDS -*-
-" Generated from https://github.com/clojure-vim/clojure.vim/blob/62b215f079ce0f3834fd295c7a7f6bd8cc54bcc3/clj/src/vim_clojure_static/generate.clj
-" Clojure version 1.10.3
-let s:words = ["*","*'","*1","*2","*3","*agent*","*allow-unresolved-vars*","*assert*","*clojure-version*","*command-line-args*","*compile-files*","*compile-path*","*compiler-options*","*data-readers*","*default-data-reader-fn*","*e","*err*","*file*","*flush-on-newline*","*fn-loader*","*in*","*math-context*","*ns*","*out*","*print-dup*","*print-length*","*print-level*","*print-meta*","*print-namespace-maps*","*print-readably*","*read-eval*","*reader-resolver*","*source-path*","*suppress-read*","*unchecked-math*","*use-context-classloader*","*verbose-defrecords*","*warn-on-reflection*","+","+'","-","-'","->","->>","->ArrayChunk","->Eduction","->Vec","->VecNode","->VecSeq","-cache-protocol-fn","-reset-methods",".","..","/","<","<=","=","==",">",">=","EMPTY-NODE","Inst","PrintWriter-on","StackTraceElement->vec","Throwable->map","accessor","aclone","add-classpath","add-tap","add-watch","agent","agent-error","agent-errors","aget","alength","alias","all-ns","alter","alter-meta!","alter-var-root","amap","ancestors","and","any?","apply","areduce","array-map","as->","aset","aset-boolean","aset-byte","aset-char","aset-double","aset-float","aset-int","aset-long","aset-short","assert","assoc!","assoc","assoc-in","associative?","atom","await","await-for","await1","bases","bean","bigdec","bigint","biginteger","binding","bit-and","bit-and-not","bit-clear","bit-flip","bit-not","bit-or","bit-set","bit-shift-left","bit-shift-right","bit-test","bit-xor","boolean","boolean-array","boolean?","booleans","bound-fn","bound-fn*","bound?","bounded-count","butlast","byte","byte-array","bytes","bytes?","case","cast","cat","catch","char","char-array","char-escape-string","char-name-string","char?","chars","chunk","chunk-append","chunk-buffer","chunk-cons","chunk-first","chunk-next","chunk-rest","chunked-seq?","class","class?","clear-agent-errors","clojure-version","coll?","comment","commute","comp","comparator","compare","compare-and-set!","compile","complement","completing","concat","cond","cond->","cond->>","condp","conj!","conj","cons","constantly","construct-proxy","contains?","count","counted?","create-ns","create-struct","cycle","dec","dec'","decimal?","declare","dedupe","def","default-data-readers","definline","definterface","defmacro","defmethod","defmulti","defn","defn-","defonce","defprotocol","defrecord","defstruct","deftype","delay","delay?","deliver","denominator","deref","derive","descendants","destructure","disj!","disj","dissoc!","dissoc","distinct","distinct?","do","doall","dorun","doseq","dosync","dotimes","doto","double","double-array","double?","doubles","drop","drop-last","drop-while","eduction","empty","empty?","ensure","ensure-reduced","enumeration-seq","error-handler","error-mode","eval","even?","every-pred","every?","ex-cause","ex-data","ex-info","ex-message","extend","extend-protocol","extend-type","extenders","extends?","false?","ffirst","file-seq","filter","filterv","finally","find","find-keyword","find-ns","find-protocol-impl","find-protocol-method","find-var","first","flatten","float","float-array","float?","floats","flush","fn","fn","fn?","fnext","fnil","for","force","format","frequencies","future","future-call","future-cancel","future-cancelled?","future-done?","future?","gen-class","gen-interface","gensym","get","get-in","get-method","get-proxy-class","get-thread-bindings","get-validator","group-by","halt-when","hash","hash-combine","hash-map","hash-ordered-coll","hash-set","hash-unordered-coll","ident?","identical?","identity","if","if-let","if-not","if-some","ifn?","import","in-ns","inc","inc'","indexed?","init-proxy","inst-ms","inst-ms*","inst?","instance?","int","int-array","int?","integer?","interleave","intern","interpose","into","into-array","ints","io!","isa?","iterate","iterator-seq","juxt","keep","keep-indexed","key","keys","keyword","keyword?","last","lazy-cat","lazy-seq","let","let","letfn","line-seq","list","list*","list?","load","load-file","load-reader","load-string","loaded-libs","locking","long","long-array","longs","loop","loop","macroexpand","macroexpand-1","make-array","make-hierarchy","map","map-entry?","map-indexed","map?","mapcat","mapv","max","max-key","memfn","memoize","merge","merge-with","meta","method-sig","methods","min","min-key","mix-collection-hash","mod","monitor-enter","monitor-exit","munge","name","namespace","namespace-munge","nat-int?","neg-int?","neg?","new","newline","next","nfirst","nil?","nnext","not","not-any?","not-empty","not-every?","not=","ns","ns-aliases","ns-imports","ns-interns","ns-map","ns-name","ns-publics","ns-refers","ns-resolve","ns-unalias","ns-unmap","nth","nthnext","nthrest","num","number?","numerator","object-array","odd?","or","parents","partial","partition","partition-all","partition-by","pcalls","peek","persistent!","pmap","pop!","pop","pop-thread-bindings","pos-int?","pos?","pr","pr-str","prefer-method","prefers","primitives-classnames","print","print-ctor","print-dup","print-method","print-simple","print-str","printf","println","println-str","prn","prn-str","promise","proxy","proxy-call-with-super","proxy-mappings","proxy-name","proxy-super","push-thread-bindings","pvalues","qualified-ident?","qualified-keyword?","qualified-symbol?","quot","quote","rand","rand-int","rand-nth","random-sample","range","ratio?","rational?","rationalize","re-find","re-groups","re-matcher","re-matches","re-pattern","re-seq","read","read+string","read-line","read-string","reader-conditional","reader-conditional?","realized?","record?","recur","reduce","reduce-kv","reduced","reduced?","reductions","ref","ref-history-count","ref-max-history","ref-min-history","ref-set","refer","refer-clojure","reify","release-pending-sends","rem","remove","remove-all-methods","remove-method","remove-ns","remove-tap","remove-watch","repeat","repeatedly","replace","replicate","require","requiring-resolve","reset!","reset-meta!","reset-vals!","resolve","rest","restart-agent","resultset-seq","reverse","reversible?","rseq","rsubseq","run!","satisfies?","second","select-keys","send","send-off","send-via","seq","seq?","seqable?","seque","sequence","sequential?","set!","set","set-agent-send-executor!","set-agent-send-off-executor!","set-error-handler!","set-error-mode!","set-validator!","set?","short","short-array","shorts","shuffle","shutdown-agents","simple-ident?","simple-keyword?","simple-symbol?","slurp","some","some->","some->>","some-fn","some?","sort","sort-by","sorted-map","sorted-map-by","sorted-set","sorted-set-by","sorted?","special-symbol?","spit","split-at","split-with","str","string?","struct","struct-map","subs","subseq","subvec","supers","swap!","swap-vals!","symbol","symbol?","sync","tagged-literal","tagged-literal?","take","take-last","take-nth","take-while","tap>","test","the-ns","thread-bound?","throw","time","to-array","to-array-2d","trampoline","transduce","transient","tree-seq","true?","try","type","unchecked-add","unchecked-add-int","unchecked-byte","unchecked-char","unchecked-dec","unchecked-dec-int","unchecked-divide-int","unchecked-double","unchecked-float","unchecked-inc","unchecked-inc-int","unchecked-int","unchecked-long","unchecked-multiply","unchecked-multiply-int","unchecked-negate","unchecked-negate-int","unchecked-remainder-int","unchecked-short","unchecked-subtract","unchecked-subtract-int","underive","unquote","unquote-splicing","unreduced","unsigned-bit-shift-right","update","update-in","update-proxy","uri?","use","uuid?","val","vals","var","var-get","var-set","var?","vary-meta","vec","vector","vector-of","vector?","volatile!","volatile?","vreset!","vswap!","when","when-first","when-let","when-not","when-some","while","with-bindings","with-bindings*","with-in-str","with-loading-context","with-local-vars","with-meta","with-open","with-out-str","with-precision","with-redefs","with-redefs-fn","xml-seq","zero?","zipmap"]
+" Generated from https://github.com/clojure-vim/clojure.vim/blob/fd280e33e84c88e97860930557dba3ff80b1a82d/clj/src/vim_clojure_static/generate.clj
+" Clojure version 1.11.0
+let s:words = ["&","*","*'","*1","*2","*3","*agent*","*allow-unresolved-vars*","*assert*","*clojure-version*","*command-line-args*","*compile-files*","*compile-path*","*compiler-options*","*data-readers*","*default-data-reader-fn*","*e","*err*","*file*","*flush-on-newline*","*fn-loader*","*in*","*math-context*","*ns*","*out*","*print-dup*","*print-length*","*print-level*","*print-meta*","*print-namespace-maps*","*print-readably*","*read-eval*","*reader-resolver*","*source-path*","*suppress-read*","*unchecked-math*","*use-context-classloader*","*verbose-defrecords*","*warn-on-reflection*","+","+'","-","-'","->","->>","->ArrayChunk","->Eduction","->Vec","->VecNode","->VecSeq","-cache-protocol-fn","-reset-methods",".","..","/","<","<=","=","==",">",">=","EMPTY-NODE","Inst","NaN?","PrintWriter-on","StackTraceElement->vec","Throwable->map","abs","accessor","aclone","add-classpath","add-tap","add-watch","agent","agent-error","agent-errors","aget","alength","alias","all-ns","alter","alter-meta!","alter-var-root","amap","ancestors","and","any?","apply","areduce","array-map","as->","aset","aset-boolean","aset-byte","aset-char","aset-double","aset-float","aset-int","aset-long","aset-short","assert","assoc","assoc!","assoc-in","associative?","atom","await","await-for","await1","bases","bean","bigdec","bigint","biginteger","binding","bit-and","bit-and-not","bit-clear","bit-flip","bit-not","bit-or","bit-set","bit-shift-left","bit-shift-right","bit-test","bit-xor","boolean","boolean-array","boolean?","booleans","bound-fn","bound-fn*","bound?","bounded-count","butlast","byte","byte-array","bytes","bytes?","case","case*","cast","cat","catch","char","char-array","char-escape-string","char-name-string","char?","chars","chunk","chunk-append","chunk-buffer","chunk-cons","chunk-first","chunk-next","chunk-rest","chunked-seq?","class","class?","clear-agent-errors","clojure-version","coll?","comment","commute","comp","comparator","compare","compare-and-set!","compile","complement","completing","concat","cond","cond->","cond->>","condp","conj","conj!","cons","constantly","construct-proxy","contains?","count","counted?","create-ns","create-struct","cycle","dec","dec'","decimal?","declare","dedupe","def","default-data-readers","definline","definterface","defmacro","defmethod","defmulti","defn","defn-","defonce","defprotocol","defrecord","defstruct","deftype","deftype*","delay","delay?","deliver","denominator","deref","derive","descendants","destructure","disj","disj!","dissoc","dissoc!","distinct","distinct?","do","doall","dorun","doseq","dosync","dotimes","doto","double","double-array","double?","doubles","drop","drop-last","drop-while","eduction","empty","empty?","ensure","ensure-reduced","enumeration-seq","error-handler","error-mode","eval","even?","every-pred","every?","ex-cause","ex-data","ex-info","ex-message","extend","extend-protocol","extend-type","extenders","extends?","false","false?","ffirst","file-seq","filter","filterv","finally","find","find-keyword","find-ns","find-protocol-impl","find-protocol-method","find-var","first","flatten","float","float-array","float?","floats","flush","fn","fn*","fn?","fnext","fnil","for","force","format","frequencies","future","future-call","future-cancel","future-cancelled?","future-done?","future?","gen-class","gen-interface","gensym","get","get-in","get-method","get-proxy-class","get-thread-bindings","get-validator","group-by","halt-when","hash","hash-combine","hash-map","hash-ordered-coll","hash-set","hash-unordered-coll","ident?","identical?","identity","if","if-let","if-not","if-some","ifn?","import","in-ns","inc","inc'","indexed?","infinite?","init-proxy","inst-ms","inst-ms*","inst?","instance?","int","int-array","int?","integer?","interleave","intern","interpose","into","into-array","ints","io!","isa?","iterate","iteration","iterator-seq","juxt","keep","keep-indexed","key","keys","keyword","keyword?","last","lazy-cat","lazy-seq","let","let*","letfn","letfn*","line-seq","list","list*","list?","load","load-file","load-reader","load-string","loaded-libs","locking","long","long-array","longs","loop","loop*","macroexpand","macroexpand-1","make-array","make-hierarchy","map","map-entry?","map-indexed","map?","mapcat","mapv","max","max-key","memfn","memoize","merge","merge-with","meta","method-sig","methods","min","min-key","mix-collection-hash","mod","monitor-enter","monitor-exit","munge","name","namespace","namespace-munge","nat-int?","neg-int?","neg?","new","newline","next","nfirst","nil","nil?","nnext","not","not-any?","not-empty","not-every?","not=","ns","ns-aliases","ns-imports","ns-interns","ns-map","ns-name","ns-publics","ns-refers","ns-resolve","ns-unalias","ns-unmap","nth","nthnext","nthrest","num","number?","numerator","object-array","odd?","or","parents","parse-boolean","parse-double","parse-long","parse-uuid","partial","partition","partition-all","partition-by","pcalls","peek","persistent!","pmap","pop","pop!","pop-thread-bindings","pos-int?","pos?","pr","pr-str","prefer-method","prefers","primitives-classnames","print","print-ctor","print-dup","print-method","print-simple","print-str","printf","println","println-str","prn","prn-str","promise","proxy","proxy-call-with-super","proxy-mappings","proxy-name","proxy-super","push-thread-bindings","pvalues","qualified-ident?","qualified-keyword?","qualified-symbol?","quot","quote","rand","rand-int","rand-nth","random-sample","random-uuid","range","ratio?","rational?","rationalize","re-find","re-groups","re-matcher","re-matches","re-pattern","re-seq","read","read+string","read-line","read-string","reader-conditional","reader-conditional?","realized?","record?","recur","reduce","reduce-kv","reduced","reduced?","reductions","ref","ref-history-count","ref-max-history","ref-min-history","ref-set","refer","refer-clojure","reify","reify*","release-pending-sends","rem","remove","remove-all-methods","remove-method","remove-ns","remove-tap","remove-watch","repeat","repeatedly","replace","replicate","require","requiring-resolve","reset!","reset-meta!","reset-vals!","resolve","rest","restart-agent","resultset-seq","reverse","reversible?","rseq","rsubseq","run!","satisfies?","second","select-keys","send","send-off","send-via","seq","seq-to-map-for-destructuring","seq?","seqable?","seque","sequence","sequential?","set","set!","set-agent-send-executor!","set-agent-send-off-executor!","set-error-handler!","set-error-mode!","set-validator!","set?","short","short-array","shorts","shuffle","shutdown-agents","simple-ident?","simple-keyword?","simple-symbol?","slurp","some","some->","some->>","some-fn","some?","sort","sort-by","sorted-map","sorted-map-by","sorted-set","sorted-set-by","sorted?","special-symbol?","spit","split-at","split-with","str","string?","struct","struct-map","subs","subseq","subvec","supers","swap!","swap-vals!","symbol","symbol?","sync","tagged-literal","tagged-literal?","take","take-last","take-nth","take-while","tap>","test","the-ns","thread-bound?","throw","time","to-array","to-array-2d","trampoline","transduce","transient","tree-seq","true","true?","try","type","unchecked-add","unchecked-add-int","unchecked-byte","unchecked-char","unchecked-dec","unchecked-dec-int","unchecked-divide-int","unchecked-double","unchecked-float","unchecked-inc","unchecked-inc-int","unchecked-int","unchecked-long","unchecked-multiply","unchecked-multiply-int","unchecked-negate","unchecked-negate-int","unchecked-remainder-int","unchecked-short","unchecked-subtract","unchecked-subtract-int","underive","unquote","unquote-splicing","unreduced","unsigned-bit-shift-right","update","update-in","update-keys","update-proxy","update-vals","uri?","use","uuid?","val","vals","var","var-get","var-set","var?","vary-meta","vec","vector","vector-of","vector?","volatile!","volatile?","vreset!","vswap!","when","when-first","when-let","when-not","when-some","while","with-bindings","with-bindings*","with-in-str","with-loading-context","with-local-vars","with-meta","with-open","with-out-str","with-precision","with-redefs","with-redefs-fn","xml-seq","zero?","zipmap"]
" Simple word completion for special forms and public vars in clojure.core
function! clojurecomplete#Complete(findstart, base)
diff --git a/runtime/autoload/health.vim b/runtime/autoload/health.vim
index ec030adf04..1292e4344e 100644
--- a/runtime/autoload/health.vim
+++ b/runtime/autoload/health.vim
@@ -188,7 +188,7 @@ function! s:get_healthcheck_list(plugin_names) abort
\ + nvim_get_runtime_file('lua/**/'.p.'/health/init.lua', v:true)
\ + nvim_get_runtime_file('lua/**/'.p.'/health.lua', v:true)
if len(paths) == 0
- let healthchecks += [[p, '', '']] " healthchek not found
+ let healthchecks += [[p, '', '']] " healthcheck not found
else
let healthchecks += map(uniq(sort(paths)),
\'<SID>filepath_to_healthcheck(v:val)')
diff --git a/runtime/autoload/health/provider.vim b/runtime/autoload/health/provider.vim
index 6022e05c22..a01cb9631c 100644
--- a/runtime/autoload/health/provider.vim
+++ b/runtime/autoload/health/provider.vim
@@ -690,7 +690,7 @@ function! s:check_perl() abort
if empty(perl_exec)
if !empty(perl_warnings)
call health#report_warn(perl_warnings, ['See :help provider-perl for more information.',
- \ 'You may disable this provider (and warning) by adding `let g:loaded_node_provider = 0` to your init.vim'])
+ \ 'You may disable this provider (and warning) by adding `let g:loaded_perl_provider = 0` to your init.vim'])
else
call health#report_warn('No usable perl executable found')
endif
diff --git a/runtime/autoload/python3complete.vim b/runtime/autoload/python3complete.vim
index 192e9e6df8..b0781864c5 100644
--- a/runtime/autoload/python3complete.vim
+++ b/runtime/autoload/python3complete.vim
@@ -2,7 +2,7 @@
" Maintainer: <vacancy>
" Previous Maintainer: Aaron Griffin <aaronmgriffin@gmail.com>
" Version: 0.9
-" Last Updated: 2020 Oct 9
+" Last Updated: 2022 Mar 30
"
" Roland Puntaier: this file contains adaptations for python3 and is parallel to pythoncomplete.vim
"
@@ -91,6 +91,9 @@ endfunction
function! s:DefPython()
py3 << PYTHONEOF
+import warnings
+warnings.simplefilter(action='ignore', category=FutureWarning)
+
import sys, tokenize, io, types
from token import NAME, DEDENT, NEWLINE, STRING
diff --git a/runtime/doc/api.txt b/runtime/doc/api.txt
index fa2f8f974a..b383c5eaef 100644
--- a/runtime/doc/api.txt
+++ b/runtime/doc/api.txt
@@ -452,7 +452,7 @@ Extended marks (extmarks) represent buffer annotations that track text changes
in the buffer. They can represent cursors, folds, misspelled words, anything
that needs to track a logical location in the buffer over time. |api-indexing|
-Extmark position works like "bar" cursor: it exists between characters. Thus
+Extmark position works like "bar" cursor: it exists between characters. Thus,
the maximum extmark index on a line is 1 more than the character index: >
f o o b a r line contents
@@ -468,7 +468,7 @@ extmark position and enter some text, the extmark migrates forward. >
f o o z|b a r line (| = cursor)
4 extmark (after typing "z")
-If an extmark is on the last index of a line and you inputs a newline at that
+If an extmark is on the last index of a line and you input a newline at that
point, the extmark will accordingly migrate to the next line: >
f o o z b a r| line (| = cursor)
@@ -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,130 +3151,234 @@ nvim_tabpage_set_var({tabpage}, {name}, {value})
==============================================================================
Autocmd Functions *api-autocmd*
+nvim_clear_autocmds({*opts}) *nvim_clear_autocmds()*
+ 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 augroup.
+ Create or get an autocommand group |autocmd-groups|.
- To get an existing augroup ID, do: >
- local id = vim.api.nvim_create_augroup(name, {
+ To get an existing group id, do: >
+ local id = vim.api.nvim_create_augroup("MyGroup", {
clear = false
})
<
Parameters: ~
- {name} String: The name of the augroup to create
- {opts} Parameters
- • clear (bool): Whether to clear existing commands
- or not. Defaults to true. See |autocmd-groups|
+ {name} String: The name of the group
+ {opts} Dictionary Parameters
+ • clear (bool) optional: defaults to true. Clear
+ existing commands if the group already exists
+ |autocmd-groups|.
Return: ~
- opaque value to use with nvim_del_augroup_by_id
+ Integer id of the created group.
+
+ See also: ~
+ |autocmd-groups|
nvim_create_autocmd({event}, {*opts}) *nvim_create_autocmd()*
- Create an autocmd.
+ Create an |autocommand|
- Examples:
- • event: "pat1,pat2,pat3",
- • event: "pat1"
- • event: { "pat1" }
- • event: { "pat1", "pat2", "pat3" }
+ The API allows for two (mutually exclusive) types of actions
+ to be executed when the autocommand triggers: a callback
+ function (Lua or Vimscript), or a command (like regular
+ autocommands).
- Parameters: ~
- {event} The event or events to register this autocmd
- Required keys: event: string | ArrayOf(string)
+ Example using callback: >
+ -- Lua function
+ local myluafun = function() print("This buffer enters") end
- Parameters: ~
- {opts} Optional Parameters:
- • callback: (string|function)
- • (string): The name of the viml function to
- execute when triggering this autocmd
- • (function): The lua function to execute when
- triggering this autocmd
- • NOTE: Cannot be used with {command}
+ -- Vimscript function name (as a string)
+ local myvimfun = "g:MyVimFunction"
- • command: (string) command
- • vimscript command
- • NOTE: Cannot be used with {callback} Eg.
- command = "let g:value_set = v:true"
+ vim.api.nvim_create_autocmd({"BufEnter", "BufWinEnter"}, {
+ pattern = {"*.c", "*.h"},
+ callback = myluafun, -- Or myvimfun
+ })
+<
- • pattern: (string|table)
- • pattern or patterns to match against
- • defaults to "*".
- • NOTE: Cannot be used with {buffer}
+ Example using command: >
+ vim.api.nvim_create_autocmd({"BufEnter", "BufWinEnter"}, {
+ pattern = {"*.c", "*.h"},
+ command = "echo 'Entering a C or C++ file'",
+ })
+<
- • buffer: (bufnr)
- • create a |autocmd-buflocal| autocmd.
- • NOTE: Cannot be used with {pattern}
+ Example values for pattern: >
+ pattern = "*.py"
+ pattern = { "*.py", "*.pyi" }
+<
- • group: (string|int) The augroup name or id
- • once: (boolean) - See |autocmd-once|
- • nested: (boolean) - See |autocmd-nested|
- • desc: (string) - Description of the autocmd
+ Examples values for event: >
+ "BufPreWrite"
+ {"CursorHold", "BufPreWrite", "BufPostWrite"}
+<
- Return: ~
- opaque value to use with nvim_del_autocmd
+ Parameters: ~
+ {event} (String|Array) The event or events to register
+ this autocommand
+ {opts} Dictionary of autocommand options:
+ • group (string|integer) optional: the
+ autocommand group name or id to match against.
+ • pattern (string|array) optional: pattern or
+ patterns to match against |autocmd-pattern|.
+ • buffer (integer) optional: buffer number for
+ buffer local autocommands |autocmd-buflocal|.
+ Cannot be used with {pattern}.
+ • desc (string) optional: description of the
+ autocommand.
+ • callback (function|string) optional: Lua
+ function or Vim function (as string) to execute
+ on event. Cannot be used with {command}
+ • command (string) optional: Vim command to
+ execute on event. Cannot be used with
+ {callback}
+ • once (boolean) optional: defaults to false. Run
+ the autocommand only once |autocmd-once|.
+ • nested (boolean) optional: defaults to false.
+ Run nested autocommands |autocmd-nested|.
+
+ Return: ~
+ Integer id of the created autocommand.
+
+ See also: ~
+ |autocommand|
+ |nvim_del_autocmd()|
nvim_del_augroup_by_id({id}) *nvim_del_augroup_by_id()*
- Delete an augroup by {id}. {id} can only be returned when
- augroup was created with |nvim_create_augroup|.
+ Delete an autocommand group by id.
- NOTE: behavior differs from augroup-delete.
+ To get a group id one can use |nvim_get_autocmds()|.
- When deleting an augroup, autocmds contained by this augroup
- will also be deleted and cleared. This augroup will no longer
- exist
+ NOTE: behavior differs from |augroup-delete|. When deleting a
+ group, autocommands contained in this group will also be
+ deleted and cleared. This group will no longer exist.
-nvim_del_augroup_by_name({name}) *nvim_del_augroup_by_name()*
- Delete an augroup by {name}.
+ Parameters: ~
+ {id} Integer The id of the group.
- NOTE: behavior differs from augroup-delete.
+ See also: ~
+ |nvim_del_augroup_by_name()|
+ |nvim_create_augroup()|
- When deleting an augroup, autocmds contained by this augroup
- will also be deleted and cleared. This augroup will no longer
- exist
+nvim_del_augroup_by_name({name}) *nvim_del_augroup_by_name()*
+ Delete an autocommand group by name.
-nvim_del_autocmd({id}) *nvim_del_autocmd()*
- Delete an autocmd by {id}. Autocmds only return IDs when
- created via the API. Will not error if called and no autocmds
- match the {id}.
+ NOTE: behavior differs from |augroup-delete|. When deleting a
+ group, autocommands contained in this group will also be
+ deleted and cleared. This group will no longer exist.
Parameters: ~
- {id} Integer The ID returned by nvim_create_autocmd
+ {name} String The name of the group.
+
+ See also: ~
+ |autocommand-groups|
-nvim_do_autocmd({event}, {*opts}) *nvim_do_autocmd()*
- Do one autocmd.
+nvim_del_autocmd({id}) *nvim_del_autocmd()*
+ Delete an autocommand by id.
+
+ NOTE: Only autocommands created via the API have an id.
Parameters: ~
- {event} The event or events to execute
- {opts} Optional Parameters:
- • buffer (number) - buffer number
- • NOTE: Cannot be used with {pattern}
+ {id} Integer The id returned by nvim_create_autocmd
- • pattern (string|table) - optional, defaults to
- "*".
- • NOTE: Cannot be used with {buffer}
+ See also: ~
+ |nvim_create_autocmd()|
+
+nvim_exec_autocmds({event}, {*opts}) *nvim_exec_autocmds()*
+ Execute all autocommands for {event} that match the
+ corresponding {opts} |autocmd-execute|.
+
+ Parameters: ~
+ {event} (String|Array) The event or events to execute
+ {opts} Dictionary of autocommand options:
+ • group (string|integer) optional: the
+ autocommand group name or id to match against.
+ |autocmd-groups|.
+ • pattern (string|array) optional: defaults to
+ "*" |autocmd-pattern|. Cannot be used with
+ {buffer}.
+ • buffer (integer) optional: buffer number
+ |autocmd-buflocal|. Cannot be used with
+ {pattern}.
+ • modeline (bool) optional: defaults to true.
+ Process the modeline after the autocommands
+ |<nomodeline>|.
- • group (string|int) - autocmd group name or id
- • modeline (boolean) - Default true, see
- |<nomodeline>|
+ See also: ~
+ |:doautocmd|
nvim_get_autocmds({*opts}) *nvim_get_autocmds()*
- Get autocmds that match the requirements passed to {opts}.
-
- Parameters: ~
- {opts} Optional Parameters:
- • event : Name or list of name of events 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}
+ Get all autocommands that match the corresponding {opts}.
+
+ These examples will get autocommands matching ALL the given
+ criteria: >
+ -- Matches all criteria
+ autocommands = vim.api.nvim_get_autocmds({
+ group = "MyGroup",
+ event = {"BufEnter", "BufWinEnter"},
+ pattern = {"*.c", "*.h"}
+ })
+
+ -- All commands from one group
+ autocommands = vim.api.nvim_get_autocmds({
+ group = "MyGroup",
+ })
+<
- Return: ~
- A list of autocmds that match
+ NOTE: When multiple patterns or events are provided, it will
+ find all the autocommands that match any combination of them.
+
+ Parameters: ~
+ {opts} Dictionary with at least one of the following:
+ • group (string|integer): the autocommand group
+ name or id to match against.
+ • event (string|array): event or events to match
+ against |autocmd-events|.
+ • pattern (string|array): pattern or patterns to
+ match against |autocmd-pattern|.
+
+ Return: ~
+ Array of autocommands matching the criteria, with each
+ item containing the following fields:
+ • id (number): the autocommand id (only when defined with
+ the API).
+ • group (integer): the autocommand group id.
+ • desc (string): the autocommand description.
+ • event (string): the autocommand event.
+ • command (string): the autocommand command.
+ • once (boolean): whether the autocommand is only run
+ once.
+ • pattern (string): the autocommand pattern. If the
+ autocommand is buffer local |autocmd-buffer-local|:
+ • buflocal (boolean): true if the autocommand is buffer
+ local.
+ • buffer (number): the buffer number.
==============================================================================
diff --git a/runtime/doc/autocmd.txt b/runtime/doc/autocmd.txt
index ab0b0cd07c..7cfac4b5d1 100644
--- a/runtime/doc/autocmd.txt
+++ b/runtime/doc/autocmd.txt
@@ -499,10 +499,10 @@ CursorMoved After the cursor was moved in Normal or Visual
mode or to another window. Also when the text
of the cursor line has been changed, e.g. with
"x", "rx" or "p".
- Not triggered when there is typeahead, while
- executing a script file, when an operator is
- pending, or when moving to another window while
- remaining at the same cursor position.
+ Not always triggered when there is typeahead,
+ while executing commands in a script file, or
+ when an operator is pending. Always triggered
+ when moving to another window.
For an example see |match-parens|.
Note: Cannot be skipped with |:noautocmd|.
Careful: This is triggered very often, don't
diff --git a/runtime/doc/builtin.txt b/runtime/doc/builtin.txt
index 14353662d1..062f39f3e7 100644
--- a/runtime/doc/builtin.txt
+++ b/runtime/doc/builtin.txt
@@ -1319,14 +1319,15 @@ confirm({msg} [, {choices} [, {default} [, {type}]]])
or another valid interrupt key, confirm() returns 0.
An example: >
- :let choice = confirm("What do you want?", "&Apples\n&Oranges\n&Bananas", 2)
- :if choice == 0
- : echo "make up your mind!"
- :elseif choice == 3
- : echo "tasteful"
- :else
- : echo "I prefer bananas myself."
- :endif
+ let choice = confirm("What do you want?",
+ \ "&Apples\n&Oranges\n&Bananas", 2)
+ if choice == 0
+ echo "make up your mind!"
+ elseif choice == 3
+ echo "tasteful"
+ else
+ echo "I prefer bananas myself."
+ endif
< In a GUI dialog, buttons are used. The layout of the buttons
depends on the 'v' flag in 'guioptions'. If it is included,
the buttons are always put vertically. Otherwise, confirm()
diff --git a/runtime/doc/insert.txt b/runtime/doc/insert.txt
index cd6c2c8622..05bf0fe4ba 100644
--- a/runtime/doc/insert.txt
+++ b/runtime/doc/insert.txt
@@ -780,7 +780,7 @@ If the previous expansion was split, because it got longer than 'textwidth',
then just the text in the current line will be used.
If the match found is at the end of a line, then the first word in the next
-line will be inserted and the message "word from next line" displayed, if
+line will be inserted and the message "Word from other line" displayed, if
this word is accepted the next CTRL-X CTRL-P or CTRL-X CTRL-N will search
for those lines starting with this word.
diff --git a/runtime/doc/lsp.txt b/runtime/doc/lsp.txt
index 9dfc65f999..b704d2d6e8 100644
--- a/runtime/doc/lsp.txt
+++ b/runtime/doc/lsp.txt
@@ -1356,8 +1356,7 @@ apply_text_edits({text_edits}, {bufnr}, {offset_encoding})
Parameters: ~
{text_edits} table list of `TextEdit` objects
{bufnr} number Buffer id
- {offset_encoding} string utf-8|utf-16|utf-32 defaults to
- encoding of first client of `bufnr`
+ {offset_encoding} string utf-8|utf-16|utf-32
See also: ~
https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textEdit
diff --git a/runtime/doc/lua.txt b/runtime/doc/lua.txt
index e5bc60a8cd..d13e883c28 100644
--- a/runtime/doc/lua.txt
+++ b/runtime/doc/lua.txt
@@ -1634,6 +1634,22 @@ tbl_flatten({t}) *vim.tbl_flatten()*
See also: ~
From https://github.com/premake/premake-core/blob/master/src/base/table.lua
+tbl_get({o}, {...}) *vim.tbl_get()*
+ Index into a table (first argument) via string keys passed as
+ subsequent arguments. Return `nil` if the key does not exist. Examples: >
+
+ vim.tbl_get({ key = { nested_key = true }}, 'key', 'nested_key') == true
+ vim.tbl_get({ key = {}}, 'key', 'nested_key') == nil
+<
+
+ Parameters: ~
+ {o} Table to index
+ {...} Optional strings (0 or more, variadic) via which to
+ index the table
+
+ Return: ~
+ nested value indexed by key if it exists, else nil
+
tbl_isempty({t}) *vim.tbl_isempty()*
Checks if a table is empty.
diff --git a/runtime/doc/message.txt b/runtime/doc/message.txt
index fa1bc6f7da..dac4df5ee9 100644
--- a/runtime/doc/message.txt
+++ b/runtime/doc/message.txt
@@ -61,7 +61,7 @@ If you are lazy, it also works without the shift key: >
When an error message is displayed, but it is removed before you could read
it, you can see it again with: >
- :echo errmsg
+ :echo v:errmsg
Or view a list of recent messages with: >
:messages
See `:messages` above.
diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt
index 8323ec3e9d..b825a5fe15 100644
--- a/runtime/doc/options.txt
+++ b/runtime/doc/options.txt
@@ -751,7 +751,8 @@ A jump table for the options with a short description can be found at |Q_op|.
nostop like start, except CTRL-W and CTRL-U do not stop at the start of
insert.
- When the value is empty, Vi compatible backspacing is used.
+ When the value is empty, Vi compatible backspacing is used, none of
+ the ways mentioned for the items above are possible.
For backwards compatibility with version 5.4 and earlier:
value effect ~
@@ -3670,8 +3671,7 @@ A jump table for the options with a short description can be found at |Q_op|.
0: never
1: only if there are at least two windows
2: always
- 3: have a global statusline at the bottom instead of one for
- each window
+ 3: always and ONLY the last window
The screen looks nicer with a status line if you have several
windows, but it takes another screen line. |status-line|
diff --git a/runtime/doc/pattern.txt b/runtime/doc/pattern.txt
index 680b853dab..35f5b311ff 100644
--- a/runtime/doc/pattern.txt
+++ b/runtime/doc/pattern.txt
@@ -914,17 +914,24 @@ $ At end of pattern or in front of "\|", "\)" or "\n" ('magic' on):
becomes invalid. Vim doesn't automatically update the matches.
Similar to moving the cursor for "\%#" |/\%#|.
- */\%l* */\%>l* */\%<l* *E951*
+ */\%l* */\%>l* */\%<l* *E951* *E1204*
\%23l Matches in a specific line.
\%<23l Matches above a specific line (lower line number).
\%>23l Matches below a specific line (higher line number).
- These three can be used to match specific lines in a buffer. The "23"
+\%.l Matches at the cursor line.
+\%<.l Matches above the cursor line.
+\%>.l Matches below the cursor line.
+ These six can be used to match specific lines in a buffer. The "23"
can be any line number. The first line is 1.
WARNING: When inserting or deleting lines Vim does not automatically
update the matches. This means Syntax highlighting quickly becomes
- wrong.
+ wrong. Also when referring to the cursor position (".") and
+ the cursor moves the display isn't updated for this change. An update
+ is done when using the |CTRL-L| command (the whole screen is updated).
Example, to highlight the line where the cursor currently is: >
- :exe '/\%' .. line(".") .. 'l.*'
+ :exe '/\%' .. line(".") .. 'l'
+< Alternatively use: >
+ /\%.l
< When 'hlsearch' is set and you move the cursor around and make changes
this will clearly show when the match is updated or not.
@@ -932,15 +939,22 @@ $ At end of pattern or in front of "\|", "\)" or "\n" ('magic' on):
\%23c Matches in a specific column.
\%<23c Matches before a specific column.
\%>23c Matches after a specific column.
- These three can be used to match specific columns in a buffer or
- string. The "23" can be any column number. The first column is 1.
- Actually, the column is the byte number (thus it's not exactly right
- for multibyte characters).
+\%.c Matches at the cursor column.
+\%<.c Matches before the cursor column.
+\%>.c Matches after the cursor column.
+ These six can be used to match specific columns in a buffer or string.
+ The "23" can be any column number. The first column is 1. Actually,
+ the column is the byte number (thus it's not exactly right for
+ multibyte characters).
WARNING: When inserting or deleting text Vim does not automatically
update the matches. This means Syntax highlighting quickly becomes
- wrong.
+ wrong. Also when referring to the cursor position (".") and
+ the cursor moves the display isn't updated for this change. An update
+ is done when using the |CTRL-L| command (the whole screen is updated).
Example, to highlight the column where the cursor currently is: >
:exe '/\%' .. col(".") .. 'c'
+< Alternatively use: >
+ /\%.c
< When 'hlsearch' is set and you move the cursor around and make changes
this will clearly show when the match is updated or not.
Example for matching a single byte in column 44: >
@@ -951,8 +965,11 @@ $ At end of pattern or in front of "\|", "\)" or "\n" ('magic' on):
\%23v Matches in a specific virtual column.
\%<23v Matches before a specific virtual column.
\%>23v Matches after a specific virtual column.
- These three can be used to match specific virtual columns in a buffer
- or string. When not matching with a buffer in a window, the option
+\%.v Matches at the current virtual column.
+\%<.v Matches before the current virtual column.
+\%>.v Matches after the current virtual column.
+ These six can be used to match specific virtual columns in a buffer or
+ string. When not matching with a buffer in a window, the option
values of the current window are used (e.g., 'tabstop').
The "23" can be any column number. The first column is 1.
Note that some virtual column positions will never match, because they
@@ -960,13 +977,18 @@ $ At end of pattern or in front of "\|", "\)" or "\n" ('magic' on):
one screen character.
WARNING: When inserting or deleting text Vim does not automatically
update highlighted matches. This means Syntax highlighting quickly
- becomes wrong.
+ becomes wrong. Also when referring to the cursor position (".") and
+ the cursor moves the display isn't updated for this change. An update
+ is done when using the |CTRL-L| command (the whole screen is updated).
Example, to highlight all the characters after virtual column 72: >
/\%>72v.*
< When 'hlsearch' is set and you move the cursor around and make changes
this will clearly show when the match is updated or not.
To match the text up to column 17: >
/^.*\%17v
+< To match all characters after the current virtual column (where the
+ cursor is): >
+ /\%>.v.*
< Column 17 is not included, because this is a |/zero-width| match. To
include the column use: >
/^.*\%17v.
diff --git a/runtime/doc/repeat.txt b/runtime/doc/repeat.txt
index 994f97bba0..508565dea4 100644
--- a/runtime/doc/repeat.txt
+++ b/runtime/doc/repeat.txt
@@ -182,8 +182,7 @@ For writing a Vim script, see chapter 41 of the user manual |usr_41.txt|.
*:so* *:source* *load-vim-script*
:[range]so[urce] [file] Runs |Ex| commands or Lua code (".lua" files) from
- [file], or from the current buffer if no [file] is
- given.
+ [file], or current buffer if no [file].
Triggers the |SourcePre| autocommand.
*:source!*
:[range]so[urce]! {file}
diff --git a/runtime/doc/syntax.txt b/runtime/doc/syntax.txt
index 2af4ec1549..2d239d9198 100644
--- a/runtime/doc/syntax.txt
+++ b/runtime/doc/syntax.txt
@@ -5226,7 +5226,8 @@ VisualNOS Visual mode selection when vim is "Not Owning the Selection".
*hl-WarningMsg*
WarningMsg warning messages
*hl-Whitespace*
-Whitespace "nbsp", "space", "tab" and "trail" in 'listchars'
+Whitespace "nbsp", "space", "tab", "multispace", "lead" and "trail"
+ in 'listchars'
*hl-WildMenu*
WildMenu current match in 'wildmenu' completion
diff --git a/runtime/doc/vim_diff.txt b/runtime/doc/vim_diff.txt
index 9ca5faf112..59f085977b 100644
--- a/runtime/doc/vim_diff.txt
+++ b/runtime/doc/vim_diff.txt
@@ -180,6 +180,7 @@ Commands:
|:Man| is available by default, with many improvements such as completion
|:sign-define| accepts a `numhl` argument, to highlight the line number
|:match| can be invoked before highlight group is defined
+ |:source| works with Lua and anonymous (no file) scripts
Events:
|RecordingEnter|
diff --git a/runtime/filetype.vim b/runtime/filetype.vim
index 9df89674e3..65e0b49e61 100644
--- a/runtime/filetype.vim
+++ b/runtime/filetype.vim
@@ -1273,6 +1273,9 @@ au BufNewFile,BufRead *.[Oo][Pp][Ll] setf opl
" Oracle config file
au BufNewFile,BufRead *.ora setf ora
+" Org
+au BufNewFile,BufRead *.org,*.org_archive setf org
+
" Packet filter conf
au BufNewFile,BufRead pf.conf setf pf
@@ -1728,7 +1731,7 @@ au BufNewFile,BufRead .zshrc,.zshenv,.zlogin,.zlogout,.zcompdump setf zsh
au BufNewFile,BufRead *.zsh setf zsh
" Scheme
-au BufNewFile,BufRead *.scm,*.ss,*.sld,*.rkt,*.rktd,*.rktl setf scheme
+au BufNewFile,BufRead *.scm,*.ss,*.sld,*.rkt,*.rktd,*.rktl setf scheme
" Screen RC
au BufNewFile,BufRead .screenrc,screenrc setf screen
diff --git a/runtime/ftplugin/clojure.vim b/runtime/ftplugin/clojure.vim
index 81d53b1227..c922d75699 100644
--- a/runtime/ftplugin/clojure.vim
+++ b/runtime/ftplugin/clojure.vim
@@ -5,7 +5,7 @@
" Meikel Brandmeyer <mb@kotka.de>
" URL: https://github.com/clojure-vim/clojure.vim
" License: Vim (see :h license)
-" Last Change: 2021-10-26
+" Last Change: 2022-03-24
if exists("b:did_ftplugin")
finish
@@ -43,7 +43,7 @@ setlocal commentstring=;\ %s
" specially and hence are not indented specially.
"
" -*- LISPWORDS -*-
-" Generated from https://github.com/clojure-vim/clojure.vim/blob/62b215f079ce0f3834fd295c7a7f6bd8cc54bcc3/clj/src/vim_clojure_static/generate.clj
+" Generated from https://github.com/clojure-vim/clojure.vim/blob/fd280e33e84c88e97860930557dba3ff80b1a82d/clj/src/vim_clojure_static/generate.clj
setlocal lispwords=as->,binding,bound-fn,case,catch,cond->,cond->>,condp,def,definline,definterface,defmacro,defmethod,defmulti,defn,defn-,defonce,defprotocol,defrecord,defstruct,deftest,deftest-,deftype,doseq,dotimes,doto,extend,extend-protocol,extend-type,fn,for,if,if-let,if-not,if-some,let,letfn,locking,loop,ns,proxy,reify,set-test,testing,when,when-first,when-let,when-not,when-some,while,with-bindings,with-in-str,with-local-vars,with-open,with-precision,with-redefs,with-redefs-fn,with-test
" Provide insert mode completions for special forms and clojure.core. As
@@ -66,10 +66,10 @@ endif
" Filter files in the browse dialog
if (has("gui_win32") || has("gui_gtk")) && !exists("b:browsefilter")
- let b:browsefilter = "Clojure Source Files (*.clj)\t*.clj\n" .
- \ "ClojureScript Source Files (*.cljs)\t*.cljs\n" .
- \ "Java Source Files (*.java)\t*.java\n" .
- \ "All Files (*.*)\t*.*\n"
+ let b:browsefilter = "All Files\t*\n" .
+ \ "Clojure Files\t*.clj;*.cljc;*.cljs;*.cljx\n" .
+ \ "EDN Files\t*.edn\n" .
+ \ "Java Files\t*.java\n"
let b:undo_ftplugin .= ' | unlet! b:browsefilter'
endif
diff --git a/runtime/ftplugin/cpp.vim b/runtime/ftplugin/cpp.vim
index f9d31cbec3..58c4e4b24a 100644
--- a/runtime/ftplugin/cpp.vim
+++ b/runtime/ftplugin/cpp.vim
@@ -10,6 +10,7 @@ endif
" Behaves mostly just like C
runtime! ftplugin/c.vim ftplugin/c_*.vim ftplugin/c/*.vim
+runtime! ftplugin/c.lua ftplugin/c_*.lua ftplugin/c/*.lua
" C++ uses templates with <things>
" Disabled, because it gives an error for typing an unmatched ">".
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/ftplugin/ruby.vim b/runtime/ftplugin/ruby.vim
index 4a476fd8cf..8c1f47731c 100644
--- a/runtime/ftplugin/ruby.vim
+++ b/runtime/ftplugin/ruby.vim
@@ -3,7 +3,7 @@
" Maintainer: Tim Pope <vimNOSPAM@tpope.org>
" URL: https://github.com/vim-ruby/vim-ruby
" Release Coordinator: Doug Kearns <dougkearns@gmail.com>
-" Last Change: 2020 Feb 13
+" Last Change: 2022 Mar 21
if (exists("b:did_ftplugin"))
finish
@@ -53,7 +53,7 @@ endif
" TODO:
"setlocal define=^\\s*def
-setlocal comments=:#
+setlocal comments=b:#
setlocal commentstring=#\ %s
if !exists('g:ruby_version_paths')
@@ -87,8 +87,14 @@ endfunction
function! s:build_path(path) abort
let path = join(map(copy(a:path), 'v:val ==# "." ? "" : v:val'), ',')
- if &g:path !~# '\v^%(\.,)=%(/%(usr|emx)/include,)=,$'
- let path = substitute(&g:path,',,$',',','') . ',' . path
+ if &g:path =~# '\v^%(\.,)=%(/%(usr|emx)/include,)=,$'
+ let path = path . ',.,,'
+ elseif &g:path =~# ',\.,,$'
+ let path = &g:path[0:-4] . path . ',.,,'
+ elseif &g:path =~# ',,$'
+ let path = &g:path[0:-2] . path . ',,'
+ else
+ let path = substitute(&g:path, '[^,]\zs$', ',', '') . path
endif
return path
endfunction
@@ -164,6 +170,8 @@ let b:undo_ftplugin .= "| sil! cunmap <buffer> <Plug><ctag>| sil! cunmap <buffer
if !exists("g:no_plugin_maps") && !exists("g:no_ruby_maps")
nmap <buffer><script> <SID>: :<C-U>
nmap <buffer><script> <SID>c: :<C-U><C-R>=v:count ? v:count : ''<CR>
+ cmap <buffer> <SID><cfile> <Plug><cfile>
+ cmap <buffer> <SID><ctag> <Plug><ctag>
nnoremap <silent> <buffer> [m :<C-U>call <SID>searchsyn('\<def\>',['rubyDefine'],'b','n')<CR>
nnoremap <silent> <buffer> ]m :<C-U>call <SID>searchsyn('\<def\>',['rubyDefine'],'','n')<CR>
@@ -210,20 +218,20 @@ if !exists("g:no_plugin_maps") && !exists("g:no_ruby_maps")
call s:map('c', '', '<C-R><C-F> <Plug><cfile>')
cmap <buffer><script><expr> <SID>tagzv &foldopen =~# 'tag' ? '<Bar>norm! zv' : ''
- call s:map('n', '<silent>', '<C-]> <SID>:exe v:count1."tag <Plug><ctag>"<SID>tagzv<CR>')
- call s:map('n', '<silent>', 'g<C-]> <SID>:exe "tjump <Plug><ctag>"<SID>tagzv<CR>')
- call s:map('n', '<silent>', 'g] <SID>:exe "tselect <Plug><ctag>"<SID>tagzv<CR>')
- call s:map('n', '<silent>', '<C-W>] <SID>:exe v:count1."stag <Plug><ctag>"<SID>tagzv<CR>')
- call s:map('n', '<silent>', '<C-W><C-]> <SID>:exe v:count1."stag <Plug><ctag>"<SID>tagzv<CR>')
- call s:map('n', '<silent>', '<C-W>g<C-]> <SID>:exe "stjump <Plug><ctag>"<SID>tagzv<CR>')
- call s:map('n', '<silent>', '<C-W>g] <SID>:exe "stselect <Plug><ctag>"<SID>tagzv<CR>')
- call s:map('n', '<silent>', '<C-W>} <SID>:exe v:count1."ptag <Plug><ctag>"<CR>')
- call s:map('n', '<silent>', '<C-W>g} <SID>:exe "ptjump <Plug><ctag>"<CR>')
-
- call s:map('n', '<silent>', 'gf <SID>c:find <Plug><cfile><CR>')
- call s:map('n', '<silent>', '<C-W>f <SID>c:sfind <Plug><cfile><CR>')
- call s:map('n', '<silent>', '<C-W><C-F> <SID>c:sfind <Plug><cfile><CR>')
- call s:map('n', '<silent>', '<C-W>gf <SID>c:tabfind <Plug><cfile><CR>')
+ call s:map('n', '<script><silent>', '<C-]> <SID>:exe v:count1."tag <SID><ctag>"<SID>tagzv<CR>')
+ call s:map('n', '<script><silent>', 'g<C-]> <SID>:exe "tjump <SID><ctag>"<SID>tagzv<CR>')
+ call s:map('n', '<script><silent>', 'g] <SID>:exe "tselect <SID><ctag>"<SID>tagzv<CR>')
+ call s:map('n', '<script><silent>', '<C-W>] <SID>:exe v:count1."stag <SID><ctag>"<SID>tagzv<CR>')
+ call s:map('n', '<script><silent>', '<C-W><C-]> <SID>:exe v:count1."stag <SID><ctag>"<SID>tagzv<CR>')
+ call s:map('n', '<script><silent>', '<C-W>g<C-]> <SID>:exe "stjump <SID><ctag>"<SID>tagzv<CR>')
+ call s:map('n', '<script><silent>', '<C-W>g] <SID>:exe "stselect <SID><ctag>"<SID>tagzv<CR>')
+ call s:map('n', '<script><silent>', '<C-W>} <SID>:exe v:count1."ptag <SID><ctag>"<CR>')
+ call s:map('n', '<script><silent>', '<C-W>g} <SID>:exe "ptjump <SID><ctag>"<CR>')
+
+ call s:map('n', '<script><silent>', 'gf <SID>c:find <SID><cfile><CR>')
+ call s:map('n', '<script><silent>', '<C-W>f <SID>c:sfind <SID><cfile><CR>')
+ call s:map('n', '<script><silent>', '<C-W><C-F> <SID>c:sfind <SID><cfile><CR>')
+ call s:map('n', '<script><silent>', '<C-W>gf <SID>c:tabfind <SID><cfile><CR>')
endif
let &cpo = s:cpo_save
diff --git a/runtime/indent/clojure.vim b/runtime/indent/clojure.vim
index fadcaf4b4a..5bfbfbb197 100644
--- a/runtime/indent/clojure.vim
+++ b/runtime/indent/clojure.vim
@@ -5,7 +5,7 @@
" Meikel Brandmeyer <mb@kotka.de>
" URL: https://github.com/clojure-vim/clojure.vim
" License: Vim (see :h license)
-" Last Change: 2021-10-26
+" Last Change: 2022-03-24
if exists("b:did_indent")
finish
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/indent/ruby.vim b/runtime/indent/ruby.vim
index 559d8652a6..6ce8529fd1 100644
--- a/runtime/indent/ruby.vim
+++ b/runtime/indent/ruby.vim
@@ -4,7 +4,7 @@
" Previous Maintainer: Nikolai Weibull <now at bitwi.se>
" URL: https://github.com/vim-ruby/vim-ruby
" Release Coordinator: Doug Kearns <dougkearns@gmail.com>
-" Last Change: 2021 Feb 03
+" Last Change: 2022 Mar 22
" 0. Initialization {{{1
" =================
@@ -40,9 +40,11 @@ setlocal nosmartindent
" Now, set up our indentation expression and keys that trigger it.
setlocal indentexpr=GetRubyIndent(v:lnum)
setlocal indentkeys=0{,0},0),0],!^F,o,O,e,:,.
-setlocal indentkeys+==end,=else,=elsif,=when,=ensure,=rescue,==begin,==end
+setlocal indentkeys+==end,=else,=elsif,=when,=in\ ,=ensure,=rescue,==begin,==end
setlocal indentkeys+==private,=protected,=public
+let b:undo_indent = "setlocal indentexpr< indentkeys< smartindent<"
+
" Only define the function once.
if exists("*GetRubyIndent")
finish
@@ -85,14 +87,17 @@ let s:skip_expr =
" Regex used for words that, at the start of a line, add a level of indent.
let s:ruby_indent_keywords =
\ '^\s*\zs\<\%(module\|class\|if\|for' .
- \ '\|while\|until\|else\|elsif\|case\|when\|unless\|begin\|ensure\|rescue' .
+ \ '\|while\|until\|else\|elsif\|case\|when\|in\|unless\|begin\|ensure\|rescue' .
\ '\|\%(\K\k*[!?]\?\s\+\)\=def\):\@!\>' .
\ '\|\%([=,*/%+-]\|<<\|>>\|:\s\)\s*\zs' .
\ '\<\%(if\|for\|while\|until\|case\|unless\|begin\):\@!\>'
+" Def without an end clause: def method_call(...) = <expression>
+let s:ruby_endless_def = '\<def\s\+\k\+[!?]\=\%((.*)\|\s\)\s*='
+
" Regex used for words that, at the start of a line, remove a level of indent.
let s:ruby_deindent_keywords =
- \ '^\s*\zs\<\%(ensure\|else\|rescue\|elsif\|when\|end\):\@!\>'
+ \ '^\s*\zs\<\%(ensure\|else\|rescue\|elsif\|when\|in\|end\):\@!\>'
" Regex that defines the start-match for the 'end' keyword.
"let s:end_start_regex = '\%(^\|[^.]\)\<\%(module\|class\|def\|if\|for\|while\|until\|case\|unless\|begin\|do\)\>'
@@ -104,15 +109,31 @@ let s:end_start_regex =
\ '\|\%(^\|[^.:@$]\)\@<=\<do:\@!\>'
" Regex that defines the middle-match for the 'end' keyword.
-let s:end_middle_regex = '\<\%(ensure\|else\|\%(\%(^\|;\)\s*\)\@<=\<rescue:\@!\>\|when\|elsif\):\@!\>'
+let s:end_middle_regex = '\<\%(ensure\|else\|\%(\%(^\|;\)\s*\)\@<=\<rescue:\@!\>\|when\|\%(\%(^\|;\)\s*\)\@<=\<in\|elsif\):\@!\>'
" Regex that defines the end-match for the 'end' keyword.
let s:end_end_regex = '\%(^\|[^.:@$]\)\@<=\<end:\@!\>'
-" Expression used for searchpair() call for finding match for 'end' keyword.
-let s:end_skip_expr = s:skip_expr .
- \ ' || (expand("<cword>") == "do"' .
- \ ' && getline(".") =~ "^\\s*\\<\\(while\\|until\\|for\\):\\@!\\>")'
+" Expression used for searchpair() call for finding a match for an 'end' keyword.
+function! s:EndSkipExpr()
+ if eval(s:skip_expr)
+ return 1
+ elseif expand('<cword>') == 'do'
+ \ && getline(".") =~ '^\s*\<\(while\|until\|for\):\@!\>'
+ return 1
+ elseif getline('.') =~ s:ruby_endless_def
+ return 1
+ elseif getline('.') =~ '\<def\s\+\k\+[!?]\=([^)]*$'
+ " Then it's a `def method(` with a possible `) =` later
+ call search('\<def\s\+\k\+\zs(', 'W', line('.'))
+ normal! %
+ return getline('.') =~ ')\s*='
+ else
+ return 0
+ endif
+endfunction
+
+let s:end_skip_expr = function('s:EndSkipExpr')
" Regex that defines continuation lines, not including (, {, or [.
let s:non_bracket_continuation_regex =
@@ -572,6 +593,11 @@ function! s:AfterUnbalancedBracket(pline_info) abort
call cursor(info.plnum, closing.pos + 1)
normal! %
+ if strpart(info.pline, closing.pos) =~ '^)\s*='
+ " special case: the closing `) =` of an endless def
+ return indent(s:GetMSL(line('.')))
+ endif
+
if s:Match(line('.'), s:ruby_indent_keywords)
return indent('.') + info.sw
else
@@ -610,7 +636,7 @@ function! s:AfterIndentKeyword(pline_info) abort
let info = a:pline_info
let col = s:Match(info.plnum, s:ruby_indent_keywords)
- if col > 0
+ if col > 0 && s:Match(info.plnum, s:ruby_endless_def) <= 0
call cursor(info.plnum, col)
let ind = virtcol('.') - 1 + info.sw
" TODO: make this better (we need to count them) (or, if a searchpair
@@ -657,7 +683,7 @@ function! s:IndentingKeywordInMSL(msl_info) abort
" TODO: this does not take into account contrived things such as
" module Foo; class Bar; end
let col = s:Match(info.plnum_msl, s:ruby_indent_keywords)
- if col > 0
+ if col > 0 && s:Match(info.plnum_msl, s:ruby_endless_def) <= 0
let ind = indent(info.plnum_msl) + info.sw
if s:Match(info.plnum_msl, s:end_end_regex)
let ind = ind - info.sw
diff --git a/runtime/lua/vim/diagnostic.lua b/runtime/lua/vim/diagnostic.lua
index fcb1e61764..1ec66d7c55 100644
--- a/runtime/lua/vim/diagnostic.lua
+++ b/runtime/lua/vim/diagnostic.lua
@@ -1224,6 +1224,18 @@ function M.open_float(opts, ...)
opts = opts or {}
bufnr = get_bufnr(bufnr or opts.bufnr)
+
+ do
+ -- Resolve options with user settings from vim.diagnostic.config
+ -- Unlike the other decoration functions (e.g. set_virtual_text, set_signs, etc.) `open_float`
+ -- does not have a dedicated table for configuration options; instead, the options are mixed in
+ -- with its `opts` table which also includes "keyword" parameters. So we create a dedicated
+ -- options table that inherits missing keys from the global configuration before resolving.
+ local t = global_diagnostic_options.float
+ local float_opts = vim.tbl_extend("keep", opts, type(t) == "table" and t or {})
+ opts = get_resolved_options({ float = float_opts }, nil, bufnr).float
+ end
+
local scope = ({l = "line", c = "cursor", b = "buffer"})[opts.scope] or opts.scope or "line"
local lnum, col
if scope == "line" or scope == "cursor" then
@@ -1242,17 +1254,6 @@ function M.open_float(opts, ...)
error("Invalid value for option 'scope'")
end
- do
- -- Resolve options with user settings from vim.diagnostic.config
- -- Unlike the other decoration functions (e.g. set_virtual_text, set_signs, etc.) `open_float`
- -- does not have a dedicated table for configuration options; instead, the options are mixed in
- -- with its `opts` table which also includes "keyword" parameters. So we create a dedicated
- -- options table that inherits missing keys from the global configuration before resolving.
- local t = global_diagnostic_options.float
- local float_opts = vim.tbl_extend("keep", opts, type(t) == "table" and t or {})
- opts = get_resolved_options({ float = float_opts }, nil, bufnr).float
- end
-
local diagnostics = get_diagnostics(bufnr, opts, true)
if scope == "line" then
diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua
index b356f5e3dc..927ef36391 100644
--- a/runtime/lua/vim/filetype.lua
+++ b/runtime/lua/vim/filetype.lua
@@ -21,7 +21,7 @@ end
---@private
local function getline(bufnr, lnum)
- return api.nvim_buf_get_lines(bufnr, lnum-1, lnum, false)[1]
+ return api.nvim_buf_get_lines(bufnr, lnum-1, lnum, false)[1] or ""
end
-- Filetypes based on file extension
@@ -438,6 +438,8 @@ local extension = {
opam = "opam",
["or"] = "openroad",
ora = "ora",
+ org = "org",
+ org_archive = "org",
pxsl = "papp",
papp = "papp",
pxml = "papp",
@@ -1424,6 +1426,8 @@ local pattern = {
return "git"
end
end,
+ -- Neovim only
+ [".*/queries/.*%.scm"] = "query", -- tree-sitter queries
-- END PATTERN
}
-- luacheck: pop
diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua
index cec3891418..401dac9acd 100644
--- a/runtime/lua/vim/lsp/util.lua
+++ b/runtime/lua/vim/lsp/util.lua
@@ -360,7 +360,7 @@ end
--- Applies a list of text edits to a buffer.
---@param text_edits table list of `TextEdit` objects
---@param bufnr number Buffer id
----@param offset_encoding string utf-8|utf-16|utf-32 defaults to encoding of first client of `bufnr`
+---@param offset_encoding string utf-8|utf-16|utf-32
---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textEdit
function M.apply_text_edits(text_edits, bufnr, offset_encoding)
validate {
@@ -1138,7 +1138,7 @@ function M.stylize_markdown(bufnr, contents, opts)
block = {nil, "```+([a-zA-Z0-9_]*)", "```+"},
pre = {"", "<pre>", "</pre>"},
code = {"", "<code>", "</code>"},
- text = {"plaintex", "<text>", "</text>"},
+ text = {"text", "<text>", "</text>"},
}
local match_begin = function(line)
diff --git a/runtime/lua/vim/shared.lua b/runtime/lua/vim/shared.lua
index 3eb332279a..f0dc34608c 100644
--- a/runtime/lua/vim/shared.lua
+++ b/runtime/lua/vim/shared.lua
@@ -347,6 +347,33 @@ function vim.tbl_add_reverse_lookup(o)
return o
end
+--- Index into a table (first argument) via string keys passed as subsequent arguments.
+--- Return `nil` if the key does not exist.
+--_
+--- Examples:
+--- <pre>
+--- vim.tbl_get({ key = { nested_key = true }}, 'key', 'nested_key') == true
+--- vim.tbl_get({ key = {}}, 'key', 'nested_key') == nil
+--- </pre>
+---
+---@param o Table to index
+---@param ... Optional strings (0 or more, variadic) via which to index the table
+---
+---@returns nested value indexed by key if it exists, else nil
+function vim.tbl_get(o, ...)
+ local keys = {...}
+ if #keys == 0 then
+ return
+ end
+ for _, k in ipairs(keys) do
+ o = o[k]
+ if o == nil then
+ return
+ end
+ end
+ return o
+end
+
--- Extends a list-like table with the values of another list-like table.
---
--- NOTE: This mutates dst!
diff --git a/runtime/lua/vim/treesitter/highlighter.lua b/runtime/lua/vim/treesitter/highlighter.lua
index e1ffd42a7f..0ec4ab37ec 100644
--- a/runtime/lua/vim/treesitter/highlighter.lua
+++ b/runtime/lua/vim/treesitter/highlighter.lua
@@ -38,6 +38,9 @@ local subcapture_fallback = {
TSHighlighter.hl_map = setmetatable({
["error"] = "Error",
+ ["text.underline"] = "Underlined",
+ ["todo"] = "Todo",
+ ["debug"] = "Debug",
-- Miscs
["comment"] = "Comment",
@@ -49,10 +52,13 @@ TSHighlighter.hl_map = setmetatable({
["constant"] = "Constant",
["constant.builtin"] = "Special",
["constant.macro"] = "Define",
+ ["define"] = "Define",
+ ["macro"] = "Macro",
["string"] = "String",
["string.regex"] = "String",
["string.escape"] = "SpecialChar",
["character"] = "Character",
+ ["character.special"] = "SpecialChar",
["number"] = "Number",
["boolean"] = "Boolean",
["float"] = "Float",
@@ -78,8 +84,12 @@ TSHighlighter.hl_map = setmetatable({
["type"] = "Type",
["type.builtin"] = "Type",
+ ["type.qualifier"] = "Type",
+ ["type.definition"] = "Typedef",
+ ["storageclass"] = "StorageClass",
["structure"] = "Structure",
["include"] = "Include",
+ ["preproc"] = "PreProc",
}, subcapture_fallback)
---@private
diff --git a/runtime/syntax/clojure.vim b/runtime/syntax/clojure.vim
index 9782dc41ad..0d63728250 100644
--- a/runtime/syntax/clojure.vim
+++ b/runtime/syntax/clojure.vim
@@ -7,7 +7,7 @@
" Contributors: Joel Holdbrooks <cjholdbrooks@gmail.com> (Regexp support, bug fixes)
" URL: https://github.com/clojure-vim/clojure.vim
" License: Vim (see :h license)
-" Last Change: 2021-10-26
+" Last Change: 2022-03-24
if exists("b:current_syntax")
finish
@@ -21,20 +21,20 @@ if has("folding") && exists("g:clojure_fold") && g:clojure_fold > 0
endif
" -*- KEYWORDS -*-
-" Generated from https://github.com/clojure-vim/clojure.vim/blob/62b215f079ce0f3834fd295c7a7f6bd8cc54bcc3/clj/src/vim_clojure_static/generate.clj
-" Clojure version 1.10.3
+" Generated from https://github.com/clojure-vim/clojure.vim/blob/fd280e33e84c88e97860930557dba3ff80b1a82d/clj/src/vim_clojure_static/generate.clj
+" Clojure version 1.11.0
let s:clojure_syntax_keywords = {
- \ 'clojureBoolean': ["false","true"]
- \ , 'clojureCond': ["case","clojure.core/case","clojure.core/cond","clojure.core/cond->","clojure.core/cond->>","clojure.core/condp","clojure.core/if-let","clojure.core/if-not","clojure.core/if-some","clojure.core/when","clojure.core/when-first","clojure.core/when-let","clojure.core/when-not","clojure.core/when-some","cond","cond->","cond->>","condp","if-let","if-not","if-some","when","when-first","when-let","when-not","when-some"]
- \ , 'clojureConstant': ["nil"]
- \ , 'clojureDefine': ["clojure.core/definline","clojure.core/definterface","clojure.core/defmacro","clojure.core/defmethod","clojure.core/defmulti","clojure.core/defn","clojure.core/defn-","clojure.core/defonce","clojure.core/defprotocol","clojure.core/defrecord","clojure.core/defstruct","clojure.core/deftype","definline","definterface","defmacro","defmethod","defmulti","defn","defn-","defonce","defprotocol","defrecord","defstruct","deftype"]
- \ , 'clojureException': ["catch","finally","throw","try"]
- \ , 'clojureFunc': ["*","*'","+","+'","-","-'","->ArrayChunk","->Eduction","->Vec","->VecNode","->VecSeq","-cache-protocol-fn","-reset-methods","/","<","<=","=","==",">",">=","PrintWriter-on","StackTraceElement->vec","Throwable->map","accessor","aclone","add-classpath","add-tap","add-watch","agent","agent-error","agent-errors","aget","alength","alias","all-ns","alter","alter-meta!","alter-var-root","ancestors","any?","apply","array-map","aset","aset-boolean","aset-byte","aset-char","aset-double","aset-float","aset-int","aset-long","aset-short","assoc","assoc!","assoc-in","associative?","atom","await","await-for","await1","bases","bean","bigdec","bigint","biginteger","bit-and","bit-and-not","bit-clear","bit-flip","bit-not","bit-or","bit-set","bit-shift-left","bit-shift-right","bit-test","bit-xor","boolean","boolean-array","boolean?","booleans","bound-fn*","bound?","bounded-count","butlast","byte","byte-array","bytes","bytes?","cast","cat","char","char-array","char?","chars","chunk","chunk-append","chunk-buffer","chunk-cons","chunk-first","chunk-next","chunk-rest","chunked-seq?","class","class?","clear-agent-errors","clojure-version","clojure.core/*","clojure.core/*'","clojure.core/+","clojure.core/+'","clojure.core/-","clojure.core/-'","clojure.core/->ArrayChunk","clojure.core/->Eduction","clojure.core/->Vec","clojure.core/->VecNode","clojure.core/->VecSeq","clojure.core/-cache-protocol-fn","clojure.core/-reset-methods","clojure.core//","clojure.core/<","clojure.core/<=","clojure.core/=","clojure.core/==","clojure.core/>","clojure.core/>=","clojure.core/PrintWriter-on","clojure.core/StackTraceElement->vec","clojure.core/Throwable->map","clojure.core/accessor","clojure.core/aclone","clojure.core/add-classpath","clojure.core/add-tap","clojure.core/add-watch","clojure.core/agent","clojure.core/agent-error","clojure.core/agent-errors","clojure.core/aget","clojure.core/alength","clojure.core/alias","clojure.core/all-ns","clojure.core/alter","clojure.core/alter-meta!","clojure.core/alter-var-root","clojure.core/ancestors","clojure.core/any?","clojure.core/apply","clojure.core/array-map","clojure.core/aset","clojure.core/aset-boolean","clojure.core/aset-byte","clojure.core/aset-char","clojure.core/aset-double","clojure.core/aset-float","clojure.core/aset-int","clojure.core/aset-long","clojure.core/aset-short","clojure.core/assoc","clojure.core/assoc!","clojure.core/assoc-in","clojure.core/associative?","clojure.core/atom","clojure.core/await","clojure.core/await-for","clojure.core/await1","clojure.core/bases","clojure.core/bean","clojure.core/bigdec","clojure.core/bigint","clojure.core/biginteger","clojure.core/bit-and","clojure.core/bit-and-not","clojure.core/bit-clear","clojure.core/bit-flip","clojure.core/bit-not","clojure.core/bit-or","clojure.core/bit-set","clojure.core/bit-shift-left","clojure.core/bit-shift-right","clojure.core/bit-test","clojure.core/bit-xor","clojure.core/boolean","clojure.core/boolean-array","clojure.core/boolean?","clojure.core/booleans","clojure.core/bound-fn*","clojure.core/bound?","clojure.core/bounded-count","clojure.core/butlast","clojure.core/byte","clojure.core/byte-array","clojure.core/bytes","clojure.core/bytes?","clojure.core/cast","clojure.core/cat","clojure.core/char","clojure.core/char-array","clojure.core/char?","clojure.core/chars","clojure.core/chunk","clojure.core/chunk-append","clojure.core/chunk-buffer","clojure.core/chunk-cons","clojure.core/chunk-first","clojure.core/chunk-next","clojure.core/chunk-rest","clojure.core/chunked-seq?","clojure.core/class","clojure.core/class?","clojure.core/clear-agent-errors","clojure.core/clojure-version","clojure.core/coll?","clojure.core/commute","clojure.core/comp","clojure.core/comparator","clojure.core/compare","clojure.core/compare-and-set!","clojure.core/compile","clojure.core/complement","clojure.core/completing","clojure.core/concat","clojure.core/conj","clojure.core/conj!","clojure.core/cons","clojure.core/constantly","clojure.core/construct-proxy","clojure.core/contains?","clojure.core/count","clojure.core/counted?","clojure.core/create-ns","clojure.core/create-struct","clojure.core/cycle","clojure.core/dec","clojure.core/dec'","clojure.core/decimal?","clojure.core/dedupe","clojure.core/delay?","clojure.core/deliver","clojure.core/denominator","clojure.core/deref","clojure.core/derive","clojure.core/descendants","clojure.core/destructure","clojure.core/disj","clojure.core/disj!","clojure.core/dissoc","clojure.core/dissoc!","clojure.core/distinct","clojure.core/distinct?","clojure.core/doall","clojure.core/dorun","clojure.core/double","clojure.core/double-array","clojure.core/double?","clojure.core/doubles","clojure.core/drop","clojure.core/drop-last","clojure.core/drop-while","clojure.core/eduction","clojure.core/empty","clojure.core/empty?","clojure.core/ensure","clojure.core/ensure-reduced","clojure.core/enumeration-seq","clojure.core/error-handler","clojure.core/error-mode","clojure.core/eval","clojure.core/even?","clojure.core/every-pred","clojure.core/every?","clojure.core/ex-cause","clojure.core/ex-data","clojure.core/ex-info","clojure.core/ex-message","clojure.core/extend","clojure.core/extenders","clojure.core/extends?","clojure.core/false?","clojure.core/ffirst","clojure.core/file-seq","clojure.core/filter","clojure.core/filterv","clojure.core/find","clojure.core/find-keyword","clojure.core/find-ns","clojure.core/find-protocol-impl","clojure.core/find-protocol-method","clojure.core/find-var","clojure.core/first","clojure.core/flatten","clojure.core/float","clojure.core/float-array","clojure.core/float?","clojure.core/floats","clojure.core/flush","clojure.core/fn?","clojure.core/fnext","clojure.core/fnil","clojure.core/force","clojure.core/format","clojure.core/frequencies","clojure.core/future-call","clojure.core/future-cancel","clojure.core/future-cancelled?","clojure.core/future-done?","clojure.core/future?","clojure.core/gensym","clojure.core/get","clojure.core/get-in","clojure.core/get-method","clojure.core/get-proxy-class","clojure.core/get-thread-bindings","clojure.core/get-validator","clojure.core/group-by","clojure.core/halt-when","clojure.core/hash","clojure.core/hash-combine","clojure.core/hash-map","clojure.core/hash-ordered-coll","clojure.core/hash-set","clojure.core/hash-unordered-coll","clojure.core/ident?","clojure.core/identical?","clojure.core/identity","clojure.core/ifn?","clojure.core/in-ns","clojure.core/inc","clojure.core/inc'","clojure.core/indexed?","clojure.core/init-proxy","clojure.core/inst-ms","clojure.core/inst-ms*","clojure.core/inst?","clojure.core/instance?","clojure.core/int","clojure.core/int-array","clojure.core/int?","clojure.core/integer?","clojure.core/interleave","clojure.core/intern","clojure.core/interpose","clojure.core/into","clojure.core/into-array","clojure.core/ints","clojure.core/isa?","clojure.core/iterate","clojure.core/iterator-seq","clojure.core/juxt","clojure.core/keep","clojure.core/keep-indexed","clojure.core/key","clojure.core/keys","clojure.core/keyword","clojure.core/keyword?","clojure.core/last","clojure.core/line-seq","clojure.core/list","clojure.core/list*","clojure.core/list?","clojure.core/load","clojure.core/load-file","clojure.core/load-reader","clojure.core/load-string","clojure.core/loaded-libs","clojure.core/long","clojure.core/long-array","clojure.core/longs","clojure.core/macroexpand","clojure.core/macroexpand-1","clojure.core/make-array","clojure.core/make-hierarchy","clojure.core/map","clojure.core/map-entry?","clojure.core/map-indexed","clojure.core/map?","clojure.core/mapcat","clojure.core/mapv","clojure.core/max","clojure.core/max-key","clojure.core/memoize","clojure.core/merge","clojure.core/merge-with","clojure.core/meta","clojure.core/method-sig","clojure.core/methods","clojure.core/min","clojure.core/min-key","clojure.core/mix-collection-hash","clojure.core/mod","clojure.core/munge","clojure.core/name","clojure.core/namespace","clojure.core/namespace-munge","clojure.core/nat-int?","clojure.core/neg-int?","clojure.core/neg?","clojure.core/newline","clojure.core/next","clojure.core/nfirst","clojure.core/nil?","clojure.core/nnext","clojure.core/not","clojure.core/not-any?","clojure.core/not-empty","clojure.core/not-every?","clojure.core/not=","clojure.core/ns-aliases","clojure.core/ns-imports","clojure.core/ns-interns","clojure.core/ns-map","clojure.core/ns-name","clojure.core/ns-publics","clojure.core/ns-refers","clojure.core/ns-resolve","clojure.core/ns-unalias","clojure.core/ns-unmap","clojure.core/nth","clojure.core/nthnext","clojure.core/nthrest","clojure.core/num","clojure.core/number?","clojure.core/numerator","clojure.core/object-array","clojure.core/odd?","clojure.core/parents","clojure.core/partial","clojure.core/partition","clojure.core/partition-all","clojure.core/partition-by","clojure.core/pcalls","clojure.core/peek","clojure.core/persistent!","clojure.core/pmap","clojure.core/pop","clojure.core/pop!","clojure.core/pop-thread-bindings","clojure.core/pos-int?","clojure.core/pos?","clojure.core/pr","clojure.core/pr-str","clojure.core/prefer-method","clojure.core/prefers","clojure.core/print","clojure.core/print-ctor","clojure.core/print-dup","clojure.core/print-method","clojure.core/print-simple","clojure.core/print-str","clojure.core/printf","clojure.core/println","clojure.core/println-str","clojure.core/prn","clojure.core/prn-str","clojure.core/promise","clojure.core/proxy-call-with-super","clojure.core/proxy-mappings","clojure.core/proxy-name","clojure.core/push-thread-bindings","clojure.core/qualified-ident?","clojure.core/qualified-keyword?","clojure.core/qualified-symbol?","clojure.core/quot","clojure.core/rand","clojure.core/rand-int","clojure.core/rand-nth","clojure.core/random-sample","clojure.core/range","clojure.core/ratio?","clojure.core/rational?","clojure.core/rationalize","clojure.core/re-find","clojure.core/re-groups","clojure.core/re-matcher","clojure.core/re-matches","clojure.core/re-pattern","clojure.core/re-seq","clojure.core/read","clojure.core/read+string","clojure.core/read-line","clojure.core/read-string","clojure.core/reader-conditional","clojure.core/reader-conditional?","clojure.core/realized?","clojure.core/record?","clojure.core/reduce","clojure.core/reduce-kv","clojure.core/reduced","clojure.core/reduced?","clojure.core/reductions","clojure.core/ref","clojure.core/ref-history-count","clojure.core/ref-max-history","clojure.core/ref-min-history","clojure.core/ref-set","clojure.core/refer","clojure.core/release-pending-sends","clojure.core/rem","clojure.core/remove","clojure.core/remove-all-methods","clojure.core/remove-method","clojure.core/remove-ns","clojure.core/remove-tap","clojure.core/remove-watch","clojure.core/repeat","clojure.core/repeatedly","clojure.core/replace","clojure.core/replicate","clojure.core/require","clojure.core/requiring-resolve","clojure.core/reset!","clojure.core/reset-meta!","clojure.core/reset-vals!","clojure.core/resolve","clojure.core/rest","clojure.core/restart-agent","clojure.core/resultset-seq","clojure.core/reverse","clojure.core/reversible?","clojure.core/rseq","clojure.core/rsubseq","clojure.core/run!","clojure.core/satisfies?","clojure.core/second","clojure.core/select-keys","clojure.core/send","clojure.core/send-off","clojure.core/send-via","clojure.core/seq","clojure.core/seq?","clojure.core/seqable?","clojure.core/seque","clojure.core/sequence","clojure.core/sequential?","clojure.core/set","clojure.core/set-agent-send-executor!","clojure.core/set-agent-send-off-executor!","clojure.core/set-error-handler!","clojure.core/set-error-mode!","clojure.core/set-validator!","clojure.core/set?","clojure.core/short","clojure.core/short-array","clojure.core/shorts","clojure.core/shuffle","clojure.core/shutdown-agents","clojure.core/simple-ident?","clojure.core/simple-keyword?","clojure.core/simple-symbol?","clojure.core/slurp","clojure.core/some","clojure.core/some-fn","clojure.core/some?","clojure.core/sort","clojure.core/sort-by","clojure.core/sorted-map","clojure.core/sorted-map-by","clojure.core/sorted-set","clojure.core/sorted-set-by","clojure.core/sorted?","clojure.core/special-symbol?","clojure.core/spit","clojure.core/split-at","clojure.core/split-with","clojure.core/str","clojure.core/string?","clojure.core/struct","clojure.core/struct-map","clojure.core/subs","clojure.core/subseq","clojure.core/subvec","clojure.core/supers","clojure.core/swap!","clojure.core/swap-vals!","clojure.core/symbol","clojure.core/symbol?","clojure.core/tagged-literal","clojure.core/tagged-literal?","clojure.core/take","clojure.core/take-last","clojure.core/take-nth","clojure.core/take-while","clojure.core/tap>","clojure.core/test","clojure.core/the-ns","clojure.core/thread-bound?","clojure.core/to-array","clojure.core/to-array-2d","clojure.core/trampoline","clojure.core/transduce","clojure.core/transient","clojure.core/tree-seq","clojure.core/true?","clojure.core/type","clojure.core/unchecked-add","clojure.core/unchecked-add-int","clojure.core/unchecked-byte","clojure.core/unchecked-char","clojure.core/unchecked-dec","clojure.core/unchecked-dec-int","clojure.core/unchecked-divide-int","clojure.core/unchecked-double","clojure.core/unchecked-float","clojure.core/unchecked-inc","clojure.core/unchecked-inc-int","clojure.core/unchecked-int","clojure.core/unchecked-long","clojure.core/unchecked-multiply","clojure.core/unchecked-multiply-int","clojure.core/unchecked-negate","clojure.core/unchecked-negate-int","clojure.core/unchecked-remainder-int","clojure.core/unchecked-short","clojure.core/unchecked-subtract","clojure.core/unchecked-subtract-int","clojure.core/underive","clojure.core/unreduced","clojure.core/unsigned-bit-shift-right","clojure.core/update","clojure.core/update-in","clojure.core/update-proxy","clojure.core/uri?","clojure.core/use","clojure.core/uuid?","clojure.core/val","clojure.core/vals","clojure.core/var-get","clojure.core/var-set","clojure.core/var?","clojure.core/vary-meta","clojure.core/vec","clojure.core/vector","clojure.core/vector-of","clojure.core/vector?","clojure.core/volatile!","clojure.core/volatile?","clojure.core/vreset!","clojure.core/with-bindings*","clojure.core/with-meta","clojure.core/with-redefs-fn","clojure.core/xml-seq","clojure.core/zero?","clojure.core/zipmap","coll?","commute","comp","comparator","compare","compare-and-set!","compile","complement","completing","concat","conj","conj!","cons","constantly","construct-proxy","contains?","count","counted?","create-ns","create-struct","cycle","dec","dec'","decimal?","dedupe","delay?","deliver","denominator","deref","derive","descendants","destructure","disj","disj!","dissoc","dissoc!","distinct","distinct?","doall","dorun","double","double-array","double?","doubles","drop","drop-last","drop-while","eduction","empty","empty?","ensure","ensure-reduced","enumeration-seq","error-handler","error-mode","eval","even?","every-pred","every?","ex-cause","ex-data","ex-info","ex-message","extend","extenders","extends?","false?","ffirst","file-seq","filter","filterv","find","find-keyword","find-ns","find-protocol-impl","find-protocol-method","find-var","first","flatten","float","float-array","float?","floats","flush","fn?","fnext","fnil","force","format","frequencies","future-call","future-cancel","future-cancelled?","future-done?","future?","gensym","get","get-in","get-method","get-proxy-class","get-thread-bindings","get-validator","group-by","halt-when","hash","hash-combine","hash-map","hash-ordered-coll","hash-set","hash-unordered-coll","ident?","identical?","identity","ifn?","in-ns","inc","inc'","indexed?","init-proxy","inst-ms","inst-ms*","inst?","instance?","int","int-array","int?","integer?","interleave","intern","interpose","into","into-array","ints","isa?","iterate","iterator-seq","juxt","keep","keep-indexed","key","keys","keyword","keyword?","last","line-seq","list","list*","list?","load","load-file","load-reader","load-string","loaded-libs","long","long-array","longs","macroexpand","macroexpand-1","make-array","make-hierarchy","map","map-entry?","map-indexed","map?","mapcat","mapv","max","max-key","memoize","merge","merge-with","meta","method-sig","methods","min","min-key","mix-collection-hash","mod","munge","name","namespace","namespace-munge","nat-int?","neg-int?","neg?","newline","next","nfirst","nil?","nnext","not","not-any?","not-empty","not-every?","not=","ns-aliases","ns-imports","ns-interns","ns-map","ns-name","ns-publics","ns-refers","ns-resolve","ns-unalias","ns-unmap","nth","nthnext","nthrest","num","number?","numerator","object-array","odd?","parents","partial","partition","partition-all","partition-by","pcalls","peek","persistent!","pmap","pop","pop!","pop-thread-bindings","pos-int?","pos?","pr","pr-str","prefer-method","prefers","print","print-ctor","print-dup","print-method","print-simple","print-str","printf","println","println-str","prn","prn-str","promise","proxy-call-with-super","proxy-mappings","proxy-name","push-thread-bindings","qualified-ident?","qualified-keyword?","qualified-symbol?","quot","rand","rand-int","rand-nth","random-sample","range","ratio?","rational?","rationalize","re-find","re-groups","re-matcher","re-matches","re-pattern","re-seq","read","read+string","read-line","read-string","reader-conditional","reader-conditional?","realized?","record?","reduce","reduce-kv","reduced","reduced?","reductions","ref","ref-history-count","ref-max-history","ref-min-history","ref-set","refer","release-pending-sends","rem","remove","remove-all-methods","remove-method","remove-ns","remove-tap","remove-watch","repeat","repeatedly","replace","replicate","require","requiring-resolve","reset!","reset-meta!","reset-vals!","resolve","rest","restart-agent","resultset-seq","reverse","reversible?","rseq","rsubseq","run!","satisfies?","second","select-keys","send","send-off","send-via","seq","seq?","seqable?","seque","sequence","sequential?","set","set-agent-send-executor!","set-agent-send-off-executor!","set-error-handler!","set-error-mode!","set-validator!","set?","short","short-array","shorts","shuffle","shutdown-agents","simple-ident?","simple-keyword?","simple-symbol?","slurp","some","some-fn","some?","sort","sort-by","sorted-map","sorted-map-by","sorted-set","sorted-set-by","sorted?","special-symbol?","spit","split-at","split-with","str","string?","struct","struct-map","subs","subseq","subvec","supers","swap!","swap-vals!","symbol","symbol?","tagged-literal","tagged-literal?","take","take-last","take-nth","take-while","tap>","test","the-ns","thread-bound?","to-array","to-array-2d","trampoline","transduce","transient","tree-seq","true?","type","unchecked-add","unchecked-add-int","unchecked-byte","unchecked-char","unchecked-dec","unchecked-dec-int","unchecked-divide-int","unchecked-double","unchecked-float","unchecked-inc","unchecked-inc-int","unchecked-int","unchecked-long","unchecked-multiply","unchecked-multiply-int","unchecked-negate","unchecked-negate-int","unchecked-remainder-int","unchecked-short","unchecked-subtract","unchecked-subtract-int","underive","unreduced","unsigned-bit-shift-right","update","update-in","update-proxy","uri?","use","uuid?","val","vals","var-get","var-set","var?","vary-meta","vec","vector","vector-of","vector?","volatile!","volatile?","vreset!","with-bindings*","with-meta","with-redefs-fn","xml-seq","zero?","zipmap"]
- \ , 'clojureMacro': ["->","->>","..","amap","and","areduce","as->","assert","binding","bound-fn","clojure.core/->","clojure.core/->>","clojure.core/..","clojure.core/amap","clojure.core/and","clojure.core/areduce","clojure.core/as->","clojure.core/assert","clojure.core/binding","clojure.core/bound-fn","clojure.core/comment","clojure.core/declare","clojure.core/delay","clojure.core/dosync","clojure.core/doto","clojure.core/extend-protocol","clojure.core/extend-type","clojure.core/for","clojure.core/future","clojure.core/gen-class","clojure.core/gen-interface","clojure.core/import","clojure.core/io!","clojure.core/lazy-cat","clojure.core/lazy-seq","clojure.core/letfn","clojure.core/locking","clojure.core/memfn","clojure.core/ns","clojure.core/or","clojure.core/proxy","clojure.core/proxy-super","clojure.core/pvalues","clojure.core/refer-clojure","clojure.core/reify","clojure.core/some->","clojure.core/some->>","clojure.core/sync","clojure.core/time","clojure.core/vswap!","clojure.core/with-bindings","clojure.core/with-in-str","clojure.core/with-loading-context","clojure.core/with-local-vars","clojure.core/with-open","clojure.core/with-out-str","clojure.core/with-precision","clojure.core/with-redefs","comment","declare","delay","dosync","doto","extend-protocol","extend-type","for","future","gen-class","gen-interface","import","io!","lazy-cat","lazy-seq","letfn","locking","memfn","ns","or","proxy","proxy-super","pvalues","refer-clojure","reify","some->","some->>","sync","time","vswap!","with-bindings","with-in-str","with-loading-context","with-local-vars","with-open","with-out-str","with-precision","with-redefs"]
- \ , 'clojureRepeat': ["clojure.core/doseq","clojure.core/dotimes","clojure.core/while","doseq","dotimes","while"]
- \ , 'clojureSpecial': [".","clojure.core/fn","clojure.core/let","clojure.core/loop","def","do","fn","if","let","loop","monitor-enter","monitor-exit","new","quote","recur","set!","var"]
- \ , 'clojureVariable': ["*1","*2","*3","*agent*","*allow-unresolved-vars*","*assert*","*clojure-version*","*command-line-args*","*compile-files*","*compile-path*","*compiler-options*","*data-readers*","*default-data-reader-fn*","*e","*err*","*file*","*flush-on-newline*","*fn-loader*","*in*","*math-context*","*ns*","*out*","*print-dup*","*print-length*","*print-level*","*print-meta*","*print-namespace-maps*","*print-readably*","*read-eval*","*reader-resolver*","*source-path*","*suppress-read*","*unchecked-math*","*use-context-classloader*","*verbose-defrecords*","*warn-on-reflection*","EMPTY-NODE","Inst","char-escape-string","char-name-string","clojure.core/*1","clojure.core/*2","clojure.core/*3","clojure.core/*agent*","clojure.core/*allow-unresolved-vars*","clojure.core/*assert*","clojure.core/*clojure-version*","clojure.core/*command-line-args*","clojure.core/*compile-files*","clojure.core/*compile-path*","clojure.core/*compiler-options*","clojure.core/*data-readers*","clojure.core/*default-data-reader-fn*","clojure.core/*e","clojure.core/*err*","clojure.core/*file*","clojure.core/*flush-on-newline*","clojure.core/*fn-loader*","clojure.core/*in*","clojure.core/*math-context*","clojure.core/*ns*","clojure.core/*out*","clojure.core/*print-dup*","clojure.core/*print-length*","clojure.core/*print-level*","clojure.core/*print-meta*","clojure.core/*print-namespace-maps*","clojure.core/*print-readably*","clojure.core/*read-eval*","clojure.core/*reader-resolver*","clojure.core/*source-path*","clojure.core/*suppress-read*","clojure.core/*unchecked-math*","clojure.core/*use-context-classloader*","clojure.core/*verbose-defrecords*","clojure.core/*warn-on-reflection*","clojure.core/EMPTY-NODE","clojure.core/Inst","clojure.core/char-escape-string","clojure.core/char-name-string","clojure.core/default-data-readers","clojure.core/primitives-classnames","clojure.core/unquote","clojure.core/unquote-splicing","default-data-readers","primitives-classnames","unquote","unquote-splicing"]
- \ }
+ \ 'clojureBoolean': ["false","true"],
+ \ 'clojureCond': ["case","case*","clojure.core/case","clojure.core/cond","clojure.core/cond->","clojure.core/cond->>","clojure.core/condp","clojure.core/if-let","clojure.core/if-not","clojure.core/if-some","clojure.core/when","clojure.core/when-first","clojure.core/when-let","clojure.core/when-not","clojure.core/when-some","cond","cond->","cond->>","condp","if","if-let","if-not","if-some","when","when-first","when-let","when-not","when-some"],
+ \ 'clojureConstant': ["nil"],
+ \ 'clojureDefine': ["clojure.core/definline","clojure.core/definterface","clojure.core/defmacro","clojure.core/defmethod","clojure.core/defmulti","clojure.core/defn","clojure.core/defn-","clojure.core/defonce","clojure.core/defprotocol","clojure.core/defrecord","clojure.core/defstruct","clojure.core/deftype","def","definline","definterface","defmacro","defmethod","defmulti","defn","defn-","defonce","defprotocol","defrecord","defstruct","deftype","deftype*"],
+ \ 'clojureException': ["catch","finally","throw","try"],
+ \ 'clojureFunc': ["*","*'","+","+'","-","-'","->ArrayChunk","->Eduction","->Vec","->VecNode","->VecSeq","-cache-protocol-fn","-reset-methods","/","<","<=","=","==",">",">=","NaN?","PrintWriter-on","StackTraceElement->vec","Throwable->map","abs","accessor","aclone","add-classpath","add-tap","add-watch","agent","agent-error","agent-errors","aget","alength","alias","all-ns","alter","alter-meta!","alter-var-root","ancestors","any?","apply","array-map","aset","aset-boolean","aset-byte","aset-char","aset-double","aset-float","aset-int","aset-long","aset-short","assoc","assoc!","assoc-in","associative?","atom","await","await-for","await1","bases","bean","bigdec","bigint","biginteger","bit-and","bit-and-not","bit-clear","bit-flip","bit-not","bit-or","bit-set","bit-shift-left","bit-shift-right","bit-test","bit-xor","boolean","boolean-array","boolean?","booleans","bound-fn*","bound?","bounded-count","butlast","byte","byte-array","bytes","bytes?","cast","cat","char","char-array","char?","chars","chunk","chunk-append","chunk-buffer","chunk-cons","chunk-first","chunk-next","chunk-rest","chunked-seq?","class","class?","clear-agent-errors","clojure-version","clojure.core/*","clojure.core/*'","clojure.core/+","clojure.core/+'","clojure.core/-","clojure.core/-'","clojure.core/->ArrayChunk","clojure.core/->Eduction","clojure.core/->Vec","clojure.core/->VecNode","clojure.core/->VecSeq","clojure.core/-cache-protocol-fn","clojure.core/-reset-methods","clojure.core//","clojure.core/<","clojure.core/<=","clojure.core/=","clojure.core/==","clojure.core/>","clojure.core/>=","clojure.core/NaN?","clojure.core/PrintWriter-on","clojure.core/StackTraceElement->vec","clojure.core/Throwable->map","clojure.core/abs","clojure.core/accessor","clojure.core/aclone","clojure.core/add-classpath","clojure.core/add-tap","clojure.core/add-watch","clojure.core/agent","clojure.core/agent-error","clojure.core/agent-errors","clojure.core/aget","clojure.core/alength","clojure.core/alias","clojure.core/all-ns","clojure.core/alter","clojure.core/alter-meta!","clojure.core/alter-var-root","clojure.core/ancestors","clojure.core/any?","clojure.core/apply","clojure.core/array-map","clojure.core/aset","clojure.core/aset-boolean","clojure.core/aset-byte","clojure.core/aset-char","clojure.core/aset-double","clojure.core/aset-float","clojure.core/aset-int","clojure.core/aset-long","clojure.core/aset-short","clojure.core/assoc","clojure.core/assoc!","clojure.core/assoc-in","clojure.core/associative?","clojure.core/atom","clojure.core/await","clojure.core/await-for","clojure.core/await1","clojure.core/bases","clojure.core/bean","clojure.core/bigdec","clojure.core/bigint","clojure.core/biginteger","clojure.core/bit-and","clojure.core/bit-and-not","clojure.core/bit-clear","clojure.core/bit-flip","clojure.core/bit-not","clojure.core/bit-or","clojure.core/bit-set","clojure.core/bit-shift-left","clojure.core/bit-shift-right","clojure.core/bit-test","clojure.core/bit-xor","clojure.core/boolean","clojure.core/boolean-array","clojure.core/boolean?","clojure.core/booleans","clojure.core/bound-fn*","clojure.core/bound?","clojure.core/bounded-count","clojure.core/butlast","clojure.core/byte","clojure.core/byte-array","clojure.core/bytes","clojure.core/bytes?","clojure.core/cast","clojure.core/cat","clojure.core/char","clojure.core/char-array","clojure.core/char?","clojure.core/chars","clojure.core/chunk","clojure.core/chunk-append","clojure.core/chunk-buffer","clojure.core/chunk-cons","clojure.core/chunk-first","clojure.core/chunk-next","clojure.core/chunk-rest","clojure.core/chunked-seq?","clojure.core/class","clojure.core/class?","clojure.core/clear-agent-errors","clojure.core/clojure-version","clojure.core/coll?","clojure.core/commute","clojure.core/comp","clojure.core/comparator","clojure.core/compare","clojure.core/compare-and-set!","clojure.core/compile","clojure.core/complement","clojure.core/completing","clojure.core/concat","clojure.core/conj","clojure.core/conj!","clojure.core/cons","clojure.core/constantly","clojure.core/construct-proxy","clojure.core/contains?","clojure.core/count","clojure.core/counted?","clojure.core/create-ns","clojure.core/create-struct","clojure.core/cycle","clojure.core/dec","clojure.core/dec'","clojure.core/decimal?","clojure.core/dedupe","clojure.core/delay?","clojure.core/deliver","clojure.core/denominator","clojure.core/deref","clojure.core/derive","clojure.core/descendants","clojure.core/destructure","clojure.core/disj","clojure.core/disj!","clojure.core/dissoc","clojure.core/dissoc!","clojure.core/distinct","clojure.core/distinct?","clojure.core/doall","clojure.core/dorun","clojure.core/double","clojure.core/double-array","clojure.core/double?","clojure.core/doubles","clojure.core/drop","clojure.core/drop-last","clojure.core/drop-while","clojure.core/eduction","clojure.core/empty","clojure.core/empty?","clojure.core/ensure","clojure.core/ensure-reduced","clojure.core/enumeration-seq","clojure.core/error-handler","clojure.core/error-mode","clojure.core/eval","clojure.core/even?","clojure.core/every-pred","clojure.core/every?","clojure.core/ex-cause","clojure.core/ex-data","clojure.core/ex-info","clojure.core/ex-message","clojure.core/extend","clojure.core/extenders","clojure.core/extends?","clojure.core/false?","clojure.core/ffirst","clojure.core/file-seq","clojure.core/filter","clojure.core/filterv","clojure.core/find","clojure.core/find-keyword","clojure.core/find-ns","clojure.core/find-protocol-impl","clojure.core/find-protocol-method","clojure.core/find-var","clojure.core/first","clojure.core/flatten","clojure.core/float","clojure.core/float-array","clojure.core/float?","clojure.core/floats","clojure.core/flush","clojure.core/fn?","clojure.core/fnext","clojure.core/fnil","clojure.core/force","clojure.core/format","clojure.core/frequencies","clojure.core/future-call","clojure.core/future-cancel","clojure.core/future-cancelled?","clojure.core/future-done?","clojure.core/future?","clojure.core/gensym","clojure.core/get","clojure.core/get-in","clojure.core/get-method","clojure.core/get-proxy-class","clojure.core/get-thread-bindings","clojure.core/get-validator","clojure.core/group-by","clojure.core/halt-when","clojure.core/hash","clojure.core/hash-combine","clojure.core/hash-map","clojure.core/hash-ordered-coll","clojure.core/hash-set","clojure.core/hash-unordered-coll","clojure.core/ident?","clojure.core/identical?","clojure.core/identity","clojure.core/ifn?","clojure.core/in-ns","clojure.core/inc","clojure.core/inc'","clojure.core/indexed?","clojure.core/infinite?","clojure.core/init-proxy","clojure.core/inst-ms","clojure.core/inst-ms*","clojure.core/inst?","clojure.core/instance?","clojure.core/int","clojure.core/int-array","clojure.core/int?","clojure.core/integer?","clojure.core/interleave","clojure.core/intern","clojure.core/interpose","clojure.core/into","clojure.core/into-array","clojure.core/ints","clojure.core/isa?","clojure.core/iterate","clojure.core/iteration","clojure.core/iterator-seq","clojure.core/juxt","clojure.core/keep","clojure.core/keep-indexed","clojure.core/key","clojure.core/keys","clojure.core/keyword","clojure.core/keyword?","clojure.core/last","clojure.core/line-seq","clojure.core/list","clojure.core/list*","clojure.core/list?","clojure.core/load","clojure.core/load-file","clojure.core/load-reader","clojure.core/load-string","clojure.core/loaded-libs","clojure.core/long","clojure.core/long-array","clojure.core/longs","clojure.core/macroexpand","clojure.core/macroexpand-1","clojure.core/make-array","clojure.core/make-hierarchy","clojure.core/map","clojure.core/map-entry?","clojure.core/map-indexed","clojure.core/map?","clojure.core/mapcat","clojure.core/mapv","clojure.core/max","clojure.core/max-key","clojure.core/memoize","clojure.core/merge","clojure.core/merge-with","clojure.core/meta","clojure.core/method-sig","clojure.core/methods","clojure.core/min","clojure.core/min-key","clojure.core/mix-collection-hash","clojure.core/mod","clojure.core/munge","clojure.core/name","clojure.core/namespace","clojure.core/namespace-munge","clojure.core/nat-int?","clojure.core/neg-int?","clojure.core/neg?","clojure.core/newline","clojure.core/next","clojure.core/nfirst","clojure.core/nil?","clojure.core/nnext","clojure.core/not","clojure.core/not-any?","clojure.core/not-empty","clojure.core/not-every?","clojure.core/not=","clojure.core/ns-aliases","clojure.core/ns-imports","clojure.core/ns-interns","clojure.core/ns-map","clojure.core/ns-name","clojure.core/ns-publics","clojure.core/ns-refers","clojure.core/ns-resolve","clojure.core/ns-unalias","clojure.core/ns-unmap","clojure.core/nth","clojure.core/nthnext","clojure.core/nthrest","clojure.core/num","clojure.core/number?","clojure.core/numerator","clojure.core/object-array","clojure.core/odd?","clojure.core/parents","clojure.core/parse-boolean","clojure.core/parse-double","clojure.core/parse-long","clojure.core/parse-uuid","clojure.core/partial","clojure.core/partition","clojure.core/partition-all","clojure.core/partition-by","clojure.core/pcalls","clojure.core/peek","clojure.core/persistent!","clojure.core/pmap","clojure.core/pop","clojure.core/pop!","clojure.core/pop-thread-bindings","clojure.core/pos-int?","clojure.core/pos?","clojure.core/pr","clojure.core/pr-str","clojure.core/prefer-method","clojure.core/prefers","clojure.core/print","clojure.core/print-ctor","clojure.core/print-dup","clojure.core/print-method","clojure.core/print-simple","clojure.core/print-str","clojure.core/printf","clojure.core/println","clojure.core/println-str","clojure.core/prn","clojure.core/prn-str","clojure.core/promise","clojure.core/proxy-call-with-super","clojure.core/proxy-mappings","clojure.core/proxy-name","clojure.core/push-thread-bindings","clojure.core/qualified-ident?","clojure.core/qualified-keyword?","clojure.core/qualified-symbol?","clojure.core/quot","clojure.core/rand","clojure.core/rand-int","clojure.core/rand-nth","clojure.core/random-sample","clojure.core/random-uuid","clojure.core/range","clojure.core/ratio?","clojure.core/rational?","clojure.core/rationalize","clojure.core/re-find","clojure.core/re-groups","clojure.core/re-matcher","clojure.core/re-matches","clojure.core/re-pattern","clojure.core/re-seq","clojure.core/read","clojure.core/read+string","clojure.core/read-line","clojure.core/read-string","clojure.core/reader-conditional","clojure.core/reader-conditional?","clojure.core/realized?","clojure.core/record?","clojure.core/reduce","clojure.core/reduce-kv","clojure.core/reduced","clojure.core/reduced?","clojure.core/reductions","clojure.core/ref","clojure.core/ref-history-count","clojure.core/ref-max-history","clojure.core/ref-min-history","clojure.core/ref-set","clojure.core/refer","clojure.core/release-pending-sends","clojure.core/rem","clojure.core/remove","clojure.core/remove-all-methods","clojure.core/remove-method","clojure.core/remove-ns","clojure.core/remove-tap","clojure.core/remove-watch","clojure.core/repeat","clojure.core/repeatedly","clojure.core/replace","clojure.core/replicate","clojure.core/require","clojure.core/requiring-resolve","clojure.core/reset!","clojure.core/reset-meta!","clojure.core/reset-vals!","clojure.core/resolve","clojure.core/rest","clojure.core/restart-agent","clojure.core/resultset-seq","clojure.core/reverse","clojure.core/reversible?","clojure.core/rseq","clojure.core/rsubseq","clojure.core/run!","clojure.core/satisfies?","clojure.core/second","clojure.core/select-keys","clojure.core/send","clojure.core/send-off","clojure.core/send-via","clojure.core/seq","clojure.core/seq-to-map-for-destructuring","clojure.core/seq?","clojure.core/seqable?","clojure.core/seque","clojure.core/sequence","clojure.core/sequential?","clojure.core/set","clojure.core/set-agent-send-executor!","clojure.core/set-agent-send-off-executor!","clojure.core/set-error-handler!","clojure.core/set-error-mode!","clojure.core/set-validator!","clojure.core/set?","clojure.core/short","clojure.core/short-array","clojure.core/shorts","clojure.core/shuffle","clojure.core/shutdown-agents","clojure.core/simple-ident?","clojure.core/simple-keyword?","clojure.core/simple-symbol?","clojure.core/slurp","clojure.core/some","clojure.core/some-fn","clojure.core/some?","clojure.core/sort","clojure.core/sort-by","clojure.core/sorted-map","clojure.core/sorted-map-by","clojure.core/sorted-set","clojure.core/sorted-set-by","clojure.core/sorted?","clojure.core/special-symbol?","clojure.core/spit","clojure.core/split-at","clojure.core/split-with","clojure.core/str","clojure.core/string?","clojure.core/struct","clojure.core/struct-map","clojure.core/subs","clojure.core/subseq","clojure.core/subvec","clojure.core/supers","clojure.core/swap!","clojure.core/swap-vals!","clojure.core/symbol","clojure.core/symbol?","clojure.core/tagged-literal","clojure.core/tagged-literal?","clojure.core/take","clojure.core/take-last","clojure.core/take-nth","clojure.core/take-while","clojure.core/tap>","clojure.core/test","clojure.core/the-ns","clojure.core/thread-bound?","clojure.core/to-array","clojure.core/to-array-2d","clojure.core/trampoline","clojure.core/transduce","clojure.core/transient","clojure.core/tree-seq","clojure.core/true?","clojure.core/type","clojure.core/unchecked-add","clojure.core/unchecked-add-int","clojure.core/unchecked-byte","clojure.core/unchecked-char","clojure.core/unchecked-dec","clojure.core/unchecked-dec-int","clojure.core/unchecked-divide-int","clojure.core/unchecked-double","clojure.core/unchecked-float","clojure.core/unchecked-inc","clojure.core/unchecked-inc-int","clojure.core/unchecked-int","clojure.core/unchecked-long","clojure.core/unchecked-multiply","clojure.core/unchecked-multiply-int","clojure.core/unchecked-negate","clojure.core/unchecked-negate-int","clojure.core/unchecked-remainder-int","clojure.core/unchecked-short","clojure.core/unchecked-subtract","clojure.core/unchecked-subtract-int","clojure.core/underive","clojure.core/unreduced","clojure.core/unsigned-bit-shift-right","clojure.core/update","clojure.core/update-in","clojure.core/update-keys","clojure.core/update-proxy","clojure.core/update-vals","clojure.core/uri?","clojure.core/use","clojure.core/uuid?","clojure.core/val","clojure.core/vals","clojure.core/var-get","clojure.core/var-set","clojure.core/var?","clojure.core/vary-meta","clojure.core/vec","clojure.core/vector","clojure.core/vector-of","clojure.core/vector?","clojure.core/volatile!","clojure.core/volatile?","clojure.core/vreset!","clojure.core/with-bindings*","clojure.core/with-meta","clojure.core/with-redefs-fn","clojure.core/xml-seq","clojure.core/zero?","clojure.core/zipmap","coll?","commute","comp","comparator","compare","compare-and-set!","compile","complement","completing","concat","conj","conj!","cons","constantly","construct-proxy","contains?","count","counted?","create-ns","create-struct","cycle","dec","dec'","decimal?","dedupe","delay?","deliver","denominator","deref","derive","descendants","destructure","disj","disj!","dissoc","dissoc!","distinct","distinct?","doall","dorun","double","double-array","double?","doubles","drop","drop-last","drop-while","eduction","empty","empty?","ensure","ensure-reduced","enumeration-seq","error-handler","error-mode","eval","even?","every-pred","every?","ex-cause","ex-data","ex-info","ex-message","extend","extenders","extends?","false?","ffirst","file-seq","filter","filterv","find","find-keyword","find-ns","find-protocol-impl","find-protocol-method","find-var","first","flatten","float","float-array","float?","floats","flush","fn?","fnext","fnil","force","format","frequencies","future-call","future-cancel","future-cancelled?","future-done?","future?","gensym","get","get-in","get-method","get-proxy-class","get-thread-bindings","get-validator","group-by","halt-when","hash","hash-combine","hash-map","hash-ordered-coll","hash-set","hash-unordered-coll","ident?","identical?","identity","ifn?","in-ns","inc","inc'","indexed?","infinite?","init-proxy","inst-ms","inst-ms*","inst?","instance?","int","int-array","int?","integer?","interleave","intern","interpose","into","into-array","ints","isa?","iterate","iteration","iterator-seq","juxt","keep","keep-indexed","key","keys","keyword","keyword?","last","line-seq","list","list*","list?","load","load-file","load-reader","load-string","loaded-libs","long","long-array","longs","macroexpand","macroexpand-1","make-array","make-hierarchy","map","map-entry?","map-indexed","map?","mapcat","mapv","max","max-key","memoize","merge","merge-with","meta","method-sig","methods","min","min-key","mix-collection-hash","mod","munge","name","namespace","namespace-munge","nat-int?","neg-int?","neg?","newline","next","nfirst","nil?","nnext","not","not-any?","not-empty","not-every?","not=","ns-aliases","ns-imports","ns-interns","ns-map","ns-name","ns-publics","ns-refers","ns-resolve","ns-unalias","ns-unmap","nth","nthnext","nthrest","num","number?","numerator","object-array","odd?","parents","parse-boolean","parse-double","parse-long","parse-uuid","partial","partition","partition-all","partition-by","pcalls","peek","persistent!","pmap","pop","pop!","pop-thread-bindings","pos-int?","pos?","pr","pr-str","prefer-method","prefers","print","print-ctor","print-dup","print-method","print-simple","print-str","printf","println","println-str","prn","prn-str","promise","proxy-call-with-super","proxy-mappings","proxy-name","push-thread-bindings","qualified-ident?","qualified-keyword?","qualified-symbol?","quot","rand","rand-int","rand-nth","random-sample","random-uuid","range","ratio?","rational?","rationalize","re-find","re-groups","re-matcher","re-matches","re-pattern","re-seq","read","read+string","read-line","read-string","reader-conditional","reader-conditional?","realized?","record?","reduce","reduce-kv","reduced","reduced?","reductions","ref","ref-history-count","ref-max-history","ref-min-history","ref-set","refer","release-pending-sends","rem","remove","remove-all-methods","remove-method","remove-ns","remove-tap","remove-watch","repeat","repeatedly","replace","replicate","require","requiring-resolve","reset!","reset-meta!","reset-vals!","resolve","rest","restart-agent","resultset-seq","reverse","reversible?","rseq","rsubseq","run!","satisfies?","second","select-keys","send","send-off","send-via","seq","seq-to-map-for-destructuring","seq?","seqable?","seque","sequence","sequential?","set","set-agent-send-executor!","set-agent-send-off-executor!","set-error-handler!","set-error-mode!","set-validator!","set?","short","short-array","shorts","shuffle","shutdown-agents","simple-ident?","simple-keyword?","simple-symbol?","slurp","some","some-fn","some?","sort","sort-by","sorted-map","sorted-map-by","sorted-set","sorted-set-by","sorted?","special-symbol?","spit","split-at","split-with","str","string?","struct","struct-map","subs","subseq","subvec","supers","swap!","swap-vals!","symbol","symbol?","tagged-literal","tagged-literal?","take","take-last","take-nth","take-while","tap>","test","the-ns","thread-bound?","to-array","to-array-2d","trampoline","transduce","transient","tree-seq","true?","type","unchecked-add","unchecked-add-int","unchecked-byte","unchecked-char","unchecked-dec","unchecked-dec-int","unchecked-divide-int","unchecked-double","unchecked-float","unchecked-inc","unchecked-inc-int","unchecked-int","unchecked-long","unchecked-multiply","unchecked-multiply-int","unchecked-negate","unchecked-negate-int","unchecked-remainder-int","unchecked-short","unchecked-subtract","unchecked-subtract-int","underive","unreduced","unsigned-bit-shift-right","update","update-in","update-keys","update-proxy","update-vals","uri?","use","uuid?","val","vals","var-get","var-set","var?","vary-meta","vec","vector","vector-of","vector?","volatile!","volatile?","vreset!","with-bindings*","with-meta","with-redefs-fn","xml-seq","zero?","zipmap"],
+ \ 'clojureMacro': ["->","->>","..","amap","and","areduce","as->","assert","binding","bound-fn","clojure.core/->","clojure.core/->>","clojure.core/..","clojure.core/amap","clojure.core/and","clojure.core/areduce","clojure.core/as->","clojure.core/assert","clojure.core/binding","clojure.core/bound-fn","clojure.core/comment","clojure.core/declare","clojure.core/delay","clojure.core/dosync","clojure.core/doto","clojure.core/extend-protocol","clojure.core/extend-type","clojure.core/for","clojure.core/future","clojure.core/gen-class","clojure.core/gen-interface","clojure.core/import","clojure.core/io!","clojure.core/lazy-cat","clojure.core/lazy-seq","clojure.core/locking","clojure.core/memfn","clojure.core/ns","clojure.core/or","clojure.core/proxy","clojure.core/proxy-super","clojure.core/pvalues","clojure.core/refer-clojure","clojure.core/reify","clojure.core/some->","clojure.core/some->>","clojure.core/sync","clojure.core/time","clojure.core/vswap!","clojure.core/with-bindings","clojure.core/with-in-str","clojure.core/with-loading-context","clojure.core/with-local-vars","clojure.core/with-open","clojure.core/with-out-str","clojure.core/with-precision","clojure.core/with-redefs","comment","declare","delay","dosync","doto","extend-protocol","extend-type","for","future","gen-class","gen-interface","import","io!","lazy-cat","lazy-seq","locking","memfn","ns","or","proxy","proxy-super","pvalues","refer-clojure","reify","some->","some->>","sync","time","vswap!","with-bindings","with-in-str","with-loading-context","with-local-vars","with-open","with-out-str","with-precision","with-redefs"],
+ \ 'clojureRepeat': ["clojure.core/doseq","clojure.core/dotimes","clojure.core/loop","clojure.core/while","doseq","dotimes","loop","loop*","recur","while"],
+ \ 'clojureSpecial': ["&",".","clojure.core/fn","clojure.core/import*","clojure.core/let","clojure.core/letfn","do","fn","fn*","let","let*","letfn","letfn*","monitor-enter","monitor-exit","new","quote","reify*","set!","var"],
+ \ 'clojureVariable': ["*1","*2","*3","*agent*","*allow-unresolved-vars*","*assert*","*clojure-version*","*command-line-args*","*compile-files*","*compile-path*","*compiler-options*","*data-readers*","*default-data-reader-fn*","*e","*err*","*file*","*flush-on-newline*","*fn-loader*","*in*","*math-context*","*ns*","*out*","*print-dup*","*print-length*","*print-level*","*print-meta*","*print-namespace-maps*","*print-readably*","*read-eval*","*reader-resolver*","*source-path*","*suppress-read*","*unchecked-math*","*use-context-classloader*","*verbose-defrecords*","*warn-on-reflection*","EMPTY-NODE","Inst","char-escape-string","char-name-string","clojure.core/*1","clojure.core/*2","clojure.core/*3","clojure.core/*agent*","clojure.core/*allow-unresolved-vars*","clojure.core/*assert*","clojure.core/*clojure-version*","clojure.core/*command-line-args*","clojure.core/*compile-files*","clojure.core/*compile-path*","clojure.core/*compiler-options*","clojure.core/*data-readers*","clojure.core/*default-data-reader-fn*","clojure.core/*e","clojure.core/*err*","clojure.core/*file*","clojure.core/*flush-on-newline*","clojure.core/*fn-loader*","clojure.core/*in*","clojure.core/*math-context*","clojure.core/*ns*","clojure.core/*out*","clojure.core/*print-dup*","clojure.core/*print-length*","clojure.core/*print-level*","clojure.core/*print-meta*","clojure.core/*print-namespace-maps*","clojure.core/*print-readably*","clojure.core/*read-eval*","clojure.core/*reader-resolver*","clojure.core/*source-path*","clojure.core/*suppress-read*","clojure.core/*unchecked-math*","clojure.core/*use-context-classloader*","clojure.core/*verbose-defrecords*","clojure.core/*warn-on-reflection*","clojure.core/EMPTY-NODE","clojure.core/Inst","clojure.core/char-escape-string","clojure.core/char-name-string","clojure.core/default-data-readers","clojure.core/primitives-classnames","clojure.core/print-dup","clojure.core/print-method","clojure.core/unquote","clojure.core/unquote-splicing","default-data-readers","primitives-classnames","print-dup","print-method","unquote","unquote-splicing"]
+ \ }
function! s:syntax_keyword(dict)
for key in keys(a:dict)
@@ -81,8 +81,6 @@ syntax match clojureSymbol "\v%([a-zA-Z!$&*_+=|<.>?-]|[^\x00-\x7F])+%(:?%([a-zA-
" NB. Correct matching of radix literals was removed for better performance.
syntax match clojureNumber "\v<[-+]?%(%([2-9]|[12]\d|3[0-6])[rR][[:alnum:]]+|%(0\o*|0x\x+|[1-9]\d*)N?|%(0|[1-9]\d*|%(0|[1-9]\d*)\.\d*)%(M|[eE][-+]?\d+)?|%(0|[1-9]\d*)/%(0|[1-9]\d*))>"
-syntax match clojureVarArg "&"
-
syntax match clojureQuote "\v['`]"
syntax match clojureUnquote "\v\~\@?"
syntax match clojureMeta "\^"
@@ -97,8 +95,8 @@ syntax region clojureRegexpQuoted start=/\\Q/ms=e+1 skip=/\\\\\|\\"/ end=/\\E/me
syntax region clojureRegexpQuote start=/\\Q/ skip=/\\\\\|\\"/ end=/\\E/ end=/"/me=s-1 contains=clojureRegexpQuoted keepend contained
" -*- CHARACTER PROPERTY CLASSES -*-
-" Generated from https://github.com/clojure-vim/clojure.vim/blob/62b215f079ce0f3834fd295c7a7f6bd8cc54bcc3/clj/src/vim_clojure_static/generate.clj
-" Java version 17
+" Generated from https://github.com/clojure-vim/clojure.vim/blob/fd280e33e84c88e97860930557dba3ff80b1a82d/clj/src/vim_clojure_static/generate.clj
+" Java version 17.0.2
syntax match clojureRegexpPosixCharClass "\v\\[pP]\{%(Cntrl|A%(l%(pha|num)|SCII)|Space|Graph|Upper|P%(rint|unct)|Blank|XDigit|Digit|Lower)\}" contained display
syntax match clojureRegexpJavaCharClass "\v\\[pP]\{java%(Whitespace|JavaIdentifier%(Part|Start)|SpaceChar|Mirrored|TitleCase|I%(SOControl|de%(ographic|ntifierIgnorable))|D%(efined|igit)|U%(pperCase|nicodeIdentifier%(Part|Start))|L%(etter%(OrDigit)?|owerCase)|Alphabetic)\}" contained display
syntax match clojureRegexpUnicodeCharClass "\v\\[pP]\{\cIs%(l%(owercase|etter)|hex%(digit|_digit)|w%(hite%(_space|space)|ord)|noncharacter%(_code_point|codepoint)|p%(rint|unctuation)|ideographic|graph|a%(l%(num|phabetic)|ssigned)|uppercase|join%(control|_control)|titlecase|blank|digit|control)\}" contained display
@@ -127,7 +125,7 @@ syntax match clojureRegexpMod "\v\(@<=\?%(\<?[=!]|\>)" contained display
syntax match clojureRegexpMod "\v\(@<=\?\<[[:alpha:]]+\>" contained display
syntax region clojureRegexpGroup start="(" skip=/\\\\\|\\)/ end=")" matchgroup=clojureRegexpGroup contained contains=clojureRegexpMod,clojureRegexpQuantifier,clojureRegexpBoundary,clojureRegexpEscape,@clojureRegexpCharClasses
-syntax region clojureRegexp start=/\#"/ skip=/\\\\\|\\"/ end=/"/ contains=@clojureRegexpCharClasses,clojureRegexpEscape,clojureRegexpQuote,clojureRegexpBoundary,clojureRegexpQuantifier,clojureRegexpOr,clojureRegexpBackRef,clojureRegexpGroup keepend
+syntax region clojureRegexp matchgroup=clojureRegexpDelimiter start=/\#"/ skip=/\\\\\|\\"/ end=/"/ contains=@clojureRegexpCharClasses,clojureRegexpEscape,clojureRegexpQuote,clojureRegexpBoundary,clojureRegexpQuantifier,clojureRegexpOr,clojureRegexpBackRef,clojureRegexpGroup keepend
syntax keyword clojureCommentTodo contained FIXME XXX TODO BUG NOTE HACK FIXME: XXX: TODO: BUG: NOTE: HACK:
@@ -149,8 +147,8 @@ if exists('g:clojure_discard_macro') && g:clojure_discard_macro
endif
" -*- TOP CLUSTER -*-
-" Generated from https://github.com/clojure-vim/clojure.vim/blob/62b215f079ce0f3834fd295c7a7f6bd8cc54bcc3/clj/src/vim_clojure_static/generate.clj
-syntax cluster clojureTop contains=@Spell,clojureAnonArg,clojureBoolean,clojureCharacter,clojureComment,clojureCond,clojureConstant,clojureDefine,clojureDeref,clojureDiscard,clojureDispatch,clojureError,clojureException,clojureFunc,clojureKeyword,clojureMacro,clojureMap,clojureMeta,clojureNumber,clojureQuote,clojureRegexp,clojureRepeat,clojureSexp,clojureSpecial,clojureString,clojureSymbol,clojureUnquote,clojureVarArg,clojureVariable,clojureVector
+" Generated from https://github.com/clojure-vim/clojure.vim/blob/fd280e33e84c88e97860930557dba3ff80b1a82d/clj/src/vim_clojure_static/generate.clj
+syntax cluster clojureTop contains=@Spell,clojureAnonArg,clojureBoolean,clojureCharacter,clojureComment,clojureCond,clojureConstant,clojureDefine,clojureDeref,clojureDiscard,clojureDispatch,clojureError,clojureException,clojureFunc,clojureKeyword,clojureMacro,clojureMap,clojureMeta,clojureNumber,clojureQuote,clojureRegexp,clojureRepeat,clojureSexp,clojureSpecial,clojureString,clojureSymbol,clojureUnquote,clojureVariable,clojureVector
syntax region clojureSexp matchgroup=clojureParen start="(" end=")" contains=@clojureTop fold
syntax region clojureVector matchgroup=clojureParen start="\[" end="]" contains=@clojureTop fold
@@ -171,6 +169,7 @@ highlight default link clojureStringDelimiter String
highlight default link clojureStringEscape Character
highlight default link clojureRegexp Constant
+highlight default link clojureRegexpDelimiter Constant
highlight default link clojureRegexpEscape Character
highlight default link clojureRegexpCharClass SpecialChar
highlight default link clojureRegexpPosixCharClass clojureRegexpCharClass
@@ -195,7 +194,6 @@ highlight default link clojureMacro Macro
highlight default link clojureRepeat Repeat
highlight default link clojureSpecial Special
-highlight default link clojureVarArg Special
highlight default link clojureQuote SpecialChar
highlight default link clojureUnquote SpecialChar
highlight default link clojureMeta SpecialChar
diff --git a/runtime/syntax/debchangelog.vim b/runtime/syntax/debchangelog.vim
index 79352c0827..8d09af0886 100644
--- a/runtime/syntax/debchangelog.vim
+++ b/runtime/syntax/debchangelog.vim
@@ -3,7 +3,7 @@
" Maintainer: Debian Vim Maintainers
" Former Maintainers: Gerfried Fuchs <alfie@ist.org>
" Wichert Akkerman <wakkerma@debian.org>
-" Last Change: 2021 Oct 19
+" Last Change: 2022 Mar 28
" URL: https://salsa.debian.org/vim-team/vim-debian/blob/master/syntax/debchangelog.vim
" Standard syntax initialization
@@ -24,7 +24,7 @@ let s:supported = [
\ 'jessie', 'stretch', 'buster', 'bullseye', 'bookworm',
\ 'trixie', 'sid', 'rc-buggy',
\
- \ 'trusty', 'xenial', 'bionic', 'focal', 'hirsute', 'impish', 'jammy',
+ \ 'trusty', 'xenial', 'bionic', 'focal', 'impish', 'jammy',
\ 'devel'
\ ]
let s:unsupported = [
@@ -35,7 +35,7 @@ let s:unsupported = [
\ 'gutsy', 'hardy', 'intrepid', 'jaunty', 'karmic', 'lucid',
\ 'maverick', 'natty', 'oneiric', 'precise', 'quantal', 'raring', 'saucy',
\ 'utopic', 'vivid', 'wily', 'yakkety', 'zesty', 'artful', 'cosmic',
- \ 'disco', 'eoan', 'groovy'
+ \ 'disco', 'eoan', 'hirsute', 'groovy'
\ ]
let &cpo=s:cpo
diff --git a/runtime/syntax/debsources.vim b/runtime/syntax/debsources.vim
index 4b4c497f18..d79ce4b573 100644
--- a/runtime/syntax/debsources.vim
+++ b/runtime/syntax/debsources.vim
@@ -2,7 +2,7 @@
" Language: Debian sources.list
" Maintainer: Debian Vim Maintainers
" Former Maintainer: Matthijs Mohlmann <matthijs@cacholong.nl>
-" Last Change: 2021 Oct 19
+" Last Change: 2022 Mar 28
" URL: https://salsa.debian.org/vim-team/vim-debian/blob/master/syntax/debsources.vim
" Standard syntax initialization
@@ -26,7 +26,7 @@ let s:supported = [
\ 'jessie', 'stretch', 'buster', 'bullseye', 'bookworm',
\ 'trixie', 'sid', 'rc-buggy',
\
- \ 'trusty', 'xenial', 'bionic', 'focal', 'hirsute', 'impish', 'jammy',
+ \ 'trusty', 'xenial', 'bionic', 'focal', 'impish', 'jammy',
\ 'devel'
\ ]
let s:unsupported = [
@@ -37,7 +37,7 @@ let s:unsupported = [
\ 'gutsy', 'hardy', 'intrepid', 'jaunty', 'karmic', 'lucid',
\ 'maverick', 'natty', 'oneiric', 'precise', 'quantal', 'raring', 'saucy',
\ 'utopic', 'vivid', 'wily', 'yakkety', 'zesty', 'artful', 'cosmic',
- \ 'disco', 'eoan', 'groovy'
+ \ 'disco', 'eoan', 'hirsute', 'groovy'
\ ]
let &cpo=s:cpo
diff --git a/runtime/syntax/eruby.vim b/runtime/syntax/eruby.vim
index 6bb24fe562..3d1bf715db 100644
--- a/runtime/syntax/eruby.vim
+++ b/runtime/syntax/eruby.vim
@@ -3,9 +3,9 @@
" Maintainer: Tim Pope <vimNOSPAM@tpope.org>
" URL: https://github.com/vim-ruby/vim-ruby
" Release Coordinator: Doug Kearns <dougkearns@gmail.com>
-" Last Change: 2018 Jul 04
+" Last Change: 2022 Mar 18
-if &syntax !~# '\<eruby\>' || get(b:, 'current_syntax') =~# '\<eruby\>'
+if exists("b:current_syntax")
finish
endif
@@ -19,8 +19,6 @@ endif
if &filetype =~ '^eruby\.'
let b:eruby_subtype = matchstr(&filetype,'^eruby\.\zs\w\+')
-elseif &filetype =~ '^.*\.eruby\>'
- let b:eruby_subtype = matchstr(&filetype,'^.\{-\}\ze\.eruby\>')
elseif !exists("b:eruby_subtype") && main_syntax == 'eruby'
let s:lines = getline(1)."\n".getline(2)."\n".getline(3)."\n".getline(4)."\n".getline(5)."\n".getline("$")
let b:eruby_subtype = matchstr(s:lines,'eruby_subtype=\zs\w\+')
@@ -54,10 +52,10 @@ if !b:eruby_nest_level
let b:eruby_nest_level = 1
endif
-if get(b:, 'eruby_subtype', '') !~# '^\%(eruby\)\=$' && &syntax =~# '^eruby\>'
+if exists("b:eruby_subtype") && b:eruby_subtype != '' && b:eruby_subtype !=? 'eruby'
exe "runtime! syntax/".b:eruby_subtype.".vim"
+ unlet! b:current_syntax
endif
-unlet! b:current_syntax
syn include @rubyTop syntax/ruby.vim
syn cluster erubyRegions contains=erubyOneLiner,erubyBlock,erubyExpression,erubyComment
@@ -72,7 +70,7 @@ exe 'syn region erubyComment matchgroup=erubyDelimiter start="<%\{1,'.b:erub
hi def link erubyDelimiter PreProc
hi def link erubyComment Comment
-let b:current_syntax = matchstr(&syntax, '^.*\<eruby\>')
+let b:current_syntax = 'eruby'
if main_syntax == 'eruby'
unlet main_syntax
diff --git a/runtime/syntax/ruby.vim b/runtime/syntax/ruby.vim
index 13d6d9efd8..c951fcfe1d 100644
--- a/runtime/syntax/ruby.vim
+++ b/runtime/syntax/ruby.vim
@@ -3,7 +3,7 @@
" Maintainer: Doug Kearns <dougkearns@gmail.com>
" URL: https://github.com/vim-ruby/vim-ruby
" Release Coordinator: Doug Kearns <dougkearns@gmail.com>
-" Last Change: 2021 Jun 06
+" Last Change: 2021 Nov 03
" ----------------------------------------------------------------------------
"
" Previous Maintainer: Mirko Nasato
@@ -66,7 +66,7 @@ endfunction
com! -nargs=* SynFold call s:run_syntax_fold(<q-args>)
" Not-Top Cluster {{{1
-syn cluster rubyNotTop contains=@rubyCommentNotTop,@rubyStringNotTop,@rubyRegexpSpecial,@rubyDeclaration,@rubyExceptionHandler,@rubyClassOperator,rubyConditional,rubyModuleName,rubyClassName,rubySymbolDelimiter,rubyParentheses,@Spell
+syn cluster rubyNotTop contains=@rubyCommentNotTop,@rubyStringNotTop,@rubyRegexpSpecial,@rubyDeclaration,@rubyExceptionHandler,@rubyClassOperator,rubyConditional,rubyModuleName,rubyClassName,rubySymbolDelimiter,rubyDoubleQuoteSymbolDelimiter,rubySingleQuoteSymbolDelimiter,rubyParentheses,@Spell
" Whitespace Errors {{{1
if exists("ruby_space_errors")
@@ -364,6 +364,9 @@ if !exists("b:ruby_no_expensive") && !exists("ruby_no_expensive")
SynFold 'class' syn region rubyClassBlock start="\<class\>" matchgroup=rubyClass skip="\<end:" end="\<end\>" contains=ALLBUT,@rubyNotTop
SynFold 'module' syn region rubyModuleBlock start="\<module\>" matchgroup=rubyModule skip="\<end:" end="\<end\>" contains=ALLBUT,@rubyNotTop
+ " endless def
+ syn match rubyDefine "\<def\s\+\ze[^[:space:];#(]\+\%(\s\+\|\s*(.*)\s*\)=" nextgroup=rubyMethodDeclaration skipwhite
+
" modifiers
syn match rubyLineContinuation "\\$" nextgroup=@rubyModifier skipwhite skipnl
syn match rubyConditionalModifier "\<\%(if\|unless\)\>"
@@ -430,9 +433,10 @@ endif
" Comments and Documentation {{{1
syn match rubySharpBang "\%^#!.*" display
syn keyword rubyTodo FIXME NOTE TODO OPTIMIZE HACK REVIEW XXX todo contained
-syn match rubyEncoding "[[:alnum:]-]\+" contained display
+syn match rubyEncoding "[[:alnum:]-_]\+" contained display
syn match rubyMagicComment "\c\%<3l#\s*\zs\%(coding\|encoding\):" contained nextgroup=rubyEncoding skipwhite
syn match rubyMagicComment "\c\%<10l#\s*\zs\%(frozen_string_literal\|warn_indent\|warn_past_scope\):" contained nextgroup=rubyBoolean skipwhite
+syn match rubyMagicComment "\c\%<10l#\s*\zs\%(shareable_constant_value\):" contained nextgroup=rubyEncoding skipwhite
syn match rubyComment "#.*" contains=@rubyCommentSpecial,rubySpaceError,@Spell
syn cluster rubyCommentSpecial contains=rubySharpBang,rubyTodo,rubyMagicComment
@@ -465,6 +469,10 @@ syn match rubyDefinedOperator "\%#=1\<defined?" display
syn match rubySymbol "\%(\w\|[^\x00-\x7F]\)\%(\w\|[^\x00-\x7F]\)*[?!]\=::\@!"he=e-1 contained containedin=rubyBlockParameterList,rubyCurlyBlock
syn match rubySymbol "[]})\"':]\@1<!\<\%(\h\|[^\x00-\x7F]\)\%(\w\|[^\x00-\x7F]\)*[!?]\=:[[:space:],;]\@="he=e-1
syn match rubySymbol "[[:space:],{(]\%(\h\|[^\x00-\x7F]\)\%(\w\|[^\x00-\x7F]\)*[!?]\=:[[:space:],;]\@="hs=s+1,he=e-1
+syn match rubySingleQuoteSymbolDelimiter "'" contained
+syn match rubySymbol "'\%(\\.\|[^']\)*'::\@!"he=e-1 contains=rubyQuoteEscape,rubyBackslashEscape,rubySingleQuoteSymbolDelimiter
+syn match rubyDoubleQuoteSymbolDelimiter "\"" contained
+syn match rubySymbol "\"\%(\\.\|[^\"]\)*\"::\@!"he=e-1 contains=@rubyStringSpecial,rubyDoubleQuoteSymbolDelimiter
" __END__ Directive {{{1
SynFold '__END__' syn region rubyData matchgroup=rubyDataDirective start="^__END__$" end="\%$"
@@ -565,6 +573,8 @@ hi def link rubyHeredocDelimiter rubyStringDelimiter
hi def link rubyPercentRegexpDelimiter rubyRegexpDelimiter
hi def link rubyPercentStringDelimiter rubyStringDelimiter
hi def link rubyPercentSymbolDelimiter rubySymbolDelimiter
+hi def link rubyDoubleQuoteSymbolDelimiter rubySymbolDelimiter
+hi def link rubySingleQuoteSymbolDelimiter rubySymbolDelimiter
hi def link rubyRegexpDelimiter rubyStringDelimiter
hi def link rubySymbolDelimiter rubySymbol
hi def link rubyString String
diff --git a/runtime/syntax/tmux.vim b/runtime/syntax/tmux.vim
index 867c033cb5..042b96e872 100644
--- a/runtime/syntax/tmux.vim
+++ b/runtime/syntax/tmux.vim
@@ -1,5 +1,5 @@
" Language: tmux(1) configuration file
-" Version: 3.2a (git-44ada9cd)
+" Version: 3.3-rc (git-964deae4)
" URL: https://github.com/ericpruitt/tmux.vim/
" Maintainer: Eric Pruitt <eric.pruitt@gmail.com>
" License: 2-Clause BSD (http://opensource.org/licenses/BSD-2-Clause)
@@ -18,40 +18,49 @@ syntax iskeyword @,48-57,_,192-255,-
syntax case match
syn keyword tmuxAction none any current other
-syn keyword tmuxBoolean off on
+syn keyword tmuxBoolean off on yes no
syn keyword tmuxTodo FIXME NOTE TODO XXX contained
-syn match tmuxColour /\<colour[0-9]\+/ display
+syn match tmuxColour /\<colou\?r[0-9]\+\>/ display
syn match tmuxKey /\(C-\|M-\|\^\)\+\S\+/ display
syn match tmuxNumber /\<\d\+\>/ display
syn match tmuxFlags /\s-\a\+/ display
-syn match tmuxVariable /\w\+=/ display
-syn match tmuxVariableExpansion /\${\=\w\+}\=/ display
-syn match tmuxControl /%\(if\|elif\|else\|endif\)/
+syn match tmuxVariableExpansion /\$\({[A-Za-z_]\w*}\|[A-Za-z_]\w*\)/ display
+syn match tmuxControl /^\s*%\(if\|elif\|else\|endif\)\>/
+syn match tmuxEscape /\\\(u\x\{4\}\|U\x\{8\}\|\o\{3\}\|[\\ernt$]\)/ display
syn region tmuxComment start=/#/ skip=/\\\@<!\\$/ end=/$/ contains=tmuxTodo,@Spell
-syn region tmuxString start=+"+ skip=+\\\\\|\\"\|\\$+ excludenl end=+"+ end='$' contains=tmuxFormatString,@Spell
-syn region tmuxString start=+'+ skip=+\\\\\|\\'\|\\$+ excludenl end=+'+ end='$' contains=tmuxFormatString,@Spell
+syn region tmuxString start=+"+ skip=+\\\\\|\\"\|\\$+ excludenl end=+"+ end='$' contains=tmuxFormatString,tmuxEscape,tmuxVariableExpansion,@Spell
+syn region tmuxUninterpolatedString start=+'+ skip=+\\$+ excludenl end=+'+ end='$' contains=tmuxFormatString,@Spell
" TODO: Figure out how escaping works inside of #(...) and #{...} blocks.
syn region tmuxFormatString start=/#[#DFhHIPSTW]/ end=// contained keepend
syn region tmuxFormatString start=/#{/ skip=/#{.\{-}}/ end=/}/ keepend
syn region tmuxFormatString start=/#(/ skip=/#(.\{-})/ end=/)/ contained keepend
+" At the time of this writing, the latest tmux release will parse a line
+" reading "abc=xyz set-option ..." as an assignment followed by a command
+" hence the presence of "\s" in the "end" argument.
+syn region tmuxAssignment matchgroup=tmuxVariable start=/^\s*[A-Za-z_]\w*=\@=/ skip=/\\$\|\\\s/ end=/\s\|$/ contains=tmuxString,tmuxUninterpolatedString,tmuxVariableExpansion,tmuxControl,tmuxEscape
+
hi def link tmuxFormatString Identifier
hi def link tmuxAction Boolean
hi def link tmuxBoolean Boolean
hi def link tmuxCommands Keyword
-hi def link tmuxControl Keyword
+hi def link tmuxControl PreCondit
hi def link tmuxComment Comment
+hi def link tmuxEscape Special
+hi def link tmuxEscapeUnquoted Special
hi def link tmuxKey Special
hi def link tmuxNumber Number
hi def link tmuxFlags Identifier
hi def link tmuxOptions Function
hi def link tmuxString String
hi def link tmuxTodo Todo
+hi def link tmuxUninterpolatedString
+\ String
hi def link tmuxVariable Identifier
hi def link tmuxVariableExpansion Identifier
@@ -61,63 +70,85 @@ hi def link tmuxVariableExpansion Identifier
if get(g:, "tmux_syntax_colors", 1)
for s:i in range(0, 255)
let s:bg = (!s:i || s:i == 16 || (s:i > 231 && s:i < 235)) ? 15 : "none"
- exec "syn match tmuxColour" . s:i . " /\\<colour" . s:i . "\\>/ display"
+ exec "syn match tmuxColour" . s:i . " /\\<colou\\?r" . s:i . "\\>/ display"
\ " | highlight tmuxColour" . s:i . " ctermfg=" . s:i . " ctermbg=" . s:bg
endfor
endif
syn keyword tmuxOptions
-\ backspace buffer-limit command-alias copy-command default-terminal editor
-\ escape-time exit-empty activity-action assume-paste-time base-index
-\ bell-action default-command default-shell default-size destroy-unattached
+\ activity-action after-bind-key after-capture-pane after-copy-mode
+\ after-display-message after-display-panes after-kill-pane
+\ after-list-buffers after-list-clients after-list-keys after-list-panes
+\ after-list-sessions after-list-windows after-load-buffer after-lock-server
+\ after-new-session after-new-window after-paste-buffer after-pipe-pane
+\ after-queue after-refresh-client after-rename-session after-rename-window
+\ after-resize-pane after-resize-window after-save-buffer
+\ after-select-layout after-select-pane after-select-window after-send-keys
+\ after-set-buffer after-set-environment after-set-hook after-set-option
+\ after-show-environment after-show-messages after-show-options
+\ after-split-window after-unbind-key aggressive-resize alert-activity
+\ alert-bell alert-silence allow-passthrough allow-rename alternate-screen
+\ assume-paste-time automatic-rename automatic-rename-format backspace
+\ base-index bell-action buffer-limit client-active client-attached
+\ client-detached client-focus-in client-focus-out client-resized
+\ client-session-changed clock-mode-colour clock-mode-style command-alias
+\ copy-command copy-mode-current-match-style copy-mode-mark-style
+\ copy-mode-match-style cursor-colour cursor-style default-command
+\ default-shell default-size default-terminal destroy-unattached
\ detach-on-destroy display-panes-active-colour display-panes-colour
-\ display-panes-time display-time exit-unattached extended-keys focus-events
-\ history-file history-limit key-table lock-after-time lock-command
-\ message-command-style message-limit message-style aggressive-resize
-\ allow-rename alternate-screen automatic-rename automatic-rename-format
-\ clock-mode-colour clock-mode-style copy-mode-current-match-style
-\ copy-mode-mark-style copy-mode-match-style main-pane-height
-\ main-pane-width mode-keys mode-style monitor-activity monitor-bell
-\ monitor-silence mouse other-pane-height other-pane-width
-\ pane-active-border-style pane-base-index pane-border-format
-\ pane-border-lines pane-border-status pane-border-style pane-colours prefix
-\ prefix2 prompt-history-limit remain-on-exit renumber-windows repeat-time
-\ set-clipboard set-titles set-titles-string silence-action status status-bg
-\ status-fg status-format status-interval status-justify status-keys
-\ status-left status-left-length status-left-style status-position
-\ status-right status-right-length status-right-style status-style
-\ synchronize-panes terminal-features terminal-overrides update-environment
-\ user-keys visual-activity visual-bell visual-silence window-active-style
+\ display-panes-time display-time editor escape-time exit-empty
+\ exit-unattached extended-keys fill-character focus-events history-file
+\ history-limit key-table lock-after-time lock-command main-pane-height
+\ main-pane-width message-command-style message-limit message-style
+\ mode-keys mode-style monitor-activity monitor-bell monitor-silence mouse
+\ other-pane-height other-pane-width pane-active-border-style
+\ pane-base-index pane-border-format pane-border-indicators
+\ pane-border-lines pane-border-status pane-border-style pane-colours
+\ pane-died pane-exited pane-focus-in pane-focus-out pane-mode-changed
+\ pane-set-clipboard pane-title-changed popup-border-lines
+\ popup-border-style popup-style prefix prefix2 prompt-history-limit
+\ remain-on-exit remain-on-exit-format renumber-windows repeat-time
+\ scroll-on-clear session-closed session-created session-renamed
+\ session-window-changed set-clipboard set-titles set-titles-string
+\ silence-action status status-bg status-fg status-format status-interval
+\ status-justify status-keys status-left status-left-length
+\ status-left-style status-position status-right status-right-length
+\ status-right-style status-style synchronize-panes terminal-features
+\ terminal-overrides update-environment user-keys visual-activity
+\ visual-bell visual-silence window-active-style window-layout-changed
+\ window-linked window-pane-changed window-renamed window-resized
\ window-size window-status-activity-style window-status-bell-style
\ window-status-current-format window-status-current-style
\ window-status-format window-status-last-style window-status-separator
-\ window-status-style window-style word-separators wrap-search
+\ window-status-style window-style window-unlinked word-separators
+\ wrap-search xterm-keys
syn keyword tmuxCommands
\ attach attach-session bind bind-key break-pane breakp capture-pane
-\ capturep choose-buffer choose-client choose-tree clear-history clearhist
+\ capturep choose-buffer choose-client choose-session choose-tree
+\ choose-window clear-history clear-prompt-history clearhist clearphist
\ clock-mode command-prompt confirm confirm-before copy-mode customize-mode
-\ detach detach-client display display-menu display-message display-panes
-\ display-popup displayp find-window findw if if-shell join-pane joinp
-\ kill-pane kill-server kill-session kill-window killp has has-session killw
+\ delete-buffer deleteb detach detach-client display display-menu
+\ display-message display-panes display-popup displayp find-window findw has
+\ has-session if if-shell info join-pane joinp kill-pane kill-server
+\ kill-session kill-window killp killw last last-pane last-window lastp
\ link-window linkw list-buffers list-clients list-commands list-keys
\ list-panes list-sessions list-windows load-buffer loadb lock lock-client
-\ lock-server lock-session lockc last-pane lastp locks ls last last-window
-\ lsb delete-buffer deleteb lsc lscm lsk lsp lsw menu move-pane move-window
-\ clear-prompt-history clearphist movep movew new new-session new-window
-\ neww next next-layout next-window nextl paste-buffer pasteb pipe-pane
-\ pipep popup prev previous-layout previous-window prevl refresh
-\ refresh-client rename rename-session rename-window renamew resize-pane
-\ resize-window resizep resizew respawn-pane respawn-window respawnp
-\ respawnw rotate-window rotatew run run-shell save-buffer saveb
-\ select-layout select-pane select-window selectl selectp selectw send
-\ send-keys send-prefix set set-buffer set-environment set-hook set-option
+\ lock-server lock-session lockc locks ls lsb lsc lscm lsk lsp lsw menu
+\ move-pane move-window movep movew new new-session new-window neww next
+\ next-layout next-window nextl paste-buffer pasteb pipe-pane pipep popup
+\ prev previous-layout previous-window prevl refresh refresh-client rename
+\ rename-session rename-window renamew resize-pane resize-window resizep
+\ resizew respawn-pane respawn-window respawnp respawnw rotate-window
+\ rotatew run run-shell save-buffer saveb select-layout select-pane
+\ select-window selectl selectp selectw send send-keys send-prefix
+\ server-info set set-buffer set-environment set-hook set-option
\ set-window-option setb setenv setw show show-buffer show-environment
\ show-hooks show-messages show-options show-prompt-history
\ show-window-options showb showenv showmsgs showphist showw source
-\ source-file split-window splitw start start-server suspend-client suspendc
-\ swap-pane swap-window swapp swapw switch-client switchc unbind unbind-key
-\ unlink-window unlinkw wait wait-for
+\ source-file split-pane split-window splitp splitw start start-server
+\ suspend-client suspendc swap-pane swap-window swapp swapw switch-client
+\ switchc unbind unbind-key unlink-window unlinkw wait wait-for
let &cpo = s:original_cpo
unlet! s:original_cpo s:bg s:i
diff --git a/src/clint.py b/src/clint.py
index 10f33d22e2..75aaba176d 100755
--- a/src/clint.py
+++ b/src/clint.py
@@ -3187,8 +3187,8 @@ def CheckLanguage(filename, clean_lines, linenum, file_extension,
r'|li_(?:next|prev|tv))\b', line)
if match:
error(filename, linenum, 'runtime/deprecated', 4,
- 'Accessing list_T internals directly is prohibited '
- '(hint: see commit d46e37cb4c71)')
+ 'Accessing list_T internals directly is prohibited; '
+ 'see https://github.com/neovim/neovim/wiki/List-management-in-Neovim')
# Check for suspicious usage of "if" like
# } if (a == b) {
diff --git a/src/nvim/api/autocmd.c b/src/nvim/api/autocmd.c
index 8a7dd00b2a..57f392f98e 100644
--- a/src/nvim/api/autocmd.c
+++ b/src/nvim/api/autocmd.c
@@ -36,16 +36,42 @@
// Used to delete autocmds from nvim_del_autocmd
static int64_t next_autocmd_id = 1;
-/// Get autocmds that match the requirements passed to {opts}.
+/// Get all autocommands that match the corresponding {opts}.
///
-/// @param opts Optional Parameters:
-/// - event : Name or list of name of events 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}
+/// These examples will get autocommands matching ALL the given criteria:
+/// <pre>
+/// -- Matches all criteria
+/// autocommands = vim.api.nvim_get_autocmds({
+/// group = "MyGroup",
+/// event = {"BufEnter", "BufWinEnter"},
+/// pattern = {"*.c", "*.h"}
+/// })
+///
+/// -- All commands from one group
+/// autocommands = vim.api.nvim_get_autocmds({
+/// group = "MyGroup",
+/// })
+/// </pre>
+///
+/// NOTE: When multiple patterns or events are provided, it will find all the autocommands that
+/// match any combination of them.
///
-/// @return A list of autocmds that match
+/// @param opts Dictionary with at least one of the following:
+/// - group (string|integer): the autocommand group name or id to match against.
+/// - event (string|array): event or events to match against |autocmd-events|.
+/// - pattern (string|array): pattern or patterns to match against |autocmd-pattern|.
+/// @return Array of autocommands matching the criteria, with each item
+/// containing the following fields:
+/// - id (number): the autocommand id (only when defined with the API).
+/// - group (integer): the autocommand group id.
+/// - desc (string): the autocommand description.
+/// - event (string): the autocommand event.
+/// - command (string): the autocommand command.
+/// - once (boolean): whether the autocommand is only run once.
+/// - pattern (string): the autocommand pattern.
+/// If the autocommand is buffer local |autocmd-buffer-local|:
+/// - buflocal (boolean): true if the autocommand is buffer local.
+/// - buffer (number): the buffer number.
Array nvim_get_autocmds(Dict(get_autocmds) *opts, Error *err)
FUNC_API_SINCE(9)
{
@@ -301,48 +327,71 @@ cleanup:
return autocmd_list;
}
-/// Create an autocmd.
+/// Create an |autocommand|
///
-/// @param event The event or events to register this autocmd
-/// Required keys:
-/// event: string | ArrayOf(string)
+/// The API allows for two (mutually exclusive) types of actions to be executed when the autocommand
+/// triggers: a callback function (Lua or Vimscript), or a command (like regular autocommands).
///
-/// Examples:
-/// - event: "pat1,pat2,pat3",
-/// - event: "pat1"
-/// - event: { "pat1" }
-/// - event: { "pat1", "pat2", "pat3" }
+/// Example using callback:
+/// <pre>
+/// -- Lua function
+/// local myluafun = function() print("This buffer enters") end
///
-/// @param opts Optional Parameters:
-/// - callback: (string|function)
-/// - (string): The name of the viml function to execute when triggering this autocmd
-/// - (function): The lua function to execute when triggering this autocmd
-/// - NOTE: Cannot be used with {command}
-/// - command: (string) command
-/// - vimscript command
-/// - NOTE: Cannot be used with {callback}
-/// Eg. command = "let g:value_set = v:true"
-/// - pattern: (string|table)
-/// - pattern or patterns to match against
-/// - defaults to "*".
-/// - NOTE: Cannot be used with {buffer}
-/// - buffer: (bufnr)
-/// - create a |autocmd-buflocal| autocmd.
-/// - NOTE: Cannot be used with {pattern}
-/// - group: (string|int) The augroup name or id
-/// - once: (boolean) - See |autocmd-once|
-/// - nested: (boolean) - See |autocmd-nested|
-/// - desc: (string) - Description of the autocmd
+/// -- Vimscript function name (as a string)
+/// local myvimfun = "g:MyVimFunction"
+///
+/// vim.api.nvim_create_autocmd({"BufEnter", "BufWinEnter"}, {
+/// pattern = {"*.c", "*.h"},
+/// callback = myluafun, -- Or myvimfun
+/// })
+/// </pre>
///
-/// @returns opaque value to use with nvim_del_autocmd
+/// Example using command:
+/// <pre>
+/// vim.api.nvim_create_autocmd({"BufEnter", "BufWinEnter"}, {
+/// pattern = {"*.c", "*.h"},
+/// command = "echo 'Entering a C or C++ file'",
+/// })
+/// </pre>
+///
+/// Example values for pattern:
+/// <pre>
+/// pattern = "*.py"
+/// pattern = { "*.py", "*.pyi" }
+/// </pre>
+///
+/// Examples values for event:
+/// <pre>
+/// "BufPreWrite"
+/// {"CursorHold", "BufPreWrite", "BufPostWrite"}
+/// </pre>
+///
+/// @param event (String|Array) The event or events to register this autocommand
+/// @param opts Dictionary of autocommand options:
+/// - group (string|integer) optional: the autocommand group name or
+/// id to match against.
+/// - pattern (string|array) optional: pattern or patterns to match
+/// against |autocmd-pattern|.
+/// - buffer (integer) optional: buffer number for buffer local autocommands
+/// |autocmd-buflocal|. Cannot be used with {pattern}.
+/// - desc (string) optional: description of the autocommand.
+/// - callback (function|string) optional: Lua function or Vim function (as string) to
+/// execute on event. Cannot be used with {command}
+/// - command (string) optional: Vim command to execute on event. Cannot be used with
+/// {callback}
+/// - once (boolean) optional: defaults to false. Run the autocommand
+/// only once |autocmd-once|.
+/// - nested (boolean) optional: defaults to false. Run nested
+/// autocommands |autocmd-nested|.
+///
+/// @return Integer id of the created autocommand.
+/// @see |autocommand|
+/// @see |nvim_del_autocmd()|
Integer nvim_create_autocmd(uint64_t channel_id, Object event, Dict(create_autocmd) *opts,
Error *err)
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;
@@ -352,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;
}
@@ -414,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) {
@@ -552,33 +530,126 @@ cleanup:
return autocmd_id;
}
-/// Delete an autocmd by {id}. Autocmds only return IDs when created
-/// via the API. Will not error if called and no autocmds match
-/// the {id}.
+/// Delete an autocommand by id.
///
-/// @param id Integer The ID returned by nvim_create_autocmd
-void nvim_del_autocmd(Integer id)
+/// NOTE: Only autocommands created via the API have an id.
+/// @param id Integer The id returned by nvim_create_autocmd
+/// @see |nvim_create_autocmd()|
+void nvim_del_autocmd(Integer id, Error *err)
FUNC_API_SINCE(9)
{
- autocmd_delete_id(id);
+ if (id <= 0) {
+ api_set_error(err, kErrorTypeException, "Invalid autocmd id");
+ return;
+ }
+ if (!autocmd_delete_id(id)) {
+ api_set_error(err, kErrorTypeException, "Failed to delete autocmd");
+ }
}
-/// Create or get an augroup.
+/// 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.
///
-/// To get an existing augroup ID, do:
+void nvim_clear_autocmds(Dict(clear_autocmds) *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:
/// <pre>
-/// local id = vim.api.nvim_create_augroup(name, {
+/// local id = vim.api.nvim_create_augroup("MyGroup", {
/// clear = false
/// })
/// </pre>
///
-/// @param name String: The name of the augroup to create
-/// @param opts Parameters
-/// - clear (bool): Whether to clear existing commands or not.
-/// Defaults to true.
-/// See |autocmd-groups|
-///
-/// @returns opaque value to use with nvim_del_augroup_by_id
+/// @param name String: The name of the group
+/// @param opts Dictionary Parameters
+/// - clear (bool) optional: defaults to true. Clear existing
+/// commands if the group already exists |autocmd-groups|.
+/// @return Integer id of the created group.
+/// @see |autocmd-groups|
Integer nvim_create_augroup(uint64_t channel_id, String name, Dict(create_augroup) *opts,
Error *err)
FUNC_API_SINCE(9)
@@ -604,43 +675,56 @@ Integer nvim_create_augroup(uint64_t channel_id, String name, Dict(create_augrou
return augroup;
}
-/// Delete an augroup by {id}. {id} can only be returned when augroup was
-/// created with |nvim_create_augroup|.
+/// Delete an autocommand group by id.
///
-/// NOTE: behavior differs from augroup-delete.
+/// To get a group id one can use |nvim_get_autocmds()|.
///
-/// When deleting an augroup, autocmds contained by this augroup will also be deleted and cleared.
-/// This augroup will no longer exist
-void nvim_del_augroup_by_id(Integer id)
+/// NOTE: behavior differs from |augroup-delete|. When deleting a group, autocommands contained in
+/// this group will also be deleted and cleared. This group will no longer exist.
+/// @param id Integer The id of the group.
+/// @see |nvim_del_augroup_by_name()|
+/// @see |nvim_create_augroup()|
+void nvim_del_augroup_by_id(Integer id, Error *err)
FUNC_API_SINCE(9)
{
- char *name = augroup_name((int)id);
- augroup_del(name, false);
+ TRY_WRAP({
+ try_start();
+ char *name = augroup_name((int)id);
+ augroup_del(name, false);
+ try_end(err);
+ });
}
-/// Delete an augroup by {name}.
-///
-/// NOTE: behavior differs from augroup-delete.
+/// Delete an autocommand group by name.
///
-/// When deleting an augroup, autocmds contained by this augroup will also be deleted and cleared.
-/// This augroup will no longer exist
-void nvim_del_augroup_by_name(String name)
+/// NOTE: behavior differs from |augroup-delete|. When deleting a group, autocommands contained in
+/// this group will also be deleted and cleared. This group will no longer exist.
+/// @param name String The name of the group.
+/// @see |autocommand-groups|
+void nvim_del_augroup_by_name(String name, Error *err)
FUNC_API_SINCE(9)
{
- augroup_del(name.data, false);
+ TRY_WRAP({
+ try_start();
+ augroup_del(name.data, false);
+ try_end(err);
+ });
}
-/// Do one autocmd.
-///
-/// @param event The event or events to execute
-/// @param opts Optional Parameters:
-/// - buffer (number) - buffer number
-/// - NOTE: Cannot be used with {pattern}
-/// - pattern (string|table) - optional, defaults to "*".
-/// - NOTE: Cannot be used with {buffer}
-/// - 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)
+/// Execute all autocommands for {event} that match the corresponding
+/// {opts} |autocmd-execute|.
+/// @param event (String|Array) The event or events to execute
+/// @param opts Dictionary of autocommand options:
+/// - group (string|integer) optional: the autocommand group name or
+/// id to match against. |autocmd-groups|.
+/// - pattern (string|array) optional: defaults to "*" |autocmd-pattern|. Cannot be used
+/// with {buffer}.
+/// - buffer (integer) optional: buffer number |autocmd-buflocal|. Cannot be used with
+/// {pattern}.
+/// - modeline (bool) optional: defaults to true. Process the
+/// modeline after the autocommands |<nomodeline>|.
+/// @see |:doautocmd|
+void nvim_exec_autocmds(Object event, Dict(exec_autocmds) *opts, Error *err)
FUNC_API_SINCE(9)
{
int au_group = AUGROUP_ALL;
@@ -654,7 +738,7 @@ void nvim_do_autocmd(Object event, Dict(do_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;
}
@@ -753,7 +837,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));
@@ -763,10 +847,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 b6264cdfab..8ad4dae928 100644
--- a/src/nvim/api/keysets.lua
+++ b/src/nvim/api/keysets.lua
@@ -123,17 +123,23 @@ return {
"nocombine";
};
-- Autocmds
+ clear_autocmds = {
+ "buffer";
+ "event";
+ "group";
+ "pattern";
+ };
create_autocmd = {
"buffer";
"callback";
"command";
"desc";
"group";
- "once";
"nested";
+ "once";
"pattern";
};
- do_autocmd = {
+ exec_autocmds = {
"buffer";
"group";
"modeline";
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/autocmd.c b/src/nvim/autocmd.c
index a36f2c97b5..c0a22d058c 100644
--- a/src/nvim/autocmd.c
+++ b/src/nvim/autocmd.c
@@ -2022,6 +2022,11 @@ char_u *getnextac(int c, void *cookie, int indent, bool do_concat)
verbose_leave_scroll();
}
+ // Make sure to set autocmd_nested before executing
+ // lua code, so that it works properly
+ autocmd_nested = ac->nested;
+ current_sctx = ac->script_ctx;
+
if (ac->exec.type == CALLABLE_CB) {
typval_T argsin = TV_INITIAL_VALUE;
typval_T rettv = TV_INITIAL_VALUE;
@@ -2052,8 +2057,6 @@ char_u *getnextac(int c, void *cookie, int indent, bool do_concat)
if (oneshot) {
aucmd_del(ac);
}
- autocmd_nested = ac->nested;
- current_sctx = ac->script_ctx;
if (ac->last) {
acp->nextcmd = NULL;
} else {
@@ -2347,17 +2350,20 @@ int autocmd_delete_event(int group, event_T event, char_u *pat)
/// Deletes an autocmd by ID.
/// Only autocmds created via the API have IDs associated with them. There
/// is no way to delete a specific autocmd created via :autocmd
-void autocmd_delete_id(int64_t id)
+bool autocmd_delete_id(int64_t id)
{
+ assert(id > 0);
FOR_ALL_AUEVENTS(event) {
FOR_ALL_AUPATS_IN_EVENT(event, ap) {
for (AutoCmd *ac = ap->cmds; ac != NULL; ac = ac->next) {
if (ac->id == id) {
aucmd_del(ac);
+ return true;
}
}
}
}
+ return false;
}
// ===========================================================================
diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c
index f200f16a5f..bf592a626d 100644
--- a/src/nvim/buffer.c
+++ b/src/nvim/buffer.c
@@ -590,6 +590,10 @@ bool close_buffer(win_T *win, buf_T *buf, int action, bool abort_if_last)
// Remove the buffer from the list.
if (wipe_buf) {
+ // Do not wipe out the buffer if it is used in a window.
+ if (buf->b_nwindows > 0) {
+ return false;
+ }
if (buf->b_sfname != buf->b_ffname) {
XFREE_CLEAR(buf->b_sfname);
} else {
@@ -1284,8 +1288,10 @@ int do_buffer(int action, int start, int dir, int count, int forceit)
while (jumpidx != curwin->w_jumplistidx) {
buf = buflist_findnr(curwin->w_jumplist[jumpidx].fmark.fnum);
if (buf != NULL) {
- if (buf == curbuf || !buf->b_p_bl) {
- buf = NULL; // skip current and unlisted bufs
+ // Skip current and unlisted bufs. Also skip a quickfix
+ // buffer, it might be deleted soon.
+ if (buf == curbuf || !buf->b_p_bl || bt_quickfix(buf)) {
+ buf = NULL;
} else if (buf->b_ml.ml_mfp == NULL) {
// skip unloaded buf, but may keep it for later
if (bp == NULL) {
@@ -1323,7 +1329,7 @@ int do_buffer(int action, int start, int dir, int count, int forceit)
continue;
}
// in non-help buffer, try to skip help buffers, and vv
- if (buf->b_help == curbuf->b_help && buf->b_p_bl) {
+ if (buf->b_help == curbuf->b_help && buf->b_p_bl && !bt_quickfix(buf)) {
if (buf->b_ml.ml_mfp != NULL) { // found loaded buffer
break;
}
@@ -1343,7 +1349,7 @@ int do_buffer(int action, int start, int dir, int count, int forceit)
}
if (buf == NULL) { // No loaded buffer, find listed one
FOR_ALL_BUFFERS(buf2) {
- if (buf2->b_p_bl && buf2 != curbuf) {
+ if (buf2->b_p_bl && buf2 != curbuf && !bt_quickfix(buf2)) {
buf = buf2;
break;
}
@@ -1355,6 +1361,9 @@ int do_buffer(int action, int start, int dir, int count, int forceit)
} else {
buf = curbuf->b_prev;
}
+ if (bt_quickfix(buf)) {
+ buf = NULL;
+ }
}
}
@@ -1486,8 +1495,15 @@ void set_curbuf(buf_T *buf, int action)
// An autocommand may have deleted "buf", already entered it (e.g., when
// it did ":bunload") or aborted the script processing!
// If curwin->w_buffer is null, enter_buffer() will make it valid again
- if ((buf_valid(buf) && buf != curbuf && !aborting()) || curwin->w_buffer == NULL) {
- enter_buffer(buf);
+ bool valid = buf_valid(buf);
+ if ((valid && buf != curbuf && !aborting()) || curwin->w_buffer == NULL) {
+ // If the buffer is not valid but curwin->w_buffer is NULL we must
+ // enter some buffer. Using the last one is hopefully OK.
+ if (!valid) {
+ enter_buffer(lastbuf);
+ } else {
+ enter_buffer(buf);
+ }
if (old_tw != curbuf->b_p_tw) {
check_colorcolumn(curwin);
}
diff --git a/src/nvim/buffer_defs.h b/src/nvim/buffer_defs.h
index 29413281ad..08ca1a6247 100644
--- a/src/nvim/buffer_defs.h
+++ b/src/nvim/buffer_defs.h
@@ -1211,6 +1211,8 @@ struct window_S {
colnr_T w_old_visual_col; ///< last known start of visual part
colnr_T w_old_curswant; ///< last known value of Curswant
+ linenr_T w_last_cursor_lnum_rnu; ///< cursor lnum when 'rnu' was last redrawn
+
// 'listchars' characters. Defaults set in set_chars_option().
struct {
int eol;
diff --git a/src/nvim/change.c b/src/nvim/change.c
index 6c3dbf72e4..0644b1d601 100644
--- a/src/nvim/change.c
+++ b/src/nvim/change.c
@@ -287,7 +287,7 @@ static void changed_common(linenr_T lnum, colnr_T col, linenr_T lnume, long xtra
}
// Relative numbering may require updating more.
- if (wp->w_p_rnu) {
+ if (wp->w_p_rnu && xtra != 0) {
redraw_later(wp, SOME_VALID);
}
diff --git a/src/nvim/diff.c b/src/nvim/diff.c
index 1b8a9f41e9..a6bbe40999 100644
--- a/src/nvim/diff.c
+++ b/src/nvim/diff.c
@@ -1536,7 +1536,7 @@ static void diff_read(int idx_orig, int idx_new, diffio_T *dio)
long off;
int i;
int notset = true; // block "*dp" not set yet
- diffhunk_T *hunk;
+ diffhunk_T *hunk = NULL; // init to avoid gcc warning
enum {
DIFF_ED,
DIFF_UNIFIED,
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/eval.c b/src/nvim/eval.c
index fbbc543893..6c72c2866e 100644
--- a/src/nvim/eval.c
+++ b/src/nvim/eval.c
@@ -9217,6 +9217,8 @@ dictitem_T *find_var_in_ht(hashtab_T *const ht, int htname, const char *const va
/// Finds the dict (g:, l:, s:, …) and hashtable used for a variable.
///
+/// Assigns SID if s: scope is accessed from Lua or anonymous Vimscript. #15994
+///
/// @param[in] name Variable name, possibly with scope prefix.
/// @param[in] name_len Variable name length.
/// @param[out] varname Will be set to the start of the name without scope
@@ -9304,6 +9306,7 @@ static hashtab_T *find_var_ht_dict(const char *name, const size_t name_len, cons
}
}
if (current_sctx.sc_sid == SID_STR || current_sctx.sc_sid == SID_LUA) {
+ // Create SID if s: scope is accessed from Lua or anon Vimscript. #15994
new_script_item(NULL, &current_sctx.sc_sid);
}
*d = &SCRIPT_SV(current_sctx.sc_sid)->sv_dict;
diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c
index 41b419c150..ae9cb3b1e8 100644
--- a/src/nvim/eval/funcs.c
+++ b/src/nvim/eval/funcs.c
@@ -9466,6 +9466,11 @@ static int item_compare2(const void *s1, const void *s2, bool keep_zero)
res = ITEM_COMPARE_FAIL;
} else {
res = tv_get_number_chk(&rettv, &sortinfo->item_compare_func_err);
+ if (res > 0) {
+ res = 1;
+ } else if (res < 0) {
+ res = -1;
+ }
}
if (sortinfo->item_compare_func_err) {
res = ITEM_COMPARE_FAIL; // return value has wrong type
diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c
index 0dbc9d6b14..20325509c4 100644
--- a/src/nvim/ex_docmd.c
+++ b/src/nvim/ex_docmd.c
@@ -6839,7 +6839,7 @@ void tabpage_close_other(tabpage_T *tp, int forceit)
// Autocommands may delete the tab page under our fingers and we may
// fail to close a window with a modified buffer.
- if (!valid_tabpage(tp) || tp->tp_firstwin == wp) {
+ if (!valid_tabpage(tp) || tp->tp_lastwin == wp) {
break;
}
}
diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c
index 84fca137d2..1d02c74c41 100644
--- a/src/nvim/ex_getln.c
+++ b/src/nvim/ex_getln.c
@@ -192,13 +192,12 @@ typedef struct command_line_state {
typedef struct cmdline_info CmdlineInfo;
-/* The current cmdline_info. It is initialized in getcmdline() and after that
- * used by other functions. When invoking getcmdline() recursively it needs
- * to be saved with save_cmdline() and restored with restore_cmdline().
- * TODO: make it local to getcmdline() and pass it around. */
+/// The current cmdline_info. It is initialized in getcmdline() and after that
+/// used by other functions. When invoking getcmdline() recursively it needs
+/// to be saved with save_cmdline() and restored with restore_cmdline().
static struct cmdline_info ccline;
-static int cmd_showtail; // Only show path tail in lists ?
+static int cmd_showtail; // Only show path tail in lists ?
static int new_cmdpos; // position set by set_cmdline_pos()
@@ -732,9 +731,10 @@ static void finish_incsearch_highlighting(int gotesc, incsearch_state_T *s, bool
/// Internal entry point for cmdline mode.
///
-/// caller must use save_cmdline and restore_cmdline. Best is to use
-/// getcmdline or getcmdline_prompt, instead of calling this directly.
-static uint8_t *command_line_enter(int firstc, long count, int indent)
+/// @param count only used for incremental search
+/// @param indent indent for inside conditionals
+/// @param init_ccline clear ccline first
+static uint8_t *command_line_enter(int firstc, long count, int indent, bool init_ccline)
{
// can be invoked recursively, identify each level
static int cmdline_level = 0;
@@ -751,6 +751,20 @@ static uint8_t *command_line_enter(int firstc, long count, int indent)
CommandLineState *s = &state;
s->save_p_icm = vim_strsave(p_icm);
init_incsearch_state(&s->is_state);
+ CmdlineInfo save_ccline;
+ bool did_save_ccline = false;
+
+ if (ccline.cmdbuff != NULL) {
+ // Currently ccline can never be in use if init_ccline is false.
+ // Some changes will be needed if this is no longer the case.
+ assert(init_ccline);
+ // Being called recursively. Since ccline is global, we need to save
+ // the current buffer and restore it when returning.
+ save_cmdline(&save_ccline);
+ did_save_ccline = true;
+ } else if (init_ccline) {
+ memset(&ccline, 0, sizeof(struct cmdline_info));
+ }
if (s->firstc == -1) {
s->firstc = NUL;
@@ -997,6 +1011,13 @@ static uint8_t *command_line_enter(int firstc, long count, int indent)
}
cmdline_level--;
+
+ if (did_save_ccline) {
+ restore_cmdline(&save_ccline);
+ } else {
+ ccline.cmdbuff = NULL;
+ }
+
return p;
}
@@ -1340,15 +1361,9 @@ static int command_line_execute(VimState *state, int key)
s->c = get_expr_register();
if (s->c == '=') {
- // Need to save and restore ccline. And set "textlock"
- // to avoid nasty things like going to another buffer when
- // evaluating an expression.
- CmdlineInfo save_ccline;
- save_cmdline(&save_ccline);
textlock++;
p = get_expr_line();
textlock--;
- restore_cmdline(&save_ccline);
if (p != NULL) {
len = (int)STRLEN(p);
@@ -1889,10 +1904,7 @@ static int command_line_handle_key(CommandLineState *s)
beep_flush();
s->c = ESC;
} else {
- CmdlineInfo save_ccline;
- save_cmdline(&save_ccline);
s->c = get_expr_register();
- restore_cmdline(&save_ccline);
}
}
@@ -2120,7 +2132,7 @@ static int command_line_handle_key(CommandLineState *s)
int len = 0;
int old_firstc;
- xfree(ccline.cmdbuff);
+ XFREE_CLEAR(ccline.cmdbuff);
s->xpc.xp_context = EXPAND_NOTHING;
if (s->hiscnt == hislen) {
p = s->lookfor; // back to the old one
@@ -2403,14 +2415,7 @@ static void abandon_cmdline(void)
/// @param indent indent for inside conditionals
char_u *getcmdline(int firstc, long count, int indent, bool do_concat FUNC_ATTR_UNUSED)
{
- // Be prepared for situations where cmdline can be invoked recursively.
- // That includes cmd mappings, event handlers, as well as update_screen()
- // (custom status line eval), which all may invoke ":normal :".
- CmdlineInfo save_ccline;
- save_cmdline(&save_ccline);
- char_u *retval = command_line_enter(firstc, count, indent);
- restore_cmdline(&save_ccline);
- return retval;
+ return command_line_enter(firstc, count, indent, true);
}
/// Get a command line with a prompt
@@ -2434,8 +2439,14 @@ char *getcmdline_prompt(const char firstc, const char *const prompt, const int a
const int msg_col_save = msg_col;
CmdlineInfo save_ccline;
- save_cmdline(&save_ccline);
-
+ bool did_save_ccline = false;
+ if (ccline.cmdbuff != NULL) {
+ // Save the values of the current cmdline and restore them below.
+ save_cmdline(&save_ccline);
+ did_save_ccline = true;
+ } else {
+ memset(&ccline, 0, sizeof(struct cmdline_info));
+ }
ccline.prompt_id = last_prompt_id++;
ccline.cmdprompt = (char_u *)prompt;
ccline.cmdattr = attr;
@@ -2447,9 +2458,11 @@ char *getcmdline_prompt(const char firstc, const char *const prompt, const int a
int msg_silent_saved = msg_silent;
msg_silent = 0;
- char *const ret = (char *)command_line_enter(firstc, 1L, 0);
+ char *const ret = (char *)command_line_enter(firstc, 1L, 0, false);
- restore_cmdline(&save_ccline);
+ if (did_save_ccline) {
+ restore_cmdline(&save_ccline);
+ }
msg_silent = msg_silent_saved;
// Restore msg_col, the prompt from input() may have changed it.
// But only if called recursively and the commandline is therefore being
@@ -2601,7 +2614,6 @@ bool cmdline_at_end(void)
/*
* Allocate a new command line buffer.
* Assigns the new buffer to ccline.cmdbuff and ccline.cmdbufflen.
- * Returns the new value of ccline.cmdbuff and ccline.cmdbufflen.
*/
static void alloc_cmdbuff(int len)
{
@@ -3367,53 +3379,23 @@ void put_on_cmdline(char_u *str, int len, int redraw)
}
}
-/*
- * Save ccline, because obtaining the "=" register may execute "normal :cmd"
- * and overwrite it. But get_cmdline_str() may need it, thus make it
- * available globally in prev_ccline.
- */
+/// Save ccline, because obtaining the "=" register may execute "normal :cmd"
+/// and overwrite it.
static void save_cmdline(struct cmdline_info *ccp)
{
*ccp = ccline;
+ memset(&ccline, 0, sizeof(struct cmdline_info));
ccline.prev_ccline = ccp;
- ccline.cmdbuff = NULL;
- ccline.cmdprompt = NULL;
- ccline.xpc = NULL;
- ccline.special_char = NUL;
- ccline.level = 0;
+ ccline.cmdbuff = NULL; // signal that ccline is not in use
}
-/*
- * Restore ccline after it has been saved with save_cmdline().
- */
+/// Restore ccline after it has been saved with save_cmdline().
static void restore_cmdline(struct cmdline_info *ccp)
FUNC_ATTR_NONNULL_ALL
{
ccline = *ccp;
}
-/*
- * Save the command line into allocated memory. Returns a pointer to be
- * passed to restore_cmdline_alloc() later.
- */
-char_u *save_cmdline_alloc(void)
- FUNC_ATTR_NONNULL_RET
-{
- struct cmdline_info *p = xmalloc(sizeof(struct cmdline_info));
- save_cmdline(p);
- return (char_u *)p;
-}
-
-/*
- * Restore the command line from the return value of save_cmdline_alloc().
- */
-void restore_cmdline_alloc(char_u *p)
- FUNC_ATTR_NONNULL_ALL
-{
- restore_cmdline((struct cmdline_info *)p);
- xfree(p);
-}
-
/// Paste a yank register into the command line.
/// Used by CTRL-R command in command-line mode.
/// insert_reg() can't be used here, because special characters from the
@@ -3429,7 +3411,6 @@ static bool cmdline_paste(int regname, bool literally, bool remcr)
char_u *arg;
char_u *p;
bool allocated;
- struct cmdline_info save_ccline;
// check for valid regname; also accept special characters for CTRL-R in
// the command line
@@ -3447,13 +3428,11 @@ static bool cmdline_paste(int regname, bool literally, bool remcr)
}
- // Need to save and restore ccline. And set "textlock" to avoid nasty
- // things like going to another buffer when evaluating an expression.
- save_cmdline(&save_ccline);
+ // Need to set "textlock" to avoid nasty things like going to another
+ // buffer when evaluating an expression.
textlock++;
const bool i = get_spec_reg(regname, &arg, &allocated, true);
textlock--;
- restore_cmdline(&save_ccline);
if (i) {
// Got the value of a special register in "arg".
@@ -5307,7 +5286,6 @@ static void *call_user_expand_func(user_expand_func_T user_expand_func, expand_T
typval_T args[4];
char_u *pat = NULL;
const sctx_T save_current_sctx = current_sctx;
- struct cmdline_info save_ccline;
if (xp->xp_arg == NULL || xp->xp_arg[0] == '\0' || xp->xp_line == NULL) {
return NULL;
@@ -5329,15 +5307,10 @@ static void *call_user_expand_func(user_expand_func_T user_expand_func, expand_T
args[1].vval.v_string = xp->xp_line;
args[2].vval.v_number = xp->xp_col;
- // Save the cmdline, we don't know what the function may do.
- save_ccline = ccline;
- ccline.cmdbuff = NULL;
- ccline.cmdprompt = NULL;
current_sctx = xp->xp_script_ctx;
void *const ret = user_expand_func(xp->xp_arg, 3, args);
- ccline = save_ccline;
current_sctx = save_current_sctx;
if (ccline.cmdbuff != NULL) {
ccline.cmdbuff[ccline.cmdlen] = keep;
@@ -5947,10 +5920,8 @@ int get_history_idx(int histype)
}
-/*
- * Get pointer to the command line info to use. cmdline_paste() may clear
- * ccline and put the previous value in prev_ccline.
- */
+/// Get pointer to the command line info to use. save_cmdline() may clear
+/// ccline and put the previous value in ccline.prev_ccline.
static struct cmdline_info *get_ccline_ptr(void)
{
if ((State & CMDLINE) == 0) {
@@ -6350,6 +6321,11 @@ int hist_type2char(int type)
return NUL;
}
+void cmdline_init(void)
+{
+ memset(&ccline, 0, sizeof(struct cmdline_info));
+}
+
/// Open a window on the current command line and history. Allow editing in
/// the window. Returns when the window is closed.
/// Returns:
@@ -6358,7 +6334,6 @@ int hist_type2char(int type)
/// K_IGNORE if editing continues
static int open_cmdwin(void)
{
- struct cmdline_info save_ccline;
bufref_T old_curbuf;
bufref_T bufref;
win_T *old_curwin = curwin;
@@ -6459,9 +6434,6 @@ static int open_cmdwin(void)
}
redraw_later(curwin, SOME_VALID);
- // Save the command line info, can be used recursively.
- save_cmdline(&save_ccline);
-
// No Ex mode here!
exmode_active = false;
@@ -6499,8 +6471,6 @@ static int open_cmdwin(void)
// Restore KeyTyped in case it is modified by autocommands
KeyTyped = save_KeyTyped;
- // Restore the command line info.
- restore_cmdline(&save_ccline);
cmdwin_type = 0;
cmdwin_level = 0;
diff --git a/src/nvim/ex_session.c b/src/nvim/ex_session.c
index 39ff75d8c2..1235087500 100644
--- a/src/nvim/ex_session.c
+++ b/src/nvim/ex_session.c
@@ -589,12 +589,18 @@ static int makeopens(FILE *fd, char_u *dirnow)
"if expand('%') == '' && !&modified && line('$') <= 1"
" && getline(1) == ''\n"
" let s:wipebuf = bufnr('%')\n"
- "endif\n"
- // Now save the current files, current buffer first.
- "set shortmess=aoO\n") < 0) {
+ "endif\n") < 0) {
return FAIL;
}
+ // save 'shortmess' if not storing options
+ if ((ssop_flags & SSOP_OPTIONS) == 0) {
+ PUTLINE_FAIL("let s:shortmess_save = &shortmess");
+ }
+
+ // Now save the current files, current buffer first.
+ PUTLINE_FAIL("set shortmess=aoO");
+
// Put all buffers into the buffer list.
// Do it very early to preserve buffer order after loading session (which
// can be disrupted by prior `edit` or `tabedit` calls).
@@ -842,15 +848,21 @@ static int makeopens(FILE *fd, char_u *dirnow)
return FAIL;
}
- // Re-apply 'winheight', 'winwidth' and 'shortmess'.
- if (fprintf(fd,
- "set winheight=%" PRId64 " winwidth=%" PRId64
- " shortmess=%s\n",
- (int64_t)p_wh,
- (int64_t)p_wiw,
- p_shm) < 0) {
+ // Re-apply 'winheight' and 'winwidth'.
+ if (fprintf(fd, "set winheight=%" PRId64 " winwidth=%" PRId64 "\n",
+ (int64_t)p_wh, (int64_t)p_wiw) < 0) {
return FAIL;
}
+
+ // Restore 'shortmess'.
+ if (ssop_flags & SSOP_OPTIONS) {
+ if (fprintf(fd, "set shortmess=%s\n", p_shm) < 0) {
+ return FAIL;
+ }
+ } else {
+ PUTLINE_FAIL("let &shortmess = s:shortmess_save");
+ }
+
if (tab_firstwin != NULL && tab_firstwin->w_next != NULL) {
// Restore 'winminheight' and 'winminwidth'.
PUTLINE_FAIL("let &winminheight = s:save_winminheight");
diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c
index fe61a2fc90..7905b29876 100644
--- a/src/nvim/fileio.c
+++ b/src/nvim/fileio.c
@@ -361,7 +361,7 @@ int readfile(char_u *fname, char_u *sfname, linenr_T from, linenr_T lines_to_ski
filemess(curbuf, fname, (char_u *)_(msg_is_a_directory), 0);
msg_end();
msg_scroll = msg_save;
- return FAIL;
+ return NOTDONE;
}
}
diff --git a/src/nvim/getchar.c b/src/nvim/getchar.c
index c10172cc52..b12b99b7ee 100644
--- a/src/nvim/getchar.c
+++ b/src/nvim/getchar.c
@@ -4001,7 +4001,6 @@ static char_u *eval_map_expr(mapblock_T *mp, int c)
char_u *res;
char_u *p = NULL;
char_u *expr = NULL;
- char_u *save_cmd;
pos_T save_cursor;
int save_msg_col;
int save_msg_row;
@@ -4013,8 +4012,6 @@ static char_u *eval_map_expr(mapblock_T *mp, int c)
vim_unescape_ks(expr);
}
- save_cmd = save_cmdline_alloc();
-
// Forbid changing text or using ":normal" to avoid most of the bad side
// effects. Also restore the cursor position.
textlock++;
@@ -4045,8 +4042,6 @@ static char_u *eval_map_expr(mapblock_T *mp, int c)
msg_col = save_msg_col;
msg_row = save_msg_row;
- restore_cmdline_alloc(save_cmd);
-
if (p == NULL) {
return NULL;
}
diff --git a/src/nvim/main.c b/src/nvim/main.c
index afb9313cba..6ea1cb0875 100644
--- a/src/nvim/main.c
+++ b/src/nvim/main.c
@@ -20,6 +20,7 @@
#include "nvim/ex_cmds.h"
#include "nvim/ex_cmds2.h"
#include "nvim/ex_docmd.h"
+#include "nvim/ex_getln.h"
#include "nvim/fileio.h"
#include "nvim/fold.h"
#include "nvim/getchar.h"
@@ -156,6 +157,7 @@ bool event_teardown(void)
void early_init(mparm_T *paramp)
{
env_init();
+ cmdline_init();
eval_init(); // init global variables
init_path(argv0 ? argv0 : "nvim");
init_normal_cmds(); // Init the table of Normal mode commands.
diff --git a/src/nvim/message.c b/src/nvim/message.c
index b3fefbc0f4..6708001495 100644
--- a/src/nvim/message.c
+++ b/src/nvim/message.c
@@ -327,11 +327,12 @@ bool msg_attr_keep(const char *s, int attr, bool keep, bool multiline)
}
retval = msg_end();
- if (keep && retval && vim_strsize((char_u *)s) < (Rows - cmdline_row - 1)
- * Columns + sc_col) {
+ if (keep && retval && vim_strsize((char_u *)s) < (Rows - cmdline_row - 1) * Columns + sc_col) {
set_keep_msg((char *)s, 0);
}
+ need_fileinfo = false;
+
xfree(buf);
--entered;
return retval;
@@ -382,6 +383,13 @@ void trunc_string(char_u *s, char_u *buf, int room_in, int buflen)
int i;
int n;
+ if (*s == NUL) {
+ if (buflen > 0) {
+ *buf = NUL;
+ }
+ return;
+ }
+
if (room_in < 3) {
room = 0;
}
@@ -1348,6 +1356,7 @@ void msg_start(void)
if (!msg_silent) {
XFREE_CLEAR(keep_msg); // don't display old message now
+ need_fileinfo = false;
}
if (need_clr_eos) {
@@ -1486,6 +1495,10 @@ int msg_outtrans_len_attr(const char_u *msgstr, int len, int attr)
char_u *s;
int mb_l;
int c;
+ int save_got_int = got_int;
+
+ // Only quit when got_int was set in here.
+ got_int = false;
// if MSG_HIST flag set, add message to history
if (attr & MSG_HIST) {
@@ -1503,7 +1516,7 @@ int msg_outtrans_len_attr(const char_u *msgstr, int len, int attr)
* Go over the string. Special characters are translated and printed.
* Normal characters are printed several at a time.
*/
- while (--len >= 0) {
+ while (--len >= 0 && !got_int) {
// Don't include composing chars after the end.
mb_l = utfc_ptr2len_len((char_u *)str, len + 1);
if (mb_l > 1) {
@@ -1542,11 +1555,13 @@ int msg_outtrans_len_attr(const char_u *msgstr, int len, int attr)
}
}
- if (str > plain_start) {
+ if (str > plain_start && !got_int) {
// Print the printable chars at the end.
msg_puts_attr_len(plain_start, str - plain_start, attr);
}
+ got_int |= save_got_int;
+
return retval;
}
@@ -2013,6 +2028,8 @@ void msg_puts_attr_len(const char *const str, const ptrdiff_t len, int attr)
if (!msg_use_printf() || (headless_mode && default_grid.chars)) {
msg_puts_display((const char_u *)str, len, attr, false);
}
+
+ need_fileinfo = false;
}
/// Print a formatted message
diff --git a/src/nvim/move.c b/src/nvim/move.c
index 751e0046bc..5e02e355bf 100644
--- a/src/nvim/move.c
+++ b/src/nvim/move.c
@@ -95,18 +95,41 @@ static void comp_botline(win_T *wp)
win_check_anchored_floats(wp);
}
-// Redraw when w_cline_row changes and 'relativenumber' or 'cursorline' is set.
+/// 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);
}
}
+/// 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
+{
+ if ((wp->w_valid & VALID_VIRTCOL) == 0 && !pum_visible()) {
+ if (wp->w_p_cuc) {
+ // When 'cursorcolumn' is set need to redraw with SOME_VALID.
+ redraw_later(wp, SOME_VALID);
+ } else if (wp->w_p_cul && (wp->w_p_culopt_flags & CULOPT_SCRLINE)) {
+ // When 'cursorlineopt' contains "screenline" need to redraw with VALID.
+ 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);
+ }
+}
+
/*
* Update curwin->w_topline and redraw if necessary.
* Used to update the screen before printing a message.
@@ -623,11 +646,8 @@ void validate_virtcol_win(win_T *wp)
check_cursor_moved(wp);
if (!(wp->w_valid & VALID_VIRTCOL)) {
getvvcol(wp, &wp->w_cursor, NULL, &(wp->w_virtcol), NULL);
+ redraw_for_cursorcolumn(wp);
wp->w_valid |= VALID_VIRTCOL;
- if (wp->w_p_cuc
- && !pum_visible()) {
- redraw_later(wp, SOME_VALID);
- }
}
}
@@ -930,11 +950,7 @@ void curs_columns(win_T *wp, int may_scroll)
redraw_later(wp, NOT_VALID);
}
- // Redraw when w_virtcol changes and 'cursorcolumn' is set
- if (wp->w_p_cuc && (wp->w_valid & VALID_VIRTCOL) == 0
- && !pum_visible()) {
- redraw_later(wp, SOME_VALID);
- }
+ redraw_for_cursorcolumn(curwin);
// now w_leftcol is valid, avoid check_cursor_moved() thinking otherwise
wp->w_valid_leftcol = wp->w_leftcol;
diff --git a/src/nvim/normal.c b/src/nvim/normal.c
index e773351d63..72e80952ff 100644
--- a/src/nvim/normal.c
+++ b/src/nvim/normal.c
@@ -1288,16 +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);
- }
-
- // Might need to update for 'cursorline'.
- check_redraw_cursorline();
-
if (VIsual_active) {
update_curbuf(INVERTED); // update inverted part
} else if (must_redraw) {
diff --git a/src/nvim/ops.c b/src/nvim/ops.c
index fc66fb5f06..dab6d237bf 100644
--- a/src/nvim/ops.c
+++ b/src/nvim/ops.c
@@ -3893,7 +3893,7 @@ void ex_display(exarg_T *eap)
msg_puts_attr("^J", attr);
n -= 2;
}
- for (p = yb->y_array[j]; *p && (n -= ptr2cells(p)) >= 0; p++) {
+ for (p = yb->y_array[j]; *p != NUL && (n -= ptr2cells(p)) >= 0; p++) { // -V1019
clen = utfc_ptr2len(p);
msg_outtrans_len(p, clen);
p += clen - 1;
diff --git a/src/nvim/option_defs.h b/src/nvim/option_defs.h
index d88cd6b9b9..98c2b84770 100644
--- a/src/nvim/option_defs.h
+++ b/src/nvim/option_defs.h
@@ -523,11 +523,11 @@ EXTERN long p_mmd; // 'maxmapdepth'
EXTERN long p_mmp; // 'maxmempattern'
EXTERN long p_mis; // 'menuitems'
EXTERN char_u *p_msm; // 'mkspellmem'
-EXTERN long p_mle; // 'modelineexpr'
+EXTERN int p_mle; // 'modelineexpr'
EXTERN long p_mls; // 'modelines'
EXTERN char_u *p_mouse; // 'mouse'
EXTERN char_u *p_mousem; // 'mousemodel'
-EXTERN long p_mousef; // 'mousefocus'
+EXTERN int p_mousef; // 'mousefocus'
EXTERN long p_mouset; // 'mousetime'
EXTERN int p_more; // 'more'
EXTERN char_u *p_opfunc; // 'operatorfunc'
diff --git a/src/nvim/path.c b/src/nvim/path.c
index d3aa5e5bf2..75624778e3 100644
--- a/src/nvim/path.c
+++ b/src/nvim/path.c
@@ -1777,7 +1777,7 @@ int path_with_url(const char *fname)
}
// check body: alpha or dash
- for (p = fname; (isalpha(*p) || (*p == '-')); p++) {}
+ for (p = fname + 1; (isalpha(*p) || (*p == '-')); p++) {}
// check last char is not a dash
if (p[-1] == '-') {
diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c
index 9ee7b1cc8a..c8d9e91fb5 100644
--- a/src/nvim/quickfix.c
+++ b/src/nvim/quickfix.c
@@ -2780,6 +2780,7 @@ static int qf_jump_edit_buffer(qf_info_T *qi, qfline_T *qf_ptr, int forceit, int
// present.
if (qfl_type == QFLT_LOCATION) {
win_T *wp = win_id2wp(prev_winid);
+
if (wp == NULL && curwin->w_llist != qi) {
emsg(_("E924: Current window was closed"));
*opened_window = false;
diff --git a/src/nvim/regexp.c b/src/nvim/regexp.c
index 009a26d4e0..d3c43e530a 100644
--- a/src/nvim/regexp.c
+++ b/src/nvim/regexp.c
@@ -107,8 +107,10 @@ static char_u e_unmatchedpar[] = N_("E55: Unmatched %s)");
static char_u e_z_not_allowed[] = N_("E66: \\z( not allowed here");
static char_u e_z1_not_allowed[] = N_("E67: \\z1 - \\z9 not allowed here");
static char_u e_missing_sb[] = N_("E69: Missing ] after %s%%[");
-static char_u e_empty_sb[] = N_("E70: Empty %s%%[]");
-static char_u e_recursive[] = N_("E956: Cannot use pattern recursively");
+static char_u e_empty_sb[] = N_("E70: Empty %s%%[]");
+static char_u e_recursive[] = N_("E956: Cannot use pattern recursively");
+static char_u e_regexp_number_after_dot_pos_search[]
+ = N_("E1204: No Number allowed after .: '\\%%%c'");
#define NOT_MULTI 0
#define MULTI_ONE 1
diff --git a/src/nvim/regexp_bt.c b/src/nvim/regexp_bt.c
index 7340957903..7d0b9a7a77 100644
--- a/src/nvim/regexp_bt.c
+++ b/src/nvim/regexp_bt.c
@@ -1578,14 +1578,19 @@ static char_u *regatom(int *flagp)
}
default:
- if (ascii_isdigit(c) || c == '<' || c == '>'
- || c == '\'') {
+ if (ascii_isdigit(c) || c == '<' || c == '>' || c == '\'' || c == '.') {
uint32_t n = 0;
int cmp;
+ bool cur = false;
cmp = c;
- if (cmp == '<' || cmp == '>')
+ if (cmp == '<' || cmp == '>') {
c = getchr();
+ }
+ if (no_Magic(c) == '.') {
+ cur = true;
+ c = getchr();
+ }
while (ascii_isdigit(c)) {
n = n * 10 + (uint32_t)(c - '0');
c = getchr();
@@ -1602,14 +1607,31 @@ static char_u *regatom(int *flagp)
}
break;
} else if (c == 'l' || c == 'c' || c == 'v') {
+ if (cur && n) {
+ semsg(_(e_regexp_number_after_dot_pos_search), no_Magic(c));
+ rc_did_emsg = true;
+ return NULL;
+ }
if (c == 'l') {
+ if (cur) {
+ n = curwin->w_cursor.lnum;
+ }
ret = regnode(RE_LNUM);
if (save_prev_at_start) {
at_start = true;
}
} else if (c == 'c') {
+ if (cur) {
+ n = curwin->w_cursor.col;
+ n++;
+ }
ret = regnode(RE_COL);
} else {
+ if (cur) {
+ colnr_T vcol = 0;
+ getvvcol(curwin, &curwin->w_cursor, NULL, NULL, &vcol);
+ n = ++vcol;
+ }
ret = regnode(RE_VCOL);
}
if (ret == JUST_CALC_SIZE) {
@@ -3130,9 +3152,17 @@ static bool regmatch(
{
int mark = OPERAND(scan)[0];
int cmp = OPERAND(scan)[1];
- pos_T *pos;
+ pos_T *pos;
+ size_t col = REG_MULTI ? rex.input - rex.line : 0;
pos = getmark_buf(rex.reg_buf, mark, false);
+
+ // Line may have been freed, get it again.
+ if (REG_MULTI) {
+ rex.line = reg_getline(rex.lnum);
+ rex.input = rex.line + col;
+ }
+
if (pos == NULL // mark doesn't exist
|| pos->lnum <= 0) { // mark isn't set in reg_buf
status = RA_NOMATCH;
diff --git a/src/nvim/regexp_nfa.c b/src/nvim/regexp_nfa.c
index 7e316624f8..a8d6e9c40b 100644
--- a/src/nvim/regexp_nfa.c
+++ b/src/nvim/regexp_nfa.c
@@ -1639,10 +1639,20 @@ static int nfa_regatom(void)
{
int64_t n = 0;
const int cmp = c;
+ bool cur = false;
- if (c == '<' || c == '>')
+ if (c == '<' || c == '>') {
c = getchr();
+ }
+ if (no_Magic(c) == '.') {
+ cur = true;
+ c = getchr();
+ }
while (ascii_isdigit(c)) {
+ if (cur) {
+ semsg(_(e_regexp_number_after_dot_pos_search), no_Magic(c));
+ return FAIL;
+ }
if (n > (INT32_MAX - (c - '0')) / 10) {
// overflow.
emsg(_(e_value_too_large));
@@ -1655,6 +1665,9 @@ static int nfa_regatom(void)
int32_t limit = INT32_MAX;
if (c == 'l') {
+ if (cur) {
+ n = curwin->w_cursor.lnum;
+ }
// \%{n}l \%{n}<l \%{n}>l
EMIT(cmp == '<' ? NFA_LNUM_LT :
cmp == '>' ? NFA_LNUM_GT : NFA_LNUM);
@@ -1662,10 +1675,19 @@ static int nfa_regatom(void)
at_start = true;
}
} else if (c == 'c') {
+ if (cur) {
+ n = curwin->w_cursor.col;
+ n++;
+ }
// \%{n}c \%{n}<c \%{n}>c
EMIT(cmp == '<' ? NFA_COL_LT :
cmp == '>' ? NFA_COL_GT : NFA_COL);
} else {
+ if (cur) {
+ colnr_T vcol = 0;
+ getvvcol(curwin, &curwin->w_cursor, NULL, NULL, &vcol);
+ n = ++vcol;
+ }
// \%{n}v \%{n}<v \%{n}>v
EMIT(cmp == '<' ? NFA_VCOL_LT :
cmp == '>' ? NFA_VCOL_GT : NFA_VCOL);
@@ -6227,8 +6249,10 @@ static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start,
case NFA_MARK_GT:
case NFA_MARK_LT:
{
- size_t col = rex.input - rex.line;
- pos_T *pos = getmark_buf(rex.reg_buf, t->state->val, false);
+ pos_T *pos;
+ size_t col = REG_MULTI ? rex.input - rex.line : 0;
+
+ pos = getmark_buf(rex.reg_buf, t->state->val, false);
// Line may have been freed, get it again.
if (REG_MULTI) {
diff --git a/src/nvim/screen.c b/src/nvim/screen.c
index 5a10543559..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));
}
/*
@@ -938,7 +934,7 @@ static void win_update(win_T *wp, DecorProviders *providers)
if (mod_top != 0
&& wp->w_topline == mod_top
&& (!wp->w_lines[0].wl_valid
- || wp->w_topline <= wp->w_lines[0].wl_lnum)) {
+ || wp->w_topline == wp->w_lines[0].wl_lnum)) {
// w_topline is the first changed line and window is not scrolled,
// the scrolling from changed lines will be done further down.
} else if (wp->w_lines[0].wl_valid
@@ -1577,9 +1573,9 @@ static void win_update(win_T *wp, DecorProviders *providers)
idx++;
lnum += foldinfo.fi_lines + 1;
} else {
- if (wp->w_p_rnu) {
- // 'relativenumber' set: The text doesn't need to be drawn, but
- // the number column nearly always does.
+ if (wp->w_p_rnu && wp->w_last_cursor_lnum_rnu != wp->w_cursor.lnum) {
+ // 'relativenumber' set and cursor moved vertically: The
+ // text doesn't need to be drawn, but the number column does.
foldinfo_T info = fold_info(wp, lnum);
(void)win_line(wp, lnum, srow, wp->w_grid.Rows, true, true,
info, &line_providers);
@@ -1607,6 +1603,8 @@ static void win_update(win_T *wp, DecorProviders *providers)
// update w_last_cursorline.
wp->w_last_cursorline = cursorline_standout ? wp->w_cursor.lnum : 0;
+ wp->w_last_cursor_lnum_rnu = wp->w_p_rnu ? wp->w_cursor.lnum : 0;
+
if (idx > wp->w_lines_valid) {
wp->w_lines_valid = idx;
}
@@ -4333,6 +4331,9 @@ static int draw_virt_text_item(buf_T *buf, int col, VirtText vt, HlMode hl_mode,
break;
}
}
+ if (!*s.p) {
+ continue;
+ }
int attr;
bool through = false;
if (hl_mode == kHlModeCombine) {
@@ -7617,16 +7618,3 @@ win_T *get_win_by_grid_handle(handle_T handle)
}
return NULL;
}
-
-/// Check if the cursor moved and 'cursorline' is set. Mark for a VALID redraw
-/// if needed.
-void check_redraw_cursorline(void)
-{
- // When 'cursorlineopt' is "screenline" need to redraw always.
- if (curwin->w_p_cul
- && (curwin->w_last_cursorline != curwin->w_cursor.lnum
- || (curwin->w_p_culopt_flags & CULOPT_SCRLINE))
- && !char_avail()) {
- redraw_later(curwin, VALID);
- }
-}
diff --git a/src/nvim/spellfile.c b/src/nvim/spellfile.c
index d7b220b3f6..07058b34fd 100644
--- a/src/nvim/spellfile.c
+++ b/src/nvim/spellfile.c
@@ -5580,6 +5580,9 @@ void spell_add_word(char_u *word, int len, SpellAddType what, int idx, bool undo
while (!vim_fgets(line, MAXWLEN * 2, fd)) {
fpos = fpos_next;
fpos_next = ftell(fd);
+ if (fpos_next < 0) {
+ break; // should never happen
+ }
if (STRNCMP(word, line, len) == 0
&& (line[len] == '/' || line[len] < ' ')) {
// Found duplicate word. Remove it by writing a '#' at
diff --git a/src/nvim/state.c b/src/nvim/state.c
index f9a3aaab7f..3a7636085b 100644
--- a/src/nvim/state.c
+++ b/src/nvim/state.c
@@ -15,6 +15,7 @@
#include "nvim/option.h"
#include "nvim/option_defs.h"
#include "nvim/os/input.h"
+#include "nvim/screen.h"
#include "nvim/state.h"
#include "nvim/ui.h"
#include "nvim/vim.h"
@@ -54,6 +55,12 @@ getkey:
// Event was made available after the last multiqueue_process_events call
key = K_EVENT;
} else {
+ // Duplicate display updating logic in vgetorpeek()
+ if (((State & INSERT) != 0 || p_lz) && (State & CMDLINE) == 0
+ && must_redraw != 0 && !need_wait_return) {
+ update_screen(0);
+ setcursor(); // put cursor back where it belongs
+ }
// Flush screen updates before blocking
ui_flush();
// Call `os_inchar` directly to block for events or user input without
diff --git a/src/nvim/testdir/test_autocmd.vim b/src/nvim/testdir/test_autocmd.vim
index c39546b9ea..76c69ad10b 100644
--- a/src/nvim/testdir/test_autocmd.vim
+++ b/src/nvim/testdir/test_autocmd.vim
@@ -2343,6 +2343,19 @@ func Test_throw_in_BufWritePre()
au! throwing
endfunc
+func Test_autocmd_in_try_block()
+ call mkdir('Xdir')
+ au BufEnter * let g:fname = expand('%')
+ try
+ edit Xdir/
+ endtry
+ call assert_match('Xdir', g:fname)
+
+ unlet g:fname
+ au! BufEnter
+ call delete('Xdir', 'rf')
+endfunc
+
func Test_autocmd_CmdWinEnter()
CheckRunVimInTerminal
" There is not cmdwin switch, so
@@ -2598,4 +2611,21 @@ func Test_autocmd_closing_cmdwin()
only
endfunc
+func Test_bufwipeout_changes_window()
+ " This should not crash, but we don't have any expectations about what
+ " happens, changing window in BufWipeout has unpredictable results.
+ tabedit
+ let g:window_id = win_getid()
+ topleft new
+ setlocal bufhidden=wipe
+ autocmd BufWipeout <buffer> call win_gotoid(g:window_id)
+ tabprevious
+ +tabclose
+
+ unlet g:window_id
+ au! BufWipeout
+ %bwipe!
+endfunc
+
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_cursorline.vim b/src/nvim/testdir/test_cursorline.vim
index bf049ec779..7e97df6027 100644
--- a/src/nvim/testdir/test_cursorline.vim
+++ b/src/nvim/testdir/test_cursorline.vim
@@ -293,5 +293,26 @@ func Test_cursorline_callback()
call delete('Xcul_timer')
endfunc
+func Test_cursorline_screenline_update()
+ CheckScreendump
+
+ let lines =<< trim END
+ call setline(1, repeat('xyz ', 30))
+ set cursorline cursorlineopt=screenline
+ inoremap <F2> <Cmd>call cursor(1, 1)<CR>
+ END
+ call writefile(lines, 'Xcul_screenline')
+
+ let buf = RunVimInTerminal('-S Xcul_screenline', #{rows: 8})
+ call term_sendkeys(buf, "A")
+ call VerifyScreenDump(buf, 'Test_cursorline_screenline_1', {})
+ call term_sendkeys(buf, "\<F2>")
+ call VerifyScreenDump(buf, 'Test_cursorline_screenline_2', {})
+ call term_sendkeys(buf, "\<Esc>")
+
+ call StopVimInTerminal(buf)
+ call delete('Xcul_screenline')
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_display.vim b/src/nvim/testdir/test_display.vim
index 9f74d0a38a..094283a3a3 100644
--- a/src/nvim/testdir/test_display.vim
+++ b/src/nvim/testdir/test_display.vim
@@ -263,6 +263,27 @@ func Test_display_scroll_at_topline()
call StopVimInTerminal(buf)
endfunc
+func Test_display_scroll_update_visual()
+ CheckScreendump
+
+ let lines =<< trim END
+ set scrolloff=0
+ call setline(1, repeat(['foo'], 10))
+ call sign_define('foo', { 'text': '>' })
+ call sign_place(1, 'bar', 'foo', bufnr(), { 'lnum': 2 })
+ call sign_place(2, 'bar', 'foo', bufnr(), { 'lnum': 1 })
+ autocmd CursorMoved * if getcurpos()[1] == 2 | call sign_unplace('bar', { 'id': 1 }) | endif
+ END
+ call writefile(lines, 'XupdateVisual.vim')
+
+ let buf = RunVimInTerminal('-S XupdateVisual.vim', #{rows: 8, cols: 60})
+ call term_sendkeys(buf, "VG7kk")
+ call VerifyScreenDump(buf, 'Test_display_scroll_update_visual', {})
+
+ call StopVimInTerminal(buf)
+ call delete('XupdateVisual.vim')
+endfunc
+
" Test for 'eob' (EndOfBuffer) item in 'fillchars'
func Test_eob_fillchars()
" default value (skipped)
diff --git a/src/nvim/testdir/test_filechanged.vim b/src/nvim/testdir/test_filechanged.vim
index 06ccd6e85f..8e1cb2c3ee 100644
--- a/src/nvim/testdir/test_filechanged.vim
+++ b/src/nvim/testdir/test_filechanged.vim
@@ -142,6 +142,7 @@ endfunc
func Test_FileChangedShell_edit_dialog()
throw 'Skipped: requires a UI to be active'
CheckNotGui
+ CheckUnix " Using low level feedkeys() does not work on MS-Windows.
new Xchanged_r
call setline(1, 'reload this')
diff --git a/src/nvim/testdir/test_filetype.vim b/src/nvim/testdir/test_filetype.vim
index 839d160e39..dd08d8bd09 100644
--- a/src/nvim/testdir/test_filetype.vim
+++ b/src/nvim/testdir/test_filetype.vim
@@ -381,6 +381,7 @@ let s:filename_checks = {
\ 'opam': ['opam', 'file.opam', 'file.opam.template'],
\ 'openroad': ['file.or'],
\ 'ora': ['file.ora'],
+ \ 'org': ['file.org', 'file.org_archive'],
\ 'pamconf': ['/etc/pam.conf', '/etc/pam.d/file', 'any/etc/pam.conf', 'any/etc/pam.d/file'],
\ 'pamenv': ['/etc/security/pam_env.conf', '/home/user/.pam_environment', '.pam_environment', 'pam_env.conf'],
\ 'papp': ['file.papp', 'file.pxml', 'file.pxsl'],
diff --git a/src/nvim/testdir/test_highlight.vim b/src/nvim/testdir/test_highlight.vim
index aa7b3a225b..6387ec62af 100644
--- a/src/nvim/testdir/test_highlight.vim
+++ b/src/nvim/testdir/test_highlight.vim
@@ -597,6 +597,31 @@ func Test_cursorline_with_visualmode()
call delete('Xtest_cursorline_with_visualmode')
endfunc
+func Test_cursorcolumn_callback()
+ CheckScreendump
+ CheckFeature timers
+
+ let lines =<< trim END
+ call setline(1, ['aaaaa', 'bbbbb', 'ccccc', 'ddddd'])
+ set cursorcolumn
+ call cursor(4, 5)
+
+ func Func(timer)
+ call cursor(1, 1)
+ endfunc
+
+ call timer_start(300, 'Func')
+ END
+ call writefile(lines, 'Xcuc_timer')
+
+ let buf = RunVimInTerminal('-S Xcuc_timer', #{rows: 8})
+ call TermWait(buf, 310)
+ call VerifyScreenDump(buf, 'Test_cursorcolumn_callback_1', {})
+
+ call StopVimInTerminal(buf)
+ call delete('Xcuc_timer')
+endfunc
+
func Test_colorcolumn()
CheckScreendump
diff --git a/src/nvim/testdir/test_messages.vim b/src/nvim/testdir/test_messages.vim
index 9c84d77dd2..82c4cc128b 100644
--- a/src/nvim/testdir/test_messages.vim
+++ b/src/nvim/testdir/test_messages.vim
@@ -2,6 +2,9 @@
source check.vim
source shared.vim
+source term_util.vim
+source view_util.vim
+source screendump.vim
func Test_messages()
let oldmore = &more
@@ -109,6 +112,22 @@ func Test_echospace()
set ruler& showcmd&
endfunc
+func Test_quit_long_message()
+ CheckScreendump
+
+ let content =<< trim END
+ echom range(9999)->join("\x01")
+ END
+ call writefile(content, 'Xtest_quit_message')
+ let buf = RunVimInTerminal('-S Xtest_quit_message', #{rows: 6})
+ call term_sendkeys(buf, "q")
+ call VerifyScreenDump(buf, 'Test_quit_long_message', {})
+
+ " clean up
+ call StopVimInTerminal(buf)
+ call delete('Xtest_quit_message')
+endfunc
+
" this was missing a terminating NUL
func Test_echo_string_partial()
function CountSpaces()
@@ -116,3 +135,37 @@ func Test_echo_string_partial()
call assert_equal("function('CountSpaces', [{'ccccccccccc': ['ab', 'cd'], 'aaaaaaaaaaa': v:false, 'bbbbbbbbbbbb': ''}])", string(function('CountSpaces', [#{aaaaaaaaaaa: v:false, bbbbbbbbbbbb: '', ccccccccccc: ['ab', 'cd']}])))
endfunc
+" Message output was previously overwritten by the fileinfo display, shown
+" when switching buffers. If a buffer is switched to, then a message if
+" echoed, we should show the message, rather than overwriting it with
+" fileinfo.
+func Test_fileinfo_after_echo()
+ CheckScreendump
+
+ let content =<< trim END
+ file a.txt
+
+ hide edit b.txt
+ call setline(1, "hi")
+ setlocal modified
+
+ hide buffer a.txt
+
+ autocmd CursorHold * buf b.txt | w | echo "'b' written"
+ END
+
+ call writefile(content, 'Xtest_fileinfo_after_echo')
+ let buf = RunVimInTerminal('-S Xtest_fileinfo_after_echo', #{rows: 6})
+ call term_sendkeys(buf, ":set updatetime=50\<CR>")
+ call term_sendkeys(buf, "0$")
+ call VerifyScreenDump(buf, 'Test_fileinfo_after_echo', {})
+
+ call term_sendkeys(buf, ":q\<CR>")
+
+ " clean up
+ call StopVimInTerminal(buf)
+ call delete('Xtest_fileinfo_after_echo')
+ call delete('b.txt')
+endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_mksession.vim b/src/nvim/testdir/test_mksession.vim
index 798cb9e54f..5dbe2cd366 100644
--- a/src/nvim/testdir/test_mksession.vim
+++ b/src/nvim/testdir/test_mksession.vim
@@ -795,6 +795,49 @@ func Test_mksession_winminheight()
set sessionoptions&
endfunc
+" Test for mksession with and without options restores shortmess
+func Test_mksession_shortmess()
+ " Without options
+ set sessionoptions-=options
+ split
+ mksession! Xtest_mks.out
+ let found_save = 0
+ let found_restore = 0
+ let lines = readfile('Xtest_mks.out')
+ for line in lines
+ let line = trim(line)
+
+ if line ==# 'let s:shortmess_save = &shortmess'
+ let found_save += 1
+ endif
+
+ if found_save !=# 0 && line ==# 'let &shortmess = s:shortmess_save'
+ let found_restore += 1
+ endif
+ endfor
+ call assert_equal(1, found_save)
+ call assert_equal(1, found_restore)
+ call delete('Xtest_mks.out')
+ close
+ set sessionoptions&
+
+ " With options
+ set sessionoptions+=options
+ split
+ mksession! Xtest_mks.out
+ let found_restore = 0
+ let lines = readfile('Xtest_mks.out')
+ for line in lines
+ if line =~# 's:shortmess_save'
+ let found_restore += 1
+ endif
+ endfor
+ call assert_equal(0, found_restore)
+ call delete('Xtest_mks.out')
+ close
+ set sessionoptions&
+endfunc
+
" Test for mksession with 'compatible' option
func Test_mksession_compatible()
throw 'skipped: Nvim does not support "compatible" option'
diff --git a/src/nvim/testdir/test_number.vim b/src/nvim/testdir/test_number.vim
index dfbdc0bffd..521b0cf706 100644
--- a/src/nvim/testdir/test_number.vim
+++ b/src/nvim/testdir/test_number.vim
@@ -298,6 +298,31 @@ func Test_relativenumber_colors()
call delete('XTest_relnr')
endfunc
+func Test_relativenumber_callback()
+ CheckScreendump
+ CheckFeature timers
+
+ let lines =<< trim END
+ call setline(1, ['aaaaa', 'bbbbb', 'ccccc', 'ddddd'])
+ set relativenumber
+ call cursor(4, 1)
+
+ func Func(timer)
+ call cursor(1, 1)
+ endfunc
+
+ call timer_start(300, 'Func')
+ END
+ call writefile(lines, 'Xrnu_timer')
+
+ let buf = RunVimInTerminal('-S Xrnu_timer', #{rows: 8})
+ call TermWait(buf, 310)
+ call VerifyScreenDump(buf, 'Test_relativenumber_callback_1', {})
+
+ call StopVimInTerminal(buf)
+ call delete('Xrnu_timer')
+endfunc
+
" Test for displaying line numbers with 'rightleft'
func Test_number_rightleft()
CheckFeature rightleft
diff --git a/src/nvim/testdir/test_quickfix.vim b/src/nvim/testdir/test_quickfix.vim
index 14d13049d9..5457223677 100644
--- a/src/nvim/testdir/test_quickfix.vim
+++ b/src/nvim/testdir/test_quickfix.vim
@@ -796,101 +796,102 @@ func ReadTestProtocol(name)
endfunc
func Test_locationlist()
- enew
+ enew
- augroup testgroup
- au!
- autocmd BufReadCmd test://* call ReadTestProtocol(expand("<amatch>"))
- augroup END
+ augroup testgroup
+ au!
+ autocmd BufReadCmd test://* call ReadTestProtocol(expand("<amatch>"))
+ augroup END
- let words = [ "foo", "bar", "baz", "quux", "shmoo", "spam", "eggs" ]
+ let words = [ "foo", "bar", "baz", "quux", "shmoo", "spam", "eggs" ]
- let qflist = []
- for word in words
- call add(qflist, {'filename': 'test://' . word . '.txt', 'text': 'file ' . word . '.txt', })
- " NOTE: problem 1:
- " intentionally not setting 'lnum' so that the quickfix entries are not
- " valid
- eval qflist->setloclist(0, ' ')
- endfor
+ let qflist = []
+ for word in words
+ call add(qflist, {'filename': 'test://' . word . '.txt', 'text': 'file ' . word . '.txt', })
+ " NOTE: problem 1:
+ " intentionally not setting 'lnum' so that the quickfix entries are not
+ " valid
+ eval qflist->setloclist(0, ' ')
+ endfor
- " Test A
- lrewind
- enew
- lopen
- 4lnext
- vert split
- wincmd L
- lopen
- wincmd p
- lnext
- let fileName = expand("%")
- wincmd p
- let locationListFileName = substitute(getline(line('.')), '\([^|]*\)|.*', '\1', '')
- let fileName = substitute(fileName, '\\', '/', 'g')
- let locationListFileName = substitute(locationListFileName, '\\', '/', 'g')
- call assert_equal("test://bar.txt", fileName)
- call assert_equal("test://bar.txt", locationListFileName)
+ " Test A
+ lrewind
+ enew
+ lopen
+ 4lnext
+ vert split
+ wincmd L
+ lopen
+ wincmd p
+ lnext
+ let fileName = expand("%")
+ wincmd p
+ let locationListFileName = substitute(getline(line('.')), '\([^|]*\)|.*', '\1', '')
+ let fileName = substitute(fileName, '\\', '/', 'g')
+ let locationListFileName = substitute(locationListFileName, '\\', '/', 'g')
+ call assert_equal("test://bar.txt", fileName)
+ call assert_equal("test://bar.txt", locationListFileName)
- wincmd n | only
+ wincmd n | only
- " Test B:
- lrewind
- lopen
- 2
- exe "normal \<CR>"
- wincmd p
- 3
- exe "normal \<CR>"
- wincmd p
- 4
- exe "normal \<CR>"
- call assert_equal(2, winnr('$'))
- wincmd n | only
+ " Test B:
+ lrewind
+ lopen
+ 2
+ exe "normal \<CR>"
+ wincmd p
+ 3
+ exe "normal \<CR>"
+ wincmd p
+ 4
+ exe "normal \<CR>"
+ call assert_equal(2, winnr('$'))
+ wincmd n | only
- " Test C:
- lrewind
- lopen
- " Let's move the location list window to the top to check whether it (the
- " first window found) will be reused when we try to open new windows:
- wincmd K
- 2
- exe "normal \<CR>"
- wincmd p
- 3
- exe "normal \<CR>"
- wincmd p
- 4
- exe "normal \<CR>"
- 1wincmd w
- call assert_equal('quickfix', &buftype)
- 2wincmd w
- let bufferName = expand("%")
- let bufferName = substitute(bufferName, '\\', '/', 'g')
- call assert_equal('test://quux.txt', bufferName)
+ " Test C:
+ lrewind
+ lopen
+ " Let's move the location list window to the top to check whether it (the
+ " first window found) will be reused when we try to open new windows:
+ wincmd K
+ 2
+ exe "normal \<CR>"
+ wincmd p
+ 3
+ exe "normal \<CR>"
+ wincmd p
+ 4
+ exe "normal \<CR>"
+ 1wincmd w
+ call assert_equal('quickfix', &buftype)
+ 2wincmd w
+ let bufferName = expand("%")
+ let bufferName = substitute(bufferName, '\\', '/', 'g')
+ call assert_equal('test://quux.txt', bufferName)
- wincmd n | only
+ wincmd n | only
- augroup! testgroup
+ augroup! testgroup
endfunc
func Test_locationlist_curwin_was_closed()
- augroup testgroup
- au!
- autocmd BufReadCmd test_curwin.txt call R(expand("<amatch>"))
- augroup END
+ augroup testgroup
+ au!
+ autocmd BufReadCmd test_curwin.txt call R(expand("<amatch>"))
+ augroup END
- func! R(n)
- quit
- endfunc
+ func! R(n)
+ quit
+ endfunc
- new
- let q = []
- call add(q, {'filename': 'test_curwin.txt' })
- call setloclist(0, q)
- call assert_fails('lrewind', 'E924:')
+ new
+ let q = []
+ call add(q, {'filename': 'test_curwin.txt' })
+ call setloclist(0, q)
+ call assert_fails('lrewind', 'E924:')
- augroup! testgroup
+ augroup! testgroup
+ delfunc R
endfunc
func Test_locationlist_cross_tab_jump()
@@ -5489,4 +5490,45 @@ func Test_two_qf_windows()
%bw!
endfunc
+" Weird sequence of commands that caused entering a wiped-out buffer
+func Test_lopen_bwipe()
+ func R()
+ silent! tab lopen
+ e x
+ silent! lfile
+ endfunc
+
+ cal R()
+ cal R()
+ cal R()
+ bw!
+ delfunc R
+endfunc
+
+" Another sequence of commands that caused all buffers to be wiped out
+func Test_lopen_bwipe_all()
+ let lines =<< trim END
+ func R()
+ silent! tab lopen
+ e foo
+ silent! lfile
+ endfunc
+ cal R()
+ exe "norm \<C-W>\<C-V>0"
+ cal R()
+ bwipe
+
+ call writefile(['done'], 'Xresult')
+ qall!
+ END
+ call writefile(lines, 'Xscript')
+ if RunVim([], [], '--clean -n -S Xscript')
+ call assert_equal(['done'], readfile('Xresult'))
+ endif
+
+ call delete('Xscript')
+ call delete('Xresult')
+endfunc
+
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_regexp_latin.vim b/src/nvim/testdir/test_regexp_latin.vim
index a0f5ebfb9f..b733e334de 100644
--- a/src/nvim/testdir/test_regexp_latin.vim
+++ b/src/nvim/testdir/test_regexp_latin.vim
@@ -787,12 +787,109 @@ func Test_regexp_error()
set re&
endfunc
+" Check patterns matching cursor position.
+func s:curpos_test2()
+ new
+ call setline(1, ['1', '2 foobar eins zwei drei vier fünf sechse',
+ \ '3 foobar eins zwei drei vier fünf sechse',
+ \ '4 foobar eins zwei drei vier fünf sechse',
+ \ '5 foobar eins zwei drei vier fünf sechse',
+ \ '6 foobar eins zwei drei vier fünf sechse',
+ \ '7 foobar eins zwei drei vier fünf sechse'])
+ call setpos('.', [0, 2, 10, 0])
+ s/\%.c.*//g
+ call setpos('.', [0, 3, 15, 0])
+ s/\%.l.*//g
+ call setpos('.', [0, 5, 3, 0])
+ s/\%.v.*/_/g
+ call assert_equal(['1',
+ \ '2 foobar ',
+ \ '',
+ \ '4 foobar eins zwei drei vier fünf sechse',
+ \ '5 _',
+ \ '6 foobar eins zwei drei vier fünf sechse',
+ \ '7 foobar eins zwei drei vier fünf sechse'],
+ \ getline(1, '$'))
+ call assert_fails('call search("\\%.1l")', 'E1204:')
+ call assert_fails('call search("\\%.1c")', 'E1204:')
+ call assert_fails('call search("\\%.1v")', 'E1204:')
+ bwipe!
+endfunc
+
+" Check patterns matching before or after cursor position.
+func s:curpos_test3()
+ new
+ call setline(1, ['1', '2 foobar eins zwei drei vier fünf sechse',
+ \ '3 foobar eins zwei drei vier fünf sechse',
+ \ '4 foobar eins zwei drei vier fünf sechse',
+ \ '5 foobar eins zwei drei vier fünf sechse',
+ \ '6 foobar eins zwei drei vier fünf sechse',
+ \ '7 foobar eins zwei drei vier fünf sechse'])
+ call setpos('.', [0, 2, 10, 0])
+ " Note: This removes all columns, except for the column directly in front of
+ " the cursor. Bug????
+ :s/^.*\%<.c//
+ call setpos('.', [0, 3, 10, 0])
+ :s/\%>.c.*$//
+ call setpos('.', [0, 5, 4, 0])
+ " Note: This removes all columns, except for the column directly in front of
+ " the cursor. Bug????
+ :s/^.*\%<.v/_/
+ call setpos('.', [0, 6, 4, 0])
+ :s/\%>.v.*$/_/
+ call assert_equal(['1',
+ \ ' eins zwei drei vier fünf sechse',
+ \ '3 foobar e',
+ \ '4 foobar eins zwei drei vier fünf sechse',
+ \ '_foobar eins zwei drei vier fünf sechse',
+ \ '6 fo_',
+ \ '7 foobar eins zwei drei vier fünf sechse'],
+ \ getline(1, '$'))
+ sil %d
+ call setline(1, ['1', '2 foobar eins zwei drei vier fünf sechse',
+ \ '3 foobar eins zwei drei vier fünf sechse',
+ \ '4 foobar eins zwei drei vier fünf sechse',
+ \ '5 foobar eins zwei drei vier fünf sechse',
+ \ '6 foobar eins zwei drei vier fünf sechse',
+ \ '7 foobar eins zwei drei vier fünf sechse'])
+ call setpos('.', [0, 4, 4, 0])
+ %s/\%<.l.*//
+ call setpos('.', [0, 5, 4, 0])
+ %s/\%>.l.*//
+ call assert_equal(['', '', '',
+ \ '4 foobar eins zwei drei vier fünf sechse',
+ \ '5 foobar eins zwei drei vier fünf sechse',
+ \ '', ''],
+ \ getline(1, '$'))
+ bwipe!
+endfunc
+
+" Test that matching below, at or after the
+" cursor position work
+func Test_matching_pos()
+ for val in range(3)
+ exe "set re=" .. val
+ " Match at cursor position
+ call s:curpos_test2()
+ " Match before or after cursor position
+ call s:curpos_test3()
+ endfor
+ set re&
+endfunc
+
func Test_using_mark_position()
" this was using freed memory
+ " new engine
new
norm O0
call assert_fails("s/\\%')", 'E486:')
bwipe!
+
+ " old engine
+ new
+ norm O0
+ call assert_fails("s/\\%#=1\\%')", 'E486:')
+ bwipe!
endfunc
func Test_using_visual_position()
diff --git a/src/nvim/testdir/test_sort.vim b/src/nvim/testdir/test_sort.vim
index f72368fc59..5d7dd7bfff 100644
--- a/src/nvim/testdir/test_sort.vim
+++ b/src/nvim/testdir/test_sort.vim
@@ -59,6 +59,7 @@ endfunc
func Test_sort_numbers()
call assert_equal([3, 13, 28], sort([13, 28, 3], 'N'))
call assert_equal(['3', '13', '28'], sort(['13', '28', '3'], 'N'))
+ call assert_equal([3997, 4996], sort([4996, 3997], 'Compare1'))
endfunc
func Test_sort_float()
diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c
index 79a6b9ed0e..a67bcf98dc 100644
--- a/src/nvim/tui/tui.c
+++ b/src/nvim/tui/tui.c
@@ -131,6 +131,7 @@ typedef struct {
int get_bg;
int set_underline_style;
int set_underline_color;
+ int enable_extended_keys, disable_extended_keys;
} unibi_ext;
char *space_buf;
} TUIData;
@@ -168,7 +169,7 @@ UI *tui_start(void)
ui->set_title = tui_set_title;
ui->set_icon = tui_set_icon;
ui->screenshot = tui_screenshot;
- ui->option_set= tui_option_set;
+ ui->option_set = tui_option_set;
ui->raw_line = tui_raw_line;
memset(ui->ui_ext, 0, sizeof(ui->ui_ext));
@@ -225,6 +226,8 @@ static void terminfo_start(UI *ui)
data->unibi_ext.reset_cursor_style = -1;
data->unibi_ext.get_bg = -1;
data->unibi_ext.set_underline_color = -1;
+ data->unibi_ext.enable_extended_keys = -1;
+ data->unibi_ext.disable_extended_keys = -1;
data->out_fd = STDOUT_FILENO;
data->out_isatty = os_isatty(data->out_fd);
@@ -308,6 +311,10 @@ static void terminfo_start(UI *ui)
// Enable bracketed paste
unibi_out_ext(ui, data->unibi_ext.enable_bracketed_paste);
+ // Enable extended keys (also known as 'modifyOtherKeys' or CSI u). On terminals that don't
+ // support this, this sequence is ignored.
+ unibi_out_ext(ui, data->unibi_ext.enable_extended_keys);
+
int ret;
uv_loop_init(&data->write_loop);
if (data->out_isatty) {
@@ -365,6 +372,8 @@ static void terminfo_stop(UI *ui)
unibi_out_ext(ui, data->unibi_ext.disable_bracketed_paste);
// Disable focus reporting
unibi_out_ext(ui, data->unibi_ext.disable_focus_reporting);
+ // Disable extended keys
+ unibi_out_ext(ui, data->unibi_ext.disable_extended_keys);
flush_buf(ui);
uv_tty_reset_mode();
uv_close((uv_handle_t *)&data->output_handle, NULL);
@@ -1378,7 +1387,6 @@ static void tui_screenshot(UI *ui, String path)
fclose(f);
}
-
static void tui_option_set(UI *ui, String name, Object value)
{
TUIData *data = ui->data;
@@ -1387,11 +1395,9 @@ static void tui_option_set(UI *ui, String name, Object value)
data->print_attr_id = -1;
invalidate(ui, 0, data->grid.height, 0, data->grid.width);
- }
- if (strequal(name.data, "ttimeout")) {
+ } else if (strequal(name.data, "ttimeout")) {
data->input.ttimeout = value.data.boolean;
- }
- if (strequal(name.data, "ttimeoutlen")) {
+ } else if (strequal(name.data, "ttimeoutlen")) {
data->input.ttimeoutlen = (long)value.data.integer;
}
}
@@ -1944,6 +1950,7 @@ static void augment_terminfo(TUIData *data, const char *term, long vte_version,
|| terminfo_is_term_family(term, "iTerm.app")
|| terminfo_is_term_family(term, "iTerm2.app");
bool alacritty = terminfo_is_term_family(term, "alacritty");
+ bool kitty = terminfo_is_term_family(term, "xterm-kitty");
// None of the following work over SSH; see :help TERM .
bool iterm_pretending_xterm = xterm && iterm_env;
@@ -2067,6 +2074,15 @@ static void augment_terminfo(TUIData *data, const char *term, long vte_version,
data->unibi_ext.set_underline_color = (int)unibi_add_ext_str(ut, "ext.set_underline_color",
"\x1b[58:2::%p1%d:%p2%d:%p3%dm");
}
+
+ if (!kitty) {
+ // Kitty does not support these sequences; it only supports it's own CSI > 1 u which enables the
+ // Kitty keyboard protocol
+ data->unibi_ext.enable_extended_keys = (int)unibi_add_ext_str(ut, "ext.enable_extended_keys",
+ "\x1b[>4;2m");
+ data->unibi_ext.disable_extended_keys = (int)unibi_add_ext_str(ut, "ext.disable_extended_keys",
+ "\x1b[>4;0m");
+ }
}
static void flush_buf(UI *ui)
diff --git a/src/nvim/ui_client.c b/src/nvim/ui_client.c
index e723a30d32..6a7695bf72 100644
--- a/src/nvim/ui_client.c
+++ b/src/nvim/ui_client.c
@@ -151,10 +151,8 @@ void ui_client_event_grid_line(Array args)
Integer startcol = args.items[2].data.integer;
Array cells = args.items[3].data.array;
- Integer endcol, clearcol;
- // TODO(hlpr98): Accomodate other LineFlags when included in grid_line
+ // TODO(hlpr98): Accommodate other LineFlags when included in grid_line
LineFlags lineflags = 0;
- endcol = startcol;
size_t j = 0;
int cur_attr = 0;
@@ -203,8 +201,8 @@ void ui_client_event_grid_line(Array args)
}
}
- endcol = startcol + (int)j;
- clearcol = endcol + clear_width;
+ Integer endcol = startcol + (int)j;
+ Integer clearcol = endcol + clear_width;
clear_attr = cur_attr;
ui_call_raw_line(grid, row, startcol, endcol, clearcol, clear_attr, lineflags,
diff --git a/src/nvim/window.c b/src/nvim/window.c
index fa71a08b94..632e9b3f44 100644
--- a/src/nvim/window.c
+++ b/src/nvim/window.c
@@ -971,7 +971,6 @@ int win_split_ins(int size, int flags, win_T *new_wp, int dir)
int before;
int minheight;
int wmh1;
- int hsep_height;
bool did_set_fraction = false;
// aucmd_win should always remain floating
@@ -1084,7 +1083,6 @@ int win_split_ins(int size, int flags, win_T *new_wp, int dir)
}
}
} else {
- hsep_height = STATUS_HEIGHT;
layout = FR_COL;
/*
@@ -1093,7 +1091,7 @@ int win_split_ins(int size, int flags, win_T *new_wp, int dir)
*/
// Current window requires at least 1 space.
wmh1 = p_wmh == 0 ? 1 : p_wmh;
- needed = wmh1 + hsep_height;
+ needed = wmh1 + STATUS_HEIGHT;
if (flags & WSP_ROOM) {
needed += p_wh - wmh1;
}
@@ -1135,15 +1133,15 @@ int win_split_ins(int size, int flags, win_T *new_wp, int dir)
new_size = oldwin_height / 2;
}
- if (new_size > available - minheight - hsep_height) {
- new_size = available - minheight - hsep_height;
+ if (new_size > available - minheight - STATUS_HEIGHT) {
+ new_size = available - minheight - STATUS_HEIGHT;
}
if (new_size < wmh1) {
new_size = wmh1;
}
// if it doesn't fit in the current window, need win_equal()
- if (oldwin_height - new_size - hsep_height < p_wmh) {
+ if (oldwin_height - new_size - STATUS_HEIGHT < p_wmh) {
do_equal = true;
}
@@ -1156,7 +1154,7 @@ int win_split_ins(int size, int flags, win_T *new_wp, int dir)
set_fraction(oldwin);
did_set_fraction = true;
- win_setheight_win(oldwin->w_height + new_size + hsep_height,
+ win_setheight_win(oldwin->w_height + new_size + STATUS_HEIGHT,
oldwin);
oldwin_height = oldwin->w_height;
if (need_status) {
@@ -1173,7 +1171,7 @@ int win_split_ins(int size, int flags, win_T *new_wp, int dir)
while (frp != NULL) {
if (frp->fr_win != oldwin && frp->fr_win != NULL
&& (frp->fr_win->w_height > new_size
- || frp->fr_win->w_height > oldwin_height - new_size - hsep_height)) {
+ || frp->fr_win->w_height > oldwin_height - new_size - STATUS_HEIGHT)) {
do_equal = true;
break;
}
@@ -2021,7 +2019,6 @@ static void win_equal_rec(win_T *next_curwin, bool current, frame_T *topfr, int
int room = 0;
int new_size;
int has_next_curwin = 0;
- int hsep_height;
bool hnc;
if (topfr->fr_layout == FR_LEAF) {
@@ -2167,7 +2164,6 @@ static void win_equal_rec(win_T *next_curwin, bool current, frame_T *topfr, int
totwincount -= wincount;
}
} else { // topfr->fr_layout == FR_COL
- hsep_height = STATUS_HEIGHT;
topfr->fr_width = width;
topfr->fr_height = height;
@@ -2182,7 +2178,7 @@ static void win_equal_rec(win_T *next_curwin, bool current, frame_T *topfr, int
} else {
extra_sep = 0;
}
- totwincount = (n + extra_sep) / (p_wmh + hsep_height);
+ totwincount = (n + extra_sep) / (p_wmh + STATUS_HEIGHT);
has_next_curwin = frame_has_win(topfr, next_curwin);
/*
@@ -2217,7 +2213,7 @@ static void win_equal_rec(win_T *next_curwin, bool current, frame_T *topfr, int
} else {
// These windows don't use up room.
totwincount -= (n + (fr->fr_next == NULL
- ? extra_sep : 0)) / (p_wmh + hsep_height);
+ ? extra_sep : 0)) / (p_wmh + STATUS_HEIGHT);
}
room -= new_size - n;
if (room < 0) {
@@ -2263,7 +2259,7 @@ static void win_equal_rec(win_T *next_curwin, bool current, frame_T *topfr, int
// Compute the maximum number of windows vert. in "fr".
n = frame_minheight(fr, NOWIN);
wincount = (n + (fr->fr_next == NULL ? extra_sep : 0))
- / (p_wmh + hsep_height);
+ / (p_wmh + STATUS_HEIGHT);
m = frame_minheight(fr, next_curwin);
if (has_next_curwin) {
hnc = frame_has_win(fr, next_curwin);
@@ -2350,6 +2346,30 @@ void entering_window(win_T *const win)
}
}
+void win_init_empty(win_T *wp)
+{
+ redraw_later(wp, NOT_VALID);
+ wp->w_lines_valid = 0;
+ wp->w_cursor.lnum = 1;
+ wp->w_curswant = wp->w_cursor.col = 0;
+ wp->w_cursor.coladd = 0;
+ wp->w_pcmark.lnum = 1; // pcmark not cleared but set to line 1
+ wp->w_pcmark.col = 0;
+ wp->w_prev_pcmark.lnum = 0;
+ wp->w_prev_pcmark.col = 0;
+ wp->w_topline = 1;
+ wp->w_topfill = 0;
+ wp->w_botline = 2;
+ wp->w_s = &wp->w_buffer->b_s;
+}
+
+/// Init the current window "curwin".
+/// Called when a new file is being edited.
+void curwin_init(void)
+{
+ win_init_empty(curwin);
+}
+
/// Closes all windows for buffer `buf` unless there is only one non-floating window.
///
/// @param keep_curwin don't close `curwin`
@@ -2867,6 +2887,13 @@ void win_close_othertab(win_T *win, int free_buf, tabpage_T *tp)
for (ptp = first_tabpage; ptp != NULL && ptp != tp; ptp = ptp->tp_next) {
}
if (ptp == NULL || tp == curtab) {
+ // If the buffer was removed from the window we have to give it any
+ // buffer.
+ if (win_valid_any_tab(win) && win->w_buffer == NULL) {
+ win->w_buffer = firstbuf;
+ firstbuf->b_nwindows++;
+ win_init_empty(win);
+ }
return;
}
@@ -3793,33 +3820,6 @@ void close_others(int message, int forceit)
}
}
-
-/*
- * Init the current window "curwin".
- * Called when a new file is being edited.
- */
-void curwin_init(void)
-{
- win_init_empty(curwin);
-}
-
-void win_init_empty(win_T *wp)
-{
- redraw_later(wp, NOT_VALID);
- wp->w_lines_valid = 0;
- wp->w_cursor.lnum = 1;
- wp->w_curswant = wp->w_cursor.col = 0;
- wp->w_cursor.coladd = 0;
- wp->w_pcmark.lnum = 1; // pcmark not cleared but set to line 1
- wp->w_pcmark.col = 0;
- wp->w_prev_pcmark.lnum = 0;
- wp->w_prev_pcmark.col = 0;
- wp->w_topline = 1;
- wp->w_topfill = 0;
- wp->w_botline = 2;
- wp->w_s = &wp->w_buffer->b_s;
-}
-
/*
* Allocate the first window and put an empty buffer in it.
* Called from main().
@@ -5857,11 +5857,11 @@ void win_drag_status_line(win_T *dragwin, int offset)
} else { // drag down
up = false;
// Only dragging the last status line can reduce p_ch.
- room = Rows - cmdline_row - global_stl_height();
+ room = Rows - cmdline_row;
if (curfr->fr_next == NULL) {
room -= 1;
} else {
- room -= p_ch;
+ room -= p_ch + global_stl_height();
}
if (room < 0) {
room = 0;
@@ -6510,38 +6510,32 @@ void last_status(bool morewin)
}
// Look for resizable frames and take lines from them to make room for the statusline
-static void resize_frame_for_status(frame_T *fr, int resize_amount)
+static void resize_frame_for_status(frame_T *fr)
{
// Find a frame to take a line from.
frame_T *fp = fr;
win_T *wp = fr->fr_win;
- int n;
- while (resize_amount > 0) {
- while (fp->fr_height <= frame_minheight(fp, NULL)) {
- if (fp == topframe) {
- emsg(_(e_noroom));
- return;
- }
- // In a column of frames: go to frame above. If already at
- // the top or in a row of frames: go to parent.
- if (fp->fr_parent->fr_layout == FR_COL && fp->fr_prev != NULL) {
- fp = fp->fr_prev;
- } else {
- fp = fp->fr_parent;
- }
+ while (fp->fr_height <= frame_minheight(fp, NULL)) {
+ if (fp == topframe) {
+ emsg(_(e_noroom));
+ return;
}
- n = MIN(fp->fr_height - frame_minheight(fp, NULL), resize_amount);
- resize_amount -= n;
-
- if (fp != fr) {
- frame_new_height(fp, fp->fr_height - n, false, false);
- frame_fix_height(wp);
- (void)win_comp_pos();
+ // In a column of frames: go to frame above. If already at
+ // the top or in a row of frames: go to parent.
+ if (fp->fr_parent->fr_layout == FR_COL && fp->fr_prev != NULL) {
+ fp = fp->fr_prev;
} else {
- win_new_height(wp, wp->w_height - n);
+ fp = fp->fr_parent;
}
}
+ if (fp != fr) {
+ frame_new_height(fp, fp->fr_height - 1, false, false);
+ frame_fix_height(wp);
+ (void)win_comp_pos();
+ } else {
+ win_new_height(wp, wp->w_height - 1);
+ }
}
static void last_status_rec(frame_T *fr, bool statusline, bool is_stl_global)
@@ -6562,15 +6556,12 @@ static void last_status_rec(frame_T *fr, bool statusline, bool is_stl_global)
} else if (wp->w_status_height == 0 && !is_stl_global && statusline) {
// Add statusline to window if needed
wp->w_status_height = STATUS_HEIGHT;
- resize_frame_for_status(fr, STATUS_HEIGHT);
+ resize_frame_for_status(fr);
comp_col();
}
} else if (wp->w_status_height != 0 && is_stl_global) {
// If statusline is global and the window has a statusline, replace it with a horizontal
// separator
- if (STATUS_HEIGHT - 1 != 0) {
- win_new_height(wp, wp->w_height + STATUS_HEIGHT - 1);
- }
wp->w_status_height = 0;
wp->w_hsep_height = 1;
comp_col();
@@ -6578,7 +6569,6 @@ static void last_status_rec(frame_T *fr, bool statusline, bool is_stl_global)
// If statusline isn't global and the window doesn't have a statusline, re-add it
wp->w_status_height = STATUS_HEIGHT;
wp->w_hsep_height = 0;
- resize_frame_for_status(fr, STATUS_HEIGHT - 1);
comp_col();
}
redraw_all_later(SOME_VALID);
diff --git a/test/busted/outputHandlers/nvim.lua b/test/busted/outputHandlers/nvim.lua
index 0e9801b94b..5e9c52e0bd 100644
--- a/test/busted/outputHandlers/nvim.lua
+++ b/test/busted/outputHandlers/nvim.lua
@@ -1,5 +1,4 @@
local pretty = require 'pl.pretty'
-local global_helpers = require('test.helpers')
-- Colors are disabled by default. #15610
local colors = setmetatable({}, {__index = function() return function(s) return s == nil and '' or tostring(s) end end})
@@ -192,7 +191,6 @@ return function(options)
local tests = (testCount == 1 and 'test' or 'tests')
local files = (fileCount == 1 and 'file' or 'files')
io.write(globalTeardown)
- io.write(global_helpers.read_nvim_log(nil, true))
io.write(suiteEndString:format(testCount, tests, fileCount, files, elapsedTime_ms))
io.write(getSummaryString())
io.flush()
diff --git a/test/functional/api/autocmd_spec.lua b/test/functional/api/autocmd_spec.lua
index a58ca00a75..b4a9a4f01f 100644
--- a/test/functional/api/autocmd_spec.lua
+++ b/test/functional/api/autocmd_spec.lua
@@ -168,7 +168,7 @@ describe('autocmd api', function()
})
]]
- meths.do_autocmd("User", {pattern = "Test"})
+ meths.exec_autocmds("User", {pattern = "Test"})
eq({{
buflocal = false,
command = 'A test autocommand',
@@ -179,7 +179,7 @@ describe('autocmd api', function()
pattern = 'Test',
}}, meths.get_autocmds({event = "User", pattern = "Test"}))
meths.set_var("some_condition", true)
- meths.do_autocmd("User", {pattern = "Test"})
+ meths.exec_autocmds("User", {pattern = "Test"})
eq({}, meths.get_autocmds({event = "User", pattern = "Test"}))
end)
end)
@@ -334,6 +334,33 @@ describe('autocmd api', function()
local aus2 = meths.get_autocmds { group = auname, event = "InsertEnter" }
eq(0, #aus2)
end)
+
+ it('should respect nested', function()
+ local bufs = exec_lua [[
+ local count = 0
+ vim.api.nvim_create_autocmd("BufNew", {
+ once = false,
+ nested = true,
+ callback = function()
+ count = count + 1
+ if count > 5 then
+ return true
+ end
+
+ vim.cmd(string.format("new README_%s.md", count))
+ end
+ })
+
+ vim.cmd "new First.md"
+
+ return vim.api.nvim_list_bufs()
+ ]]
+
+ -- 1 for the first buffer
+ -- 2 for First.md
+ -- 3-7 for the 5 we make in the autocmd
+ eq({1, 2, 3, 4, 5, 6, 7}, bufs)
+ end)
end)
describe('groups', function()
@@ -490,7 +517,7 @@ describe('autocmd api', function()
end)
end)
- describe('nvim_do_autocmd', function()
+ describe('nvim_exec_autocmds', function()
it("can trigger builtin autocmds", function()
meths.set_var("autocmd_executed", false)
@@ -500,7 +527,7 @@ describe('autocmd api', function()
})
eq(false, meths.get_var("autocmd_executed"))
- meths.do_autocmd("BufReadPost", {})
+ meths.exec_autocmds("BufReadPost", {})
eq(true, meths.get_var("autocmd_executed"))
end)
@@ -514,10 +541,10 @@ describe('autocmd api', function()
})
-- Doesn't execute for other non-matching events
- meths.do_autocmd("CursorHold", { buffer = 1 })
+ meths.exec_autocmds("CursorHold", { buffer = 1 })
eq(-1, meths.get_var("buffer_executed"))
- meths.do_autocmd("BufLeave", { buffer = 1 })
+ meths.exec_autocmds("BufLeave", { buffer = 1 })
eq(1, meths.get_var("buffer_executed"))
end)
@@ -531,7 +558,7 @@ describe('autocmd api', function()
})
-- Doesn't execute for other non-matching events
- meths.do_autocmd("CursorHold", { buffer = 1 })
+ meths.exec_autocmds("CursorHold", { buffer = 1 })
eq('none', meths.get_var("filename_executed"))
meths.command('edit __init__.py')
@@ -539,7 +566,7 @@ describe('autocmd api', function()
end)
it('cannot pass buf and fname', function()
- local ok = pcall(meths.do_autocmd, "BufReadPre", { pattern = "literally_cannot_error.rs", buffer = 1 })
+ local ok = pcall(meths.exec_autocmds, "BufReadPre", { pattern = "literally_cannot_error.rs", buffer = 1 })
eq(false, ok)
end)
@@ -557,16 +584,16 @@ describe('autocmd api', function()
})
-- Doesn't execute for other non-matching events
- meths.do_autocmd("CursorHoldI", { buffer = 1 })
+ meths.exec_autocmds("CursorHoldI", { buffer = 1 })
eq('none', meths.get_var("filename_executed"))
- meths.do_autocmd("CursorHoldI", { buffer = tonumber(meths.get_current_buf()) })
+ meths.exec_autocmds("CursorHoldI", { buffer = tonumber(meths.get_current_buf()) })
eq('__init__.py', meths.get_var("filename_executed"))
-- Reset filename
meths.set_var("filename_executed", 'none')
- meths.do_autocmd("CursorHoldI", { pattern = '__init__.py' })
+ meths.exec_autocmds("CursorHoldI", { pattern = '__init__.py' })
eq('__init__.py', meths.get_var("filename_executed"))
end)
@@ -578,9 +605,9 @@ describe('autocmd api', function()
command = 'let g:matched = "matched"'
})
- meths.do_autocmd("User", { pattern = "OtherCommand" })
+ meths.exec_autocmds("User", { pattern = "OtherCommand" })
eq('none', meths.get_var('matched'))
- meths.do_autocmd("User", { pattern = "TestCommand" })
+ meths.exec_autocmds("User", { pattern = "TestCommand" })
eq('matched', meths.get_var('matched'))
end)
@@ -594,7 +621,7 @@ describe('autocmd api', function()
})
eq(false, meths.get_var("group_executed"))
- meths.do_autocmd("FileType", { group = auid })
+ meths.exec_autocmds("FileType", { group = auid })
eq(true, meths.get_var("group_executed"))
end)
@@ -609,7 +636,7 @@ describe('autocmd api', function()
})
eq(false, meths.get_var("group_executed"))
- meths.do_autocmd("FileType", { group = auname })
+ meths.exec_autocmds("FileType", { group = auname })
eq(true, meths.get_var("group_executed"))
end)
end)
@@ -782,6 +809,14 @@ describe('autocmd api', function()
eq(2, get_executed_count(), "No additional counts")
end)
+ it('can delete non-existent groups with pcall', function()
+ eq(false, exec_lua[[return pcall(vim.api.nvim_del_augroup_by_name, 'noexist')]])
+ eq('Vim:E367: No such group: "noexist"', pcall_err(meths.del_augroup_by_name, 'noexist'))
+
+ eq(false, exec_lua[[return pcall(vim.api.nvim_del_augroup_by_id, -12342)]])
+ eq('Vim:E367: No such group: "--Deleted--"', pcall_err(meths.del_augroup_by_id, -12312))
+ end)
+
it('groups work with once', function()
local augroup = "TestGroup"
@@ -945,4 +980,95 @@ describe('autocmd api', function()
eq(0, #meths.get_autocmds { event = 'BufReadPost' })
end)
end)
+
+ describe('nvim_clear_autocmds', 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_autocmds(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_autocmds(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_autocmds(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_autocmds { 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_autocmds { buffer = 0 }
+ local without_group = meths.get_autocmds(search)
+ eq(2, #without_group)
+
+ -- Doest clear with passing group.
+ meths.clear_autocmds { buffer = 0, group = search.group }
+ local with_group = meths.get_autocmds(search)
+ eq(1, #with_group)
+ end)
+ end)
end)
diff --git a/test/functional/api/command_spec.lua b/test/functional/api/command_spec.lua
index b80004f67c..94176fc2ce 100644
--- a/test/functional/api/command_spec.lua
+++ b/test/functional/api/command_spec.lua
@@ -65,6 +65,7 @@ describe('nvim_get_commands', function()
local cmd3 = { addr=NIL, bang=false, bar=true, complete=NIL, complete_arg=NIL, count=NIL, definition='call \128\253R3_ohyeah()', name='Cmd3', nargs='0', range=NIL, register=false, keepscript=false, script_id=3, }
local cmd4 = { addr=NIL, bang=false, bar=false, complete=NIL, complete_arg=NIL, count=NIL, definition='call \128\253R4_just_great()', name='Cmd4', nargs='0', range=NIL, register=true, keepscript=false, script_id=4, }
source([[
+ let s:foo = 1
command -complete=custom,ListUsers -nargs=+ Finger !finger <args>
]])
eq({Finger=cmd1}, meths.get_commands({builtin=false}))
@@ -72,12 +73,18 @@ describe('nvim_get_commands', function()
eq({Finger=cmd1, TestCmd=cmd0}, meths.get_commands({builtin=false}))
source([[
+ function! s:foo() abort
+ endfunction
command -bang -nargs=* Cmd2 call <SID>foo(<q-args>)
]])
source([[
+ function! s:ohyeah() abort
+ endfunction
command -bar -nargs=0 Cmd3 call <SID>ohyeah()
]])
source([[
+ function! s:just_great() abort
+ endfunction
command -register Cmd4 call <SID>just_great()
]])
-- TODO(justinmk): Order is stable but undefined. Sort before return?
diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua
index ed9d915954..e6ed0f939b 100644
--- a/test/functional/api/vim_spec.lua
+++ b/test/functional/api/vim_spec.lua
@@ -1589,6 +1589,18 @@ describe('API', function()
feed(':digraphs<cr>')
eq({mode='rm', blocking=true}, nvim("get_mode"))
end)
+
+ it('after <Nop> mapping returns blocking=false #17257', function()
+ command('nnoremap <F2> <Nop>')
+ feed('<F2>')
+ eq({mode='n', blocking=false}, nvim("get_mode"))
+ end)
+
+ it('after empty string <expr> mapping returns blocking=false #17257', function()
+ command('nnoremap <expr> <F2> ""')
+ feed('<F2>')
+ eq({mode='n', blocking=false}, nvim("get_mode"))
+ end)
end)
describe('RPC (K_EVENT)', function()
diff --git a/test/functional/editor/tabpage_spec.lua b/test/functional/editor/tabpage_spec.lua
index d1d6854b07..2494daf99b 100644
--- a/test/functional/editor/tabpage_spec.lua
+++ b/test/functional/editor/tabpage_spec.lua
@@ -3,8 +3,10 @@ local helpers = require('test.functional.helpers')(after_each)
local clear = helpers.clear
local command = helpers.command
local eq = helpers.eq
+local neq = helpers.neq
local feed = helpers.feed
local eval = helpers.eval
+local exec = helpers.exec
describe('tabpage', function()
before_each(clear)
@@ -34,5 +36,20 @@ describe('tabpage', function()
eq(3, eval('tabpagenr()'))
end)
+
+ it('does not crash or loop 999 times if BufWipeout autocommand switches window #17868', function()
+ exec([[
+ tabedit
+ let s:window_id = win_getid()
+ botright new
+ setlocal bufhidden=wipe
+ let g:win_closed = 0
+ autocmd WinClosed * let g:win_closed += 1
+ autocmd BufWipeout <buffer> call win_gotoid(s:window_id)
+ tabprevious
+ +tabclose
+ ]])
+ neq(999, eval('g:win_closed'))
+ end)
end)
diff --git a/test/functional/ex_cmds/cmd_map_spec.lua b/test/functional/ex_cmds/cmd_map_spec.lua
index 0b2190bbcf..64cf53dfa9 100644
--- a/test/functional/ex_cmds/cmd_map_spec.lua
+++ b/test/functional/ex_cmds/cmd_map_spec.lua
@@ -1,21 +1,23 @@
local helpers = require('test.functional.helpers')(after_each)
local clear = helpers.clear
-local feed_command = helpers.feed_command
local feed = helpers.feed
local eq = helpers.eq
local expect = helpers.expect
local eval = helpers.eval
local funcs = helpers.funcs
local insert = helpers.insert
+local write_file = helpers.write_file
local exc_exec = helpers.exc_exec
-local source = helpers.source
+local command = helpers.command
local Screen = require('test.functional.ui.screen')
describe('mappings with <Cmd>', function()
local screen
+ local tmpfile = 'X_ex_cmds_cmd_map'
+
local function cmdmap(lhs, rhs)
- feed_command('noremap '..lhs..' <Cmd>'..rhs..'<cr>')
- feed_command('noremap! '..lhs..' <Cmd>'..rhs..'<cr>')
+ command('noremap '..lhs..' <Cmd>'..rhs..'<cr>')
+ command('noremap! '..lhs..' <Cmd>'..rhs..'<cr>')
end
before_each(function()
@@ -39,7 +41,7 @@ describe('mappings with <Cmd>', function()
cmdmap('<F4>', 'normal! ww')
cmdmap('<F5>', 'normal! "ay')
cmdmap('<F6>', 'throw "very error"')
- feed_command([[
+ command([[
function! TextObj()
if mode() !=# "v"
normal! v
@@ -55,11 +57,15 @@ describe('mappings with <Cmd>', function()
feed('gg')
cmdmap('<F8>', 'startinsert')
cmdmap('<F9>', 'stopinsert')
- feed_command("abbr foo <Cmd>let g:y = 17<cr>bar")
+ command("abbr foo <Cmd>let g:y = 17<cr>bar")
+ end)
+
+ after_each(function()
+ os.remove(tmpfile)
end)
it('can be displayed', function()
- feed_command('map <F3>')
+ command('map <F3>')
screen:expect([[
^some short lines |
of test text |
@@ -73,8 +79,8 @@ describe('mappings with <Cmd>', function()
end)
it('handles invalid mappings', function()
- feed_command('let x = 0')
- feed_command('noremap <F3> <Cmd><Cmd>let x = 1<cr>')
+ command('let x = 0')
+ command('noremap <F3> <Cmd><Cmd>let x = 1<cr>')
feed('<F3>')
screen:expect([[
^some short lines |
@@ -87,7 +93,7 @@ describe('mappings with <Cmd>', function()
{2:E5521: <Cmd> mapping must end with <CR> before second <Cmd>} |
]])
- feed_command('noremap <F3> <Cmd><F3>let x = 2<cr>')
+ command('noremap <F3> <Cmd><F3>let x = 2<cr>')
feed('<F3>')
screen:expect([[
^some short lines |
@@ -100,7 +106,7 @@ describe('mappings with <Cmd>', function()
{2:E5522: <Cmd> mapping must not include <F3> key} |
]])
- feed_command('noremap <F3> <Cmd>let x = 3')
+ command('noremap <F3> <Cmd>let x = 3')
feed('<F3>')
screen:expect([[
^some short lines |
@@ -137,7 +143,7 @@ describe('mappings with <Cmd>', function()
eq('n', eval('mode(1)'))
-- select mode mapping
- feed_command('snoremap <F3> <Cmd>let m = mode(1)<cr>')
+ command('snoremap <F3> <Cmd>let m = mode(1)<cr>')
feed('gh<F3>')
eq('s', eval('m'))
-- didn't leave select mode
@@ -184,8 +190,8 @@ describe('mappings with <Cmd>', function()
eq('n', eval('mode(1)'))
-- terminal mode
- feed_command('tnoremap <F3> <Cmd>let m = mode(1)<cr>')
- feed_command('split | terminal')
+ command('tnoremap <F3> <Cmd>let m = mode(1)<cr>')
+ command('split | terminal')
feed('i')
eq('t', eval('mode(1)'))
feed('<F3>')
@@ -264,11 +270,11 @@ describe('mappings with <Cmd>', function()
end)
it('works in :normal command', function()
- feed_command('noremap ,x <Cmd>call append(1, "xx")\\| call append(1, "aa")<cr>')
- feed_command('noremap ,f <Cmd>nosuchcommand<cr>')
- feed_command('noremap ,e <Cmd>throw "very error"\\| call append(1, "yy")<cr>')
- feed_command('noremap ,m <Cmd>echoerr "The message."\\| call append(1, "zz")<cr>')
- feed_command('noremap ,w <Cmd>for i in range(5)\\|if i==1\\|echoerr "Err"\\|endif\\|call append(1, i)\\|endfor<cr>')
+ command('noremap ,x <Cmd>call append(1, "xx")\\| call append(1, "aa")<cr>')
+ command('noremap ,f <Cmd>nosuchcommand<cr>')
+ command('noremap ,e <Cmd>throw "very error"\\| call append(1, "yy")<cr>')
+ command('noremap ,m <Cmd>echoerr "The message."\\| call append(1, "zz")<cr>')
+ command('noremap ,w <Cmd>for i in range(5)\\|if i==1\\|echoerr "Err"\\|endif\\|call append(1, i)\\|endfor<cr>')
feed(":normal ,x<cr>")
screen:expect([[
@@ -297,7 +303,7 @@ describe('mappings with <Cmd>', function()
:normal ,x |
]])
- feed_command(':%d')
+ command(':%d')
eq('Vim(echoerr):Err', exc_exec("normal ,w"))
screen:expect([[
^ |
@@ -310,8 +316,8 @@ describe('mappings with <Cmd>', function()
--No lines in buffer-- |
]])
- feed_command(':%d')
- feed_command(':normal ,w')
+ command(':%d')
+ feed(':normal ,w<cr>')
screen:expect([[
^ |
4 |
@@ -401,8 +407,8 @@ describe('mappings with <Cmd>', function()
end)
it('works in select mode', function()
- feed_command('snoremap <F1> <cmd>throw "very error"<cr>')
- feed_command('snoremap <F2> <cmd>normal! <c-g>"by<cr>')
+ command('snoremap <F1> <cmd>throw "very error"<cr>')
+ command('snoremap <F2> <cmd>normal! <c-g>"by<cr>')
-- can extend select mode
feed('gh<F4>')
screen:expect([[
@@ -830,12 +836,14 @@ describe('mappings with <Cmd>', function()
end)
it("works with <SID> mappings", function()
- source([[
+ command('new!')
+ write_file(tmpfile, [[
map <f2> <Cmd>call <SID>do_it()<Cr>
function! s:do_it()
let g:x = 10
endfunction
]])
+ command('source '..tmpfile)
feed('<f2>')
eq('', eval('v:errmsg'))
eq(10, eval('g:x'))
diff --git a/test/functional/ex_cmds/echo_spec.lua b/test/functional/ex_cmds/echo_spec.lua
index d320425de1..a6be04138b 100644
--- a/test/functional/ex_cmds/echo_spec.lua
+++ b/test/functional/ex_cmds/echo_spec.lua
@@ -181,9 +181,9 @@ describe(':echo :echon :echomsg :echoerr', function()
end)
it('dumps references to script functions', function()
- eq('<SNR>2_Test2', eval('String(Test2_f)'))
- eq("function('<SNR>2_Test2')", eval('StringMsg(Test2_f)'))
- eq("function('<SNR>2_Test2')", eval('StringErr(Test2_f)'))
+ eq('<SNR>1_Test2', eval('String(Test2_f)'))
+ eq("function('<SNR>1_Test2')", eval('StringMsg(Test2_f)'))
+ eq("function('<SNR>1_Test2')", eval('StringErr(Test2_f)'))
end)
it('dump references to lambdas', function()
@@ -205,11 +205,11 @@ describe(':echo :echon :echomsg :echoerr', function()
it('dumps automatically created partials', function()
assert_same_echo_dump(
- "function('<SNR>2_Test2', {'f': function('<SNR>2_Test2')})",
+ "function('<SNR>1_Test2', {'f': function('<SNR>1_Test2')})",
'{"f": Test2_f}.f',
true)
assert_same_echo_dump(
- "function('<SNR>2_Test2', [1], {'f': function('<SNR>2_Test2', [1])})",
+ "function('<SNR>1_Test2', [1], {'f': function('<SNR>1_Test2', [1])})",
'{"f": function(Test2_f, [1])}.f',
true)
end)
@@ -227,7 +227,7 @@ describe(':echo :echon :echomsg :echoerr', function()
function()
meths.set_var('d', {v=true})
eq(dedent([[
- {'p': function('<SNR>2_Test2', {...@0}), 'f': function('<SNR>2_Test2'), 'v': v:true}]]),
+ {'p': function('<SNR>1_Test2', {...@0}), 'f': function('<SNR>1_Test2'), 'v': v:true}]]),
exec_capture('echo String(extend(extend(g:d, {"f": g:Test2_f}), {"p": g:d.f}))'))
end)
@@ -264,7 +264,7 @@ describe(':echo :echon :echomsg :echoerr', function()
eval('add(l, function("Test1", l))')
eval('add(l, function("Test1", d))')
eq(dedent([=[
- {'p': function('<SNR>2_Test2', [[[...@3], function('Test1', [[...@3]]), function('Test1', {...@0})], function('Test1', [[[...@5], function('Test1', [[...@5]]), function('Test1', {...@0})]]), function('Test1', {...@0})], {...@0}), 'f': function('<SNR>2_Test2'), 'v': v:true}]=]),
+ {'p': function('<SNR>1_Test2', [[[...@3], function('Test1', [[...@3]]), function('Test1', {...@0})], function('Test1', [[[...@5], function('Test1', [[...@5]]), function('Test1', {...@0})]]), function('Test1', {...@0})], {...@0}), 'f': function('<SNR>1_Test2'), 'v': v:true}]=]),
exec_capture('echo String(extend(extend(g:d, {"f": g:Test2_f}), {"p": function(g:d.f, l)}))'))
end)
end)
diff --git a/test/functional/ex_cmds/script_spec.lua b/test/functional/ex_cmds/script_spec.lua
index f249b9ba7c..bf69ada820 100644
--- a/test/functional/ex_cmds/script_spec.lua
+++ b/test/functional/ex_cmds/script_spec.lua
@@ -2,18 +2,30 @@ local helpers = require('test.functional.helpers')(after_each)
local eq = helpers.eq
local neq = helpers.neq
+local command = helpers.command
+local write_file = helpers.write_file
local meths = helpers.meths
local clear = helpers.clear
local dedent = helpers.dedent
-local source = helpers.source
local exc_exec = helpers.exc_exec
local missing_provider = helpers.missing_provider
+local tmpfile = 'X_ex_cmds_script'
+
before_each(clear)
+local function source(code)
+ write_file(tmpfile, code)
+ command('source '..tmpfile)
+end
+
describe('script_get-based command', function()
local garbage = ')}{+*({}]*[;(+}{&[]}{*])('
+ after_each(function()
+ os.remove(tmpfile)
+ end)
+
local function test_garbage_exec(cmd, check_neq)
describe(cmd, function()
it('works correctly when skipping oneline variant', function()
diff --git a/test/functional/helpers.lua b/test/functional/helpers.lua
index 1845786c4b..173fc54af5 100644
--- a/test/functional/helpers.lua
+++ b/test/functional/helpers.lua
@@ -21,7 +21,6 @@ local map = global_helpers.tbl_map
local ok = global_helpers.ok
local sleep = global_helpers.sleep
local tbl_contains = global_helpers.tbl_contains
-local write_file = global_helpers.write_file
local fail = global_helpers.fail
local module = {
@@ -54,7 +53,6 @@ if module.nvim_dir == module.nvim_prog then
module.nvim_dir = "."
end
-local tmpname = global_helpers.tmpname
local iswin = global_helpers.iswin
local prepend_argv
@@ -494,24 +492,9 @@ function module.feed_command(...)
end
end
-local sourced_fnames = {}
+-- @deprecated use nvim_exec()
function module.source(code)
- local fname = tmpname()
- write_file(fname, code)
- module.command('source '..fname)
- -- DO NOT REMOVE FILE HERE.
- -- do_source() has a habit of checking whether files are “same” by using inode
- -- and device IDs. If you run two source() calls in quick succession there is
- -- a good chance that underlying filesystem will reuse the inode, making files
- -- appear as “symlinks” to do_source when it checks FileIDs. With current
- -- setup linux machines (both QB, travis and mine(ZyX-I) with XFS) do reuse
- -- inodes, Mac OS machines (again, both QB and travis) do not.
- --
- -- Files appearing as “symlinks” mean that both the first and the second
- -- source() calls will use same SID, which may fail some tests which check for
- -- exact numbers after `<SNR>` in e.g. function names.
- sourced_fnames[#sourced_fnames + 1] = fname
- return fname
+ module.exec(dedent(code))
end
function module.has_powershell()
@@ -525,7 +508,7 @@ function module.set_shell_powershell()
local cmd = set_encoding..'Remove-Item -Force '..table.concat(iswin()
and {'alias:cat', 'alias:echo', 'alias:sleep'}
or {'alias:echo'}, ',')..';'
- module.source([[
+ module.exec([[
let &shell = ']]..shell..[['
set shellquote= shellxquote=
let &shellpipe = '2>&1 | Out-File -Encoding UTF8 %s; exit $LastExitCode'
@@ -887,9 +870,6 @@ module = global_helpers.tbl_extend('error', module, global_helpers)
return function(after_each)
if after_each then
after_each(function()
- for _, fname in ipairs(sourced_fnames) do
- os.remove(fname)
- end
check_logs()
check_cores('build/bin/nvim')
if session then
diff --git a/test/functional/legacy/assert_spec.lua b/test/functional/legacy/assert_spec.lua
index dd6a9d0bde..4829a0bbe1 100644
--- a/test/functional/legacy/assert_spec.lua
+++ b/test/functional/legacy/assert_spec.lua
@@ -136,19 +136,19 @@ describe('assert function:', function()
end)
it('should have file names and passed messages', function()
- local tmpname_one = source([[
+ source([[
call assert_equal(1, 100, 'equal assertion failed')
call assert_false('true', 'true assertion failed')
call assert_true('false', 'false assertion failed')
]])
- local tmpname_two = source([[
+ source([[
call assert_true('', 'file two')
]])
expected_errors({
- tmpname_one .. " line 1: equal assertion failed: Expected 1 but got 100",
- tmpname_one .. " line 2: true assertion failed: Expected False but got 'true'",
- tmpname_one .. " line 3: false assertion failed: Expected True but got 'false'",
- tmpname_two .. " line 1: file two: Expected True but got ''",
+ "nvim_exec(): equal assertion failed: Expected 1 but got 100",
+ "nvim_exec(): true assertion failed: Expected False but got 'true'",
+ "nvim_exec(): false assertion failed: Expected True but got 'false'",
+ "nvim_exec(): file two: Expected True but got ''",
})
end)
end)
diff --git a/test/functional/legacy/display_spec.lua b/test/functional/legacy/display_spec.lua
index 3fbbe96947..59ba170e33 100644
--- a/test/functional/legacy/display_spec.lua
+++ b/test/functional/legacy/display_spec.lua
@@ -3,15 +3,15 @@ local helpers = require('test.functional.helpers')(after_each)
local Screen = require('test.functional.ui.screen')
local clear = helpers.clear
local poke_eventloop = helpers.poke_eventloop
+local exec = helpers.exec
local feed = helpers.feed
local feed_command = helpers.feed_command
describe('display', function()
- local screen
+ before_each(clear)
it('scroll when modified at topline', function()
- clear()
- screen = Screen.new(20, 4)
+ local screen = Screen.new(20, 4)
screen:attach()
screen:set_default_attr_ids({
[1] = {bold = true},
@@ -27,5 +27,35 @@ describe('display', function()
{1:-- INSERT --} |
]])
end)
+
+ it('scrolling when modified at topline in Visual mode', function()
+ local screen = Screen.new(60, 8)
+ screen:attach()
+ screen:set_default_attr_ids({
+ [1] = {bold = true}, -- ModeMsg
+ [2] = {background = Screen.colors.LightGrey}, -- Visual
+ [3] = {background = Screen.colors.Grey, foreground = Screen.colors.DarkBlue}, -- SignColumn
+ })
+
+ exec([[
+ set scrolloff=0
+ call setline(1, repeat(['foo'], 10))
+ call sign_define('foo', { 'text': '>' })
+ call sign_place(1, 'bar', 'foo', bufnr(), { 'lnum': 2 })
+ call sign_place(2, 'bar', 'foo', bufnr(), { 'lnum': 1 })
+ autocmd CursorMoved * if getcurpos()[1] == 2 | call sign_unplace('bar', { 'id': 1 }) | endif
+ ]])
+ feed('VG7kk')
+ screen:expect([[
+ {3: }^f{2:oo} |
+ {3: }foo |
+ {3: }foo |
+ {3: }foo |
+ {3: }foo |
+ {3: }foo |
+ {3: }foo |
+ {1:-- VISUAL LINE --} |
+ ]])
+ end)
end)
diff --git a/test/functional/legacy/memory_usage_spec.lua b/test/functional/legacy/memory_usage_spec.lua
index 8d25b9d927..eec89aa919 100644
--- a/test/functional/legacy/memory_usage_spec.lua
+++ b/test/functional/legacy/memory_usage_spec.lua
@@ -10,6 +10,7 @@ local source = helpers.source
local poke_eventloop = helpers.poke_eventloop
local uname = helpers.uname
local load_adjust = helpers.load_adjust
+local write_file = helpers.write_file
local isCI = helpers.isCI
local function isasan()
@@ -84,6 +85,12 @@ setmetatable(monitor_memory_usage,
end})
describe('memory usage', function()
+ local tmpfile = 'X_memory_usage'
+
+ after_each(function()
+ os.remove(tmpfile)
+ end)
+
local function check_result(tbl, status, result)
if not status then
print('')
@@ -103,7 +110,7 @@ describe('memory usage', function()
it('function capture vargs', function()
local pid = eval('getpid()')
local before = monitor_memory_usage(pid)
- source([[
+ write_file(tmpfile, [[
func s:f(...)
let x = a:000
endfunc
@@ -111,6 +118,8 @@ describe('memory usage', function()
call s:f(0)
endfor
]])
+ -- TODO: check_result fails if command() is used here. Why? #16064
+ feed_command('source '..tmpfile)
poke_eventloop()
local after = monitor_memory_usage(pid)
-- Estimate the limit of max usage as 2x initial usage.
@@ -136,7 +145,7 @@ describe('memory usage', function()
it('function capture lvars', function()
local pid = eval('getpid()')
local before = monitor_memory_usage(pid)
- local fname = source([[
+ write_file(tmpfile, [[
if !exists('s:defined_func')
func s:f()
let x = l:
@@ -147,10 +156,12 @@ describe('memory usage', function()
call s:f()
endfor
]])
+ feed_command('source '..tmpfile)
poke_eventloop()
local after = monitor_memory_usage(pid)
for _ = 1, 3 do
- feed_command('so '..fname)
+ -- TODO: check_result fails if command() is used here. Why? #16064
+ feed_command('source '..tmpfile)
poke_eventloop()
end
local last = monitor_memory_usage(pid)
diff --git a/test/functional/legacy/messages_spec.lua b/test/functional/legacy/messages_spec.lua
new file mode 100644
index 0000000000..34807a099c
--- /dev/null
+++ b/test/functional/legacy/messages_spec.lua
@@ -0,0 +1,71 @@
+local helpers = require('test.functional.helpers')(after_each)
+local Screen = require('test.functional.ui.screen')
+local clear = helpers.clear
+local command = helpers.command
+local exec = helpers.exec
+local feed = helpers.feed
+
+before_each(clear)
+
+describe('messages', function()
+ it('more prompt with control characters can be quit vim-patch:8.2.1844', function()
+ local screen = Screen.new(40, 6)
+ screen:set_default_attr_ids({
+ [1] = {foreground = Screen.colors.Blue}, -- SpecialKey
+ [2] = {bold = true, foreground = Screen.colors.SeaGreen}, -- MoreMsg
+ [3] = {bold = true, foreground = Screen.colors.Blue}, -- NonText
+ })
+ screen:attach()
+ command('set more')
+ feed([[:echom range(9999)->join("\x01")<CR>]])
+ screen:expect([[
+ 0{1:^A}1{1:^A}2{1:^A}3{1:^A}4{1:^A}5{1:^A}6{1:^A}7{1:^A}8{1:^A}9{1:^A}10{1:^A}11{1:^A}12|
+ {1:^A}13{1:^A}14{1:^A}15{1:^A}16{1:^A}17{1:^A}18{1:^A}19{1:^A}20{1:^A}21{1:^A}22|
+ {1:^A}23{1:^A}24{1:^A}25{1:^A}26{1:^A}27{1:^A}28{1:^A}29{1:^A}30{1:^A}31{1:^A}32|
+ {1:^A}33{1:^A}34{1:^A}35{1:^A}36{1:^A}37{1:^A}38{1:^A}39{1:^A}40{1:^A}41{1:^A}42|
+ {1:^A}43{1:^A}44{1:^A}45{1:^A}46{1:^A}47{1:^A}48{1:^A}49{1:^A}50{1:^A}51{1:^A}52|
+ {2:-- More --}^ |
+ ]])
+ feed('q')
+ screen:expect([[
+ ^ |
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ |
+ ]])
+ end)
+
+ it('fileinfo does not overwrite echo message vim-patch:8.2.4156', function()
+ local screen = Screen.new(40, 6)
+ screen:set_default_attr_ids({
+ [1] = {bold = true, foreground = Screen.colors.Blue}, -- NonText
+ })
+ screen:attach()
+ exec([[
+ set shortmess-=F
+
+ file a.txt
+
+ hide edit b.txt
+ call setline(1, "hi")
+ setlocal modified
+
+ hide buffer a.txt
+
+ autocmd CursorHold * buf b.txt | w | echo "'b' written"
+ ]])
+ command('set updatetime=50')
+ feed('0$')
+ screen:expect([[
+ ^hi |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ 'b' written |
+ ]])
+ os.remove('b.txt')
+ end)
+end)
diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua
index 38cb54fbc6..1547f3244e 100644
--- a/test/functional/lua/vim_spec.lua
+++ b/test/functional/lua/vim_spec.lua
@@ -490,6 +490,12 @@ describe('lua stdlib', function()
eq(false, exec_lua("return vim.tbl_isempty({a=1, b=2, c=3})"))
end)
+ it('vim.tbl_get', function()
+ eq(true, exec_lua("return vim.tbl_get({ test = { nested_test = true }}, 'test', 'nested_test')"))
+ eq(NIL, exec_lua("return vim.tbl_get({}, 'missing_key')"))
+ eq(NIL, exec_lua("return vim.tbl_get({})"))
+ end)
+
it('vim.tbl_extend', function()
ok(exec_lua([[
local a = {x = 1}
diff --git a/test/functional/plugin/matchparen_spec.lua b/test/functional/plugin/matchparen_spec.lua
index 13e1283e2c..2670734c1a 100644
--- a/test/functional/plugin/matchparen_spec.lua
+++ b/test/functional/plugin/matchparen_spec.lua
@@ -27,7 +27,7 @@ describe('matchparen', function()
feed('{<cr>')
feed('}')
- -- critical part: up + cr should result in an empty line inbetween the
+ -- critical part: up + cr should result in an empty line in between the
-- brackets... if the bug is there, the empty line will be before the '{'
feed('<up>')
feed('<cr>')
diff --git a/test/functional/ui/decorations_spec.lua b/test/functional/ui/decorations_spec.lua
index 29fbe9a93b..74eb5d5b8e 100644
--- a/test/functional/ui/decorations_spec.lua
+++ b/test/functional/ui/decorations_spec.lua
@@ -437,6 +437,7 @@ describe('extmark decorations', function()
[22] = {foreground = tonumber('0xb20000'), background = tonumber('0xf13f3f')};
[23] = {foreground = Screen.colors.Magenta1, background = Screen.colors.LightGrey};
[24] = {bold = true};
+ [25] = {background = Screen.colors.LightRed};
}
ns = meths.create_namespace 'test'
@@ -456,6 +457,31 @@ for _,item in ipairs(items) do
end
end]]
+ it('empty virtual text at eol should not break colorcolumn #17860', function()
+ insert(example_text)
+ feed('gg')
+ command('set colorcolumn=40')
+ screen:expect([[
+ ^for _,item in ipairs(items) do {25: } |
+ local text, hl_id_cell, count = unp{25:a}ck(item) |
+ if hl_id_cell ~= nil then {25: } |
+ hl_id = hl_id_cell {25: } |
+ end {25: } |
+ for _ = 1, (count or 1) do {25: } |
+ local cell = line[colpos] {25: } |
+ cell.text = text {25: } |
+ cell.hl_id = hl_id {25: } |
+ colpos = colpos+1 {25: } |
+ end {25: } |
+ end {25: } |
+ {1:~ }|
+ {1:~ }|
+ |
+ ]])
+ meths.buf_set_extmark(0, ns, 4, 0, { virt_text={{''}}, virt_text_pos='eol'})
+ screen:expect_unchanged()
+ end)
+
it('can have virtual text of overlay position', function()
insert(example_text)
feed 'gg'
@@ -471,7 +497,9 @@ end]]
-- can "float" beyond end of line
meths.buf_set_extmark(0, ns, 5, 28, { virt_text={{'loopy', 'ErrorMsg'}}, virt_text_pos='overlay'})
-- bound check: right edge of window
- meths.buf_set_extmark(0, ns, 2, 26, { virt_text={{'bork bork bork ' }, {'bork bork bork', 'ErrorMsg'}}, virt_text_pos='overlay'})
+ meths.buf_set_extmark(0, ns, 2, 26, { virt_text={{'bork bork bork '}, {'bork bork bork', 'ErrorMsg'}}, virt_text_pos='overlay'})
+ -- empty virt_text should not change anything
+ meths.buf_set_extmark(0, ns, 6, 16, { virt_text={{''}}, virt_text_pos='overlay'})
screen:expect{grid=[[
^for _,item in ipairs(items) do |
@@ -621,6 +649,8 @@ end]]
meths.buf_set_extmark(0, ns, 2, 10, { virt_text={{'Much', 'ErrorMsg'}}, virt_text_win_col=31, hl_mode='blend'})
meths.buf_set_extmark(0, ns, 3, 15, { virt_text={{'Error', 'ErrorMsg'}}, virt_text_win_col=31, hl_mode='blend'})
meths.buf_set_extmark(0, ns, 7, 21, { virt_text={{'-', 'NonText'}}, virt_text_win_col=4, hl_mode='blend'})
+ -- empty virt_text should not change anything
+ meths.buf_set_extmark(0, ns, 8, 0, { virt_text={{''}}, virt_text_win_col=14, hl_mode='blend'})
screen:expect{grid=[[
^for _,item in ipairs(items) do |
diff --git a/test/functional/ui/fold_spec.lua b/test/functional/ui/fold_spec.lua
index 3e0e15c2b7..bc52696418 100644
--- a/test/functional/ui/fold_spec.lua
+++ b/test/functional/ui/fold_spec.lua
@@ -1672,7 +1672,7 @@ describe("folded lines", function()
end
-- relax the maximum fdc thus fdc should expand to
- -- accomodate the current number of folds
+ -- accommodate the current number of folds
command("set foldcolumn=auto:4")
if multigrid then
screen:expect([[
diff --git a/test/functional/ui/global_statusline_spec.lua b/test/functional/ui/global_statusline_spec.lua
index 6b37e5e2f1..f6821ec589 100644
--- a/test/functional/ui/global_statusline_spec.lua
+++ b/test/functional/ui/global_statusline_spec.lua
@@ -1,6 +1,7 @@
local helpers = require('test.functional.helpers')(after_each)
local Screen = require('test.functional.ui.screen')
local clear, command, feed = helpers.clear, helpers.command, helpers.feed
+local eq, funcs, meths = helpers.eq, helpers.funcs, helpers.meths
describe('global statusline', function()
local screen
@@ -230,4 +231,30 @@ describe('global statusline', function()
[3] = {reverse = true, bold = true};
}}
end)
+
+ it('win_move_statusline() can reduce cmdheight to 1', function()
+ eq(1, meths.get_option('cmdheight'))
+ funcs.win_move_statusline(0, -1)
+ eq(2, meths.get_option('cmdheight'))
+ funcs.win_move_statusline(0, -1)
+ eq(3, meths.get_option('cmdheight'))
+ funcs.win_move_statusline(0, 1)
+ eq(2, meths.get_option('cmdheight'))
+ funcs.win_move_statusline(0, 1)
+ eq(1, meths.get_option('cmdheight'))
+ end)
+
+ it('mouse dragging can reduce cmdheight to 1', function()
+ command('set mouse=a')
+ meths.input_mouse('left', 'press', '', 0, 14, 10)
+ eq(1, meths.get_option('cmdheight'))
+ meths.input_mouse('left', 'drag', '', 0, 13, 10)
+ eq(2, meths.get_option('cmdheight'))
+ meths.input_mouse('left', 'drag', '', 0, 12, 10)
+ eq(3, meths.get_option('cmdheight'))
+ meths.input_mouse('left', 'drag', '', 0, 13, 10)
+ eq(2, meths.get_option('cmdheight'))
+ meths.input_mouse('left', 'drag', '', 0, 14, 10)
+ eq(1, meths.get_option('cmdheight'))
+ end)
end)
diff --git a/test/functional/ui/highlight_spec.lua b/test/functional/ui/highlight_spec.lua
index 559738ddab..bf52d9f9b4 100644
--- a/test/functional/ui/highlight_spec.lua
+++ b/test/functional/ui/highlight_spec.lua
@@ -937,17 +937,18 @@ describe('CursorLine and CursorLineNr highlights', function()
[2] = {foreground = Screen.colors.Yellow};
[3] = {foreground = Screen.colors.Red, background = Screen.colors.Green};
[4] = {foreground = Screen.colors.Green, background = Screen.colors.Red};
+ [5] = {bold = true}, -- ModeMsg
})
screen:attach()
- feed_command('set wrap cursorline cursorlineopt=screenline')
- feed_command('set showbreak=>>>')
- feed_command('highlight clear NonText')
- feed_command('highlight clear CursorLine')
- feed_command('highlight NonText guifg=Yellow gui=NONE')
- feed_command('highlight LineNr guifg=Red guibg=Green gui=NONE')
- feed_command('highlight CursorLine guifg=Black guibg=White gui=NONE')
- feed_command('highlight CursorLineNr guifg=Green guibg=Red gui=NONE')
+ command('set wrap cursorline cursorlineopt=screenline')
+ command('set showbreak=>>>')
+ command('highlight clear NonText')
+ command('highlight clear CursorLine')
+ command('highlight NonText guifg=Yellow gui=NONE')
+ command('highlight LineNr guifg=Red guibg=Green gui=NONE')
+ command('highlight CursorLine guifg=Black guibg=White gui=NONE')
+ command('highlight CursorLineNr guifg=Green guibg=Red gui=NONE')
feed('30iø<esc>o<esc>30ia<esc>')
@@ -977,7 +978,7 @@ describe('CursorLine and CursorLineNr highlights', function()
]])
-- CursorLineNr should not apply to line number when 'cursorlineopt' does not contain "number"
- feed_command('set relativenumber numberwidth=2')
+ command('set relativenumber numberwidth=2')
screen:expect([[
{3:0 }{1:øøøøøøøøøøøø^øøøøøø}|
{3: }{2:>>>}øøøøøøøøøøøø |
@@ -987,7 +988,7 @@ describe('CursorLine and CursorLineNr highlights', function()
]])
-- CursorLineNr should apply to line number when 'cursorlineopt' contains "number"
- feed_command('set cursorlineopt+=number')
+ command('set cursorlineopt+=number')
screen:expect([[
{4:0 }{1:øøøøøøøøøøøø^øøøøøø}|
{3: }{2:>>>}øøøøøøøøøøøø |
@@ -1019,6 +1020,44 @@ describe('CursorLine and CursorLineNr highlights', function()
{3: }{2:>>>}{1:aaaaaaaaa^aaa }|
|
]])
+
+ -- updated in Insert mode
+ feed('I')
+ screen:expect([[
+ {3:1 }øøøøøøøøøøøøøøøøøø|
+ {3: }{2:>>>}øøøøøøøøøøøø |
+ {4:0 }{1:^aaaaaaaaaaaaaaaaaa}|
+ {3: }{2:>>>}aaaaaaaaaaaa |
+ {5:-- INSERT --} |
+ ]])
+
+ feed('<Esc>gg')
+ screen:expect([[
+ {4:0 }{1:^øøøøøøøøøøøøøøøøøø}|
+ {3: }{2:>>>}øøøøøøøøøøøø |
+ {3:1 }aaaaaaaaaaaaaaaaaa|
+ {3: }{2:>>>}aaaaaaaaaaaa |
+ |
+ ]])
+
+ command('inoremap <F2> <Cmd>call cursor(1, 1)<CR>')
+ feed('A')
+ screen:expect([[
+ {4:0 }øøøøøøøøøøøøøøøøøø|
+ {3: }{2:>>>}{1:øøøøøøøøøøøø^ }|
+ {3:1 }aaaaaaaaaaaaaaaaaa|
+ {3: }{2:>>>}aaaaaaaaaaaa |
+ {5:-- INSERT --} |
+ ]])
+
+ feed('<F2>')
+ screen:expect([[
+ {4:0 }{1:^øøøøøøøøøøøøøøøøøø}|
+ {3: }{2:>>>}øøøøøøøøøøøø |
+ {3:1 }aaaaaaaaaaaaaaaaaa|
+ {3: }{2:>>>}aaaaaaaaaaaa |
+ {5:-- INSERT --} |
+ ]])
end)
it('always updated. vim-patch:8.1.0849', function()
@@ -1266,6 +1305,49 @@ describe('CursorLine and CursorLineNr highlights', function()
end)
end)
+describe('CursorColumn highlight', function()
+ before_each(clear)
+ it('is updated if cursor is moved from timer', function()
+ local screen = Screen.new(50, 8)
+ screen:set_default_attr_ids({
+ [1] = {background = Screen.colors.Gray90}, -- CursorColumn
+ [2] = {bold = true, foreground = Screen.colors.Blue1}, -- NonText
+ })
+ screen:attach()
+ exec([[
+ call setline(1, ['aaaaa', 'bbbbb', 'ccccc', 'ddddd'])
+ set cursorcolumn
+ call cursor(4, 5)
+
+ func Func(timer)
+ call cursor(1, 1)
+ endfunc
+
+ call timer_start(300, 'Func')
+ ]])
+ screen:expect({grid = [[
+ aaaa{1:a} |
+ bbbb{1:b} |
+ cccc{1:c} |
+ dddd^d |
+ {2:~ }|
+ {2:~ }|
+ {2:~ }|
+ |
+ ]], timeout = 100})
+ screen:expect({grid = [[
+ ^aaaaa |
+ {1:b}bbbb |
+ {1:c}cccc |
+ {1:d}dddd |
+ {2:~ }|
+ {2:~ }|
+ {2:~ }|
+ |
+ ]]})
+ end)
+end)
+
describe('ColorColumn highlight', function()
local screen
@@ -1570,6 +1652,46 @@ describe("'number' and 'relativenumber' highlight", function()
|
]])
end)
+
+ it('relative number highlight is updated if cursor is moved from timer', function()
+ local screen = Screen.new(50, 8)
+ screen:set_default_attr_ids({
+ [1] = {foreground = Screen.colors.Brown}, -- LineNr
+ [2] = {bold = true, foreground = Screen.colors.Blue1}, -- NonText
+ })
+ screen:attach()
+ exec([[
+ call setline(1, ['aaaaa', 'bbbbb', 'ccccc', 'ddddd'])
+ set relativenumber
+ call cursor(4, 1)
+
+ func Func(timer)
+ call cursor(1, 1)
+ endfunc
+
+ call timer_start(300, 'Func')
+ ]])
+ screen:expect({grid = [[
+ {1: 3 }aaaaa |
+ {1: 2 }bbbbb |
+ {1: 1 }ccccc |
+ {1: 0 }^ddddd |
+ {2:~ }|
+ {2:~ }|
+ {2:~ }|
+ |
+ ]], timeout = 100})
+ screen:expect({grid = [[
+ {1: 0 }^aaaaa |
+ {1: 1 }bbbbb |
+ {1: 2 }ccccc |
+ {1: 3 }ddddd |
+ {2:~ }|
+ {2:~ }|
+ {2:~ }|
+ |
+ ]]})
+ end)
end)
describe("'winhighlight' highlight", function()
diff --git a/test/functional/ui/input_spec.lua b/test/functional/ui/input_spec.lua
index f5ae228b1e..9df7531016 100644
--- a/test/functional/ui/input_spec.lua
+++ b/test/functional/ui/input_spec.lua
@@ -320,3 +320,47 @@ describe("event processing and input", function()
eq({'notification', 'stop', {}}, next_msg())
end)
end)
+
+describe('display is updated', function()
+ local screen
+ before_each(function()
+ screen = Screen.new(60, 8)
+ screen:set_default_attr_ids({
+ [1] = {bold = true, foreground = Screen.colors.Blue1}, -- NonText
+ [2] = {bold = true}, -- ModeMsg
+ })
+ screen:attach()
+ end)
+
+ it('in Insert mode after <Nop> mapping #17911', function()
+ command('imap <Plug>test <Nop>')
+ command('imap <F2> abc<CR><Plug>test')
+ feed('i<F2>')
+ screen:expect([[
+ abc |
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {2:-- INSERT --} |
+ ]])
+ end)
+
+ it('in Insert mode after empty string <expr> mapping #17911', function()
+ command('imap <expr> <Plug>test ""')
+ command('imap <F2> abc<CR><Plug>test')
+ feed('i<F2>')
+ screen:expect([[
+ abc |
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {2:-- INSERT --} |
+ ]])
+ 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
diff --git a/test/functional/vimscript/lang_spec.lua b/test/functional/vimscript/lang_spec.lua
index d5254986ab..90437f2ee1 100644
--- a/test/functional/vimscript/lang_spec.lua
+++ b/test/functional/vimscript/lang_spec.lua
@@ -11,6 +11,7 @@ describe('vimscript', function()
return
end
source([[
+ let s:foo = 1
func! <sid>_dummy_function()
echo 1
endfunc
diff --git a/test/functional/vimscript/timer_spec.lua b/test/functional/vimscript/timer_spec.lua
index 25e46062b7..20f2afb20f 100644
--- a/test/functional/vimscript/timer_spec.lua
+++ b/test/functional/vimscript/timer_spec.lua
@@ -273,7 +273,7 @@ describe('timers', function()
eq("Vim(call):E48: Not allowed in sandbox", exc_exec("sandbox call timer_start(0, 'Scary')"))
end)
- it('can be triggered after an empty string <expr> mapping', function()
+ it('can be triggered after an empty string <expr> mapping #17257', function()
local screen = Screen.new(40, 6)
screen:attach()
command([=[imap <expr> <F2> [timer_start(0, { _ -> execute("throw 'x'", "") }), ''][-1]]=])
diff --git a/third-party/CMakeLists.txt b/third-party/CMakeLists.txt
index 8a8720fca3..6d02a73d14 100644
--- a/third-party/CMakeLists.txt
+++ b/third-party/CMakeLists.txt
@@ -151,8 +151,8 @@ set(MSGPACK_URL https://github.com/msgpack/msgpack-c/releases/download/cpp-3.0.0
set(MSGPACK_SHA256 bfbb71b7c02f806393bc3cbc491b40523b89e64f83860c58e3e54af47de176e4)
# https://github.com/LuaJIT/LuaJIT/tree/v2.1
-set(LUAJIT_URL https://github.com/LuaJIT/LuaJIT/archive/1d20f33d2905db55fb7191076bbac10f570f9175.tar.gz)
-set(LUAJIT_SHA256 4b6e2fc726ed8bf51fe461d90db9fffbc5c894bbdc862a67d17a70190f1fb07f)
+set(LUAJIT_URL https://github.com/LuaJIT/LuaJIT/archive/e2c312e0deb874aa5fa8ce502c08d87deb38e82f.tar.gz)
+set(LUAJIT_SHA256 bff4764c19466def90667d2f7fcbd0781b8e62476b12105868f8e44babd03f8e)
set(LUA_URL https://www.lua.org/ftp/lua-5.1.5.tar.gz)
set(LUA_SHA256 2640fc56a795f29d28ef15e13c34a47e223960b0240e8cb0a82d9b0738695333)