aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.mailmap1
-rw-r--r--BUILD.md11
-rw-r--r--CONTRIBUTING.md6
-rw-r--r--INSTALL.md6
-rw-r--r--cmake.deps/deps.txt4
-rw-r--r--cmake.packaging/CMakeLists.txt4
-rw-r--r--cmake.packaging/CustomInstallDirDlg.wxs41
-rw-r--r--cmake.packaging/WixPatch.xml2
-rw-r--r--cmake.packaging/WixUI_CustomInstallDir.wxs81
-rw-r--r--runtime/autoload/netrw.vim5
-rw-r--r--runtime/doc/api.txt49
-rw-r--r--runtime/doc/builtin.txt19
-rw-r--r--runtime/doc/deprecated.txt3
-rw-r--r--runtime/doc/diagnostic.txt33
-rw-r--r--runtime/doc/editorconfig.txt4
-rw-r--r--runtime/doc/ft_sql.txt6
-rw-r--r--runtime/doc/gui.txt2
-rw-r--r--runtime/doc/help.txt5
-rw-r--r--runtime/doc/index.txt4
-rw-r--r--runtime/doc/lsp.txt56
-rw-r--r--runtime/doc/lua-guide.txt1
-rw-r--r--runtime/doc/lua.txt15
-rw-r--r--runtime/doc/map.txt1
-rw-r--r--runtime/doc/mbyte.txt2
-rw-r--r--runtime/doc/news-0.10.txt2
-rw-r--r--runtime/doc/news.txt11
-rw-r--r--runtime/doc/nvim_terminal_emulator.txt17
-rw-r--r--runtime/doc/options.txt30
-rw-r--r--runtime/doc/pattern.txt2
-rw-r--r--runtime/doc/quickfix.txt2
-rw-r--r--runtime/doc/quickref.txt1
-rw-r--r--runtime/doc/sign.txt15
-rw-r--r--runtime/doc/syntax.txt46
-rw-r--r--runtime/doc/treesitter.txt6
-rw-r--r--runtime/doc/usr_29.txt2
-rw-r--r--runtime/doc/vim_diff.txt21
-rw-r--r--runtime/ftplugin/abaqus.vim3
-rw-r--r--runtime/ftplugin/arduino.lua1
-rw-r--r--runtime/ftplugin/arduino.vim3
-rw-r--r--runtime/ftplugin/asm.vim3
-rw-r--r--runtime/ftplugin/astro.vim7
-rw-r--r--runtime/ftplugin/bitbake.vim3
-rw-r--r--runtime/ftplugin/c.lua2
-rw-r--r--runtime/ftplugin/c.vim3
-rw-r--r--runtime/ftplugin/calendar.vim3
-rw-r--r--runtime/ftplugin/calender.lua1
-rw-r--r--runtime/ftplugin/cgdbrc.vim3
-rw-r--r--runtime/ftplugin/ch.lua1
-rw-r--r--runtime/ftplugin/cpp.vim6
-rw-r--r--runtime/ftplugin/cs.lua2
-rw-r--r--runtime/ftplugin/csh.vim3
-rw-r--r--runtime/ftplugin/css.lua1
-rw-r--r--runtime/ftplugin/css.vim3
-rw-r--r--runtime/ftplugin/d.lua2
-rw-r--r--runtime/ftplugin/desktop.vim3
-rw-r--r--runtime/ftplugin/dtd.vim3
-rw-r--r--runtime/ftplugin/dtrace.vim5
-rw-r--r--runtime/ftplugin/dts.vim3
-rw-r--r--runtime/ftplugin/erlang.vim5
-rw-r--r--runtime/ftplugin/eruby.vim3
-rw-r--r--runtime/ftplugin/fennel.vim3
-rw-r--r--runtime/ftplugin/fish.vim3
-rw-r--r--runtime/ftplugin/fortran.vim3
-rw-r--r--runtime/ftplugin/fstab.vim3
-rw-r--r--runtime/ftplugin/gdb.vim3
-rw-r--r--runtime/ftplugin/glsl.lua1
-rw-r--r--runtime/ftplugin/groovy.vim3
-rw-r--r--runtime/ftplugin/hamster.vim3
-rw-r--r--runtime/ftplugin/help.lua4
-rw-r--r--runtime/ftplugin/help.vim72
-rw-r--r--runtime/ftplugin/html.vim3
-rw-r--r--runtime/ftplugin/indent.lua2
-rw-r--r--runtime/ftplugin/indent.vim3
-rw-r--r--runtime/ftplugin/initex.vim3
-rw-r--r--runtime/ftplugin/java.vim3
-rw-r--r--runtime/ftplugin/javascript.vim3
-rw-r--r--runtime/ftplugin/jq.vim3
-rw-r--r--runtime/ftplugin/jsonc.vim3
-rw-r--r--runtime/ftplugin/kdl.vim17
-rw-r--r--runtime/ftplugin/lc.vim13
-rw-r--r--runtime/ftplugin/ld.vim5
-rw-r--r--runtime/ftplugin/liquid.vim3
-rw-r--r--runtime/ftplugin/lisp.vim3
-rw-r--r--runtime/ftplugin/markdown.vim3
-rw-r--r--runtime/ftplugin/mma.vim5
-rw-r--r--runtime/ftplugin/modula2.vim3
-rw-r--r--runtime/ftplugin/modula3.vim3
-rw-r--r--runtime/ftplugin/nroff.vim6
-rw-r--r--runtime/ftplugin/objc.lua1
-rw-r--r--runtime/ftplugin/obse.vim7
-rw-r--r--runtime/ftplugin/ocaml.vim4
-rw-r--r--runtime/ftplugin/odin.vim5
-rw-r--r--runtime/ftplugin/openvpn.vim3
-rw-r--r--runtime/ftplugin/pascal.vim3
-rw-r--r--runtime/ftplugin/pdf.vim3
-rw-r--r--runtime/ftplugin/perl.vim3
-rw-r--r--runtime/ftplugin/php.vim3
-rw-r--r--runtime/ftplugin/ps1.vim3
-rw-r--r--runtime/ftplugin/ps1xml.vim3
-rw-r--r--runtime/ftplugin/qml.vim3
-rw-r--r--runtime/ftplugin/racket.vim5
-rw-r--r--runtime/ftplugin/raku.vim13
-rw-r--r--runtime/ftplugin/rasi.vim25
-rw-r--r--runtime/ftplugin/rust.vim11
-rw-r--r--runtime/ftplugin/scdoc.vim9
-rw-r--r--runtime/ftplugin/scheme.vim15
-rw-r--r--runtime/ftplugin/svelte.vim13
-rw-r--r--runtime/ftplugin/tcl.vim3
-rw-r--r--runtime/ftplugin/typescript.vim3
-rw-r--r--runtime/ftplugin/vim.vim3
-rw-r--r--runtime/ftplugin/wat.vim3
-rw-r--r--runtime/ftplugin/xdefaults.lua1
-rw-r--r--runtime/ftplugin/xdefaults.vim9
-rw-r--r--runtime/ftplugin/xml.vim3
-rw-r--r--runtime/ftplugin/xs.lua1
-rw-r--r--runtime/indent/kdl.vim26
-rw-r--r--runtime/lua/editorconfig.lua21
-rw-r--r--runtime/lua/man.lua15
-rw-r--r--runtime/lua/tohtml.lua12
-rw-r--r--runtime/lua/vim/_comment.lua11
-rw-r--r--runtime/lua/vim/_defaults.lua30
-rw-r--r--runtime/lua/vim/_editor.lua5
-rw-r--r--runtime/lua/vim/_meta/api.lua65
-rw-r--r--runtime/lua/vim/_meta/api_keysets.lua3
-rw-r--r--runtime/lua/vim/_meta/api_keysets_extra.lua4
-rw-r--r--runtime/lua/vim/_meta/builtin.lua1
-rw-r--r--runtime/lua/vim/_meta/builtin_types.lua7
-rw-r--r--runtime/lua/vim/_meta/options.lua30
-rw-r--r--runtime/lua/vim/_meta/spell.lua2
-rw-r--r--runtime/lua/vim/_meta/vimfn.lua58
-rw-r--r--runtime/lua/vim/_options.lua12
-rw-r--r--runtime/lua/vim/deprecated/health.lua2
-rw-r--r--runtime/lua/vim/diagnostic.lua23
-rw-r--r--runtime/lua/vim/filetype.lua4
-rw-r--r--runtime/lua/vim/filetype/detect.lua4
-rw-r--r--runtime/lua/vim/glob.lua11
-rw-r--r--runtime/lua/vim/highlight.lua49
-rw-r--r--runtime/lua/vim/iter.lua2
-rw-r--r--runtime/lua/vim/lsp.lua11
-rw-r--r--runtime/lua/vim/lsp/_changetracking.lua3
-rw-r--r--runtime/lua/vim/lsp/_dynamic.lua4
-rw-r--r--runtime/lua/vim/lsp/_meta/protocol.lua2
-rw-r--r--runtime/lua/vim/lsp/client.lua16
-rw-r--r--runtime/lua/vim/lsp/completion.lua333
-rw-r--r--runtime/lua/vim/lsp/handlers.lua1
-rw-r--r--runtime/lua/vim/lsp/inlay_hint.lua6
-rw-r--r--runtime/lua/vim/lsp/log.lua2
-rw-r--r--runtime/lua/vim/lsp/protocol.lua342
-rw-r--r--runtime/lua/vim/lsp/rpc.lua4
-rw-r--r--runtime/lua/vim/lsp/semantic_tokens.lua13
-rw-r--r--runtime/lua/vim/lsp/util.lua113
-rw-r--r--runtime/lua/vim/provider/health.lua2
-rw-r--r--runtime/lua/vim/shared.lua80
-rw-r--r--runtime/lua/vim/treesitter.lua2
-rw-r--r--runtime/lua/vim/treesitter/_fold.lua1
-rw-r--r--runtime/lua/vim/treesitter/_meta.lua2
-rw-r--r--runtime/lua/vim/treesitter/dev.lua2
-rw-r--r--runtime/lua/vim/treesitter/highlighter.lua6
-rw-r--r--runtime/lua/vim/treesitter/languagetree.lua10
-rw-r--r--runtime/lua/vim/ui.lua8
-rw-r--r--runtime/lua/vim/vimhelp.lua38
-rw-r--r--runtime/optwin.vim4
-rw-r--r--runtime/queries/vimdoc/highlights.scm16
-rw-r--r--runtime/syntax/deb822sources.vim2
-rw-r--r--runtime/syntax/java.vim24
-rw-r--r--runtime/syntax/kdl.vim45
-rw-r--r--runtime/syntax/lc.vim2
-rw-r--r--runtime/syntax/mma.vim2
-rw-r--r--runtime/syntax/rasi.vim298
-rw-r--r--runtime/syntax/vim.vim29
-rw-r--r--runtime/tutor/en/vim-01-beginner.tutor2
-rwxr-xr-xscripts/gen_eval_files.lua12
-rw-r--r--scripts/gen_lsp.lua8
-rwxr-xr-xscripts/gen_vimdoc.lua11
-rw-r--r--scripts/lintcommit.lua12
-rw-r--r--scripts/luacats_grammar.lua6
-rw-r--r--scripts/luacats_parser.lua2
-rwxr-xr-xsrc/clint.py2
-rw-r--r--src/man/nvim.14
-rw-r--r--src/nvim/api/buffer.c12
-rw-r--r--src/nvim/api/command.c4
-rw-r--r--src/nvim/api/deprecated.c2
-rw-r--r--src/nvim/api/extmark.c157
-rw-r--r--src/nvim/api/extmark.h15
-rw-r--r--src/nvim/api/keysets_defs.h5
-rw-r--r--src/nvim/api/options.c9
-rw-r--r--src/nvim/api/private/validate.c2
-rw-r--r--src/nvim/api/vim.c3
-rw-r--r--src/nvim/api/vimscript.c2
-rw-r--r--src/nvim/api/win_config.c1
-rw-r--r--src/nvim/api/window.c1
-rw-r--r--src/nvim/arglist.c1
-rw-r--r--src/nvim/autocmd.c13
-rw-r--r--src/nvim/base64.c4
-rw-r--r--src/nvim/buffer.c14
-rw-r--r--src/nvim/buffer_defs.h2
-rw-r--r--src/nvim/bufwrite.c3
-rw-r--r--src/nvim/change.c4
-rw-r--r--src/nvim/channel.c79
-rw-r--r--src/nvim/channel.h8
-rw-r--r--src/nvim/channel_defs.h2
-rw-r--r--src/nvim/charset.c4
-rw-r--r--src/nvim/cmdexpand.c13
-rw-r--r--src/nvim/cmdhist.c1
-rw-r--r--src/nvim/context.c4
-rw-r--r--src/nvim/debugger.c11
-rw-r--r--src/nvim/decoration.c26
-rw-r--r--src/nvim/diff.c67
-rw-r--r--src/nvim/digraph.c1
-rw-r--r--src/nvim/drawline.c3
-rw-r--r--src/nvim/drawscreen.c23
-rw-r--r--src/nvim/edit.c30
-rw-r--r--src/nvim/errors.h193
-rw-r--r--src/nvim/eval.c21
-rw-r--r--src/nvim/eval.lua55
-rw-r--r--src/nvim/eval/encode.c6
-rw-r--r--src/nvim/eval/executor.c1
-rw-r--r--src/nvim/eval/funcs.c11
-rw-r--r--src/nvim/eval/typval.c3
-rw-r--r--src/nvim/eval/userfunc.c5
-rw-r--r--src/nvim/eval/vars.c1
-rw-r--r--src/nvim/eval/window.c3
-rw-r--r--src/nvim/event/defs.h41
-rw-r--r--src/nvim/event/libuv_process.c8
-rw-r--r--src/nvim/event/process.c49
-rw-r--r--src/nvim/event/process.h4
-rw-r--r--src/nvim/event/rstream.c201
-rw-r--r--src/nvim/event/socket.c18
-rw-r--r--src/nvim/event/stream.c29
-rw-r--r--src/nvim/event/wstream.c7
-rw-r--r--src/nvim/ex_cmds.c17
-rw-r--r--src/nvim/ex_cmds2.c1
-rw-r--r--src/nvim/ex_docmd.c61
-rw-r--r--src/nvim/ex_eval.c9
-rw-r--r--src/nvim/ex_getln.c14
-rw-r--r--src/nvim/ex_session.c1
-rw-r--r--src/nvim/extmark.c4
-rw-r--r--src/nvim/file_search.c60
-rw-r--r--src/nvim/fileio.c7
-rw-r--r--src/nvim/fold.c3
-rw-r--r--src/nvim/generators/gen_api_dispatch.lua1
-rw-r--r--src/nvim/generators/gen_api_ui_events.lua8
-rw-r--r--src/nvim/generators/gen_options.lua2
-rw-r--r--src/nvim/getchar.c5
-rw-r--r--src/nvim/globals.h196
-rw-r--r--src/nvim/help.c11
-rw-r--r--src/nvim/highlight.h2
-rw-r--r--src/nvim/highlight_defs.h2
-rw-r--r--src/nvim/highlight_group.c65
-rw-r--r--src/nvim/indent.c58
-rw-r--r--src/nvim/insexpand.c159
-rw-r--r--src/nvim/keycodes.c3
-rw-r--r--src/nvim/linematch.c3
-rw-r--r--src/nvim/log.c10
-rw-r--r--src/nvim/lua/api_wrappers.c1
-rw-r--r--src/nvim/lua/executor.c1
-rw-r--r--src/nvim/lua/secure.c5
-rw-r--r--src/nvim/lua/spell.c1
-rw-r--r--src/nvim/lua/stdlib.c100
-rw-r--r--src/nvim/lua/treesitter.c2
-rw-r--r--src/nvim/main.c2
-rw-r--r--src/nvim/mapping.c29
-rw-r--r--src/nvim/mark.c1
-rw-r--r--src/nvim/marktree.c2
-rw-r--r--src/nvim/marktree.h20
-rw-r--r--src/nvim/match.c1
-rw-r--r--src/nvim/mbyte.c46
-rw-r--r--src/nvim/memfile.c1
-rw-r--r--src/nvim/memline.c4
-rw-r--r--src/nvim/memory.c18
-rw-r--r--src/nvim/memory.h2
-rw-r--r--src/nvim/menu.c27
-rw-r--r--src/nvim/message.c7
-rw-r--r--src/nvim/move.c1
-rw-r--r--src/nvim/msgpack_rpc/channel.c38
-rw-r--r--src/nvim/msgpack_rpc/packer.c1
-rw-r--r--src/nvim/msgpack_rpc/server.c3
-rw-r--r--src/nvim/normal.c3
-rw-r--r--src/nvim/ops.c17
-rw-r--r--src/nvim/option.c47
-rw-r--r--src/nvim/option_vars.h13
-rw-r--r--src/nvim/options.lua30
-rw-r--r--src/nvim/optionstr.c38
-rw-r--r--src/nvim/os/env.c28
-rw-r--r--src/nvim/os/fileio.c276
-rw-r--r--src/nvim/os/fileio_defs.h10
-rw-r--r--src/nvim/os/fs.c7
-rw-r--r--src/nvim/os/input.c131
-rw-r--r--src/nvim/os/pty_process_unix.c6
-rw-r--r--src/nvim/os/pty_process_win.c10
-rw-r--r--src/nvim/os/shell.c139
-rw-r--r--src/nvim/os/stdpaths.c2
-rw-r--r--src/nvim/path.c4
-rw-r--r--src/nvim/plines.c3
-rw-r--r--src/nvim/popupmenu.c8
-rw-r--r--src/nvim/popupmenu.h9
-rw-r--r--src/nvim/profile.c9
-rw-r--r--src/nvim/quickfix.c7
-rw-r--r--src/nvim/rbuffer.c247
-rw-r--r--src/nvim/rbuffer.h71
-rw-r--r--src/nvim/rbuffer_defs.h45
-rw-r--r--src/nvim/regexp.c11
-rw-r--r--src/nvim/runtime.c13
-rw-r--r--src/nvim/search.c27
-rw-r--r--src/nvim/sha256.c5
-rw-r--r--src/nvim/shada.c1
-rw-r--r--src/nvim/sign.c97
-rw-r--r--src/nvim/spell.c181
-rw-r--r--src/nvim/spellfile.c27
-rw-r--r--src/nvim/spellsuggest.c19
-rw-r--r--src/nvim/statusline.c2
-rw-r--r--src/nvim/strings.c27
-rw-r--r--src/nvim/syntax.c15
-rw-r--r--src/nvim/tag.c31
-rw-r--r--src/nvim/terminal.c83
-rw-r--r--src/nvim/testing.c1
-rw-r--r--src/nvim/textformat.c2
-rw-r--r--src/nvim/tui/input.c171
-rw-r--r--src/nvim/tui/input.h13
-rw-r--r--src/nvim/tui/terminfo.c2
-rw-r--r--src/nvim/tui/tui.c16
-rw-r--r--src/nvim/undo.c1
-rw-r--r--src/nvim/usercmd.c16
-rw-r--r--src/nvim/window.c3
-rw-r--r--src/nvim/winfloat.c1
-rw-r--r--test/functional/fixtures/fake-lsp-server.lua14
-rw-r--r--test/functional/lua/buffer_updates_spec.lua19
-rw-r--r--test/functional/lua/diagnostic_spec.lua114
-rw-r--r--test/functional/lua/glob_spec.lua13
-rw-r--r--test/functional/lua/highlight_spec.lua30
-rw-r--r--test/functional/lua/runtime_spec.lua2
-rw-r--r--test/functional/lua/vim_spec.lua21
-rw-r--r--test/functional/lua/with_spec.lua292
-rw-r--r--test/functional/plugin/editorconfig_spec.lua21
-rw-r--r--test/functional/plugin/lsp/completion_spec.lua37
-rw-r--r--test/functional/plugin/lsp/semantic_tokens_spec.lua24
-rw-r--r--test/functional/plugin/lsp_spec.lua49
-rw-r--r--test/functional/plugin/man_spec.lua23
-rw-r--r--test/functional/script/luacats_grammar_spec.lua7
-rw-r--r--test/functional/terminal/buffer_spec.lua6
-rw-r--r--test/functional/terminal/clipboard_spec.lua65
-rw-r--r--test/functional/terminal/mouse_spec.lua8
-rw-r--r--test/functional/terminal/testutil.lua4
-rw-r--r--test/functional/terminal/tui_spec.lua55
-rw-r--r--test/functional/terminal/window_split_tab_spec.lua8
-rw-r--r--test/functional/testnvim.lua2
-rw-r--r--test/functional/ui/cursor_spec.lua2
-rw-r--r--test/functional/ui/decorations_spec.lua238
-rw-r--r--test/functional/ui/messages_spec.lua16
-rw-r--r--test/functional/ui/screen.lua2
-rw-r--r--test/functional/ui/sign_spec.lua30
-rw-r--r--test/old/testdir/runtest.vim2
-rw-r--r--test/old/testdir/setup.vim2
-rw-r--r--test/old/testdir/test_debugger.vim10
-rw-r--r--test/old/testdir/test_diffmode.vim4
-rw-r--r--test/old/testdir/test_excmd.vim2
-rw-r--r--test/old/testdir/test_filetype.vim3
-rw-r--r--test/old/testdir/test_flatten.vim2
-rw-r--r--test/old/testdir/test_fold.vim70
-rw-r--r--test/old/testdir/test_ins_complete.vim127
-rw-r--r--test/old/testdir/test_normal.vim118
-rw-r--r--test/old/testdir/test_options.vim2
-rw-r--r--test/old/testdir/test_quickfix.vim8
-rw-r--r--test/old/testdir/test_signs.vim6
-rw-r--r--test/old/testdir/test_spellfile.vim2
-rw-r--r--test/old/testdir/test_syntax.vim3
-rw-r--r--test/old/testdir/test_textobjects.vim2
-rw-r--r--test/old/testdir/test_trycatch.vim2
-rw-r--r--test/old/testdir/test_vartabs.vim73
-rw-r--r--test/old/testdir/test_visual.vim9
-rw-r--r--test/unit/fixtures/rbuffer.c28
-rw-r--r--test/unit/fixtures/rbuffer.h9
-rw-r--r--test/unit/rbuffer_spec.lua340
373 files changed, 5062 insertions, 3793 deletions
diff --git a/.mailmap b/.mailmap
index a0af0033a1..55bc59fd75 100644
--- a/.mailmap
+++ b/.mailmap
@@ -18,6 +18,7 @@ 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
+Famiu Haque <famiuhaque@proton.me> <famiuhaque@protonmail.com>
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
diff --git a/BUILD.md b/BUILD.md
index 621a615948..4c24cf9b45 100644
--- a/BUILD.md
+++ b/BUILD.md
@@ -84,7 +84,7 @@ make deps
- Right-click _CMakeLists.txt → Delete Cache_.
- Right-click _CMakeLists.txt → Generate Cache_.
- If you see an "access violation" from `ntdll`, you can ignore it and continue.
-4. If you set an error like `msgpackc.dll not found`, try the `nvim.exe (Install)` target. Then switch back to `nvim.exe (bin\nvim.exe)`.
+4. If you see an error like `msgpackc.dll not found`, try the `nvim.exe (Install)` target. Then switch back to `nvim.exe (bin\nvim.exe)`.
### Windows / MSVC PowerShell
@@ -365,13 +365,16 @@ and replacing `neovim-unwrapped` with `neovim-dev`:
nix-shell '<nixpkgs>' -A neovim-dev
```
-Neovim contains a Nix flake in the `contrib` folder, with 3 packages:
+A flake for Neovim is hosted at [nix-community/neovim-nightly-overlay](https://github.com/nix-community/neovim-nightly-overlay/), with 3 packages:
- `neovim` to run the nightly
- `neovim-debug` to run the package with debug symbols
- `neovim-developer` to get all the tools to develop on `neovim`
-Thus you can run Neovim nightly with `nix run github:neovim/neovim?dir=contrib`.
-Similarly to develop on Neovim: `nix develop github:neovim/neovim?dir=contrib#neovim-developer`.
+Thus you can run Neovim nightly with `nix run github:nix-community/neovim-nightly-overlay`.
+Similarly to develop on Neovim: `nix run github:nix-community/neovim-nightly-overlay#neovim-developer`.
+
+To use a specific version of Neovim, you can pass `--override-input neovim-src .` to use your current directory,
+or a specific SHA1 like `--override-input neovim-src github:neovim/neovim/89dc8f8f4e754e70cbe1624f030fb61bded41bc2`.
### FreeBSD
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index d080f3079e..f40d4c54b7 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -42,10 +42,10 @@ Developer guidelines
make distclean
make # Nvim build system uses ninja automatically, if available.
```
-- Install `ccache` for faster rebuilds of Nvim. Nvim will use it automatically
- if it's found. To disable caching use:
+- Install `ccache` or `sccache` for faster rebuilds of Nvim. Nvim will use one
+ of these automatically if it's found. To disable caching use:
```bash
- CCACHE_DISABLE=true make
+ cmake -B build -D CACHE_PRG=OFF
```
Pull requests (PRs)
diff --git a/INSTALL.md b/INSTALL.md
index 056a5acb04..3e80e3e67e 100644
--- a/INSTALL.md
+++ b/INSTALL.md
@@ -112,7 +112,7 @@ sudo rm -rf /opt/nvim
sudo tar -C /opt -xzf nvim-linux64.tar.gz
```
-After this step add this to `~/.bashrc`:
+Then add this to your shell config (`~/.bashrc`, `~/. zshrc`, ...):
export PATH="$PATH:/opt/nvim-linux64/bin"
@@ -129,7 +129,7 @@ To expose nvim globally:
mkdir -p /opt/nvim
mv nvim.appimage /opt/nvim/nvim
-And the following line to `~/.bashrc`:
+And the following line to your shell config (`~/.bashrc`, `~/. zshrc`, ...):
export PATH="$PATH:/opt/nvim/"
@@ -204,7 +204,7 @@ You can also get nightly builds of git master from the [Copr automated build sys
dnf copr enable agriffis/neovim-nightly
dnf install -y neovim python3-neovim
-See the [blog post](https://arongriffis.com/2019/03/02/neovim-nightly-builds) for information on how these are built.
+See the [blog post](https://arongriffis.com/2019-03-02-neovim-nightly-builds) for information on how these are built.
### Flatpak
diff --git a/cmake.deps/deps.txt b/cmake.deps/deps.txt
index f2b152640e..356bfd92d4 100644
--- a/cmake.deps/deps.txt
+++ b/cmake.deps/deps.txt
@@ -47,8 +47,8 @@ TREESITTER_LUA_URL https://github.com/tree-sitter-grammars/tree-sitter-lua/archi
TREESITTER_LUA_SHA256 230cfcbfa74ed1f7b8149e9a1f34c2efc4c589a71fe0f5dc8560622f8020d722
TREESITTER_VIM_URL https://github.com/neovim/tree-sitter-vim/archive/v0.4.0.tar.gz
TREESITTER_VIM_SHA256 9f856f8b4a10ab43348550fa2d3cb2846ae3d8e60f45887200549c051c66f9d5
-TREESITTER_VIMDOC_URL https://github.com/neovim/tree-sitter-vimdoc/archive/v2.5.1.tar.gz
-TREESITTER_VIMDOC_SHA256 063645096504b21603585507c41c6d8718ff3c11b2150c5bfc31e8f3ee9afea3
+TREESITTER_VIMDOC_URL https://github.com/neovim/tree-sitter-vimdoc/archive/v3.0.0.tar.gz
+TREESITTER_VIMDOC_SHA256 a639bf92bf57bfa1cdc90ca16af27bfaf26a9779064776dd4be34c1ef1453f6c
TREESITTER_QUERY_URL https://github.com/tree-sitter-grammars/tree-sitter-query/archive/v0.4.0.tar.gz
TREESITTER_QUERY_SHA256 d3a423ab66dc62b2969625e280116678a8a22582b5ff087795222108db2f6a6e
TREESITTER_PYTHON_URL https://github.com/tree-sitter/tree-sitter-python/archive/v0.21.0.tar.gz
diff --git a/cmake.packaging/CMakeLists.txt b/cmake.packaging/CMakeLists.txt
index 645215ec92..7dd3f211f3 100644
--- a/cmake.packaging/CMakeLists.txt
+++ b/cmake.packaging/CMakeLists.txt
@@ -39,6 +39,10 @@ if(WIN32)
set(CPACK_WIX_PROGRAM_MENU_FOLDER "${CPACK_PACKAGE_NAME}")
set(CPACK_PACKAGE_EXECUTABLES "nvim" "Neovim")
+ set(CPACK_WIX_UI_REF "WixUI_CustomInstallDir")
+ list(APPEND CPACK_WIX_EXTRA_SOURCES ${CMAKE_CURRENT_LIST_DIR}/WixUI_CustomInstallDir.wxs)
+ list(APPEND CPACK_WIX_EXTRA_SOURCES ${CMAKE_CURRENT_LIST_DIR}/CustomInstallDirDlg.wxs)
+
# We use a wix patch to add further options to the installer.
# See: https://cmake.org/cmake/help/v3.7/module/CPackWIX.html#variable:CPACK_WIX_PATCH_FILE
list(APPEND CPACK_WIX_EXTENSIONS WixUtilExtension)
diff --git a/cmake.packaging/CustomInstallDirDlg.wxs b/cmake.packaging/CustomInstallDirDlg.wxs
new file mode 100644
index 0000000000..73864cec0b
--- /dev/null
+++ b/cmake.packaging/CustomInstallDirDlg.wxs
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. -->
+
+
+<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
+ <Fragment>
+ <UI>
+ <Dialog Id="CustomInstallDirDlg" Width="370" Height="270" Title="!(loc.InstallDirDlg_Title)">
+ <Control Id="Next" Type="PushButton" X="236" Y="243" Width="56" Height="17" Default="yes" Text="!(loc.WixUINext)" />
+ <Control Id="Back" Type="PushButton" X="180" Y="243" Width="56" Height="17" Text="!(loc.WixUIBack)" />
+ <Control Id="Cancel" Type="PushButton" X="304" Y="243" Width="56" Height="17" Cancel="yes" Text="!(loc.WixUICancel)">
+ <Publish Event="SpawnDialog" Value="CancelDlg">1</Publish>
+ </Control>
+
+ <Control Id="Description" Type="Text" X="25" Y="23" Width="280" Height="15" Transparent="yes" NoPrefix="yes" Text="!(loc.InstallDirDlgDescription)" />
+ <Control Id="Title" Type="Text" X="15" Y="6" Width="200" Height="15" Transparent="yes" NoPrefix="yes" Text="!(loc.InstallDirDlgTitle)" />
+ <Control Id="BannerBitmap" Type="Bitmap" X="0" Y="0" Width="370" Height="44" TabSkip="no" Text="!(loc.InstallDirDlgBannerBitmap)" />
+ <Control Id="BannerLine" Type="Line" X="0" Y="44" Width="370" Height="0" />
+ <Control Id="BottomLine" Type="Line" X="0" Y="234" Width="370" Height="0" />
+
+ <Control Id="Note" Type="Text" X="20" Y="45" Width="290" Height="45" NoPrefix="yes">
+ <Text>Note: besides its installation folder, [ProductName] stores configuration, data, and logs in standard locations. These can be further configured by the $NVIM_APPNAME environment variable. Also, the "base" (root) directories conform to the XDG Base Directory Specification. For more information see:</Text>
+ </Control>
+ <Control Id="Link1" Type="Hyperlink" X="20" Y="90" Width="290" Height="15">
+ <Text><![CDATA[<a href="https://neovim.io/doc/user/starting.html#standard-path">https://neovim.io/doc/user/starting.html#standard-path</a>]]></Text>
+ </Control>
+ <Control Id="Link2" Type="Hyperlink" X="20" Y="105" Width="290" Height="15">
+ <Text><![CDATA[<a href="https://neovim.io/doc/user/starting.html#base-directories">https://neovim.io/doc/user/starting.html#base-directories</a>]]></Text>
+ </Control>
+ <Control Id="Link3" Type="Hyperlink" X="20" Y="120" Width="290" Height="15">
+ <Text><![CDATA[<a href="https://neovim.io/doc/user/starting.html#%24NVIM_APPNAME">https://neovim.io/doc/user/starting.html#$NVIM_APPNAME</a>]]></Text>
+ </Control>
+ <Control Id="FolderLabel" Type="Hyperlink" X="20" Y="135" Width="290" Height="15">
+ <Text>Install [ProductName] to:</Text>
+ </Control>
+ <Control Id="Folder" Type="PathEdit" X="20" Y="150" Width="320" Height="18" Property="WIXUI_INSTALLDIR" Indirect="yes" />
+ <Control Id="ChangeFolder" Type="PushButton" X="20" Y="180" Width="56" Height="17" Text="!(loc.InstallDirDlgChange)" />
+ </Dialog>
+ </UI>
+ </Fragment>
+</Wix>
diff --git a/cmake.packaging/WixPatch.xml b/cmake.packaging/WixPatch.xml
index 1196f4f335..89c47753ce 100644
--- a/cmake.packaging/WixPatch.xml
+++ b/cmake.packaging/WixPatch.xml
@@ -6,7 +6,7 @@
Name='PATH'
Action='set'
Permanent='no'
- System='no'
+ System='yes'
Part='last'
Value='[INSTALL_ROOT]bin'
/>
diff --git a/cmake.packaging/WixUI_CustomInstallDir.wxs b/cmake.packaging/WixUI_CustomInstallDir.wxs
new file mode 100644
index 0000000000..8015758771
--- /dev/null
+++ b/cmake.packaging/WixUI_CustomInstallDir.wxs
@@ -0,0 +1,81 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. -->
+
+
+
+<!--
+First-time install dialog sequence:
+ - WixUI_WelcomeDlg
+ - WixUI_LicenseAgreementDlg
+ - WixUI_InstallDirDlg
+ - WixUI_VerifyReadyDlg
+ - WixUI_DiskCostDlg
+
+Maintenance dialog sequence:
+ - WixUI_MaintenanceWelcomeDlg
+ - WixUI_MaintenanceTypeDlg
+ - WixUI_InstallDirDlg
+ - WixUI_VerifyReadyDlg
+
+Patch dialog sequence:
+ - WixUI_WelcomeDlg
+ - WixUI_VerifyReadyDlg
+
+-->
+
+<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
+ <Fragment>
+ <UI Id="WixUI_CustomInstallDir">
+ <TextStyle Id="WixUI_Font_Normal" FaceName="Tahoma" Size="8" />
+ <TextStyle Id="WixUI_Font_Bigger" FaceName="Tahoma" Size="12" />
+ <TextStyle Id="WixUI_Font_Title" FaceName="Tahoma" Size="9" Bold="yes" />
+
+ <Property Id="DefaultUIFont" Value="WixUI_Font_Normal" />
+ <Property Id="WixUI_Mode" Value="InstallDir" />
+
+ <DialogRef Id="BrowseDlg" />
+ <DialogRef Id="DiskCostDlg" />
+ <DialogRef Id="ErrorDlg" />
+ <DialogRef Id="FatalError" />
+ <DialogRef Id="FilesInUse" />
+ <DialogRef Id="MsiRMFilesInUse" />
+ <DialogRef Id="PrepareDlg" />
+ <DialogRef Id="ProgressDlg" />
+ <DialogRef Id="ResumeDlg" />
+ <DialogRef Id="UserExit" />
+
+ <Publish Dialog="BrowseDlg" Control="OK" Event="DoAction" Value="WixUIValidatePath" Order="3">1</Publish>
+ <Publish Dialog="BrowseDlg" Control="OK" Event="SpawnDialog" Value="InvalidDirDlg" Order="4"><![CDATA[NOT WIXUI_DONTVALIDATEPATH AND WIXUI_INSTALLDIR_VALID<>"1"]]></Publish>
+
+ <Publish Dialog="ExitDialog" Control="Finish" Event="EndDialog" Value="Return" Order="999">1</Publish>
+
+ <Publish Dialog="WelcomeDlg" Control="Next" Event="NewDialog" Value="LicenseAgreementDlg">NOT Installed</Publish>
+ <Publish Dialog="WelcomeDlg" Control="Next" Event="NewDialog" Value="VerifyReadyDlg">Installed AND PATCH</Publish>
+
+ <Publish Dialog="LicenseAgreementDlg" Control="Back" Event="NewDialog" Value="WelcomeDlg">1</Publish>
+ <Publish Dialog="LicenseAgreementDlg" Control="Next" Event="NewDialog" Value="CustomInstallDirDlg">LicenseAccepted = "1"</Publish>
+
+ <Publish Dialog="CustomInstallDirDlg" Control="Back" Event="NewDialog" Value="LicenseAgreementDlg">1</Publish>
+ <Publish Dialog="CustomInstallDirDlg" Control="Next" Event="SetTargetPath" Value="[WIXUI_INSTALLDIR]" Order="1">1</Publish>
+ <Publish Dialog="CustomInstallDirDlg" Control="Next" Event="DoAction" Value="WixUIValidatePath" Order="2">NOT WIXUI_DONTVALIDATEPATH</Publish>
+ <Publish Dialog="CustomInstallDirDlg" Control="Next" Event="SpawnDialog" Value="InvalidDirDlg" Order="3"><![CDATA[NOT WIXUI_DONTVALIDATEPATH AND WIXUI_INSTALLDIR_VALID<>"1"]]></Publish>
+ <Publish Dialog="CustomInstallDirDlg" Control="Next" Event="NewDialog" Value="VerifyReadyDlg" Order="4">WIXUI_DONTVALIDATEPATH OR WIXUI_INSTALLDIR_VALID="1"</Publish>
+ <Publish Dialog="CustomInstallDirDlg" Control="ChangeFolder" Property="_BrowseProperty" Value="[WIXUI_INSTALLDIR]" Order="1">1</Publish>
+ <Publish Dialog="CustomInstallDirDlg" Control="ChangeFolder" Event="SpawnDialog" Value="BrowseDlg" Order="2">1</Publish>
+
+ <Publish Dialog="VerifyReadyDlg" Control="Back" Event="NewDialog" Value="CustomInstallDirDlg" Order="1">NOT Installed</Publish>
+ <Publish Dialog="VerifyReadyDlg" Control="Back" Event="NewDialog" Value="MaintenanceTypeDlg" Order="2">Installed AND NOT PATCH</Publish>
+ <Publish Dialog="VerifyReadyDlg" Control="Back" Event="NewDialog" Value="WelcomeDlg" Order="2">Installed AND PATCH</Publish>
+
+ <Publish Dialog="MaintenanceWelcomeDlg" Control="Next" Event="NewDialog" Value="MaintenanceTypeDlg">1</Publish>
+
+ <Publish Dialog="MaintenanceTypeDlg" Control="RepairButton" Event="NewDialog" Value="VerifyReadyDlg">1</Publish>
+ <Publish Dialog="MaintenanceTypeDlg" Control="RemoveButton" Event="NewDialog" Value="VerifyReadyDlg">1</Publish>
+ <Publish Dialog="MaintenanceTypeDlg" Control="Back" Event="NewDialog" Value="MaintenanceWelcomeDlg">1</Publish>
+
+ <Property Id="ARPNOMODIFY" Value="1" />
+ </UI>
+
+ <UIRef Id="WixUI_Common" />
+ </Fragment>
+</Wix>
diff --git a/runtime/autoload/netrw.vim b/runtime/autoload/netrw.vim
index ae602c5be6..a1929636e5 100644
--- a/runtime/autoload/netrw.vim
+++ b/runtime/autoload/netrw.vim
@@ -12,6 +12,8 @@
" 2024 May 08 by Vim Project: cleanup legacy Win9X checks
" 2024 May 09 by Vim Project: remove hard-coded private.ppk
" 2024 May 10 by Vim Project: recursively delete directories by default
+" 2024 May 13 by Vim Project: prefer scp over pscp
+" 2024 Jun 04 by Vim Project: set bufhidden if buffer changed, nohidden is set and buffer shall be switched (#14915)
" Former Maintainer: Charles E Campbell
" GetLatestVimScripts: 1075 1 :AutoInstall: netrw.vim
" Copyright: Copyright (C) 2016 Charles E. Campbell {{{1
@@ -5681,6 +5683,9 @@ fun! s:NetrwEditFile(cmd,opt,fname)
exe "NetrwKeepj keepalt ".a:opt." ".a:cmd." ".fnameescape(a:fname)
else
" call Decho("exe NetrwKeepj ".a:opt." ".a:cmd." ".fnameescape(a:fname))
+ if a:cmd =~# 'e\%[new]!' && !&hidden && getbufvar(bufname('%'), '&modified', 0)
+ call setbufvar(bufname('%'), '&bufhidden', 'hide')
+ endif
exe "NetrwKeepj ".a:opt." ".a:cmd." ".fnameescape(a:fname)
endif
" call Dret("s:NetrwEditFile")
diff --git a/runtime/doc/api.txt b/runtime/doc/api.txt
index 38960e1bc2..f92a69af4e 100644
--- a/runtime/doc/api.txt
+++ b/runtime/doc/api.txt
@@ -2138,14 +2138,14 @@ nvim_buf_attach({buffer}, {send_buffer}, {opts}) *nvim_buf_attach()*
• |api-buffer-updates-lua|
nvim_buf_call({buffer}, {fun}) *nvim_buf_call()*
- call a function with buffer as temporary current buffer
+ Call a function with buffer as temporary current buffer.
This temporarily switches current buffer to "buffer". If the current
- window already shows "buffer", the window is not switched If a window
- inside the current tabpage (including a float) already shows the buffer
- One of these windows will be set as current window temporarily. Otherwise
- a temporary scratch window (called the "autocmd window" for historical
- reasons) will be used.
+ window already shows "buffer", the window is not switched. If a window
+ inside the current tabpage (including a float) already shows the buffer,
+ then one of these windows will be set as current window temporarily.
+ Otherwise a temporary scratch window (called the "autocmd window" for
+ historical reasons) will be used.
This is useful e.g. to call Vimscript functions that only work with the
current buffer/window currently, like |termopen()|.
@@ -2758,8 +2758,6 @@ nvim_buf_set_extmark({buffer}, {ns_id}, {line}, {col}, {opts})
• url: A URL to associate with this extmark. In the TUI, the
OSC 8 control sequence is used to generate a clickable
hyperlink to this URL.
- • scoped: boolean (EXPERIMENTAL) enables "scoping" for the
- extmark. See |nvim__win_add_ns()|
Return: ~
Id of the created/updated extmark
@@ -2831,7 +2829,7 @@ nvim_set_decoration_provider({ns_id}, {opts})
["buf", bufnr, tick]
<
• on_win: called when starting to redraw a specific window. >
- ["win", winid, bufnr, topline, botline]
+ ["win", winid, bufnr, toprow, botrow]
<
• on_line: called for each buffer line being redrawn. (The
interaction with fold lines is subject to change) >
@@ -2841,41 +2839,26 @@ nvim_set_decoration_provider({ns_id}, {opts})
["end", tick]
<
-nvim__win_add_ns({window}, {ns_id}) *nvim__win_add_ns()*
+nvim__ns_get({ns_id}) *nvim__ns_get()*
EXPERIMENTAL: this API will change in the future.
- Scopes a namespace to the a window, so extmarks in the namespace will be
- active only in the given window.
+ Get the properties for namespace
Parameters: ~
- • {window} Window handle, or 0 for current window
- • {ns_id} Namespace
-
- Return: ~
- true if the namespace was added, else false
-
-nvim__win_del_ns({window}, {ns_id}) *nvim__win_del_ns()*
- EXPERIMENTAL: this API will change in the future.
-
- Unscopes a namespace (un-binds it from the given scope).
-
- Parameters: ~
- • {window} Window handle, or 0 for current window
- • {ns_id} the namespace to remove
+ • {ns_id} Namespace
Return: ~
- true if the namespace was removed, else false
+ Map defining the namespace properties, see |nvim__ns_set()|
-nvim__win_get_ns({window}) *nvim__win_get_ns()*
+nvim__ns_set({ns_id}, {opts}) *nvim__ns_set()*
EXPERIMENTAL: this API will change in the future.
- Gets the namespace scopes for a given window.
+ Set some properties for namespace
Parameters: ~
- • {window} Window handle, or 0 for current window
-
- Return: ~
- a list of namespaces ids
+ • {ns_id} Namespace
+ • {opts} Optional parameters to set:
+ • wins: a list of windows to be scoped in
==============================================================================
diff --git a/runtime/doc/builtin.txt b/runtime/doc/builtin.txt
index 1a762c6ec0..8ee01d6156 100644
--- a/runtime/doc/builtin.txt
+++ b/runtime/doc/builtin.txt
@@ -4102,10 +4102,21 @@ line({expr} [, {winid}]) *line()*
display isn't updated, e.g. in silent Ex mode)
w$ last line visible in current window (this is one
less than "w0" if no lines are visible)
- v In Visual mode: the start of the Visual area (the
- cursor is the end). When not in Visual mode
- returns the cursor position. Differs from |'<| in
- that it's updated right away.
+ v When not in Visual mode, returns the cursor
+ position. In Visual mode, returns the other end
+ of the Visual area. A good way to think about
+ this is that in Visual mode "v" and "." complement
+ each other. While "." refers to the cursor
+ position, "v" refers to where |v_o| would move the
+ cursor. As a result, you can use "v" and "."
+ together to work on all of a selection in
+ characterwise visual mode. If the cursor is at
+ the end of a characterwise visual area, "v" refers
+ to the start of the same visual area. And if the
+ cursor is at the start of a characterwise visual
+ area, "v" refers to the end of the same visual
+ area. "v" differs from |'<| and |'>| in that it's
+ updated right away.
Note that a mark in another file can be used. The line number
then applies to another buffer.
To get the column number use |col()|. To get both use
diff --git a/runtime/doc/deprecated.txt b/runtime/doc/deprecated.txt
index 3b3e6afa9e..6c6585d76e 100644
--- a/runtime/doc/deprecated.txt
+++ b/runtime/doc/deprecated.txt
@@ -22,9 +22,6 @@ API
LUA
- vim.region() Use |getregionpos()| instead.
-LSP
-- *vim.lsp.util.buf_versions* Use |b:changedtick| instead.
-
DIAGNOSTICS
- *vim.diagnostic.goto_next()* Use |vim.diagnostic.jump()| with `{count = 1}` instead.
- *vim.diagnostic.goto_prev()* Use |vim.diagnostic.jump()| with `{count = -1}` instead.
diff --git a/runtime/doc/diagnostic.txt b/runtime/doc/diagnostic.txt
index 2438c48154..05af2eddc3 100644
--- a/runtime/doc/diagnostic.txt
+++ b/runtime/doc/diagnostic.txt
@@ -363,7 +363,6 @@ Lua module: vim.diagnostic *diagnostic-api*
• {message} (`string`) The diagnostic text
• {source}? (`string`) The source of the diagnostic
• {code}? (`string|integer`) The diagnostic code
- • {_tags}? (`{ deprecated: boolean, unnecessary: boolean}`)
• {user_data}? (`any`) arbitrary data plugins can add
• {namespace}? (`integer`)
@@ -393,11 +392,11 @@ Lua module: vim.diagnostic *diagnostic-api*
by {count} diagnostics, while a negative integer moves
backward by {count} diagnostics. Mutually exclusive
with {diagnostic}.
- • {pos}? (`{[1]:integer,[2]:integer}`) Cursor position as a
- `(row, col)` tuple. See |nvim_win_get_cursor()|. Used
- to find the nearest diagnostic when {count} is used.
- Only used when {count} is non-nil. Default is the
- current cursor position.
+ • {pos}? (`[integer,integer]`) Cursor position as a `(row, col)`
+ tuple. See |nvim_win_get_cursor()|. Used to find the
+ nearest diagnostic when {count} is used. Only used when
+ {count} is non-nil. Default is the current cursor
+ position.
• {wrap}? (`boolean`, default: `true`) Whether to loop around
file or not. Similar to 'wrapscan'.
• {severity}? (`vim.diagnostic.SeverityFilter`) See
@@ -467,18 +466,18 @@ Lua module: vim.diagnostic *diagnostic-api*
current cursor position (`cursor`). Shorthand
versions are also accepted (`c` for `cursor`, `l`
for `line`, `b` for `buffer`).
- • {pos}? (`integer|{[1]:integer,[2]:integer}`) If {scope} is
- "line" or "cursor", use this position rather than
- the cursor position. If a number, interpreted as a
- line number; otherwise, a (row, col) tuple.
+ • {pos}? (`integer|[integer,integer]`) If {scope} is "line"
+ or "cursor", use this position rather than the
+ cursor position. If a number, interpreted as a line
+ number; otherwise, a (row, col) tuple.
• {severity_sort}? (`boolean|{reverse?:boolean}`, default: `false`)
Sort diagnostics by severity. Overrides the setting
from |vim.diagnostic.config()|.
• {severity}? (`vim.diagnostic.SeverityFilter`) See
|diagnostic-severity|. Overrides the setting from
|vim.diagnostic.config()|.
- • {header}? (`string|{[1]:string,[2]:any}`) String to use as the
- header for the floating window. If a table, it is
+ • {header}? (`string|[string,any]`) String to use as the header
+ for the floating window. If a table, it is
interpreted as a `[text, hl_group]` tuple. Overrides
the setting from |vim.diagnostic.config()|.
• {source}? (`boolean|'if_many'`) Include the diagnostic source
@@ -516,10 +515,11 @@ Lua module: vim.diagnostic *diagnostic-api*
*vim.diagnostic.Opts.Jump*
Fields: ~
- • {float}? (`boolean|vim.diagnostic.Opts.Float`) Default value of
- the {float} parameter of |vim.diagnostic.jump()|.
- • {wrap}? (`boolean`) Default value of the {wrap} parameter of
+ • {float}? (`boolean|vim.diagnostic.Opts.Float`, default: false)
+ Default value of the {float} parameter of
|vim.diagnostic.jump()|.
+ • {wrap}? (`boolean`, default: true) Default value of the {wrap}
+ parameter of |vim.diagnostic.jump()|.
• {severity}? (`vim.diagnostic.SeverityFilter`) Default value of the
{severity} parameter of |vim.diagnostic.jump()|.
@@ -591,8 +591,7 @@ Lua module: vim.diagnostic *diagnostic-api*
<
• {hl_mode}? (`'replace'|'combine'|'blend'`) See
|nvim_buf_set_extmark()|.
- • {virt_text}? (`{[1]:string,[2]:any}[]`) See
- |nvim_buf_set_extmark()|.
+ • {virt_text}? (`[string,any][]`) See |nvim_buf_set_extmark()|.
• {virt_text_pos}? (`'eol'|'overlay'|'right_align'|'inline'`) See
|nvim_buf_set_extmark()|.
• {virt_text_win_col}? (`integer`) See |nvim_buf_set_extmark()|.
diff --git a/runtime/doc/editorconfig.txt b/runtime/doc/editorconfig.txt
index 0b20c77801..eef14ed51c 100644
--- a/runtime/doc/editorconfig.txt
+++ b/runtime/doc/editorconfig.txt
@@ -78,6 +78,10 @@ root *editorconfig.root*
directories. This property must be at the top-level of the `.editorconfig`
file (i.e. it must not be within a glob section).
+spelling_language *editorconfig.spelling_language*
+ A code of the format ss or ss-TT, where ss is an ISO 639 language code and
+ TT is an ISO 3166 territory identifier. Sets the 'spelllang' option.
+
tab_width *editorconfig.tab_width*
The display size of a single tab character. Sets the 'tabstop' option.
diff --git a/runtime/doc/ft_sql.txt b/runtime/doc/ft_sql.txt
index 241fa4bd74..1dbac66db0 100644
--- a/runtime/doc/ft_sql.txt
+++ b/runtime/doc/ft_sql.txt
@@ -293,7 +293,7 @@ loaded by Vim: >
ftplugin/sql.vim
syntax/sqlinformix.vim
indent/sql.vim
->
+<
Notice indent/sqlinformix.sql was not loaded. There is no indent file
for Informix, Vim loads the default files if the specified files does not
exist.
@@ -349,7 +349,7 @@ The defaults static maps are: >
The use of "<C-C>" can be user chosen by using the following in your |init.vim|
as it may not work properly on all platforms: >
let g:ftplugin_sql_omni_key = '<C-C>'
->
+<
The static maps (which are based on the syntax highlight groups) follow this
format: >
imap <buffer> <C-C>k <C-\><C-O>:call sqlcomplete#Map('sqlKeyword')<CR><C-X><C-O>
@@ -664,7 +664,7 @@ your |init.vim|: >
filetype is changed temporarily to SQL, the sqlcompletion plugin
will cache the syntax groups listed in the List specified in this
option.
->
+
------------------------------------------------------------------------------
4.5 SQL Maps *sql-completion-maps*
diff --git a/runtime/doc/gui.txt b/runtime/doc/gui.txt
index a64d722177..104413ce0d 100644
--- a/runtime/doc/gui.txt
+++ b/runtime/doc/gui.txt
@@ -221,7 +221,7 @@ is right aligned, and the "O" is underlined, to indicate it is the shortcut.
*:am* *:amenu* *:an* *:anoremenu*
The ":amenu" command can be used to define menu entries for all modes at once,
-expect for Terminal mode. To make the command work correctly, a character is
+except for Terminal mode. To make the command work correctly, a character is
automatically inserted for some modes:
mode inserted appended ~
Normal nothing nothing
diff --git a/runtime/doc/help.txt b/runtime/doc/help.txt
index 43f80101ed..fefead7fc9 100644
--- a/runtime/doc/help.txt
+++ b/runtime/doc/help.txt
@@ -127,6 +127,7 @@ PROGRAMMING LANGUAGE SUPPORT
|filetype| Settings for specific types of files
|quickfix| Commands for a quick edit-compile-fix cycle
|ft_ada.txt| Ada filetype plugin
+|ft_hare.txt| Filetype plugin for Hare
|ft_ps1.txt| PowerShell filetype plugin
|ft_raku.txt| Raku filetype plugin
|ft_rust.txt| Rust filetype plugin
@@ -187,7 +188,7 @@ Local additions ~
*local-additions*
------------------------------------------------------------------------------
-*bars* Bars example
+Bars example *bars*
Now that you've jumped here with CTRL-] or a double mouse click, you can use
CTRL-T, CTRL-O, g<RightMouse>, or <C-RightMouse> to go back to where you were.
@@ -199,5 +200,5 @@ You can use CTRL-] on any word (even if it is not within "|") and Nvim will
try to find help for it. Especially for options in single quotes, e.g.
'hlsearch'.
-------------------------------------------------------------------------------
+
vim:tw=78:isk=!-~,^*,^\|,^\":ts=8:noet:ft=help:norl:
diff --git a/runtime/doc/index.txt b/runtime/doc/index.txt
index 79f10b33f1..05c8b94d94 100644
--- a/runtime/doc/index.txt
+++ b/runtime/doc/index.txt
@@ -366,7 +366,7 @@ tag char note action in Normal mode ~
or start of putted text
|`]| `] 1 cursor to the end of last operated text or
end of putted text
-|``| `` 1 cursor to the position before latest jump
+|``| "``" 1 cursor to the position before latest jump
|`{| `{ 1 cursor to the start of the current paragraph
|`}| `} 1 cursor to the end of the current paragraph
|a| a 2 append text after the cursor N times
@@ -1136,7 +1136,7 @@ tag command action ~
|:!!| :!! repeat last ":!" command
|:#| :# same as ":number"
|:&| :& repeat last ":substitute"
-|:star| :* use the last Visual area, like :'<,'>
+|:star| :* use the last Visual area, like ":'<,'>"
|:<| :< shift lines one 'shiftwidth' left
|:=| := print the last line number
|:>| :> shift lines one 'shiftwidth' right
diff --git a/runtime/doc/lsp.txt b/runtime/doc/lsp.txt
index a78a16968f..ca9dfd0350 100644
--- a/runtime/doc/lsp.txt
+++ b/runtime/doc/lsp.txt
@@ -514,10 +514,10 @@ LspAttach *LspAttach*
callback = function(args)
local bufnr = args.buf
local client = vim.lsp.get_client_by_id(args.data.client_id)
- if client.server_capabilities.completionProvider then
+ if client.supports_method("textDocument/completion") then
vim.bo[bufnr].omnifunc = "v:lua.vim.lsp.omnifunc"
end
- if client.server_capabilities.definitionProvider then
+ if client.supports_method("textDocument/definition") then
vim.bo[bufnr].tagfunc = "v:lua.vim.lsp.tagfunc"
end
end,
@@ -874,13 +874,13 @@ start({config}, {opts}) *vim.lsp.start()*
• {config} (`vim.lsp.ClientConfig`) Configuration for the server. See
|vim.lsp.ClientConfig|.
• {opts} (`table?`) Optional keyword arguments
- • {reuse_client}
+ • {reuse_client}?
(`fun(client: vim.lsp.Client, config: vim.lsp.ClientConfig): boolean`)
Predicate used to decide if a client should be re-used.
Used on all running clients. The default implementation
re-uses a client if name and root_dir matches.
- • {bufnr} (`integer`) Buffer handle to attach to if starting
- or re-using a client (0 for current).
+ • {bufnr}? (`integer`) Buffer handle to attach to if
+ starting or re-using a client (0 for current).
• {silent}? (`boolean`) Suppress error reporting if the LSP
server fails to start (default false).
@@ -1832,8 +1832,8 @@ apply_text_document_edit({text_document_edit}, {index}, {offset_encoding})
document.
Parameters: ~
- • {text_document_edit} (`table`) a `TextDocumentEdit` object
- • {index} (`integer`) Optional index of the edit, if from
+ • {text_document_edit} (`lsp.TextDocumentEdit`)
+ • {index} (`integer?`) Optional index of the edit, if from
a list of edits (or nil, if not from a list)
• {offset_encoding} (`string?`)
@@ -1845,7 +1845,7 @@ apply_text_edits({text_edits}, {bufnr}, {offset_encoding})
Applies a list of text edits to a buffer.
Parameters: ~
- • {text_edits} (`table`) list of `TextEdit` objects
+ • {text_edits} (`lsp.TextEdit[]`)
• {bufnr} (`integer`) Buffer id
• {offset_encoding} (`string`) utf-8|utf-16|utf-32
@@ -1857,7 +1857,7 @@ apply_workspace_edit({workspace_edit}, {offset_encoding})
Applies a `WorkspaceEdit`.
Parameters: ~
- • {workspace_edit} (`table`) `WorkspaceEdit`
+ • {workspace_edit} (`lsp.WorkspaceEdit`)
• {offset_encoding} (`string`) utf-8|utf-16|utf-32 (required)
See also: ~
@@ -1875,8 +1875,7 @@ buf_highlight_references({bufnr}, {references}, {offset_encoding})
Parameters: ~
• {bufnr} (`integer`) Buffer id
- • {references} (`table`) List of `DocumentHighlight` objects to
- highlight
+ • {references} (`lsp.DocumentHighlight[]`) objects to highlight
• {offset_encoding} (`string`) One of "utf-8", "utf-16", "utf-32".
See also: ~
@@ -1910,8 +1909,8 @@ convert_input_to_markdown_lines({input}, {contents})
Parameters: ~
• {input} (`lsp.MarkedString|lsp.MarkedString[]|lsp.MarkupContent`)
- • {contents} (`table?`) List of strings to extend with converted lines.
- Defaults to {}.
+ • {contents} (`string[]?`) List of strings to extend with converted
+ lines. Defaults to {}.
Return: ~
(`string[]`) extended with lines of converted markdown.
@@ -1924,15 +1923,16 @@ convert_signature_help_to_markdown_lines({signature_help}, {ft}, {triggers})
Converts `textDocument/signatureHelp` response to markdown lines.
Parameters: ~
- • {signature_help} (`table`) Response of `textDocument/SignatureHelp`
+ • {signature_help} (`lsp.SignatureHelp`) Response of
+ `textDocument/SignatureHelp`
• {ft} (`string?`) filetype that will be use as the `lang`
for the label markdown code block
• {triggers} (`table?`) list of trigger characters from the lsp
server. used to better determine parameter offsets
Return (multiple): ~
- (`table?`) table list of lines of converted markdown.
- (`table?`) table of active hl
+ (`string[]?`) table list of lines of converted markdown.
+ (`number[]?`) table of active hl
See also: ~
• https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_signatureHelp
@@ -1954,7 +1954,7 @@ jump_to_location({location}, {offset_encoding}, {reuse_win})
Jumps to a location.
Parameters: ~
- • {location} (`table`) (`Location`|`LocationLink`)
+ • {location} (`lsp.Location|lsp.LocationLink`)
• {offset_encoding} (`string?`) utf-8|utf-16|utf-32
• {reuse_win} (`boolean?`) Jump to existing window if buffer is
already open.
@@ -1983,7 +1983,9 @@ locations_to_items({locations}, {offset_encoding})
(`table[]`) A list of objects with the following fields:
• {filename} (`string`)
• {lnum} (`integer`) 1-indexed line number
+ • {end_lnum} (`integer`) 1-indexed end line number
• {col} (`integer`) 1-indexed column
+ • {end_col} (`integer`) 1-indexed end column
• {text} (`string`)
• {user_data} (`lsp.Location|lsp.LocationLink`)
@@ -2019,7 +2021,8 @@ make_formatting_params({options})
cursor position.
Parameters: ~
- • {options} (`table?`) with valid `FormattingOptions` entries
+ • {options} (`lsp.FormattingOptions?`) with valid `FormattingOptions`
+ entries
Return: ~
(`lsp.DocumentFormattingParams`) object
@@ -2059,7 +2062,7 @@ make_position_params({window}, {offset_encoding})
`window`
Return: ~
- (`table`) `TextDocumentPositionParams` object
+ (`lsp.TextDocumentPositionParams`)
See also: ~
• https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocumentPositionParams
@@ -2090,7 +2093,7 @@ make_text_document_params({bufnr})
• {bufnr} (`integer?`) Buffer handle, defaults to current
Return: ~
- (`table`) `TextDocumentIdentifier`
+ (`lsp.TextDocumentIdentifier`)
See also: ~
• https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocumentIdentifier
@@ -2100,8 +2103,11 @@ make_workspace_params({added}, {removed})
Create the workspace params
Parameters: ~
- • {added} (`table`)
- • {removed} (`table`)
+ • {added} (`lsp.WorkspaceFolder[]`)
+ • {removed} (`lsp.WorkspaceFolder[]`)
+
+ Return: ~
+ (`lsp.WorkspaceFoldersChangeEvent`)
*vim.lsp.util.open_floating_preview()*
open_floating_preview({contents}, {syntax}, {opts})
@@ -2145,7 +2151,7 @@ preview_location({location}, {opts}) *vim.lsp.util.preview_location()*
definition)
Parameters: ~
- • {location} (`table`) a single `Location` or `LocationLink`
+ • {location} (`lsp.Location|lsp.LocationLink`)
• {opts} (`table`)
Return (multiple): ~
@@ -2175,7 +2181,7 @@ show_document({location}, {offset_encoding}, {opts})
Shows document and optionally jumps to the location.
Parameters: ~
- • {location} (`table`) (`Location`|`LocationLink`)
+ • {location} (`lsp.Location|lsp.LocationLink`)
• {offset_encoding} (`string?`) utf-8|utf-16|utf-32
• {opts} (`table?`) options
• reuse_win (boolean) Jump to existing window if
@@ -2200,7 +2206,7 @@ stylize_markdown({bufnr}, {contents}, {opts})
Parameters: ~
• {bufnr} (`integer`)
- • {contents} (`table`) of lines to show in window
+ • {contents} (`string[]`) of lines to show in window
• {opts} (`table`) with optional fields
• height of floating window
• width of floating window
diff --git a/runtime/doc/lua-guide.txt b/runtime/doc/lua-guide.txt
index e8757a1859..5f06d51f42 100644
--- a/runtime/doc/lua-guide.txt
+++ b/runtime/doc/lua-guide.txt
@@ -225,7 +225,6 @@ Vimscript are automatically converted:
end
vim.fn.jobstart('ls', { on_stdout = print_stdout })
- print(vim.fn.printf('Hello from %s', 'Lua'))
<
This works for both |builtin-functions| and |user-function|s.
diff --git a/runtime/doc/lua.txt b/runtime/doc/lua.txt
index 8e600adeb9..3bfd1d1885 100644
--- a/runtime/doc/lua.txt
+++ b/runtime/doc/lua.txt
@@ -834,8 +834,8 @@ vim.spell.check({str}) *vim.spell.check()*
• {str} (`string`)
Return: ~
- (`{[1]: string, [2]: 'bad'|'rare'|'local'|'caps', [3]: integer}[]`)
- List of tuples with three items:
+ (`[string, 'bad'|'rare'|'local'|'caps', integer][]`) List of tuples
+ with three items:
• The badly spelled word.
• The type of the spelling error: "bad" spelling mistake "rare" rare
word "local" word only valid in another region "caps" word should
@@ -981,6 +981,9 @@ vim.str_byteindex({str}, {index}, {use_utf16}) *vim.str_byteindex()*
• {index} (`integer`)
• {use_utf16} (`boolean?`)
+ Return: ~
+ (`integer`)
+
vim.str_utf_end({str}, {index}) *vim.str_utf_end()*
Gets the distance (in bytes) from the last byte of the codepoint
(character) that {index} points to.
@@ -4079,10 +4082,10 @@ Iter:map({f}) *Iter:map()*
<
Parameters: ~
- • {f} (`fun(...):any`) Mapping function. Takes all values returned from
- the previous stage in the pipeline as arguments and returns one
- or more new values, which are used in the next pipeline stage.
- Nil return values are filtered from the output.
+ • {f} (`fun(...):...:any`) Mapping function. Takes all values returned
+ from the previous stage in the pipeline as arguments and returns
+ one or more new values, which are used in the next pipeline
+ stage. Nil return values are filtered from the output.
Return: ~
(`Iter`)
diff --git a/runtime/doc/map.txt b/runtime/doc/map.txt
index 9ec34d5d52..f5cbb7b732 100644
--- a/runtime/doc/map.txt
+++ b/runtime/doc/map.txt
@@ -1381,7 +1381,6 @@ completion can be enabled:
-complete=arglist file names in argument list
-complete=augroup autocmd groups
-complete=buffer buffer names
- -complete=behave :behave suboptions
-complete=color color schemes
-complete=command Ex command (and arguments)
-complete=compiler compilers
diff --git a/runtime/doc/mbyte.txt b/runtime/doc/mbyte.txt
index 0a7e0baad3..a8c5670352 100644
--- a/runtime/doc/mbyte.txt
+++ b/runtime/doc/mbyte.txt
@@ -686,7 +686,7 @@ You might want to select the font used for the menus. Unfortunately this
doesn't always work. See the system specific remarks below, and 'langmenu'.
-USING UTF-8 IN X-Windows *utf-8-in-xwindows*
+USING UTF-8 IN X-WINDOWS *utf-8-in-xwindows*
You need to specify a font to be used. For double-wide characters another
font is required, which is exactly twice as wide. There are three ways to do
diff --git a/runtime/doc/news-0.10.txt b/runtime/doc/news-0.10.txt
index d611eee242..bc868c1099 100644
--- a/runtime/doc/news-0.10.txt
+++ b/runtime/doc/news-0.10.txt
@@ -155,8 +155,6 @@ The following new features were added.
• |nvim_input_mouse()| supports mouse buttons "x1" and "x2".
• Added "force_crlf" option field in |nvim_open_term()|.
• Added |nvim_tabpage_set_win()| to set the current window of a tabpage.
- • |nvim__win_add_ns()| can bind a |namespace| to a window-local scope(s).
- • Extmarks opt-in to this scoping via the `scoped` flag of |nvim_buf_set_extmark()|.
• Mapping APIs now support abbreviations when mode short-name has suffix "a".
• Floating windows can now show footer with new `footer` and `footer_pos`
config fields. Uses |hl-FloatFooter| by default.
diff --git a/runtime/doc/news.txt b/runtime/doc/news.txt
index 13e4b23ea1..4addbf84c3 100644
--- a/runtime/doc/news.txt
+++ b/runtime/doc/news.txt
@@ -83,7 +83,7 @@ The following new features were added.
API
-• TODO
+• |nvim__ns_set()| can set properties for a namespace
DEFAULTS
@@ -113,6 +113,7 @@ LSP
• Completion side effects (including snippet expansion, execution of commands
and application of additional text edits) is now built-in.
+• |vim.lsp.util.locations_to_items()| sets `end_col` and `end_lnum` fields.
LUA
@@ -128,7 +129,8 @@ PERFORMANCE
PLUGINS
-• TODO
+• EditorConfig
+ • spelling_language property is now supported.
STARTUP
@@ -136,7 +138,10 @@ STARTUP
TERMINAL
-• TODO
+• The |terminal| now understands the OSC 52 escape sequence to write to the
+ system clipboard (copy). Querying with OSC 52 (paste) is not supported.
+• |hl-StatusLineTerm| and |hl-StatusLineTermNC| define highlights for the
+ status line in |terminal| windows.
TREESITTER
diff --git a/runtime/doc/nvim_terminal_emulator.txt b/runtime/doc/nvim_terminal_emulator.txt
index a6ebc7e958..81bcd89146 100644
--- a/runtime/doc/nvim_terminal_emulator.txt
+++ b/runtime/doc/nvim_terminal_emulator.txt
@@ -164,7 +164,22 @@ directory indicated in the request. >lua
To try it out, select the above code and source it with `:'<,'>lua`, then run
this command in a :terminal buffer: >
- printf "\033]7;file://./foo/bar\033\\"
+ printf "\033]7;file://./foo/bar\033\\"
+
+OSC 52: write to system clipboard *terminal-osc52*
+
+Applications in the :terminal buffer can write to the system clipboard by
+emitting an OSC 52 sequence. Example: >
+
+ printf '\033]52;;%s\033\\' "$(echo -n 'Hello world' | base64)"
+
+Nvim uses the configured |clipboard| provider to write to the system
+clipboard. Reading from the system clipboard with OSC 52 is not supported, as
+this would allow any arbitrary program in the :terminal to read the user's
+clipboard.
+
+OSC 52 sequences sent from the :terminal buffer do not emit a |TermRequest|
+event. The event is handled directly by Nvim and is not forwarded to plugins.
==============================================================================
Status Variables *terminal-status*
diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt
index edda46e197..f02d3c9741 100644
--- a/runtime/doc/options.txt
+++ b/runtime/doc/options.txt
@@ -1442,8 +1442,8 @@ A jump table for the options with a short description can be found at |Q_op|.
'commentstring' 'cms' string (default "")
local to buffer
A template for a comment. The "%s" in the value is replaced with the
- comment text. For example, C uses "/*%s*/". Used for |commenting| and to
- add markers for folding, see |fold-marker|.
+ comment text, and should be padded with a space when possible.
+ Used for |commenting| and to add markers for folding, see |fold-marker|.
*'complete'* *'cpt'* *E535*
'complete' 'cpt' string (default ".,w,b,u,t")
@@ -1495,7 +1495,7 @@ A jump table for the options with a short description can be found at |Q_op|.
*'completeopt'* *'cot'*
'completeopt' 'cot' string (default "menu,preview")
- global
+ global or local to buffer |global-local|
A comma-separated list of options for Insert mode completion
|ins-completion|. The supported values are:
@@ -1517,6 +1517,10 @@ A jump table for the options with a short description can be found at |Q_op|.
completion in the preview window. Only works in
combination with "menu" or "menuone".
+ popup Show extra information about the currently selected
+ completion in a popup window. Only works in combination
+ with "menu" or "menuone". Overrides "preview".
+
noinsert Do not insert any text for a match until the user selects
a match from the menu. Only works in combination with
"menu" or "menuone". No effect if "longest" is present.
@@ -1525,9 +1529,13 @@ A jump table for the options with a short description can be found at |Q_op|.
select one from the menu. Only works in combination with
"menu" or "menuone".
- popup Show extra information about the currently selected
- completion in a popup window. Only works in combination
- with "menu" or "menuone". Overrides "preview".
+ fuzzy Enable |fuzzy-matching| for completion candidates. This
+ allows for more flexible and intuitive matching, where
+ characters can be skipped and matches can be found even
+ if the exact sequence is not typed. Only makes a
+ difference how completion candidates are reduced from the
+ list of alternatives, but not how the candidates are
+ collected (using different completion types).
*'completeslash'* *'csl'*
'completeslash' 'csl' string (default "")
@@ -5459,8 +5467,8 @@ A jump table for the options with a short description can be found at |Q_op|.
message; also for quickfix message (e.g., ":cn")
s don't give "search hit BOTTOM, continuing at TOP" or *shm-s*
"search hit TOP, continuing at BOTTOM" messages; when using
- the search count do not show "W" after the count message (see
- S below)
+ the search count do not show "W" before the count message
+ (see |shm-S| below)
t truncate file message at the start if it is too long *shm-t*
to fit on the command-line, "<" will appear in the left most
column; ignored in Ex mode
@@ -5482,7 +5490,11 @@ A jump table for the options with a short description can be found at |Q_op|.
`:silent` was used for the command; note that this also
affects messages from 'autoread' reloading
S do not show search count message when searching, e.g. *shm-S*
- "[1/5]"
+ "[1/5]". When the "S" flag is not present (e.g. search count
+ is shown), the "search hit BOTTOM, continuing at TOP" and
+ "search hit TOP, continuing at BOTTOM" messages are only
+ indicated by a "W" (Mnemonic: Wrapped) letter before the
+ search count statistics.
This gives you the opportunity to avoid that a change between buffers
requires you to hit <Enter>, but still gives as useful a message as
diff --git a/runtime/doc/pattern.txt b/runtime/doc/pattern.txt
index 1ef182127c..67ef769203 100644
--- a/runtime/doc/pattern.txt
+++ b/runtime/doc/pattern.txt
@@ -1494,5 +1494,7 @@ the matching positions and the fuzzy match scores.
The "f" flag of `:vimgrep` enables fuzzy matching.
+To enable fuzzy matching for |ins-completion|, add the "fuzzy" value to the
+'completeopt' option.
vim:tw=78:ts=8:noet:ft=help:norl:
diff --git a/runtime/doc/quickfix.txt b/runtime/doc/quickfix.txt
index 5d3c0cbdc2..897e503fc4 100644
--- a/runtime/doc/quickfix.txt
+++ b/runtime/doc/quickfix.txt
@@ -1296,7 +1296,7 @@ passed to make, say :make html or :make pdf.
Additional arguments can be passed to pandoc:
- either by appending them to make, say `:make html --self-contained` .
-- or setting them in `b:pandoc_compiler_args` or `g:pandoc_compiler_args`
+- or setting them in `b:pandoc_compiler_args` or `g:pandoc_compiler_args`.
PERL *quickfix-perl* *compiler-perl*
diff --git a/runtime/doc/quickref.txt b/runtime/doc/quickref.txt
index c0d00d16cb..5eea9baa20 100644
--- a/runtime/doc/quickref.txt
+++ b/runtime/doc/quickref.txt
@@ -898,6 +898,7 @@ Short explanation of each option: *option-list*
'tagstack' 'tgst' push tags onto the tag stack
'term' name of the terminal
'termbidi' 'tbidi' terminal takes care of bi-directionality
+'termguicolors' 'tgc' enable 24-bit RGB color in the TUI
'textwidth' 'tw' maximum width of text that is being inserted
'thesaurus' 'tsr' list of thesaurus files for keyword completion
'thesaurusfunc' 'tsrfu' function to be used for thesaurus completion
diff --git a/runtime/doc/sign.txt b/runtime/doc/sign.txt
index 6fa260be40..a64ba0ea1c 100644
--- a/runtime/doc/sign.txt
+++ b/runtime/doc/sign.txt
@@ -67,15 +67,12 @@ sign group allows Vim plugins to use unique signs without interfering with
other plugins using signs.
*sign-priority*
-Each placed sign is assigned a priority value. When multiple signs are placed
-on the same line, the attributes of the sign with the highest priority is used
-independently of the sign group. The default priority for a sign is 10. The
-priority is assigned at the time of placing a sign.
-
-When multiple signs that each have an icon or text are present, signs are
-ordered with increasing priority from left to right, up until the maximum
-width set in 'signcolumn'. Lower priority signs that do not fit are hidden.
-Highest priority signs with highlight attributes are always shown.
+Each placed sign is assigned a priority value independently of the sign group.
+The default priority for a sign is 10. When multiple signs that each have an
+icon or text are placed on the same line, signs are ordered with decreasing
+priority from left to right, up until the maximum width set in 'signcolumn'.
+Lower priority signs that do not fit are hidden. Highest priority signs with
+highlight attributes are always shown.
When the line on which the sign is placed is deleted, the sign is removed along
with it.
diff --git a/runtime/doc/syntax.txt b/runtime/doc/syntax.txt
index 06d7ad8f7e..9fc415a158 100644
--- a/runtime/doc/syntax.txt
+++ b/runtime/doc/syntax.txt
@@ -466,14 +466,14 @@ ASTRO *astro.vim* *ft-astro-syntax*
Configuration
The following variables control certain syntax highlighting features.
-You can add them to your .vimrc: >
+You can add them to your .vimrc.
+
+To enable TypeScript and TSX for ".astro" files (default "disable"): >
let g:astro_typescript = "enable"
<
-Enables TypeScript and TSX for ".astro" files. Default Value: "disable" >
+To enable Stylus for ".astro" files (default "disable"): >
let g:astro_stylus = "enable"
<
-Enables Stylus for ".astro" files. Default Value: "disable"
-
NOTE: You need to install an external plugin to support stylus in astro files.
@@ -1437,7 +1437,7 @@ Note: Syntax folding might slow down syntax highlighting significantly,
especially for large files.
-HTML/OS (by Aestiva) *htmlos.vim* *ft-htmlos-syntax*
+HTML/OS (BY AESTIVA) *htmlos.vim* *ft-htmlos-syntax*
The coloring scheme for HTML/OS works as follows:
@@ -2575,6 +2575,13 @@ To highlight R code in knitr chunk headers, add to your |vimrc|: >
let rrst_syn_hl_chunk = 1
+RASI *rasi.vim* *ft-rasi-syntax*
+
+Rasi stands for Rofi Advanced Style Information. It is used by the program
+rofi to style the rendering of the search window. The language is heavily
+inspired by CSS stylesheet. Files with the following extensions are recognized
+as rasi files: .rasi.
+
READLINE *readline.vim* *ft-readline-syntax*
The readline library is primarily used by the BASH shell, which adds quite a
@@ -3320,23 +3327,31 @@ The g:vimsyn_embed option allows users to select what, if any, types of
embedded script highlighting they wish to have. >
g:vimsyn_embed == 0 : disable (don't embed any scripts)
- g:vimsyn_embed == 'lpPr' : support embedded lua, perl, python and ruby
+ g:vimsyn_embed == 'lpPr' : support embedded Lua, Perl, Python and Ruby
<
This option is disabled by default.
*g:vimsyn_folding*
-
-Some folding is now supported with syntax/vim.vim: >
+Some folding is now supported with when 'foldmethod' is set to "syntax": >
g:vimsyn_folding == 0 or doesn't exist: no syntax-based folding
g:vimsyn_folding =~ 'a' : augroups
g:vimsyn_folding =~ 'f' : fold functions
g:vimsyn_folding =~ 'h' : fold heredocs
- g:vimsyn_folding =~ 'l' : fold lua script
- g:vimsyn_folding =~ 'p' : fold perl script
- g:vimsyn_folding =~ 'P' : fold python script
- g:vimsyn_folding =~ 'r' : fold ruby script
+ g:vimsyn_folding =~ 'l' : fold Lua script
+ g:vimsyn_folding =~ 'p' : fold Perl script
+ g:vimsyn_folding =~ 'P' : fold Python script
+ g:vimsyn_folding =~ 'r' : fold Ruby script
<
- *g:vimsyn_noerror*
+
+By default, g:vimsyn_folding is unset. Concatenate the indicated characters
+to support folding of multiple syntax constructs (e.g.,
+g:vimsyn_folding = "fh" will enable folding of both functions and heredocs).
+
+ *g:vimsyn_comment_strings*
+By default, strings are highlighted inside comments. This may be disabled by
+setting g:vimsyn_comment_strings to false.
+
+ *g:vimsyn_noerror*
Not all error highlighting that syntax/vim.vim does may be correct; Vim script
is a difficult language to highlight correctly. A way to suppress error
highlighting is to put the following line in your |vimrc|: >
@@ -5092,6 +5107,11 @@ SpellRare Word that is recognized by the spellchecker as one that is
StatusLine Status line of current window.
*hl-StatusLineNC*
StatusLineNC Status lines of not-current windows.
+ *hl-StatusLineTerm*
+StatusLineTerm Status line of |terminal| window.
+ *hl-StatusLineTermNC*
+StatusLineTermNC
+ Status line of non-current |terminal| windows.
*hl-TabLine*
TabLine Tab pages line, not active tab page label.
*hl-TabLineFill*
diff --git a/runtime/doc/treesitter.txt b/runtime/doc/treesitter.txt
index 0b84bb60d4..25b070b310 100644
--- a/runtime/doc/treesitter.txt
+++ b/runtime/doc/treesitter.txt
@@ -764,9 +764,9 @@ get_node({opts}) *vim.treesitter.get_node()*
• {opts} (`table?`) Optional keyword arguments:
• {bufnr} (`integer?`) Buffer number (nil or 0 for current
buffer)
- • {pos} (`{ [1]: integer, [2]: integer }?`) 0-indexed (row,
- col) tuple. Defaults to cursor position in the current
- window. Required if {bufnr} is not the current buffer
+ • {pos} (`[integer, integer]?`) 0-indexed (row, col) tuple.
+ Defaults to cursor position in the current window. Required
+ if {bufnr} is not the current buffer
• {lang} (`string?`) Parser language. (default: from buffer
filetype)
• {ignore_injections} (`boolean?`) Ignore injected languages
diff --git a/runtime/doc/usr_29.txt b/runtime/doc/usr_29.txt
index dd8598a3a0..9929be5079 100644
--- a/runtime/doc/usr_29.txt
+++ b/runtime/doc/usr_29.txt
@@ -87,7 +87,7 @@ The ":tags" command shows the list of tags that you traversed through:
1 1 write_line 8 write_block.c ~
2 1 write_char 7 write_line.c ~
> ~
->
+<
Now to go back. The CTRL-T command goes to the preceding tag. In the example
above you get back to the "write_line" function, in the call to "write_char".
This command takes a count argument that indicates how many tags to jump
diff --git a/runtime/doc/vim_diff.txt b/runtime/doc/vim_diff.txt
index ac20948f14..a6f08402f6 100644
--- a/runtime/doc/vim_diff.txt
+++ b/runtime/doc/vim_diff.txt
@@ -166,6 +166,14 @@ nvim_terminal:
when 'background' is "light". While this may not reflect the actual
foreground/background color, it permits 'background' to be retained for a
nested Nvim instance running in the terminal emulator.
+- TermOpen: Sets default options for |terminal| buffers:
+ - 'nomodifiable'
+ - 'undolevels' set to -1
+ - 'textwidth' set to 0
+ - 'nowrap'
+ - 'nolist'
+ - 'winhighlight' uses |hl-StatusLineTerm| and |hl-StatusLineTermNC| in
+ place of |hl-StatusLine| and |hl-StatusLineNC|
nvim_cmdwin:
- CmdwinEnter: Limits syntax sync to maxlines=1 in the |cmdwin|.
@@ -538,6 +546,8 @@ Highlight groups:
- Highlight groups names are allowed to contain `@` characters.
- It is an error to define a highlight group with a name that doesn't match
the regexp `[a-zA-Z0-9_.@-]*` (see |group-name|).
+- |hl-StatusLineTerm| |hl-StatusLineTermNC| are implemented as 'winhighlight'
+ window-local highlights which are set by the default |TermOpen| handler.
Macro (|recording|) behavior:
- Replay of a macro recorded during :lmap produces the same actions as when it
@@ -665,17 +675,6 @@ Events:
- *SafeStateAgain*
- *SigUSR1* Use |Signal| to detect `SIGUSR1` signal instead.
-Highlight groups:
-- *hl-StatusLineTerm* *hl-StatusLineTermNC* are unnecessary because Nvim
- supports 'winhighlight' window-local highlights. For example, to mimic Vim's
- StatusLineTerm: >vim
- hi StatusLineTerm ctermfg=black ctermbg=green
- hi StatusLineTermNC ctermfg=green
- autocmd TermOpen,WinEnter * if &buftype=='terminal'
- \|setlocal winhighlight=StatusLine:StatusLineTerm,StatusLineNC:StatusLineTermNC
- \|else|setlocal winhighlight=|endif
-<
-
Options:
- *'aleph'* *'al'*
- antialias
diff --git a/runtime/ftplugin/abaqus.vim b/runtime/ftplugin/abaqus.vim
index c16e7b032e..d4bb6fe777 100644
--- a/runtime/ftplugin/abaqus.vim
+++ b/runtime/ftplugin/abaqus.vim
@@ -3,6 +3,7 @@
" Maintainer: Carl Osterwisch <costerwi@gmail.com>
" Last Change: 2022 Oct 08
" 2024 Jan 14 by Vim Project (browsefilter)
+" 2024 May 23 by Riley Bruins <ribru17@gmail.com> ('commentstring')
" Only do this when not done yet for this buffer
if exists("b:did_ftplugin") | finish | endif
@@ -27,7 +28,7 @@ setlocal isfname-=,
" Define format of comment lines (see 'formatoptions' for uses)
setlocal comments=:**
-setlocal commentstring=**%s
+setlocal commentstring=**\ %s
" Definitions start with a * and assign a NAME, NSET, or ELSET
" Used in [d ^wd and other commands
diff --git a/runtime/ftplugin/arduino.lua b/runtime/ftplugin/arduino.lua
new file mode 100644
index 0000000000..f398d66a63
--- /dev/null
+++ b/runtime/ftplugin/arduino.lua
@@ -0,0 +1 @@
+vim.bo.commentstring = '// %s'
diff --git a/runtime/ftplugin/arduino.vim b/runtime/ftplugin/arduino.vim
index dae3dd83d3..60b11dab1a 100644
--- a/runtime/ftplugin/arduino.vim
+++ b/runtime/ftplugin/arduino.vim
@@ -3,6 +3,7 @@
" Maintainer: The Vim Project <https://github.com/vim/vim>
" Ken Takata <https://github.com/k-takata>
" Last Change: 2024 Apr 12
+" 2024 Jun 02 by Riley Bruins <ribru17@gmail.com> ('commentstring')
"
" Most of the part was copied from c.vim.
@@ -32,7 +33,7 @@ setlocal fo-=t fo+=croql
" These options have the right value as default, but the user may have
" overruled that.
-setlocal commentstring& define& include&
+setlocal commentstring=/*\ %s\ */ define& include&
" Set completion with CTRL-X CTRL-O to autoloaded function.
if exists('&ofu')
diff --git a/runtime/ftplugin/asm.vim b/runtime/ftplugin/asm.vim
index 0ae1610394..4482b90d0b 100644
--- a/runtime/ftplugin/asm.vim
+++ b/runtime/ftplugin/asm.vim
@@ -4,13 +4,14 @@
" Last Change: 2020 May 23
" 2023 Aug 28 by Vim Project (undo_ftplugin)
" 2024 Apr 09 by Vim Project (add Matchit support)
+" 2024 May 23 by Riley Bruins <ribru17@gmail.com> ('commentstring')
if exists("b:did_ftplugin") | finish | endif
let b:did_ftplugin = 1
setl include=^\\s*%\\s*include
setl comments=:;,s1:/*,mb:*,ex:*/,://
-setl commentstring=;%s
+setl commentstring=;\ %s
let b:undo_ftplugin = "setl commentstring< comments< include<"
diff --git a/runtime/ftplugin/astro.vim b/runtime/ftplugin/astro.vim
index 0b0e03447b..5d35ba9624 100644
--- a/runtime/ftplugin/astro.vim
+++ b/runtime/ftplugin/astro.vim
@@ -2,6 +2,7 @@
" Language: Astro
" Maintainer: Romain Lafourcade <romainlafourcade@gmail.com>
" Last Change: 2024 Apr 21
+" 2024 May 24 by Riley Bruins <ribru17@gmail.com> ('commentstring')
if exists("b:did_ftplugin")
finish
@@ -25,17 +26,17 @@ function! s:AstroComments() abort
\ || s:IdentifyScope('^\s*<script', '^\s*<\/script>')
" ECMAScript comments
setlocal comments=sO:*\ -,mO:*\ \ ,exO:*/,s1:/*,mb:*,ex:*/,://
- setlocal commentstring=//%s
+ setlocal commentstring=//\ %s
elseif s:IdentifyScope('^\s*<style', '^\s*<\/style>')
" CSS comments
setlocal comments=s1:/*,mb:*,ex:*/
- setlocal commentstring=/*%s*/
+ setlocal commentstring=/*\ %s\ */
else
" HTML comments
setlocal comments=s:<!--,m:\ \ \ \ ,e:-->
- setlocal commentstring=<!--%s-->
+ setlocal commentstring=<!--\ %s\ -->
endif
endfunction
diff --git a/runtime/ftplugin/bitbake.vim b/runtime/ftplugin/bitbake.vim
index 99fe334627..4d50a7feb7 100644
--- a/runtime/ftplugin/bitbake.vim
+++ b/runtime/ftplugin/bitbake.vim
@@ -3,13 +3,14 @@
" Maintainer: Gregory Anders <greg@gpanders.com>
" Repository: https://github.com/openembedded/bitbake
" Latest Revision: 2022-07-23
+" 2024-05-23 by Riley Bruins <ribru17@gmail.com> ('commentstring')
if exists("b:did_ftplugin")
finish
endif
let b:did_ftplugin = 1
-setlocal commentstring=#%s
+setlocal commentstring=#\ %s
setlocal comments=:#
setlocal suffixesadd=.bb,.bbclass
diff --git a/runtime/ftplugin/c.lua b/runtime/ftplugin/c.lua
index 0ddbf09470..2695b642aa 100644
--- a/runtime/ftplugin/c.lua
+++ b/runtime/ftplugin/c.lua
@@ -1,5 +1,5 @@
-- These are the default option values in Vim, but not in Nvim, so must be set explicitly.
-vim.bo.commentstring = '/*%s*/'
+vim.bo.commentstring = '// %s'
vim.bo.define = '^\\s*#\\s*define'
vim.bo.include = '^\\s*#\\s*include'
diff --git a/runtime/ftplugin/c.vim b/runtime/ftplugin/c.vim
index 716b454675..8b2b784eb4 100644
--- a/runtime/ftplugin/c.vim
+++ b/runtime/ftplugin/c.vim
@@ -2,6 +2,7 @@
" Language: C
" Maintainer: The Vim Project <https://github.com/vim/vim>
" Last Change: 2023 Aug 22
+" 2024 Jun 02 by Riley Bruins <ribru17@gmail.com> ('commentstring')
" Former Maintainer: Bram Moolenaar <Bram@vim.org>
" Only do this when not done yet for this buffer
@@ -24,7 +25,7 @@ setlocal fo-=t fo+=croql
" These options have the right value as default, but the user may have
" overruled that.
-setlocal commentstring& define& include&
+setlocal commentstring=/*\ %s\ */ define& include&
" Set completion with CTRL-X CTRL-O to autoloaded function.
if exists('&ofu')
diff --git a/runtime/ftplugin/calendar.vim b/runtime/ftplugin/calendar.vim
index f454ba1dc8..c4e683acf6 100644
--- a/runtime/ftplugin/calendar.vim
+++ b/runtime/ftplugin/calendar.vim
@@ -2,6 +2,7 @@
" Language: calendar(1) input file
" Previous Maintainer: Nikolai Weibull <now@bitwi.se>
" Latest Revision: 2008-07-09
+" 2024-06-02 by Riley Bruins <ribru17@gmail.com> ('commentstring')
if exists("b:did_ftplugin")
finish
@@ -13,7 +14,7 @@ set cpo&vim
let b:undo_ftplugin = "setl com< cms< inc< fo<"
-setlocal comments=s1:/*,mb:*,ex:*/ commentstring& include&
+setlocal comments=s1:/*,mb:*,ex:*/ commentstring=/*\ %s\ */ include&
setlocal formatoptions-=t formatoptions+=croql
let &cpo = s:cpo_save
diff --git a/runtime/ftplugin/calender.lua b/runtime/ftplugin/calender.lua
deleted file mode 100644
index b4e68148f5..0000000000
--- a/runtime/ftplugin/calender.lua
+++ /dev/null
@@ -1 +0,0 @@
-vim.bo.commentstring = '/*%s*/'
diff --git a/runtime/ftplugin/cgdbrc.vim b/runtime/ftplugin/cgdbrc.vim
index 46cf135c5c..99f9702d26 100644
--- a/runtime/ftplugin/cgdbrc.vim
+++ b/runtime/ftplugin/cgdbrc.vim
@@ -3,6 +3,7 @@
" Maintainer: Wu, Zhenyu <wuzhenyu@ustc.edu>
" Documentation: https://cgdb.github.io/docs/Configuring-CGDB.html
" Latest Revision: 2024-04-09
+" 2024-05-23 by Riley Bruins <ribru17@gmail.com> ('commentstring')
if exists('b:did_ftplugin')
finish
@@ -14,7 +15,7 @@ set cpoptions&vim
let b:undo_ftplugin = 'setl com< cms<'
-setlocal commentstring=#%s
+setlocal commentstring=#\ %s
setlocal comments=:#
let &cpoptions = s:save_cpoptions
diff --git a/runtime/ftplugin/ch.lua b/runtime/ftplugin/ch.lua
new file mode 100644
index 0000000000..f398d66a63
--- /dev/null
+++ b/runtime/ftplugin/ch.lua
@@ -0,0 +1 @@
+vim.bo.commentstring = '// %s'
diff --git a/runtime/ftplugin/cpp.vim b/runtime/ftplugin/cpp.vim
index 5cdad8fdc8..73768bc592 100644
--- a/runtime/ftplugin/cpp.vim
+++ b/runtime/ftplugin/cpp.vim
@@ -1,7 +1,7 @@
" Vim filetype plugin file
" Language: C++
" Maintainer: The Vim Project <https://github.com/vim/vim>
-" Last Change: 2023 Aug 10
+" Last Change: 2024 Jun 06
" Former Maintainer: Bram Moolenaar <Bram@vim.org>
" Only do this when not done yet for this buffer
@@ -13,6 +13,10 @@ endif
" XXX: "[.]" in the first pattern makes it a wildcard on Windows
runtime! ftplugin/c[.]{vim,lua} ftplugin/c_*.{vim,lua} ftplugin/c/*.{vim,lua}
+" Change 'commentstring' to "C++ style"/"mono-line" comments
+setlocal commentstring=//\ %s
+let b:undo_ftplugin ..= ' | setl commentstring<'
+
" C++ uses templates with <things>
" Disabled, because it gives an error for typing an unmatched ">".
" set matchpairs+=<:>
diff --git a/runtime/ftplugin/cs.lua b/runtime/ftplugin/cs.lua
index b4e68148f5..f398d66a63 100644
--- a/runtime/ftplugin/cs.lua
+++ b/runtime/ftplugin/cs.lua
@@ -1 +1 @@
-vim.bo.commentstring = '/*%s*/'
+vim.bo.commentstring = '// %s'
diff --git a/runtime/ftplugin/csh.vim b/runtime/ftplugin/csh.vim
index a22bee3279..74666b9680 100644
--- a/runtime/ftplugin/csh.vim
+++ b/runtime/ftplugin/csh.vim
@@ -4,6 +4,7 @@
" Previous Maintainer: Dan Sharp
" Contributor: Johannes Zellner <johannes@zellner.org>
" Last Change: 2024 Jan 14
+" 2024 May 23 by Riley Bruins ('commentstring')
if exists("b:did_ftplugin")
finish
@@ -14,7 +15,7 @@ let s:save_cpo = &cpo
set cpo-=C
setlocal comments=:#
-setlocal commentstring=#%s
+setlocal commentstring=#\ %s
setlocal formatoptions-=t
setlocal formatoptions+=crql
diff --git a/runtime/ftplugin/css.lua b/runtime/ftplugin/css.lua
deleted file mode 100644
index b4e68148f5..0000000000
--- a/runtime/ftplugin/css.lua
+++ /dev/null
@@ -1 +0,0 @@
-vim.bo.commentstring = '/*%s*/'
diff --git a/runtime/ftplugin/css.vim b/runtime/ftplugin/css.vim
index ece2def4ee..778a9e12d6 100644
--- a/runtime/ftplugin/css.vim
+++ b/runtime/ftplugin/css.vim
@@ -3,6 +3,7 @@
" Maintainer: Doug Kearns <dougkearns@gmail.com>
" Previous Maintainer: Nikolai Weibull <now@bitwi.se>
" Last Change: 2020 Dec 21
+" 2024 Jun 02 by Riley Bruins <ribru17@gmail.com> ('commentstring')
if exists("b:did_ftplugin")
finish
@@ -14,7 +15,7 @@ set cpo&vim
let b:undo_ftplugin = "setl com< cms< inc< fo< ofu< isk<"
-setlocal comments=s1:/*,mb:*,ex:*/ commentstring&
+setlocal comments=s1:/*,mb:*,ex:*/ commentstring=/*\ %s\ */
setlocal formatoptions-=t formatoptions+=croql
setlocal omnifunc=csscomplete#CompleteCSS
setlocal iskeyword+=-
diff --git a/runtime/ftplugin/d.lua b/runtime/ftplugin/d.lua
index b4e68148f5..f398d66a63 100644
--- a/runtime/ftplugin/d.lua
+++ b/runtime/ftplugin/d.lua
@@ -1 +1 @@
-vim.bo.commentstring = '/*%s*/'
+vim.bo.commentstring = '// %s'
diff --git a/runtime/ftplugin/desktop.vim b/runtime/ftplugin/desktop.vim
index bd6fd7097c..d15afd24b9 100644
--- a/runtime/ftplugin/desktop.vim
+++ b/runtime/ftplugin/desktop.vim
@@ -2,6 +2,7 @@
" Language: XDG desktop entry
" Maintainer: Eisuke Kawashima ( e.kawaschima+vim AT gmail.com )
" Last Change: 2022-07-26
+" 2024-05-24 by Riley Bruins <ribru17@gmail.com> ('commentstring')
if exists('b:did_ftplugin')
finish
@@ -9,5 +10,5 @@ endif
let b:did_ftplugin = v:true
setl comments=:#
-setl commentstring=#%s
+setl commentstring=#\ %s
let b:undo_ftplugin = 'setl com< cms<'
diff --git a/runtime/ftplugin/dtd.vim b/runtime/ftplugin/dtd.vim
index bea8c5c18a..f97014814b 100644
--- a/runtime/ftplugin/dtd.vim
+++ b/runtime/ftplugin/dtd.vim
@@ -6,6 +6,7 @@
" Former maintainer: Dan Sharp
" Last Change: 2009 Jan 20
" 2024 Jan 14 by Vim Project (browsefilter)
+" 2024 May 23 by Riley Bruins <ribru17@gmail.com> ('commentstring')
if exists("b:did_ftplugin") | finish | endif
let b:did_ftplugin = 1
@@ -15,7 +16,7 @@ let b:did_ftplugin = 1
let s:save_cpo = &cpo
set cpo-=C
-setlocal commentstring=<!--%s-->
+setlocal commentstring=<!--\ %s\ -->
setlocal comments=s:<!--,m:\ \ \ \ \ ,e:-->
setlocal formatoptions-=t
diff --git a/runtime/ftplugin/dtrace.vim b/runtime/ftplugin/dtrace.vim
index 9288097f7f..a276b310a3 100644
--- a/runtime/ftplugin/dtrace.vim
+++ b/runtime/ftplugin/dtrace.vim
@@ -1,6 +1,7 @@
" Language: D script as described in "Solaris Dynamic Tracing Guide",
" http://docs.sun.com/app/docs/doc/817-6223
" Last Change: 2008/03/20
+" 2024/05/23 by Riley Bruins <ribru17@gmail.com ('commentstring')
" Version: 1.2
" Maintainer: Nicolas Weber <nicolasweber@gmx.de>
@@ -26,8 +27,8 @@ setlocal fo-=t fo+=croql
setlocal comments=sO:*\ -,mO:*\ \ ,exO:*/,s1:/*,mb:*,ex:*/
" dtrace uses /* */ comments. Set this explicitly, just in case the user
-" changed this (/*%s*/ is the default)
-setlocal commentstring=/*%s*/
+" changed this (/*\ %s\ */ is the default)
+setlocal commentstring=/*\ %s\ */
setlocal iskeyword+=@,$
diff --git a/runtime/ftplugin/dts.vim b/runtime/ftplugin/dts.vim
index 42e38338b7..346ff94704 100644
--- a/runtime/ftplugin/dts.vim
+++ b/runtime/ftplugin/dts.vim
@@ -2,6 +2,7 @@
" Language: dts/dtsi (device tree files)
" Maintainer: Wu, Zhenyu <wuzhenyu@ustc.edu>
" Latest Revision: 2024 Apr 12
+" 2024 Jun 02 by Riley Bruins <ribru17@gmail.com> ('commentstring')
if exists('b:did_ftplugin')
finish
@@ -12,5 +13,5 @@ let b:undo_ftplugin = 'setl inc< cms< com<'
setlocal include=^\\%(#include\\\|/include/\\)
" same as C
-setlocal commentstring&
+setlocal commentstring=/*\ %s\ */
setlocal comments=sO:*\ -,mO:*\ \ ,exO:*/,s1:/*,mb:*,ex:*/,:///,://
diff --git a/runtime/ftplugin/erlang.vim b/runtime/ftplugin/erlang.vim
index 1cb57f4c85..5a3ab717d9 100644
--- a/runtime/ftplugin/erlang.vim
+++ b/runtime/ftplugin/erlang.vim
@@ -6,7 +6,8 @@
" Eduardo Lopez (http://github.com/tapichu)
" Arvid Bjurklint (http://github.com/slarwise)
" Paweł Zacharek (http://github.com/subc2)
-" Last Update: 2023-Dec-20
+" Riley Bruins (http://github.com/ribru17) ('commentstring')
+" Last Update: 2024 May 23
" License: Vim license
" URL: https://github.com/vim-erlang/vim-erlang-runtime
@@ -27,7 +28,7 @@ if get(g:, 'erlang_folding', 0)
endif
setlocal comments=:%%%,:%%,:%
-setlocal commentstring=%%s
+setlocal commentstring=%\ %s
setlocal formatoptions+=ro
diff --git a/runtime/ftplugin/eruby.vim b/runtime/ftplugin/eruby.vim
index b5c4665d24..b3e074aa20 100644
--- a/runtime/ftplugin/eruby.vim
+++ b/runtime/ftplugin/eruby.vim
@@ -5,6 +5,7 @@
" Release Coordinator: Doug Kearns <dougkearns@gmail.com>
" Last Change: 2022 May 15
" 2024 Jan 14 by Vim Project (browsefilter)
+" 2024 May 23 by Riley Bruins <ribru17@gmail.com> ('commentstring')
" Only do this when not done yet for this buffer
if exists("b:did_ftplugin")
@@ -125,7 +126,7 @@ if exists("loaded_matchit")
endif
" TODO: comments=
-setlocal commentstring=<%#%s%>
+setlocal commentstring=<%#\ %s\ %>
let b:undo_ftplugin = "setl cms< " .
\ " | unlet! b:browsefilter b:match_words | " . b:undo_ftplugin
diff --git a/runtime/ftplugin/fennel.vim b/runtime/ftplugin/fennel.vim
index 93cf366726..2a9623faff 100644
--- a/runtime/ftplugin/fennel.vim
+++ b/runtime/ftplugin/fennel.vim
@@ -2,13 +2,14 @@
" Language: Fennel
" Maintainer: Gregory Anders <greg[NOSPAM]@gpanders.com>
" Last Update: 2023 Jun 9
+" 2024 May 24 by Riley Bruins <ribru17@gmail.com> ('commentstring')
if exists('b:did_ftplugin')
finish
endif
let b:did_ftplugin = 1
-setlocal commentstring=;%s
+setlocal commentstring=;\ %s
setlocal comments=:;;,:;
setlocal formatoptions-=t
setlocal suffixesadd=.fnl
diff --git a/runtime/ftplugin/fish.vim b/runtime/ftplugin/fish.vim
index f06ad3a0bf..55d7ea8dd9 100644
--- a/runtime/ftplugin/fish.vim
+++ b/runtime/ftplugin/fish.vim
@@ -4,6 +4,7 @@
" Repository: https://github.com/nickeb96/fish.vim
" Last Change: February 1, 2023
" 2023 Aug 28 by Vim Project (undo_ftplugin)
+" 2024 May 23 by Riley Bruins <ribru17@gmail.com> ('commentstring')
if exists("b:did_ftplugin")
finish
@@ -12,7 +13,7 @@ let b:did_ftplugin = 1
setlocal iskeyword=@,48-57,_,192-255,-,.
setlocal comments=:#
-setlocal commentstring=#%s
+setlocal commentstring=#\ %s
setlocal formatoptions+=crjq
let b:undo_ftplugin = "setl cms< com< fo< isk<"
diff --git a/runtime/ftplugin/fortran.vim b/runtime/ftplugin/fortran.vim
index 3c325818d3..19a4c1e62b 100644
--- a/runtime/ftplugin/fortran.vim
+++ b/runtime/ftplugin/fortran.vim
@@ -11,6 +11,7 @@
" Doug Kearns, and Fritz Reese.
" Last Change: 2023 Dec 22
" 2024 Jan 14 by Vim Project (browsefilter)
+" 2024 May 23 by Riley Bruins <ribru17@gmail.com> ('commentstring')
" Only do these settings when not done yet for this buffer
if exists("b:did_ftplugin")
@@ -89,7 +90,7 @@ else
endif
" Set commentstring for foldmethod=marker
-setlocal cms=!%s
+setlocal cms=!\ %s
" Tabs are not a good idea in Fortran so the default is to expand tabs
if !exists("fortran_have_tabs")
diff --git a/runtime/ftplugin/fstab.vim b/runtime/ftplugin/fstab.vim
index 99805322cd..0e7ffda498 100644
--- a/runtime/ftplugin/fstab.vim
+++ b/runtime/ftplugin/fstab.vim
@@ -3,6 +3,7 @@
" Maintainer: Radu Dineiu <radu.dineiu@gmail.com>
" URL: https://raw.github.com/rid9/vim-fstab/master/ftplugin/fstab.vim
" Last Change: 2021 Jan 02
+" 2024 May 23 by Riley Bruins <ribru17@gmail.com> ('commentstring')
" Version: 1.0
"
" Credits:
@@ -13,7 +14,7 @@ if exists("b:did_ftplugin")
endif
let b:did_ftplugin = 1
-setlocal commentstring=#%s
+setlocal commentstring=#\ %s
let b:undo_ftplugin = "setlocal commentstring<"
" vim: ts=8 ft=vim
diff --git a/runtime/ftplugin/gdb.vim b/runtime/ftplugin/gdb.vim
index 7c10633be4..af88a04d54 100644
--- a/runtime/ftplugin/gdb.vim
+++ b/runtime/ftplugin/gdb.vim
@@ -3,11 +3,12 @@
" Maintainer: Michaël Peeters <NOSPAMm.vim@noekeon.org>
" Last Changed: 2017-10-26
" 2024-04-10: - add Matchit support (by Vim Project)
+" 2024-04-23: - add space to commentstring (by Riley Bruins) ('commentstring')
if exists("b:did_ftplugin") | finish | endif
let b:did_ftplugin = 1
-setlocal commentstring=#%s
+setlocal commentstring=#\ %s
setlocal include=^\\s*source
" Undo the stuff we changed.
diff --git a/runtime/ftplugin/glsl.lua b/runtime/ftplugin/glsl.lua
new file mode 100644
index 0000000000..f398d66a63
--- /dev/null
+++ b/runtime/ftplugin/glsl.lua
@@ -0,0 +1 @@
+vim.bo.commentstring = '// %s'
diff --git a/runtime/ftplugin/groovy.vim b/runtime/ftplugin/groovy.vim
index cc7d6e35eb..a2e2b2f93e 100644
--- a/runtime/ftplugin/groovy.vim
+++ b/runtime/ftplugin/groovy.vim
@@ -2,6 +2,7 @@
" Language: groovy
" Maintainer: Justin M. Keyes <justinkz@gmail.com>
" Last Change: 2016 May 22
+" 2024 May 24 by Riley Bruins <ribru17@gmail.com> ('commentstring')
if exists('b:did_ftplugin')
finish
@@ -13,7 +14,7 @@ set cpo-=C
let b:undo_ftplugin = 'setlocal commentstring<'
-setlocal commentstring=//%s
+setlocal commentstring=//\ %s
let &cpo = s:cpo_save
unlet s:cpo_save
diff --git a/runtime/ftplugin/hamster.vim b/runtime/ftplugin/hamster.vim
index 5446e72286..904f267fdc 100644
--- a/runtime/ftplugin/hamster.vim
+++ b/runtime/ftplugin/hamster.vim
@@ -3,6 +3,7 @@
" Version: 2.0.6.0
" Maintainer: David Fishburn <dfishburn dot vim at gmail dot com>
" Last Change: 2021 Jan 19
+" 2024 May 23 by Riley Bruins <ribru17@gmail.com> ('commentstring')
" Only do this when not done yet for this buffer
if exists("b:did_ftplugin")
@@ -31,7 +32,7 @@ if &tw == 0
endif
" Comments start with a double quote
-setlocal commentstring=#%s
+setlocal commentstring=#\ %s
" Move around functions.
noremap <silent><buffer> [[ :call search('^\s*sub\>', "bW")<CR>
diff --git a/runtime/ftplugin/help.lua b/runtime/ftplugin/help.lua
index 67c417b1be..86e181504f 100644
--- a/runtime/ftplugin/help.lua
+++ b/runtime/ftplugin/help.lua
@@ -26,3 +26,7 @@ elseif vim.endswith(bufname, '/doc/lsp.txt') then
{ start = [[\*lsp-semantic-highlight\*]], stop = '^======', match = '^@[%w%p]+' },
})
end
+
+vim.keymap.set('n', 'gO', function()
+ require('vim.vimhelp').show_toc()
+end, { buffer = 0, silent = true })
diff --git a/runtime/ftplugin/help.vim b/runtime/ftplugin/help.vim
index a188e45cb4..833baf5d8f 100644
--- a/runtime/ftplugin/help.vim
+++ b/runtime/ftplugin/help.vim
@@ -21,77 +21,5 @@ endif
" Prefer Vim help instead of manpages.
setlocal keywordprg=:help
-if !exists('g:no_plugin_maps')
- function! s:show_toc() abort
- let bufname = bufname('%')
- let info = getloclist(0, {'winid': 1})
- if !empty(info) && getwinvar(info.winid, 'qf_toc') ==# bufname
- lopen
- return
- endif
-
- let toc = []
- let lnum = 2
- let last_line = line('$') - 1
- let last_added = 0
- let has_section = 0
- let has_sub_section = 0
-
- while lnum && lnum <= last_line
- let level = 0
- let add_text = ''
- let text = getline(lnum)
-
- if text =~# '^=\+$' && lnum + 1 < last_line
- " A de-facto section heading. Other headings are inferred.
- let has_section = 1
- let has_sub_section = 0
- let lnum = nextnonblank(lnum + 1)
- let text = getline(lnum)
- let add_text = text
- while add_text =~# '\*[^*]\+\*\s*$'
- let add_text = matchstr(add_text, '.*\ze\*[^*]\+\*\s*$')
- endwhile
- elseif text =~# '^[A-Z0-9][-A-ZA-Z0-9 .][-A-Z0-9 .():]*\%([ \t]\+\*.\+\*\)\?$'
- " Any line that's yelling is important.
- let has_sub_section = 1
- let level = has_section
- let add_text = matchstr(text, '.\{-}\ze\s*\%([ \t]\+\*.\+\*\)\?$')
- elseif text =~# '\~$'
- \ && matchstr(text, '^\s*\zs.\{-}\ze\s*\~$') !~# '\t\|\s\{2,}'
- \ && getline(lnum - 1) =~# '^\s*<\?$\|^\s*\*.*\*$'
- \ && getline(lnum + 1) =~# '^\s*>\?$\|^\s*\*.*\*$'
- " These lines could be headers or code examples. We only want the
- " ones that have subsequent lines at the same indent or more.
- let l = nextnonblank(lnum + 1)
- if getline(l) =~# '\*[^*]\+\*$'
- " Ignore tag lines
- let l = nextnonblank(l + 1)
- endif
-
- if indent(lnum) <= indent(l)
- let level = has_section + has_sub_section
- let add_text = matchstr(text, '\S.\{-}\ze\s\=\~$')
- endif
- endif
-
- let add_text = substitute(add_text, '\s\+$', '', 'g')
- if !empty(add_text) && last_added != lnum
- let last_added = lnum
- call add(toc, {'bufnr': bufnr('%'), 'lnum': lnum,
- \ 'text': repeat("\u00a0\u00a0", level) . add_text})
- endif
- let lnum = nextnonblank(lnum + 1)
- endwhile
-
- call setloclist(0, toc, ' ')
- call setloclist(0, [], 'a', {'title': 'Help TOC'})
- lopen
- let w:qf_toc = bufname
- endfunction
-
- nnoremap <silent><buffer> gO :call <sid>show_toc()<cr>
-endif
-
let &cpo = s:cpo_save
unlet s:cpo_save
diff --git a/runtime/ftplugin/html.vim b/runtime/ftplugin/html.vim
index 3aa60a873e..5495f859de 100644
--- a/runtime/ftplugin/html.vim
+++ b/runtime/ftplugin/html.vim
@@ -3,6 +3,7 @@
" Maintainer: Doug Kearns <dougkearns@gmail.com>
" Previous Maintainer: Dan Sharp
" Last Change: 2024 Jan 14
+" 2024 May 24 by Riley Bruins <ribru17@gmail.com> ('commentstring')
if exists("b:did_ftplugin")
finish
@@ -13,7 +14,7 @@ let s:save_cpo = &cpo
set cpo-=C
setlocal matchpairs+=<:>
-setlocal commentstring=<!--%s-->
+setlocal commentstring=<!--\ %s\ -->
setlocal comments=s:<!--,m:\ \ \ \ ,e:-->
let b:undo_ftplugin = "setlocal comments< commentstring< matchpairs<"
diff --git a/runtime/ftplugin/indent.lua b/runtime/ftplugin/indent.lua
index b4e68148f5..f398d66a63 100644
--- a/runtime/ftplugin/indent.lua
+++ b/runtime/ftplugin/indent.lua
@@ -1 +1 @@
-vim.bo.commentstring = '/*%s*/'
+vim.bo.commentstring = '// %s'
diff --git a/runtime/ftplugin/indent.vim b/runtime/ftplugin/indent.vim
index 64a650ad7b..32208d38d8 100644
--- a/runtime/ftplugin/indent.vim
+++ b/runtime/ftplugin/indent.vim
@@ -3,6 +3,7 @@
" Maintainer: Doug Kearns <dougkearns@gmail.com>
" Previous Maintainer: Nikolai Weibull <now@bitwi.se>
" Latest Revision: 2008-07-09
+" 2024-06-02 by Riley Bruins <ribru17@gmail.com> ('commentstring')
if exists("b:did_ftplugin")
finish
@@ -14,7 +15,7 @@ set cpo&vim
let b:undo_ftplugin = "setl com< cms< fo<"
-setlocal comments=s1:/*,mb:*,ex:*/ commentstring&
+setlocal comments=s1:/*,mb:*,ex:*/ commentstring=/*\ %s\ */
setlocal formatoptions-=t formatoptions+=croql
let &cpo = s:cpo_save
diff --git a/runtime/ftplugin/initex.vim b/runtime/ftplugin/initex.vim
index 0ee3e8d899..71049df6bd 100644
--- a/runtime/ftplugin/initex.vim
+++ b/runtime/ftplugin/initex.vim
@@ -3,6 +3,7 @@
" Maintainer: Benji Fisher, Ph.D. <benji@member.AMS.org>
" Version: 1.0
" Last Change: Wed 19 Apr 2006
+" Last Change: Thu 23 May 2024 by Riley Bruins <ribru17@gmail.com> ('commentstring')
" Only do this when not done yet for this buffer.
if exists("b:did_ftplugin")
@@ -23,7 +24,7 @@ setlocal com=sO:%\ -,mO:%\ \ ,eO:%%,:%
" Set 'commentstring' to recognize the % comment character:
" (Thanks to Ajit Thakkar.)
-setlocal cms=%%s
+setlocal cms=%\ %s
" Allow "[d" to be used to find a macro definition:
let &l:define='\\\([egx]\|char\|mathchar\|count\|dimen\|muskip\|skip\|toks\)\='
diff --git a/runtime/ftplugin/java.vim b/runtime/ftplugin/java.vim
index fa2b61075f..eee7ef0153 100644
--- a/runtime/ftplugin/java.vim
+++ b/runtime/ftplugin/java.vim
@@ -5,6 +5,7 @@
" Repository: https://github.com/zzzyxwvut/java-vim.git
" Last Change: 2024 Apr 18
" 2024 Jan 14 by Vim Project (browsefilter)
+" 2024 May 23 by Riley Bruins <ribru17@gmail.com> ('commentstring')
if exists("b:did_ftplugin") | finish | endif
let b:did_ftplugin = 1
@@ -61,7 +62,7 @@ setlocal formatoptions-=t formatoptions+=croql
" Set 'comments' to format dashed lists in comments. Behaves just like C.
setlocal comments& comments^=sO:*\ -,mO:*\ \ ,exO:*/
-setlocal commentstring=//%s
+setlocal commentstring=//\ %s
" Change the :browse e filter to primarily show Java-related files.
if (has("gui_win32") || has("gui_gtk")) && !exists("b:browsefilter")
diff --git a/runtime/ftplugin/javascript.vim b/runtime/ftplugin/javascript.vim
index 2633954903..455b794cf0 100644
--- a/runtime/ftplugin/javascript.vim
+++ b/runtime/ftplugin/javascript.vim
@@ -3,6 +3,7 @@
" Maintainer: Doug Kearns <dougkearns@gmail.com>
" Contributor: Romain Lafourcade <romainlafourcade@gmail.com>
" Last Change: 2024 Jan 14
+" 2024 May 23 by Riley Bruins <ribru17@gmail.com> ('commentstring')
if exists("b:did_ftplugin")
finish
@@ -24,7 +25,7 @@ endif
" Set 'comments' to format dashed lists in comments.
setlocal comments=sO:*\ -,mO:*\ \ ,exO:*/,s1:/*,mb:*,ex:*/,://
-setlocal commentstring=//%s
+setlocal commentstring=//\ %s
" Change the :browse e filter to primarily show JavaScript-related files.
if (has("gui_win32") || has("gui_gtk")) && !exists("b:browsefilter")
diff --git a/runtime/ftplugin/jq.vim b/runtime/ftplugin/jq.vim
index 88958e80dd..d25883640b 100644
--- a/runtime/ftplugin/jq.vim
+++ b/runtime/ftplugin/jq.vim
@@ -2,6 +2,7 @@
" Language: jq
" Maintainer: Vito <vito.blog@gmail.com>
" Last Change: 2024 Apr 29
+" 2024 May 23 by Riley Bruins <ribru17@gmail.com> ('commentstring')
" Upstream: https://github.com/vito-c/jq.vim
if exists('b:did_ftplugin')
@@ -10,7 +11,7 @@ endif
let b:did_ftplugin = 1
setlocal include=^\\s*\\%(import\\\|include\\)
-setlocal commentstring=#%s
+setlocal commentstring=#\ %s
compiler jq
let b:undo_ftplugin = 'setl commentstring< include<'
diff --git a/runtime/ftplugin/jsonc.vim b/runtime/ftplugin/jsonc.vim
index e47a75f574..ec3268492c 100644
--- a/runtime/ftplugin/jsonc.vim
+++ b/runtime/ftplugin/jsonc.vim
@@ -5,6 +5,7 @@
" https://github.com/kevinoid/vim-jsonc
" License: MIT
" Last Change: 2021 Nov 22
+" 2024 May 23 by Riley Bruins <ribru17@gmail.com> ('commentstring')
runtime! ftplugin/json.vim
@@ -15,7 +16,7 @@ else
endif
" Set comment (formatting) related options. {{{1
-setlocal commentstring=//%s comments=sO:*\ -,mO:*\ \ ,exO:*/,s1:/*,mb:*,ex:*/,://
+setlocal commentstring=//\ %s comments=sO:*\ -,mO:*\ \ ,exO:*/,s1:/*,mb:*,ex:*/,://
" Let Vim know how to disable the plug-in.
let b:undo_ftplugin = 'setlocal commentstring< comments<'
diff --git a/runtime/ftplugin/kdl.vim b/runtime/ftplugin/kdl.vim
new file mode 100644
index 0000000000..c9a1d8b185
--- /dev/null
+++ b/runtime/ftplugin/kdl.vim
@@ -0,0 +1,17 @@
+" Vim filetype plugin
+" Language: KDL
+" Author: Aram Drevekenin <aram@poor.dev>
+" Maintainer: Yinzuo Jiang <jiangyinzuo@foxmail.com>
+" Last Change: 2024-06-10
+
+if exists("b:did_ftplugin")
+ finish
+endif
+
+let b:did_ftplugin = 1
+
+setlocal comments=://
+setlocal commentstring=//\ %s
+setlocal formatoptions-=t
+
+let b:undo_ftplugin = 'setlocal comments< commentstring< formatoptions<'
diff --git a/runtime/ftplugin/lc.vim b/runtime/ftplugin/lc.vim
new file mode 100644
index 0000000000..e818f1aecb
--- /dev/null
+++ b/runtime/ftplugin/lc.vim
@@ -0,0 +1,13 @@
+" Vim filetype plugin
+" Language: Elsa
+" Maintainer: Riley Bruins <ribru17@gmail.com>
+" Last Change: 2024 May 25
+
+if exists('b:did_ftplugin')
+ finish
+endif
+let b:did_ftplugin = 1
+
+setl comments=:-- commentstring=--\ %s
+
+let b:undo_ftplugin = 'setl com< cms<'
diff --git a/runtime/ftplugin/ld.vim b/runtime/ftplugin/ld.vim
index 1ab80d533c..9cc70bd94d 100644
--- a/runtime/ftplugin/ld.vim
+++ b/runtime/ftplugin/ld.vim
@@ -1,7 +1,8 @@
" Vim filetype plugin file
" Language: ld(1) script
" Previous Maintainer: Nikolai Weibull <now@bitwi.se>
-" Latest Revision: 2008-07-09
+" Latest Revision: 2008 Jul 09
+" 2024 May 23 by Riley Bruins <ribru17@gmail.com> ('commentstring')
if exists("b:did_ftplugin")
finish
@@ -13,7 +14,7 @@ set cpo&vim
let b:undo_ftplugin = "setl com< cms< inc< fo<"
-setlocal comments=s1:/*,mb:*,ex:*/ commentstring=/*%s*/ include=^\\s*INCLUDE
+setlocal comments=s1:/*,mb:*,ex:*/ commentstring=/*\ %s\ */ include=^\\s*INCLUDE
setlocal formatoptions-=t formatoptions+=croql
let &cpo = s:cpo_save
diff --git a/runtime/ftplugin/liquid.vim b/runtime/ftplugin/liquid.vim
index f24ec4cbb2..dbd8abe457 100644
--- a/runtime/ftplugin/liquid.vim
+++ b/runtime/ftplugin/liquid.vim
@@ -2,6 +2,7 @@
" Language: Liquid
" Maintainer: Tim Pope <vimNOSPAM@tpope.org>
" Last Change: 2022 Mar 15
+" 2024 May 23 by Riley Bruins <ribru17@gmail.com> ('commentstring')
if exists('b:did_ftplugin')
finish
@@ -56,6 +57,6 @@ if exists('loaded_matchit')
let b:match_words .= '\<\%(if\w*\|unless\|case\)\>:\<\%(elsif\|else\|when\)\>:\<end\%(if\w*\|unless\|case\)\>,\<\%(for\|tablerow\)\>:\%({%\s*\)\@<=empty\>:\<end\%(for\|tablerow\)\>,\<\(capture\|comment\|highlight\)\>:\<end\1\>'
endif
-setlocal commentstring={%\ comment\ %}%s{%\ endcomment\ %}
+setlocal commentstring={%\ comment\ %}\ %s\ {%\ endcomment\ %}
let b:undo_ftplugin .= 'setl cms< | unlet! b:browsefilter b:match_words'
diff --git a/runtime/ftplugin/lisp.vim b/runtime/ftplugin/lisp.vim
index db3ac96631..fe3c6fe996 100644
--- a/runtime/ftplugin/lisp.vim
+++ b/runtime/ftplugin/lisp.vim
@@ -5,6 +5,7 @@
" Original author: Dorai Sitaram <ds26@gte.com>
" Original URL: http://www.ccs.neu.edu/~dorai/vimplugins/vimplugins.html
" Last Change: Mar 10, 2021
+" May 23, 2024 by Riley Bruins <ribru17@gmail.com> ('commentstring')
" Only do this when not done yet for this buffer
if exists("b:did_ftplugin")
@@ -19,6 +20,6 @@ setl define=^\\s*(def\\k*
setl formatoptions-=t
setl iskeyword+=+,-,*,/,%,<,=,>,:,$,?,!,@-@,94
setl lisp
-setl commentstring=;%s
+setl commentstring=;\ %s
let b:undo_ftplugin = "setlocal comments< define< formatoptions< iskeyword< lisp< commentstring<"
diff --git a/runtime/ftplugin/markdown.vim b/runtime/ftplugin/markdown.vim
index 022dd0d601..d4ee5ac242 100644
--- a/runtime/ftplugin/markdown.vim
+++ b/runtime/ftplugin/markdown.vim
@@ -2,6 +2,7 @@
" Language: Markdown
" Maintainer: Tim Pope <https://github.com/tpope/vim-markdown>
" Last Change: 2023 Dec 28
+" 2024 May 24 by Riley Bruins <ribru17@gmail.com> ('commentstring')
if exists("b:did_ftplugin")
finish
@@ -12,7 +13,7 @@ runtime! ftplugin/html.vim ftplugin/html_*.vim ftplugin/html/*.vim
let s:keepcpo= &cpo
set cpo&vim
-setlocal comments=fb:*,fb:-,fb:+,n:> commentstring=<!--%s-->
+setlocal comments=fb:*,fb:-,fb:+,n:> commentstring=<!--\ %s\ -->
setlocal formatoptions+=tcqln formatoptions-=r formatoptions-=o
setlocal formatlistpat=^\\s*\\d\\+\\.\\s\\+\\\|^\\s*[-*+]\\s\\+\\\|^\\[^\\ze[^\\]]\\+\\]:\\&^.\\{4\\}
diff --git a/runtime/ftplugin/mma.vim b/runtime/ftplugin/mma.vim
index ce4cee18ae..91a8111bcb 100644
--- a/runtime/ftplugin/mma.vim
+++ b/runtime/ftplugin/mma.vim
@@ -1,7 +1,8 @@
" Vim filetype plugin file
" Language: Mathematica
" Maintainer: Ian Ford <ianf@wolfram.com>
-" Last Change: 22 January 2019
+" Last Change: 2019 Jan 22
+" 2024 May 23 by Riley Bruins <ribru17@gmail.com> ('commentstring')
" Only do this when not done yet for this buffer
if exists("b:did_ftplugin")
@@ -13,4 +14,4 @@ let b:did_ftplugin = 1
let b:undo_ftplugin = "setlocal commentstring<"
-setlocal commentstring=\(*%s*\)
+setlocal commentstring=\(*\ %s\ *\)
diff --git a/runtime/ftplugin/modula2.vim b/runtime/ftplugin/modula2.vim
index 9c1acc276a..306688da05 100644
--- a/runtime/ftplugin/modula2.vim
+++ b/runtime/ftplugin/modula2.vim
@@ -2,6 +2,7 @@
" Language: Modula-2
" Maintainer: Doug Kearns <dougkearns@gmail.com>
" Last Change: 2024 Jan 14
+" 2024 May 23 by Riley Bruins <ribru17@gmail.com> ('commentstring')
if exists("b:did_ftplugin")
finish
@@ -17,7 +18,7 @@ if s:dialect ==# "r10"
setlocal comments=s:(*,m:\ ,e:*),:!
setlocal commentstring=!\ %s
else
- setlocal commentstring=(*%s*)
+ setlocal commentstring=(*\ %s\ *)
setlocal comments=s:(*,m:\ ,e:*)
endif
setlocal formatoptions-=t formatoptions+=croql
diff --git a/runtime/ftplugin/modula3.vim b/runtime/ftplugin/modula3.vim
index 45dd7ca01c..f899d1d103 100644
--- a/runtime/ftplugin/modula3.vim
+++ b/runtime/ftplugin/modula3.vim
@@ -2,6 +2,7 @@
" Language: Modula-3
" Maintainer: Doug Kearns <dougkearns@gmail.com>
" Last Change: 2024 Jan 14
+" 2024 May 24 by Riley Bruins <ribru17@gmail.com> ('commentstring')
if exists("b:did_ftplugin")
finish
@@ -12,7 +13,7 @@ let s:cpo_save = &cpo
set cpo&vim
setlocal comments=s0:(*,mb:\ ,ex:*)
-setlocal commentstring=(*%s*)
+setlocal commentstring=(*\ %s\ *)
setlocal formatoptions-=t formatoptions+=croql
setlocal suffixesadd+=.m3
setlocal formatprg=m3pp
diff --git a/runtime/ftplugin/nroff.vim b/runtime/ftplugin/nroff.vim
index cf62d02daa..ed0b32f5f3 100644
--- a/runtime/ftplugin/nroff.vim
+++ b/runtime/ftplugin/nroff.vim
@@ -2,15 +2,15 @@
" Language: roff(7)
" Maintainer: Aman Verma
" Homepage: https://github.com/a-vrma/vim-nroff-ftplugin
-" Previous Maintainer: Chris Spiegel <cspiegel@gmail.com>
-" Last Change: 2020 Nov 21
+" Previous Maintainer: Chris Spiegel <cspiegel@gmail.com>
+" 2024 May 24 by Riley Bruins <ribru17@gmail.com> ('commentstring')
if exists("b:did_ftplugin")
finish
endif
let b:did_ftplugin = 1
-setlocal commentstring=.\\\"%s
+setlocal commentstring=.\\\"\ %s
setlocal comments=:.\\\"
setlocal sections+=Sh
diff --git a/runtime/ftplugin/objc.lua b/runtime/ftplugin/objc.lua
new file mode 100644
index 0000000000..f398d66a63
--- /dev/null
+++ b/runtime/ftplugin/objc.lua
@@ -0,0 +1 @@
+vim.bo.commentstring = '// %s'
diff --git a/runtime/ftplugin/obse.vim b/runtime/ftplugin/obse.vim
index 6d865f05ee..bf5076f41f 100644
--- a/runtime/ftplugin/obse.vim
+++ b/runtime/ftplugin/obse.vim
@@ -2,8 +2,9 @@
" Language: Oblivion Language (obl)
" Original Creator: Kat <katisntgood@gmail.com>
" Maintainer: Kat <katisntgood@gmail.com>
-" Created: August 08, 2021
-" Last Change: 13 November 2022
+" Created: 2021 Aug 08
+" Last Change: 2022 Nov 13
+" 2024 May 23 by Riley Bruins <ribru17@gmail.com> ('commentstring')
if exists("b:did_ftplugin")
finish
@@ -20,7 +21,7 @@ noremap <script> <buffer> <silent> ]] <nop>
noremap <script> <buffer> <silent> [] <nop>
noremap <script> <buffer> <silent> ][ <nop>
-setlocal commentstring=;%s
+setlocal commentstring=;\ %s
setlocal comments=:;
function s:NextSection(type, backwards, visual)
diff --git a/runtime/ftplugin/ocaml.vim b/runtime/ftplugin/ocaml.vim
index 20172c9b32..8b88d8d001 100644
--- a/runtime/ftplugin/ocaml.vim
+++ b/runtime/ftplugin/ocaml.vim
@@ -5,12 +5,14 @@
" Pierre Vittet <pierre-vittet@pvittet.com>
" Stefano Zacchiroli <zack@bononia.it>
" Vincent Aravantinos <firstname.name@imag.fr>
+" Riley Bruins <ribru17@gmail.com> ('commentstring')
" URL: https://github.com/ocaml/vim-ocaml
" Last Change:
" 2013 Oct 27 - Added commentstring (MM)
" 2013 Jul 26 - load default compiler settings (MM)
" 2013 Jul 24 - removed superfluous efm-setting (MM)
" 2013 Jul 22 - applied fixes supplied by Hirotaka Hamada (MM)
+" 2024 May 23 - added space in commentstring (RB)
if exists("b:did_ftplugin")
finish
@@ -40,7 +42,7 @@ set cpo&vim
" Comment string
setlocal comments=sr:(*\ ,mb:\ ,ex:*)
setlocal comments^=sr:(**,mb:\ \ ,ex:*)
-setlocal commentstring=(*%s*)
+setlocal commentstring=(*\ %s\ *)
" Add mappings, unless the user didn't want this.
if !exists("no_plugin_maps") && !exists("no_ocaml_maps")
diff --git a/runtime/ftplugin/odin.vim b/runtime/ftplugin/odin.vim
index c50fea65a3..ca534bb30c 100644
--- a/runtime/ftplugin/odin.vim
+++ b/runtime/ftplugin/odin.vim
@@ -2,7 +2,8 @@
" Language: Odin
" Maintainer: Maxim Kim <habamax@gmail.com>
" Website: https://github.com/habamax/vim-odin
-" Last Change: 2024-01-15
+" Last Change: 2024 Jan 15
+" 2024-May 23 by Riley Bruins <ribru17@gmail.com> ('commentstring')
"
" This file has been manually translated from Vim9 script.
@@ -19,7 +20,7 @@ let b:undo_ftplugin = 'setlocal commentstring<'
\ .. '| setlocal suffixesadd<'
setlocal suffixesadd=.odin
-setlocal commentstring=//%s
+setlocal commentstring=//\ %s
setlocal comments=s1:/*,mb:*,ex:*/,://
let &cpo = s:cpo_save
diff --git a/runtime/ftplugin/openvpn.vim b/runtime/ftplugin/openvpn.vim
index 56c0f25b39..9cd7b7ad1a 100644
--- a/runtime/ftplugin/openvpn.vim
+++ b/runtime/ftplugin/openvpn.vim
@@ -2,6 +2,7 @@
" Language: OpenVPN
" Maintainer: ObserverOfTime <chronobserver@disroot.org>
" Last Change: 2022 Oct 16
+" 2024 May 23 by Riley Bruins <ribru17@gmail.com> ('commentstring')
if exists('b:did_ftplugin')
finish
@@ -9,6 +10,6 @@ endif
let b:did_ftplugin = 1
setlocal iskeyword+=-,.,/
-setlocal comments=:#,:; commentstring=#%s
+setlocal comments=:#,:; commentstring=#\ %s
let b:undo_ftplugin = 'setl isk< com< cms<'
diff --git a/runtime/ftplugin/pascal.vim b/runtime/ftplugin/pascal.vim
index 9abd7dd382..7c800c4fbd 100644
--- a/runtime/ftplugin/pascal.vim
+++ b/runtime/ftplugin/pascal.vim
@@ -3,6 +3,7 @@
" Maintainer: Doug Kearns <dougkearns@gmail.com>
" Previous Maintainer: Dan Sharp
" Last Change: 2024 Jan 14
+" 2024 May 23 by Riley Bruins <ribru17@gmail.com> ('commentstring')
if exists("b:did_ftplugin") | finish | endif
let b:did_ftplugin = 1
@@ -11,7 +12,7 @@ let s:cpo_save = &cpo
set cpo&vim
set comments=s:(*,m:\ ,e:*),s:{,m:\ ,e:}
-set commentstring={%s}
+set commentstring={\ %s\ }
if exists("pascal_delphi")
set comments+=:///
diff --git a/runtime/ftplugin/pdf.vim b/runtime/ftplugin/pdf.vim
index 1ed99117d6..96c77c870a 100644
--- a/runtime/ftplugin/pdf.vim
+++ b/runtime/ftplugin/pdf.vim
@@ -2,13 +2,14 @@
" Language: PDF
" Maintainer: Tim Pope <vimNOSPAM@tpope.info>
" Last Change: 2007 Dec 16
+" 2024 May 23 by Riley Bruins <ribru17@gmail.com> ('commentstring')
if exists("b:did_ftplugin")
finish
endif
let b:did_ftplugin = 1
-setlocal commentstring=%%s
+setlocal commentstring=%\ %s
setlocal comments=:%
let b:undo_ftplugin = "setlocal cms< com< | unlet! b:match_words"
diff --git a/runtime/ftplugin/perl.vim b/runtime/ftplugin/perl.vim
index 8c6a80eb4f..03368a7af3 100644
--- a/runtime/ftplugin/perl.vim
+++ b/runtime/ftplugin/perl.vim
@@ -8,6 +8,7 @@
" 2023 Sep 07 by Vim Project (safety check: don't execute perl
" from current directory)
" 2024 Jan 14 by Vim Project (browsefilter)
+" 2024 May 24 by Riley Bruins <ribru17@gmail.com> ('commentstring')
if exists("b:did_ftplugin") | finish | endif
let b:did_ftplugin = 1
@@ -22,7 +23,7 @@ setlocal formatoptions+=crqol
setlocal keywordprg=perldoc\ -f
setlocal comments=:#
-setlocal commentstring=#%s
+setlocal commentstring=#\ %s
" Provided by Ned Konz <ned at bike-nomad dot com>
"---------------------------------------------
diff --git a/runtime/ftplugin/php.vim b/runtime/ftplugin/php.vim
index f03f14512a..e124961ba1 100644
--- a/runtime/ftplugin/php.vim
+++ b/runtime/ftplugin/php.vim
@@ -3,6 +3,7 @@
" Maintainer: Doug Kearns <dougkearns@gmail.com>
" Previous Maintainer: Dan Sharp
" Last Change: 2024 Jan 14
+" Last Change: 2024 May 23 by Riley Bruins <ribru17@gmail.com> ('commentstring')
if exists("b:did_ftplugin")
finish
@@ -44,7 +45,7 @@ if exists("b:match_skip")
endif
setlocal comments=s1:/*,mb:*,ex:*/,://,:#
-setlocal commentstring=/*%s*/
+setlocal commentstring=/*\ %s\ */
setlocal formatoptions+=l formatoptions-=t
if get(g:, "php_autocomment", 1)
diff --git a/runtime/ftplugin/ps1.vim b/runtime/ftplugin/ps1.vim
index d6ab01016b..9d698f2423 100644
--- a/runtime/ftplugin/ps1.vim
+++ b/runtime/ftplugin/ps1.vim
@@ -3,6 +3,7 @@
" URL: https://github.com/PProvost/vim-ps1
" Last Change: 2021 Apr 02
" 2024 Jan 14 by Vim Project (browsefilter)
+" 2024 May 23 by Riley Bruins <ribru17@gmail.com> ('commentstring')
" Only do this when not done yet for this buffer
if exists("b:did_ftplugin") | finish | endif
@@ -14,7 +15,7 @@ let s:cpo_save = &cpo
set cpo&vim
setlocal tw=0
-setlocal commentstring=#%s
+setlocal commentstring=#\ %s
setlocal formatoptions=tcqro
" Enable autocompletion of hyphenated PowerShell commands,
" e.g. Get-Content or Get-ADUser
diff --git a/runtime/ftplugin/ps1xml.vim b/runtime/ftplugin/ps1xml.vim
index 17bb181f37..0052de19ce 100644
--- a/runtime/ftplugin/ps1xml.vim
+++ b/runtime/ftplugin/ps1xml.vim
@@ -3,6 +3,7 @@
" URL: https://github.com/PProvost/vim-ps1
" Last Change: 2021 Apr 02
" 2024 Jan 14 by Vim Project (browsefilter)
+" 2024 May 23 by Riley Bruins <ribru17@gmail.com> ('commentstring')
" Only do this when not done yet for this buffer
if exists("b:did_ftplugin") | finish | endif
@@ -14,7 +15,7 @@ let s:cpo_save = &cpo
set cpo&vim
setlocal tw=0
-setlocal commentstring=#%s
+setlocal commentstring=#\ %s
setlocal formatoptions=tcqro
" Change the browse dialog on Win32 and GTK to show mainly PowerShell-related files
diff --git a/runtime/ftplugin/qml.vim b/runtime/ftplugin/qml.vim
index aa05c11bf9..53df11c6b8 100644
--- a/runtime/ftplugin/qml.vim
+++ b/runtime/ftplugin/qml.vim
@@ -3,6 +3,7 @@
" Maintainer: Chase Knowlden <haroldknowlden@gmail.com>
" Last Change: 2023 Aug 16
" 2023 Aug 23 by Vim Project (browsefilter)
+" 2024 May 23 by Riley Bruins <ribru17@gmail.com> ('commentstring')
if exists( 'b:did_ftplugin' )
finish
@@ -28,7 +29,7 @@ endif
" Set 'comments' to format dashed lists in comments.
setlocal comments=sO:*\ -,mO:*\ \ ,exO:*/,s1:/*,mb:*,ex:*/,://
-setlocal commentstring=//%s
+setlocal commentstring=//\ %s
setlocal formatoptions-=t
setlocal formatoptions+=croql
diff --git a/runtime/ftplugin/racket.vim b/runtime/ftplugin/racket.vim
index 84f5422140..7bfd87ddc3 100644
--- a/runtime/ftplugin/racket.vim
+++ b/runtime/ftplugin/racket.vim
@@ -3,8 +3,7 @@
" Maintainer: D. Ben Knoble <ben.knoble+github@gmail.com>
" Previous Maintainer: Will Langstroth <will@langstroth.com>
" URL: https://github.com/benknoble/vim-racket
-" Last Change: 2022 Aug 29
-" 2024 Jan 14 by Vim Project (browsefilter)
+" Last Change: 2024 May 28
if exists("b:did_ftplugin")
finish
@@ -21,7 +20,7 @@ setlocal iskeyword=@,!,#-',*-:,<-Z,a-z,~,_,94
setlocal comments=:;;;;,:;;;,:;;,:;
setlocal formatoptions+=r
-"setlocal commentstring=;;%s
+"setlocal commentstring=;;\ %s
setlocal commentstring=#\|\ %s\ \|#
setlocal formatprg=raco\ fmt
diff --git a/runtime/ftplugin/raku.vim b/runtime/ftplugin/raku.vim
index 941222bd38..f57427e323 100644
--- a/runtime/ftplugin/raku.vim
+++ b/runtime/ftplugin/raku.vim
@@ -1,10 +1,11 @@
" Vim filetype plugin file
-" Language: Raku
-" Maintainer: vim-perl <vim-perl@googlegroups.com>
-" Homepage: https://github.com/Raku/vim-raku
+" Language: Raku
+" Maintainer: vim-perl <vim-perl@googlegroups.com>
+" Homepage: https://github.com/Raku/vim-raku
" Bugs/requests: https://github.com/Raku/vim-raku/issues
-" Last Change: 2021-04-16
-" Contributors: Hinrik Örn Sigurðsson <hinrik.sig@gmail.com>
+" Last Change: 2021 Apr 16
+" 2024 May 23 by Riley Bruins <ribru17@gmail.com> ('commentstring')
+" Contributors: Hinrik Örn Sigurðsson <hinrik.sig@gmail.com>
"
" Based on ftplugin/perl.vim by Dan Sharp <dwsharp at hotmail dot com>
@@ -21,7 +22,7 @@ setlocal formatoptions+=crqol
setlocal keywordprg=p6doc
setlocal comments=:#\|,:#=,:#
-setlocal commentstring=#%s
+setlocal commentstring=#\ %s
" Provided by Ned Konz <ned at bike-nomad dot com>
"---------------------------------------------
diff --git a/runtime/ftplugin/rasi.vim b/runtime/ftplugin/rasi.vim
new file mode 100644
index 0000000000..5f8ce862df
--- /dev/null
+++ b/runtime/ftplugin/rasi.vim
@@ -0,0 +1,25 @@
+" Vim filetype plugin file
+" Language: RASI
+" Maintainer: Pierrick Guillaume <pierguill@gmail.com>
+" Last Change: 2024 May 21
+
+if exists("b:did_ftplugin")
+ finish
+endif
+let b:did_ftplugin = 1
+
+let s:cpo_save = &cpo
+set cpo&vim
+
+let b:undo_ftplugin = "setl com< cms< isk< inc<"
+
+setlocal comments=s1:/*,mb:*,ex:*/
+setlocal commentstring=//\ %s
+setlocal iskeyword+=-
+
+let &l:include = '^\s*@import\s\+\%(url(\)\='
+
+let &cpo = s:cpo_save
+unlet s:cpo_save
+
+" vim: ts=8
diff --git a/runtime/ftplugin/rust.vim b/runtime/ftplugin/rust.vim
index fb15b444d0..c2bcdd34bc 100644
--- a/runtime/ftplugin/rust.vim
+++ b/runtime/ftplugin/rust.vim
@@ -1,7 +1,8 @@
-" Language: Rust
-" Description: Vim ftplugin for Rust
-" Maintainer: Chris Morgan <me@chrismorgan.info>
-" Last Change: 2024-03-17
+" Language: Rust
+" Description: Vim ftplugin for Rust
+" Maintainer: Chris Morgan <me@chrismorgan.info>
+" Last Change: 2024 Mar 17
+" 2024 May 23 by Riley Bruins <ribru17@gmail.com ('commentstring')
" For bugs, patches and license go to https://github.com/rust-lang/rust.vim
if exists("b:did_ftplugin")
@@ -36,7 +37,7 @@ if get(g:, 'rust_bang_comment_leader', 0)
else
setlocal comments=s0:/*!,ex:*/,s1:/*,mb:*,ex:*/,:///,://!,://
endif
-setlocal commentstring=//%s
+setlocal commentstring=//\ %s
setlocal formatoptions-=t formatoptions+=croqnl
" j was only added in 7.3.541, so stop complaints about its nonexistence
silent! setlocal formatoptions+=j
diff --git a/runtime/ftplugin/scdoc.vim b/runtime/ftplugin/scdoc.vim
index 552c865baa..8225e437a8 100644
--- a/runtime/ftplugin/scdoc.vim
+++ b/runtime/ftplugin/scdoc.vim
@@ -1,7 +1,8 @@
" scdoc filetype plugin
-" Maintainer: Gregory Anders <contact@gpanders.com>
-" Last Updated: 2022-05-09
-" Upstream: https://github.com/gpanders/vim-scdoc
+" Maintainer: Gregory Anders <contact@gpanders.com>
+" Last Updated: 2022 May 09
+" 2024 May 23 by Riley Bruins <ribru17@gmail.com> ('commentstring')
+" Upstream: https://github.com/gpanders/vim-scdoc
" Only do this when not done yet for this buffer
if exists('b:did_ftplugin')
@@ -12,7 +13,7 @@ endif
let b:did_ftplugin = 1
setlocal comments=b:;
-setlocal commentstring=;%s
+setlocal commentstring=;\ %s
setlocal formatoptions+=t
setlocal noexpandtab
setlocal shiftwidth=0
diff --git a/runtime/ftplugin/scheme.vim b/runtime/ftplugin/scheme.vim
index 04655bc136..03f625b564 100644
--- a/runtime/ftplugin/scheme.vim
+++ b/runtime/ftplugin/scheme.vim
@@ -1,11 +1,12 @@
" Vim filetype plugin file
-" Language: Scheme (R7RS)
-" Last Change: 2019-11-19
-" Author: Evan Hanson <evhan@foldling.org>
-" Maintainer: Evan Hanson <evhan@foldling.org>
+" Language: Scheme (R7RS)
+" Last Change: 2019 Nov 19
+" 2024 May 23 by Riley Bruins <ribru17@gmail.com> ('commentstring')
+" Author: Evan Hanson <evhan@foldling.org>
+" Maintainer: Evan Hanson <evhan@foldling.org>
" Previous Maintainer: Sergey Khorev <sergey.khorev@gmail.com>
-" Repository: https://git.foldling.org/vim-scheme.git
-" URL: https://foldling.org/vim/ftplugin/scheme.vim
+" Repository: https://git.foldling.org/vim-scheme.git
+" URL: https://foldling.org/vim/ftplugin/scheme.vim
if exists('b:did_ftplugin')
finish
@@ -16,7 +17,7 @@ set cpo&vim
setl lisp
setl comments=:;;;;,:;;;,:;;,:;,sr:#\|,mb:\|,ex:\|#
-setl commentstring=;%s
+setl commentstring=;\ %s
setl define=^\\s*(def\\k*
setl iskeyword=33,35-39,42-43,45-58,60-90,94,95,97-122,126
diff --git a/runtime/ftplugin/svelte.vim b/runtime/ftplugin/svelte.vim
new file mode 100644
index 0000000000..e0ec4e0ae3
--- /dev/null
+++ b/runtime/ftplugin/svelte.vim
@@ -0,0 +1,13 @@
+" Vim filetype plugin
+" Language: svelte
+" Maintainer: Igor Lacerda <igorlafarsi@gmail.com>
+" Last Change: 2024 Jun 09
+
+if exists('b:did_ftplugin')
+ finish
+endif
+let b:did_ftplugin = 1
+
+setl commentstring=<!--\ %s\ -->
+
+let b:undo_ftplugin = 'setl cms<'
diff --git a/runtime/ftplugin/tcl.vim b/runtime/ftplugin/tcl.vim
index fa900096c0..214d9c256d 100644
--- a/runtime/ftplugin/tcl.vim
+++ b/runtime/ftplugin/tcl.vim
@@ -3,6 +3,7 @@
" Maintainer: Robert L Hicks <sigzero@gmail.com>
" Latest Revision: 2009-05-01
" 2024 Jan 14 by Vim Project (browsefilter)
+" 2024 May 23 by Riley Bruins <ribru17@gmail.com> ('commentstring')
if exists("b:did_ftplugin")
finish
@@ -15,7 +16,7 @@ let s:cpo_save = &cpo
set cpo-=C
setlocal comments=:#
-setlocal commentstring=#%s
+setlocal commentstring=#\ %s
setlocal formatoptions+=croql
" Change the browse dialog on Windows to show mainly Tcl-related files
diff --git a/runtime/ftplugin/typescript.vim b/runtime/ftplugin/typescript.vim
index 680521df31..fb5f4e135f 100644
--- a/runtime/ftplugin/typescript.vim
+++ b/runtime/ftplugin/typescript.vim
@@ -2,6 +2,7 @@
" Language: TypeScript
" Maintainer: Doug Kearns <dougkearns@gmail.com>
" Last Change: 2024 Jan 14
+" 2024 May 23 by Riley Bruins <ribru17@gmail.com> ('commentstring')
if exists("b:did_ftplugin")
finish
@@ -18,7 +19,7 @@ setlocal formatoptions-=t formatoptions+=croql
" Set 'comments' to format dashed lists in comments.
setlocal comments=sO:*\ -,mO:*\ \ ,exO:*/,s1:/*,mb:*,ex:*/,://
-setlocal commentstring=//%s
+setlocal commentstring=//\ %s
setlocal suffixesadd+=.ts,.d.ts,.tsx,.js,.jsx,.cjs,.mjs
diff --git a/runtime/ftplugin/vim.vim b/runtime/ftplugin/vim.vim
index 5c99df7f5a..34412f8fec 100644
--- a/runtime/ftplugin/vim.vim
+++ b/runtime/ftplugin/vim.vim
@@ -2,6 +2,7 @@
" Language: Vim
" Maintainer: Doug Kearns <dougkearns@gmail.com>
" Last Change: 2024 Apr 13
+" 2024 May 23 by Riley Bruins <ribru17@gmail.com> ('commentstring')
" Former Maintainer: Bram Moolenaar <Bram@vim.org>
" Only do this when not done yet for this buffer
@@ -51,7 +52,7 @@ setlocal keywordprg=:help
" Comments starts with # in Vim9 script. We have to guess which one to use.
if "\n" .. getline(1, 32)->join("\n") =~# '\n\s*vim9\%[script]\>'
- setlocal commentstring=#%s
+ setlocal commentstring=#\ %s
else
setlocal commentstring=\"%s
endif
diff --git a/runtime/ftplugin/wat.vim b/runtime/ftplugin/wat.vim
index 35d2d6a322..ad1140bbb5 100644
--- a/runtime/ftplugin/wat.vim
+++ b/runtime/ftplugin/wat.vim
@@ -2,6 +2,7 @@
" Language: WebAssembly
" Maintainer: rhysd <lin90162@yahoo.co.jp>
" Last Change: Nov 14, 2023
+" May 24, 2024 by Riley Bruins <ribru17@gmail.com> ('commentstring')
" For bugs, patches and license go to https://github.com/rhysd/vim-wasm
if exists("b:did_ftplugin")
@@ -10,7 +11,7 @@ endif
let b:did_ftplugin = 1
setlocal comments=s:(;,e:;),:;;
-setlocal commentstring=(;%s;)
+setlocal commentstring=(;\ %s\ ;)
setlocal formatoptions-=t
setlocal iskeyword+=$,.,/
diff --git a/runtime/ftplugin/xdefaults.lua b/runtime/ftplugin/xdefaults.lua
deleted file mode 100644
index b4e68148f5..0000000000
--- a/runtime/ftplugin/xdefaults.lua
+++ /dev/null
@@ -1 +0,0 @@
-vim.bo.commentstring = '/*%s*/'
diff --git a/runtime/ftplugin/xdefaults.vim b/runtime/ftplugin/xdefaults.vim
index c1aff70176..26c7516f8e 100644
--- a/runtime/ftplugin/xdefaults.vim
+++ b/runtime/ftplugin/xdefaults.vim
@@ -1,7 +1,8 @@
" Vim filetype plugin file
-" Language: X resources files like ~/.Xdefaults (xrdb)
-" Previous Maintainer: Nikolai Weibull <now@bitwi.se>
-" Latest Revision: 2008-07-09
+" Language: X resources files like ~/.Xdefaults (xrdb)
+" Previous Maintainer: Nikolai Weibull <now@bitwi.se>
+" Latest Revision: 2008 Jul 09
+" 2024 Jun 03 by Riley Bruins <ribru17@gmail.com> ('commentstring')
if exists("b:did_ftplugin")
finish
@@ -13,7 +14,7 @@ set cpo&vim
let b:undo_ftplugin = "setl com< cms< inc< fo<"
-setlocal comments=s1:/*,mb:*,ex:*/,:! commentstring& inc&
+setlocal comments=s1:/*,mb:*,ex:*/,:! commentstring=!\ %s inc&
setlocal formatoptions-=t formatoptions+=croql
let &cpo = s:cpo_save
diff --git a/runtime/ftplugin/xml.vim b/runtime/ftplugin/xml.vim
index b81c3980d2..83c528eff2 100644
--- a/runtime/ftplugin/xml.vim
+++ b/runtime/ftplugin/xml.vim
@@ -3,6 +3,7 @@
" Maintainer: Christian Brabandt <cb@256bit.org>
" Last Changed: Dec 07th, 2018
" 2024 Jan 14 by Vim Project (browsefilter)
+" 2024 May 23 by Riley Bruins <ribru17@gmail.com> ('commentstring')
" Repository: https://github.com/chrisbra/vim-xml-ftplugin
" Previous Maintainer: Dan Sharp
" URL: http://dwsharp.users.sourceforge.net/vim/ftplugin
@@ -15,7 +16,7 @@ let b:did_ftplugin = 1
let s:save_cpo = &cpo
set cpo&vim
-setlocal commentstring=<!--%s-->
+setlocal commentstring=<!--\ %s\ -->
" Remove the middlepart from the comments section, as this causes problems:
" https://groups.google.com/d/msg/vim_dev/x4GT-nqa0Kg/jvtRnEbtAnMJ
setlocal comments=s:<!--,e:-->
diff --git a/runtime/ftplugin/xs.lua b/runtime/ftplugin/xs.lua
new file mode 100644
index 0000000000..f398d66a63
--- /dev/null
+++ b/runtime/ftplugin/xs.lua
@@ -0,0 +1 @@
+vim.bo.commentstring = '// %s'
diff --git a/runtime/indent/kdl.vim b/runtime/indent/kdl.vim
new file mode 100644
index 0000000000..b1b004d0a2
--- /dev/null
+++ b/runtime/indent/kdl.vim
@@ -0,0 +1,26 @@
+" Vim indent file
+" Language: KDL
+" Author: Aram Drevekenin <aram@poor.dev>
+" Maintainer: Yinzuo Jiang <jiangyinzuo@foxmail.com>
+" Last Change: 2024-06-11
+
+" Only load this indent file when no other was loaded.
+if exists("b:did_indent")
+ finish
+endif
+let b:did_indent = 1
+
+setlocal indentexpr=KdlIndent()
+let b:undo_indent = "setlocal indentexpr<"
+
+function! KdlIndent(...)
+ let line = getline(v:lnum)
+ let previousNum = prevnonblank(v:lnum - 1)
+ let previous = getline(previousNum)
+
+ if previous =~ "{" && previous !~ "}" && line !~ "}" && line !~ ":$"
+ return indent(previousNum) + shiftwidth()
+ else
+ return indent(previousNum)
+ endif
+endfunction
diff --git a/runtime/lua/editorconfig.lua b/runtime/lua/editorconfig.lua
index dcd7425c29..e65d267a70 100644
--- a/runtime/lua/editorconfig.lua
+++ b/runtime/lua/editorconfig.lua
@@ -190,6 +190,27 @@ function properties.insert_final_newline(bufnr, val)
end
end
+--- A code of the format ss or ss-TT, where ss is an ISO 639 language code and TT is an ISO 3166 territory identifier.
+--- Sets the 'spelllang' option.
+function properties.spelling_language(bufnr, val)
+ local error_msg =
+ 'spelling_language must be of the format ss or ss-TT, where ss is an ISO 639 language code and TT is an ISO 3166 territory identifier.'
+
+ assert(val:len() == 2 or val:len() == 5, error_msg)
+
+ local language_code = val:sub(1, 2):lower()
+ assert(language_code:match('%l%l'), error_msg)
+ if val:len() == 2 then
+ vim.bo[bufnr].spelllang = language_code
+ else
+ assert(val:sub(3, 3) == '-', error_msg)
+
+ local territory_code = val:sub(4, 5):lower()
+ assert(territory_code:match('%l%l'), error_msg)
+ vim.bo[bufnr].spelllang = language_code .. '_' .. territory_code
+ end
+end
+
--- @private
--- Modified version of [glob2regpat()] that does not match path separators on `*`.
---
diff --git a/runtime/lua/man.lua b/runtime/lua/man.lua
index 02e841030f..348e502f34 100644
--- a/runtime/lua/man.lua
+++ b/runtime/lua/man.lua
@@ -35,7 +35,7 @@ local function highlight_line(line, linenr)
---@type string[]
local chars = {}
local prev_char = ''
- local overstrike, escape = false, false
+ local overstrike, escape, osc8 = false, false, false
---@type table<integer,{attr:integer,start:integer,final:integer}>
local hls = {} -- Store highlight groups as { attr, start, final }
@@ -139,6 +139,12 @@ local function highlight_line(line, linenr)
prev_char = ''
byte = byte + #char
chars[#chars + 1] = char
+ elseif osc8 then
+ -- eat characters until String Terminator or bell
+ if (prev_char == '\027' and char == '\\') or char == '\a' then
+ osc8 = false
+ end
+ prev_char = char
elseif escape then
-- Use prev_char to store the escape sequence
prev_char = prev_char .. char
@@ -157,8 +163,11 @@ local function highlight_line(line, linenr)
add_attr_hl(match + 0) -- coerce to number
end
escape = false
- elseif not prev_char:match('^%[[\032-\063]*$') then
- -- Stop looking if this isn't a partial CSI sequence
+ elseif prev_char == ']8;' then
+ osc8 = true
+ escape = false
+ elseif not prev_char:match('^[][][\032-\063]*$') then
+ -- Stop looking if this isn't a partial CSI or OSC sequence
escape = false
end
elseif char == '\027' then
diff --git a/runtime/lua/tohtml.lua b/runtime/lua/tohtml.lua
index 120247ed4e..a67e1c69e2 100644
--- a/runtime/lua/tohtml.lua
+++ b/runtime/lua/tohtml.lua
@@ -46,7 +46,7 @@
--- @field [integer] vim.tohtml.line (integer: (1-index, exclusive))
--- @class (private) vim.tohtml.line
---- @field virt_lines {[integer]:{[1]:string,[2]:integer}[]}
+--- @field virt_lines {[integer]:[string,integer][]}
--- @field pre_text string[][]
--- @field hide? boolean
--- @field [integer] vim.tohtml.cell? (integer: (1-index, exclusive))
@@ -481,7 +481,7 @@ local function styletable_treesitter(state)
end
--- @param state vim.tohtml.state
---- @param extmark {[1]:integer,[2]:integer,[3]:integer,[4]:vim.api.keyset.set_extmark|any}
+--- @param extmark [integer, integer, integer, vim.api.keyset.set_extmark|any]
--- @param namespaces table<integer,string>
local function _styletable_extmarks_highlight(state, extmark, namespaces)
if not extmark[4].hl_group then
@@ -503,7 +503,7 @@ local function _styletable_extmarks_highlight(state, extmark, namespaces)
end
--- @param state vim.tohtml.state
---- @param extmark {[1]:integer,[2]:integer,[3]:integer,[4]:vim.api.keyset.set_extmark|any}
+--- @param extmark [integer, integer, integer, vim.api.keyset.set_extmark|any]
--- @param namespaces table<integer,string>
local function _styletable_extmarks_virt_text(state, extmark, namespaces)
if not extmark[4].virt_text then
@@ -559,7 +559,7 @@ local function _styletable_extmarks_virt_text(state, extmark, namespaces)
end
--- @param state vim.tohtml.state
---- @param extmark {[1]:integer,[2]:integer,[3]:integer,[4]:vim.api.keyset.set_extmark|any}
+--- @param extmark [integer, integer, integer, vim.api.keyset.set_extmark|any]
local function _styletable_extmarks_virt_lines(state, extmark)
---TODO(altermo) if the fold start is equal to virt_line start then the fold hides the virt_line
if not extmark[4].virt_lines then
@@ -580,7 +580,7 @@ local function _styletable_extmarks_virt_lines(state, extmark)
end
--- @param state vim.tohtml.state
---- @param extmark {[1]:integer,[2]:integer,[3]:integer,[4]:vim.api.keyset.set_extmark|any}
+--- @param extmark [integer, integer, integer, vim.api.keyset.set_extmark|any]
local function _styletable_extmarks_conceal(state, extmark)
if not extmark[4].conceal or state.opt.conceallevel == 0 then
return
@@ -648,7 +648,7 @@ local function styletable_conceal(state)
local bufnr = state.bufnr
vim.api.nvim_buf_call(bufnr, function()
for row = 1, state.buflen do
- --- @type table<integer,{[1]:integer,[2]:integer,[3]:string}>
+ --- @type table<integer,[integer,integer,string]>
local conceals = {}
local line_len_exclusive = #vim.fn.getline(row) + 1
for col = 1, line_len_exclusive do
diff --git a/runtime/lua/vim/_comment.lua b/runtime/lua/vim/_comment.lua
index 044cd69716..efe289b3e1 100644
--- a/runtime/lua/vim/_comment.lua
+++ b/runtime/lua/vim/_comment.lua
@@ -194,14 +194,9 @@ local function toggle_lines(line_start, line_end, ref_position)
-- - Debatable for highlighting in text area (like LSP semantic tokens).
-- Mostly because it causes flicker as highlighting is preserved during
-- comment toggling.
- package.loaded['vim._comment']._lines = vim.tbl_map(f, lines)
- local lua_cmd = string.format(
- 'vim.api.nvim_buf_set_lines(0, %d, %d, false, package.loaded["vim._comment"]._lines)',
- line_start - 1,
- line_end
- )
- vim.cmd.lua({ lua_cmd, mods = { lockmarks = true } })
- package.loaded['vim._comment']._lines = nil
+ vim._with({ lockmarks = true }, function()
+ vim.api.nvim_buf_set_lines(0, line_start - 1, line_end, false, vim.tbl_map(f, lines))
+ end)
end
--- Operator which toggles user-supplied range of lines
diff --git a/runtime/lua/vim/_defaults.lua b/runtime/lua/vim/_defaults.lua
index 79fe5a8513..f417bda3fb 100644
--- a/runtime/lua/vim/_defaults.lua
+++ b/runtime/lua/vim/_defaults.lua
@@ -282,6 +282,26 @@ do
end,
})
+ vim.api.nvim_create_autocmd('TermOpen', {
+ group = nvim_terminal_augroup,
+ desc = 'Default settings for :terminal buffers',
+ callback = function()
+ vim.bo.modifiable = false
+ vim.bo.undolevels = -1
+ vim.bo.scrollback = vim.o.scrollback < 0 and 10000 or math.max(1, vim.o.scrollback)
+ vim.bo.textwidth = 0
+ vim.wo.wrap = false
+ vim.wo.list = false
+
+ -- This is gross. Proper list options support when?
+ local winhl = vim.o.winhighlight
+ if winhl ~= '' then
+ winhl = winhl .. ','
+ end
+ vim.wo.winhighlight = winhl .. 'StatusLine:StatusLineTerm,StatusLineNC:StatusLineTermNC'
+ end,
+ })
+
vim.api.nvim_create_autocmd('CmdwinEnter', {
pattern = '[:>]',
desc = 'Limit syntax sync to maxlines=1 in the command window',
@@ -470,10 +490,14 @@ do
--- response indicates that it does support truecolor enable 'termguicolors',
--- but only if the user has not already disabled it.
do
- if tty.rgb then
- -- The TUI was able to determine truecolor support
+ local colorterm = os.getenv('COLORTERM')
+ if tty.rgb or colorterm == 'truecolor' or colorterm == '24bit' then
+ -- The TUI was able to determine truecolor support or $COLORTERM explicitly indicates
+ -- truecolor support
setoption('termguicolors', true)
- else
+ elseif colorterm == nil or colorterm == '' then
+ -- Neither the TUI nor $COLORTERM indicate that truecolor is supported, so query the
+ -- terminal
local caps = {} ---@type table<string, boolean>
require('vim.termcap').query({ 'Tc', 'RGB', 'setrgbf', 'setrgbb' }, function(cap, found)
if not found then
diff --git a/runtime/lua/vim/_editor.lua b/runtime/lua/vim/_editor.lua
index 9f952db4fc..c7c8362bfb 100644
--- a/runtime/lua/vim/_editor.lua
+++ b/runtime/lua/vim/_editor.lua
@@ -608,10 +608,9 @@ end
--- Displays a notification to the user.
---
---- This function can be overridden by plugins to display notifications using a
---- custom provider (such as the system notification provider). By default,
+--- This function can be overridden by plugins to display notifications using
+--- a custom provider (such as the system notification provider). By default,
--- writes to |:messages|.
----
---@param msg string Content of the notification to show to the user.
---@param level integer|nil One of the values from |vim.log.levels|.
---@param opts table|nil Optional parameters. Unused by default.
diff --git a/runtime/lua/vim/_meta/api.lua b/runtime/lua/vim/_meta/api.lua
index c99eefa4f6..d91b2d08bf 100644
--- a/runtime/lua/vim/_meta/api.lua
+++ b/runtime/lua/vim/_meta/api.lua
@@ -100,6 +100,25 @@ function vim.api.nvim__inspect_cell(grid, row, col) end
function vim.api.nvim__invalidate_glyph_cache() end
--- @private
+--- EXPERIMENTAL: this API will change in the future.
+---
+--- Get the properties for namespace
+---
+--- @param ns_id integer Namespace
+--- @return vim.api.keyset.ns_opts
+function vim.api.nvim__ns_get(ns_id) end
+
+--- @private
+--- EXPERIMENTAL: this API will change in the future.
+---
+--- Set some properties for namespace
+---
+--- @param ns_id integer Namespace
+--- @param opts vim.api.keyset.ns_opts Optional parameters to set:
+--- • wins: a list of windows to be scoped in
+function vim.api.nvim__ns_set(ns_id, opts) end
+
+--- @private
--- EXPERIMENTAL: this API may change in the future.
---
--- Instruct Nvim to redraw various components.
@@ -144,36 +163,6 @@ function vim.api.nvim__stats() end
--- @return any
function vim.api.nvim__unpack(str) end
---- @private
---- EXPERIMENTAL: this API will change in the future.
----
---- Scopes a namespace to the a window, so extmarks in the namespace will be
---- active only in the given window.
----
---- @param window integer Window handle, or 0 for current window
---- @param ns_id integer Namespace
---- @return boolean
-function vim.api.nvim__win_add_ns(window, ns_id) end
-
---- @private
---- EXPERIMENTAL: this API will change in the future.
----
---- Unscopes a namespace (un-binds it from the given scope).
----
---- @param window integer Window handle, or 0 for current window
---- @param ns_id integer the namespace to remove
---- @return boolean
-function vim.api.nvim__win_del_ns(window, ns_id) end
-
---- @private
---- EXPERIMENTAL: this API will change in the future.
----
---- Gets the namespace scopes for a given window.
----
---- @param window integer Window handle, or 0 for current window
---- @return integer[]
-function vim.api.nvim__win_get_ns(window) end
-
--- Adds a highlight to buffer.
---
--- Useful for plugins that dynamically generate highlights to a buffer (like
@@ -276,14 +265,14 @@ function vim.api.nvim_buf_add_highlight(buffer, ns_id, hl_group, line, col_start
--- @return boolean
function vim.api.nvim_buf_attach(buffer, send_buffer, opts) end
---- call a function with buffer as temporary current buffer
+--- Call a function with buffer as temporary current buffer.
---
--- This temporarily switches current buffer to "buffer". If the current
---- window already shows "buffer", the window is not switched If a window
---- inside the current tabpage (including a float) already shows the buffer
---- One of these windows will be set as current window temporarily. Otherwise
---- a temporary scratch window (called the "autocmd window" for historical
---- reasons) will be used.
+--- window already shows "buffer", the window is not switched. If a window
+--- inside the current tabpage (including a float) already shows the buffer,
+--- then one of these windows will be set as current window temporarily.
+--- Otherwise a temporary scratch window (called the "autocmd window" for
+--- historical reasons) will be used.
---
--- This is useful e.g. to call Vimscript functions that only work with the
--- current buffer/window currently, like `termopen()`.
@@ -686,8 +675,6 @@ function vim.api.nvim_buf_line_count(buffer) end
--- • url: A URL to associate with this extmark. In the TUI, the
--- OSC 8 control sequence is used to generate a clickable
--- hyperlink to this URL.
---- • scoped: boolean (EXPERIMENTAL) enables "scoping" for the
---- extmark. See `nvim__win_add_ns()`
--- @return integer
function vim.api.nvim_buf_set_extmark(buffer, ns_id, line, col, opts) end
@@ -1953,7 +1940,7 @@ function vim.api.nvim_set_current_win(window) end
---
--- • on_win: called when starting to redraw a specific window.
--- ```
---- ["win", winid, bufnr, topline, botline]
+--- ["win", winid, bufnr, toprow, botrow]
--- ```
---
--- • on_line: called for each buffer line being redrawn. (The
diff --git a/runtime/lua/vim/_meta/api_keysets.lua b/runtime/lua/vim/_meta/api_keysets.lua
index f7cd92a3b2..2fe5c32faf 100644
--- a/runtime/lua/vim/_meta/api_keysets.lua
+++ b/runtime/lua/vim/_meta/api_keysets.lua
@@ -197,6 +197,9 @@ error('Cannot require a meta file')
--- @field desc? string
--- @field replace_keycodes? boolean
+--- @class vim.api.keyset.ns_opts
+--- @field wins? any[]
+
--- @class vim.api.keyset.open_term
--- @field on_input? function
--- @field force_crlf? boolean
diff --git a/runtime/lua/vim/_meta/api_keysets_extra.lua b/runtime/lua/vim/_meta/api_keysets_extra.lua
index 76b56b04e7..e1f12868d0 100644
--- a/runtime/lua/vim/_meta/api_keysets_extra.lua
+++ b/runtime/lua/vim/_meta/api_keysets_extra.lua
@@ -26,13 +26,13 @@ error('Cannot require a meta file')
--- @field url? boolean
--- @field hl_mode? string
---
---- @field virt_text? {[1]: string, [2]: string}[]
+--- @field virt_text? [string, string][]
--- @field virt_text_hide? boolean
--- @field virt_text_repeat_linebreak? boolean
--- @field virt_text_win_col? integer
--- @field virt_text_pos? string
---
---- @field virt_lines? {[1]: string, [2]: string}[][]
+--- @field virt_lines? [string, string][][]
--- @field virt_lines_above? boolean
--- @field virt_lines_leftcol? boolean
---
diff --git a/runtime/lua/vim/_meta/builtin.lua b/runtime/lua/vim/_meta/builtin.lua
index 75737bd040..3aca3cdfa5 100644
--- a/runtime/lua/vim/_meta/builtin.lua
+++ b/runtime/lua/vim/_meta/builtin.lua
@@ -121,6 +121,7 @@ function vim.stricmp(a, b) end
--- @param str string
--- @param index integer
--- @param use_utf16? boolean
+--- @return integer
function vim.str_byteindex(str, index, use_utf16) end
--- Gets a list of the starting byte positions of each UTF-8 codepoint in the given string.
diff --git a/runtime/lua/vim/_meta/builtin_types.lua b/runtime/lua/vim/_meta/builtin_types.lua
index 9f0d2e7038..9afb8c84f4 100644
--- a/runtime/lua/vim/_meta/builtin_types.lua
+++ b/runtime/lua/vim/_meta/builtin_types.lua
@@ -25,7 +25,7 @@
--- @field variables table<string,any>
--- @field windows integer[]
---- @alias vim.fn.getjumplist.ret {[1]: vim.fn.getjumplist.ret.item[], [2]: integer}
+--- @alias vim.fn.getjumplist.ret [vim.fn.getjumplist.ret.item[], integer]
--- @class vim.fn.getjumplist.ret.item
--- @field bufnr integer
@@ -34,6 +34,11 @@
--- @field filename? string
--- @field lnum integer
+--- @class vim.fn.getmarklist.ret.item
+--- @field mark string
+--- @field pos [integer, integer, integer, integer]
+--- @field file string
+
--- @class vim.fn.getmousepos.ret
--- @field screenrow integer
--- @field screencol integer
diff --git a/runtime/lua/vim/_meta/options.lua b/runtime/lua/vim/_meta/options.lua
index 428b7c4d4f..155c93726b 100644
--- a/runtime/lua/vim/_meta/options.lua
+++ b/runtime/lua/vim/_meta/options.lua
@@ -974,8 +974,8 @@ vim.bo.comments = vim.o.comments
vim.bo.com = vim.bo.comments
--- A template for a comment. The "%s" in the value is replaced with the
---- comment text. For example, C uses "/*%s*/". Used for `commenting` and to
---- add markers for folding, see `fold-marker`.
+--- comment text, and should be padded with a space when possible.
+--- Used for `commenting` and to add markers for folding, see `fold-marker`.
---
--- @type string
vim.o.commentstring = ""
@@ -1061,6 +1061,10 @@ vim.bo.cfu = vim.bo.completefunc
--- completion in the preview window. Only works in
--- combination with "menu" or "menuone".
---
+--- popup Show extra information about the currently selected
+--- completion in a popup window. Only works in combination
+--- with "menu" or "menuone". Overrides "preview".
+---
--- noinsert Do not insert any text for a match until the user selects
--- a match from the menu. Only works in combination with
--- "menu" or "menuone". No effect if "longest" is present.
@@ -1069,13 +1073,19 @@ vim.bo.cfu = vim.bo.completefunc
--- select one from the menu. Only works in combination with
--- "menu" or "menuone".
---
---- popup Show extra information about the currently selected
---- completion in a popup window. Only works in combination
---- with "menu" or "menuone". Overrides "preview".
+--- fuzzy Enable `fuzzy-matching` for completion candidates. This
+--- allows for more flexible and intuitive matching, where
+--- characters can be skipped and matches can be found even
+--- if the exact sequence is not typed. Only makes a
+--- difference how completion candidates are reduced from the
+--- list of alternatives, but not how the candidates are
+--- collected (using different completion types).
---
--- @type string
vim.o.completeopt = "menu,preview"
vim.o.cot = vim.o.completeopt
+vim.bo.completeopt = vim.o.completeopt
+vim.bo.cot = vim.bo.completeopt
vim.go.completeopt = vim.o.completeopt
vim.go.cot = vim.go.completeopt
@@ -5781,8 +5791,8 @@ vim.bo.sw = vim.bo.shiftwidth
--- message; also for quickfix message (e.g., ":cn")
--- s don't give "search hit BOTTOM, continuing at TOP" or *shm-s*
--- "search hit TOP, continuing at BOTTOM" messages; when using
---- the search count do not show "W" after the count message (see
---- S below)
+--- the search count do not show "W" before the count message
+--- (see `shm-S` below)
--- t truncate file message at the start if it is too long *shm-t*
--- to fit on the command-line, "<" will appear in the left most
--- column; ignored in Ex mode
@@ -5804,7 +5814,11 @@ vim.bo.sw = vim.bo.shiftwidth
--- `:silent` was used for the command; note that this also
--- affects messages from 'autoread' reloading
--- S do not show search count message when searching, e.g. *shm-S*
---- "[1/5]"
+--- "[1/5]". When the "S" flag is not present (e.g. search count
+--- is shown), the "search hit BOTTOM, continuing at TOP" and
+--- "search hit TOP, continuing at BOTTOM" messages are only
+--- indicated by a "W" (Mnemonic: Wrapped) letter before the
+--- search count statistics.
---
--- This gives you the opportunity to avoid that a change between buffers
--- requires you to hit <Enter>, but still gives as useful a message as
diff --git a/runtime/lua/vim/_meta/spell.lua b/runtime/lua/vim/_meta/spell.lua
index c636db3b53..b4e3bf6ca4 100644
--- a/runtime/lua/vim/_meta/spell.lua
+++ b/runtime/lua/vim/_meta/spell.lua
@@ -20,7 +20,7 @@
--- ```
---
--- @param str string
---- @return {[1]: string, [2]: 'bad'|'rare'|'local'|'caps', [3]: integer}[]
+--- @return [string, 'bad'|'rare'|'local'|'caps', integer][]
--- List of tuples with three items:
--- - The badly spelled word.
--- - The type of the spelling error:
diff --git a/runtime/lua/vim/_meta/vimfn.lua b/runtime/lua/vim/_meta/vimfn.lua
index 84bb26a135..ad057d902b 100644
--- a/runtime/lua/vim/_meta/vimfn.lua
+++ b/runtime/lua/vim/_meta/vimfn.lua
@@ -2766,8 +2766,9 @@ function vim.fn.getchangelist(buf) end
--- endfunction
--- <
---
+--- @param expr? 0|1
--- @return integer
-function vim.fn.getchar() end
+function vim.fn.getchar(expr) end
--- The result is a Number which is the state of the modifiers for
--- the last obtained character with getchar() or in another way.
@@ -2837,8 +2838,9 @@ function vim.fn.getcharsearch() end
--- Otherwise this works like |getchar()|, except that a number
--- result is converted to a string.
---
+--- @param expr? 0|1
--- @return string
-function vim.fn.getcharstr() end
+function vim.fn.getcharstr(expr) end
--- Return the type of the current command-line completion.
--- Only works when the command line is being edited, thus
@@ -3249,8 +3251,8 @@ function vim.fn.getloclist(nr, what) end
--- Refer to |getpos()| for getting information about a specific
--- mark.
---
---- @param buf? any
---- @return any
+--- @param buf? integer?
+--- @return vim.fn.getmarklist.ret.item[]
function vim.fn.getmarklist(buf) end
--- Returns a |List| with all matches previously defined for the
@@ -4969,10 +4971,21 @@ function vim.fn.libcallnr(libname, funcname, argument) end
--- display isn't updated, e.g. in silent Ex mode)
--- w$ last line visible in current window (this is one
--- less than "w0" if no lines are visible)
---- v In Visual mode: the start of the Visual area (the
---- cursor is the end). When not in Visual mode
---- returns the cursor position. Differs from |'<| in
---- that it's updated right away.
+--- v When not in Visual mode, returns the cursor
+--- position. In Visual mode, returns the other end
+--- of the Visual area. A good way to think about
+--- this is that in Visual mode "v" and "." complement
+--- each other. While "." refers to the cursor
+--- position, "v" refers to where |v_o| would move the
+--- cursor. As a result, you can use "v" and "."
+--- together to work on all of a selection in
+--- characterwise visual mode. If the cursor is at
+--- the end of a characterwise visual area, "v" refers
+--- to the start of the same visual area. And if the
+--- cursor is at the start of a characterwise visual
+--- area, "v" refers to the end of the same visual
+--- area. "v" differs from |'<| and |'>| in that it's
+--- updated right away.
--- Note that a mark in another file can be used. The line number
--- then applies to another buffer.
--- To get the column number use |col()|. To get both use
@@ -5297,8 +5310,9 @@ function vim.fn.mapcheck(name, mode, abbr) end
--- ounmap xyzzy
--- echo printf("Operator-pending mode bit: 0x%x", op_bit)
---
---- @return any
-function vim.fn.maplist() end
+--- @param abbr? 0|1
+--- @return table[]
+function vim.fn.maplist(abbr) end
--- Like |map()| but instead of replacing items in {expr1} a new
--- List or Dictionary is created and returned. {expr1} remains
@@ -7634,8 +7648,15 @@ function vim.fn.searchdecl(name, global, thisblock) end
--- \ 'synIDattr(synID(line("."), col("."), 0), "name") =~? "string"')
--- <
---
---- @return any
-function vim.fn.searchpair() end
+--- @param start any
+--- @param middle any
+--- @param end_ any
+--- @param flags? string
+--- @param skip? any
+--- @param stopline? any
+--- @param timeout? integer
+--- @return integer
+function vim.fn.searchpair(start, middle, end_, flags, skip, stopline, timeout) end
--- Same as |searchpair()|, but returns a |List| with the line and
--- column position of the match. The first element of the |List|
@@ -7647,8 +7668,15 @@ function vim.fn.searchpair() end
--- <
--- See |match-parens| for a bigger and more useful example.
---
---- @return any
-function vim.fn.searchpairpos() end
+--- @param start any
+--- @param middle any
+--- @param end_ any
+--- @param flags? string
+--- @param skip? any
+--- @param stopline? any
+--- @param timeout? integer
+--- @return [integer, integer]
+function vim.fn.searchpairpos(start, middle, end_, flags, skip, stopline, timeout) end
--- Same as |search()|, but returns a |List| with the line and
--- column position of the match. The first element of the |List|
@@ -9796,7 +9824,7 @@ function vim.fn.synIDtrans(synID) end
---
--- @param lnum integer
--- @param col integer
---- @return {[1]: integer, [2]: string, [3]: integer}
+--- @return [integer, string, integer]
function vim.fn.synconcealed(lnum, col) end
--- Return a |List|, which is the stack of syntax items at the
diff --git a/runtime/lua/vim/_options.lua b/runtime/lua/vim/_options.lua
index b41e298dd7..a61fa61256 100644
--- a/runtime/lua/vim/_options.lua
+++ b/runtime/lua/vim/_options.lua
@@ -95,7 +95,6 @@
local api = vim.api
-- TODO(tjdevries): Improve option metadata so that this doesn't have to be hardcoded.
--- Can be done in a separate PR.
local key_value_options = {
fillchars = true,
fcs = true,
@@ -175,6 +174,11 @@ local function new_buf_opt_accessor(bufnr)
end
local function new_win_opt_accessor(winid, bufnr)
+ -- TODO(lewis6991): allow passing both buf and win to nvim_get_option_value
+ if bufnr ~= nil and bufnr ~= 0 then
+ error('only bufnr=0 is supported')
+ end
+
return setmetatable({}, {
__index = function(_, k)
if bufnr == nil and type(k) == 'number' then
@@ -185,11 +189,6 @@ local function new_win_opt_accessor(winid, bufnr)
end
end
- if bufnr ~= nil and bufnr ~= 0 then
- error('only bufnr=0 is supported')
- end
-
- -- TODO(lewis6991): allow passing both buf and win to nvim_get_option_value
return api.nvim_get_option_value(k, {
scope = bufnr and 'local' or nil,
win = winid or 0,
@@ -197,7 +196,6 @@ local function new_win_opt_accessor(winid, bufnr)
end,
__newindex = function(_, k, v)
- -- TODO(lewis6991): allow passing both buf and win to nvim_set_option_value
return api.nvim_set_option_value(k, v, {
scope = bufnr and 'local' or nil,
win = winid or 0,
diff --git a/runtime/lua/vim/deprecated/health.lua b/runtime/lua/vim/deprecated/health.lua
index 64a755b248..eed889d90a 100644
--- a/runtime/lua/vim/deprecated/health.lua
+++ b/runtime/lua/vim/deprecated/health.lua
@@ -1,7 +1,7 @@
local M = {}
local health = vim.health
-local deprecated = {} ---@type {[1]: string, [2]: table, [3]: string}[]
+local deprecated = {} ---@type [string, table, string][]
function M.check()
if next(deprecated) == nil then
diff --git a/runtime/lua/vim/diagnostic.lua b/runtime/lua/vim/diagnostic.lua
index dca7698356..c8e34258f5 100644
--- a/runtime/lua/vim/diagnostic.lua
+++ b/runtime/lua/vim/diagnostic.lua
@@ -108,7 +108,7 @@ local M = {}
--- If {scope} is "line" or "cursor", use this position rather than the cursor
--- position. If a number, interpreted as a line number; otherwise, a
--- (row, col) tuple.
---- @field pos? integer|{[1]:integer,[2]:integer}
+--- @field pos? integer|[integer,integer]
---
--- Sort diagnostics by severity.
--- Overrides the setting from |vim.diagnostic.config()|.
@@ -122,7 +122,7 @@ local M = {}
--- String to use as the header for the floating window. If a table, it is
--- interpreted as a `[text, hl_group]` tuple.
--- Overrides the setting from |vim.diagnostic.config()|.
---- @field header? string|{[1]:string,[2]:any}
+--- @field header? string|[string,any]
---
--- Include the diagnostic source in the message.
--- Use "if_many" to only show sources if there is more than one source of
@@ -203,7 +203,7 @@ local M = {}
--- @field hl_mode? 'replace'|'combine'|'blend'
---
--- See |nvim_buf_set_extmark()|.
---- @field virt_text? {[1]:string,[2]:any}[]
+--- @field virt_text? [string,any][]
---
--- See |nvim_buf_set_extmark()|.
--- @field virt_text_pos? 'eol'|'overlay'|'right_align'|'inline'
@@ -247,9 +247,11 @@ local M = {}
--- @class vim.diagnostic.Opts.Jump
---
--- Default value of the {float} parameter of |vim.diagnostic.jump()|.
+--- (default: false)
--- @field float? boolean|vim.diagnostic.Opts.Float
---
--- Default value of the {wrap} parameter of |vim.diagnostic.jump()|.
+--- (default: true)
--- @field wrap? boolean
---
--- Default value of the {severity} parameter of |vim.diagnostic.jump()|.
@@ -1252,7 +1254,7 @@ end
--- Cursor position as a `(row, col)` tuple. See |nvim_win_get_cursor()|. Used
--- to find the nearest diagnostic when {count} is used. Only used when {count}
--- is non-nil. Default is the current cursor position.
---- @field pos? {[1]:integer,[2]:integer}
+--- @field pos? [integer,integer]
---
--- Whether to loop around file or not. Similar to 'wrapscan'.
--- (default: `true`)
@@ -1857,16 +1859,19 @@ function M.open_float(opts, ...)
if scope == 'line' then
--- @param d vim.Diagnostic
diagnostics = vim.tbl_filter(function(d)
- return lnum >= d.lnum and lnum <= d.end_lnum
+ return lnum >= d.lnum
+ and lnum <= d.end_lnum
+ and (d.lnum == d.end_lnum or lnum ~= d.end_lnum or d.end_col ~= 0)
end, diagnostics)
elseif scope == 'cursor' then
- -- LSP servers can send diagnostics with `end_col` past the length of the line
+ -- If `col` is past the end of the line, show if the cursor is on the last char in the line
local line_length = #api.nvim_buf_get_lines(bufnr, lnum, lnum + 1, true)[1]
--- @param d vim.Diagnostic
diagnostics = vim.tbl_filter(function(d)
- return d.lnum == lnum
- and math.min(d.col, line_length - 1) <= col
- and (d.end_col >= col or d.end_lnum > lnum)
+ return lnum >= d.lnum
+ and lnum <= d.end_lnum
+ and (lnum ~= d.lnum or col >= math.min(d.col, line_length - 1))
+ and ((d.lnum == d.end_lnum and d.col == d.end_col) or lnum ~= d.end_lnum or col < d.end_col)
end, diagnostics)
end
diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua
index 2ab6cc6059..cc2fbe0cec 100644
--- a/runtime/lua/vim/filetype.lua
+++ b/runtime/lua/vim/filetype.lua
@@ -4,7 +4,7 @@ local fn = vim.fn
local M = {}
--- @alias vim.filetype.mapfn fun(path:string,bufnr:integer, ...):string?, fun(b:integer)?
---- @alias vim.filetype.maptbl {[1]:string|vim.filetype.mapfn, [2]:{priority:integer}}
+--- @alias vim.filetype.maptbl [string|vim.filetype.mapfn, {priority:integer}]
--- @alias vim.filetype.mapping.value string|vim.filetype.mapfn|vim.filetype.maptbl
--- @alias vim.filetype.mapping table<string,vim.filetype.mapping.value>
@@ -873,6 +873,7 @@ local extension = {
t6 = 'raku',
p6 = 'raku',
raml = 'raml',
+ rasi = 'rasi',
rbs = 'rbs',
rego = 'rego',
rem = 'remind',
@@ -1450,6 +1451,7 @@ local filename = {
['.firebaserc'] = 'json',
['.prettierrc'] = 'json',
['.stylelintrc'] = 'json',
+ ['.lintstagedrc'] = 'json',
['flake.lock'] = 'json',
['.babelrc'] = 'jsonc',
['.eslintrc'] = 'jsonc',
diff --git a/runtime/lua/vim/filetype/detect.lua b/runtime/lua/vim/filetype/detect.lua
index 58d2666564..c56ece6289 100644
--- a/runtime/lua/vim/filetype/detect.lua
+++ b/runtime/lua/vim/filetype/detect.lua
@@ -594,7 +594,7 @@ function M.frm(_, bufnr)
end
--- @type vim.filetype.mapfn
-function M.fvwm_1(_, _)
+function M.fvwm_v1(_, _)
return 'fvwm', function(bufnr)
vim.b[bufnr].fvwm_version = 1
end
@@ -1355,7 +1355,7 @@ end
function M.sgml(_, bufnr)
local lines = table.concat(getlines(bufnr, 1, 5))
if lines:find('linuxdoc') then
- return 'smgllnx'
+ return 'sgmllnx'
elseif lines:find('<!DOCTYPE.*DocBook') then
return 'docbk',
function(b)
diff --git a/runtime/lua/vim/glob.lua b/runtime/lua/vim/glob.lua
index ad4a915a94..6de2bc3e94 100644
--- a/runtime/lua/vim/glob.lua
+++ b/runtime/lua/vim/glob.lua
@@ -29,8 +29,10 @@ function M.to_lpeg(pattern)
return patt
end
- local function add(acc, a)
- return acc + a
+ local function condlist(conds, after)
+ return vim.iter(conds):fold(P(false), function(acc, cond)
+ return acc + cond * after
+ end)
end
local function mul(acc, m)
@@ -63,15 +65,14 @@ function M.to_lpeg(pattern)
* C(P('!') ^ -1)
* Ct(Ct(C(P(1)) * P('-') * C(P(1) - P(']'))) ^ 1 * P(']'))
/ class,
- CondList = P('{') * Cf(V('Cond') * (P(',') * V('Cond')) ^ 0, add) * P('}'),
+ CondList = P('{') * Ct(V('Cond') * (P(',') * V('Cond')) ^ 0) * P('}') * V('Pattern') / condlist,
-- TODO: '*' inside a {} condition is interpreted literally but should probably have the same
-- wildcard semantics it usually has.
-- Fixing this is non-trivial because '*' should match non-greedily up to "the rest of the
-- pattern" which in all other cases is the entire succeeding part of the pattern, but at the end of a {}
-- condition means "everything after the {}" where several other options separated by ',' may
-- exist in between that should not be matched by '*'.
- Cond = Cf((V('Ques') + V('Class') + V('CondList') + (V('Literal') - S(',}'))) ^ 1, mul)
- + Cc(P(0)),
+ Cond = Cf((V('Ques') + V('Class') + V('Literal') - S(',}')) ^ 1, mul) + Cc(P(0)),
Literal = P(1) / P,
End = P(-1) * Cc(P(-1)),
})
diff --git a/runtime/lua/vim/highlight.lua b/runtime/lua/vim/highlight.lua
index 89298ce568..233bc50237 100644
--- a/runtime/lua/vim/highlight.lua
+++ b/runtime/lua/vim/highlight.lua
@@ -31,8 +31,6 @@ M.priorities = {
--- Indicates priority of highlight
--- (default: `vim.highlight.priorities.user`)
--- @field priority? integer
----
---- @field package _scoped? boolean
--- Apply highlight group to range of text.
---
@@ -47,12 +45,23 @@ function M.range(bufnr, ns, higroup, start, finish, opts)
local regtype = opts.regtype or 'v'
local inclusive = opts.inclusive or false
local priority = opts.priority or M.priorities.user
- local scoped = opts._scoped or false
+
+ local v_maxcol = vim.v.maxcol
local pos1 = type(start) == 'string' and vim.fn.getpos(start)
- or { bufnr, start[1] + 1, start[2] + 1, 0 }
+ or {
+ bufnr,
+ start[1] + 1,
+ start[2] ~= -1 and start[2] ~= v_maxcol and start[2] + 1 or v_maxcol,
+ 0,
+ }
local pos2 = type(finish) == 'string' and vim.fn.getpos(finish)
- or { bufnr, finish[1] + 1, finish[2] + 1, 0 }
+ or {
+ bufnr,
+ finish[1] + 1,
+ finish[2] ~= -1 and start[2] ~= v_maxcol and finish[2] + 1 or v_maxcol,
+ 0,
+ }
local buf_line_count = vim.api.nvim_buf_line_count(bufnr)
pos1[2] = math.min(pos1[2], buf_line_count)
@@ -63,10 +72,14 @@ function M.range(bufnr, ns, higroup, start, finish, opts)
end
vim.api.nvim_buf_call(bufnr, function()
- local max_col1 = vim.fn.col({ pos1[2], '$' })
- pos1[3] = math.min(pos1[3], max_col1)
- local max_col2 = vim.fn.col({ pos2[2], '$' })
- pos2[3] = math.min(pos2[3], max_col2)
+ if pos1[3] ~= v_maxcol then
+ local max_col1 = vim.fn.col({ pos1[2], '$' })
+ pos1[3] = math.min(pos1[3], max_col1)
+ end
+ if pos2[3] ~= v_maxcol then
+ local max_col2 = vim.fn.col({ pos2[2], '$' })
+ pos2[3] = math.min(pos2[3], max_col2)
+ end
end)
local region = vim.fn.getregionpos(pos1, pos2, {
@@ -77,6 +90,14 @@ function M.range(bufnr, ns, higroup, start, finish, opts)
-- For non-blockwise selection, use a single extmark.
if regtype == 'v' or regtype == 'V' then
region = { { region[1][1], region[#region][2] } }
+ if
+ regtype == 'V'
+ or region[1][2][2] == pos1[2] and pos1[3] == v_maxcol
+ or region[1][2][2] == pos2[2] and pos2[3] == v_maxcol
+ then
+ region[1][2][2] = region[1][2][2] + 1
+ region[1][2][3] = 0
+ end
end
for _, res in ipairs(region) do
@@ -84,17 +105,12 @@ function M.range(bufnr, ns, higroup, start, finish, opts)
local start_col = res[1][3] - 1
local end_row = res[2][2] - 1
local end_col = res[2][3]
- if regtype == 'V' then
- end_row = end_row + 1
- end_col = 0
- end
api.nvim_buf_set_extmark(bufnr, ns, start_row, start_col, {
hl_group = higroup,
end_row = end_row,
end_col = end_col,
priority = priority,
strict = false,
- scoped = scoped,
})
end
end
@@ -158,19 +174,18 @@ function M.on_yank(opts)
yank_cancel()
end
- vim.api.nvim__win_add_ns(winid, yank_ns)
+ vim.api.nvim__ns_set(yank_ns, { wins = { winid } })
M.range(bufnr, yank_ns, higroup, "'[", "']", {
regtype = event.regtype,
inclusive = event.inclusive,
priority = opts.priority or M.priorities.user,
- _scoped = true,
})
yank_cancel = function()
yank_timer = nil
yank_cancel = nil
pcall(vim.api.nvim_buf_clear_namespace, bufnr, yank_ns, 0, -1)
- pcall(vim.api.nvim__win_del_ns, winid, yank_ns)
+ pcall(vim.api.nvim__ns_set, { wins = {} })
end
yank_timer = vim.defer_fn(yank_cancel, timeout)
diff --git a/runtime/lua/vim/iter.lua b/runtime/lua/vim/iter.lua
index 1093759efe..6bddf0bc5e 100644
--- a/runtime/lua/vim/iter.lua
+++ b/runtime/lua/vim/iter.lua
@@ -276,7 +276,7 @@ end
--- -- { 6, 12 }
--- ```
---
----@param f fun(...):any Mapping function. Takes all values returned from
+---@param f fun(...):...:any Mapping function. Takes all values returned from
--- the previous stage in the pipeline as arguments
--- and returns one or more new values, which are used
--- in the next pipeline stage. Nil return values
diff --git a/runtime/lua/vim/lsp.lua b/runtime/lua/vim/lsp.lua
index c2deac0113..623ccdd5cd 100644
--- a/runtime/lua/vim/lsp.lua
+++ b/runtime/lua/vim/lsp.lua
@@ -201,10 +201,10 @@ end
--- Predicate used to decide if a client should be re-used. Used on all
--- running clients. The default implementation re-uses a client if name and
--- root_dir matches.
---- @field reuse_client fun(client: vim.lsp.Client, config: vim.lsp.ClientConfig): boolean
+--- @field reuse_client? fun(client: vim.lsp.Client, config: vim.lsp.ClientConfig): boolean
---
--- Buffer handle to attach to if starting or re-using a client (0 for current).
---- @field bufnr integer
+--- @field bufnr? integer
---
--- Suppress error reporting if the LSP server fails to start (default false).
--- @field silent? boolean
@@ -393,7 +393,7 @@ local function on_client_exit(code, signal, client_id)
vim.schedule(function()
for bufnr in pairs(client.attached_buffers) do
- if client and client.attached_buffers[bufnr] then
+ if client and client.attached_buffers[bufnr] and api.nvim_buf_is_valid(bufnr) then
api.nvim_exec_autocmds('LspDetach', {
buffer = bufnr,
modeline = false,
@@ -484,6 +484,7 @@ local function text_document_did_save_handler(bufnr)
text = lsp._buf_get_full_text(bufnr),
},
})
+ util.buf_versions[bufnr] = 0
end
local save_capability = vim.tbl_get(client.server_capabilities, 'textDocumentSync', 'save')
if save_capability then
@@ -574,11 +575,12 @@ local function buf_attach(bufnr)
})
-- First time, so attach and set up stuff.
api.nvim_buf_attach(bufnr, false, {
- on_lines = function(_, _, _, firstline, lastline, new_lastline)
+ on_lines = function(_, _, changedtick, firstline, lastline, new_lastline)
if #lsp.get_clients({ bufnr = bufnr }) == 0 then
-- detach if there are no clients
return #lsp.get_clients({ bufnr = bufnr, _uninitialized = true }) == 0
end
+ util.buf_versions[bufnr] = changedtick
changetracking.send_changes(bufnr, firstline, lastline, new_lastline)
end,
@@ -602,6 +604,7 @@ local function buf_attach(bufnr)
buf_detach_client(bufnr, client)
end
attached_buffers[bufnr] = nil
+ util.buf_versions[bufnr] = nil
end,
-- TODO if we know all of the potential clients ahead of time, then we
diff --git a/runtime/lua/vim/lsp/_changetracking.lua b/runtime/lua/vim/lsp/_changetracking.lua
index ce701f0772..b2be53269f 100644
--- a/runtime/lua/vim/lsp/_changetracking.lua
+++ b/runtime/lua/vim/lsp/_changetracking.lua
@@ -1,5 +1,6 @@
local protocol = require('vim.lsp.protocol')
local sync = require('vim.lsp.sync')
+local util = require('vim.lsp.util')
local api = vim.api
local uv = vim.uv
@@ -276,7 +277,7 @@ local function send_changes(bufnr, sync_kind, state, buf_state)
client.notify(protocol.Methods.textDocument_didChange, {
textDocument = {
uri = uri,
- version = vim.b[bufnr].changedtick,
+ version = util.buf_versions[bufnr],
},
contentChanges = changes,
})
diff --git a/runtime/lua/vim/lsp/_dynamic.lua b/runtime/lua/vim/lsp/_dynamic.lua
index 819b03a63a..27113c0e74 100644
--- a/runtime/lua/vim/lsp/_dynamic.lua
+++ b/runtime/lua/vim/lsp/_dynamic.lua
@@ -24,7 +24,6 @@ function M:supports_registration(method)
end
--- @param registrations lsp.Registration[]
---- @package
function M:register(registrations)
-- remove duplicates
self:unregister(registrations)
@@ -38,7 +37,6 @@ function M:register(registrations)
end
--- @param unregisterations lsp.Unregistration[]
---- @package
function M:unregister(unregisterations)
for _, unreg in ipairs(unregisterations) do
local method = unreg.method
@@ -58,7 +56,6 @@ end
--- @param method string
--- @param opts? {bufnr: integer?}
--- @return lsp.Registration? (table|nil) the registration if found
---- @package
function M:get(method, opts)
opts = opts or {}
opts.bufnr = opts.bufnr or vim.api.nvim_get_current_buf()
@@ -78,7 +75,6 @@ end
--- @param method string
--- @param opts? {bufnr: integer?}
---- @package
function M:supports(method, opts)
return self:get(method, opts) ~= nil
end
diff --git a/runtime/lua/vim/lsp/_meta/protocol.lua b/runtime/lua/vim/lsp/_meta/protocol.lua
index 9a11972007..cbddd24630 100644
--- a/runtime/lua/vim/lsp/_meta/protocol.lua
+++ b/runtime/lua/vim/lsp/_meta/protocol.lua
@@ -3235,7 +3235,7 @@ error('Cannot require a meta file')
---
---*Note*: a label of type string should be a substring of its containing signature label.
---Its intended use case is to highlight the parameter label part in the `SignatureInformation.label`.
----@field label string|{ [1]: uinteger, [2]: uinteger }
+---@field label string|[uinteger, uinteger]
---
---The human-readable doc-comment of this parameter. Will be shown
---in the UI but can be omitted.
diff --git a/runtime/lua/vim/lsp/client.lua b/runtime/lua/vim/lsp/client.lua
index b28fe2f797..d3ff918792 100644
--- a/runtime/lua/vim/lsp/client.lua
+++ b/runtime/lua/vim/lsp/client.lua
@@ -436,7 +436,7 @@ local function ensure_list(x)
return { x }
end
---- @package
+--- @nodoc
--- @param config vim.lsp.ClientConfig
--- @return vim.lsp.Client?
function Client.create(config)
@@ -535,7 +535,7 @@ function Client:_run_callbacks(cbs, error_id, ...)
end
end
---- @package
+--- @nodoc
function Client:initialize()
local config = self.config
@@ -656,7 +656,7 @@ end
--- @param method string LSP method name.
--- @param params? table LSP request params.
--- @param handler? lsp.Handler Response |lsp-handler| for this method.
---- @param bufnr? integer Buffer handle (0 for current).
+--- @param bufnr integer Buffer handle (0 for current).
--- @return boolean status, integer? request_id {status} is a bool indicating
--- whether the request was successful. If it is `false`, then it will
--- always be `false` (the client has shutdown). If it was
@@ -673,8 +673,8 @@ function Client:_request(method, params, handler, bufnr)
end
-- Ensure pending didChange notifications are sent so that the server doesn't operate on a stale state
changetracking.flush(self, bufnr)
+ local version = lsp.util.buf_versions[bufnr]
bufnr = resolve_bufnr(bufnr)
- local version = vim.b[bufnr].changedtick
log.debug(self._log_prefix, 'client.request', self.id, method, params, handler, bufnr)
local success, request_id = self.rpc.request(method, params, function(err, result)
local context = {
@@ -861,7 +861,6 @@ function Client:_is_stopped()
return self.rpc.is_closing()
end
---- @package
--- Execute a lsp command, either via client command function (if available)
--- or via workspace/executeCommand (if supported by the server)
---
@@ -906,7 +905,6 @@ function Client:_exec_cmd(command, context, handler, on_unsupported)
self.request(ms.workspace_executeCommand, params, handler, context.bufnr)
end
---- @package
--- Default handler for the 'textDocument/didOpen' LSP notification.
---
--- @param bufnr integer Number of the buffer, or 0 for current
@@ -922,13 +920,14 @@ function Client:_text_document_did_open_handler(bufnr)
local params = {
textDocument = {
- version = vim.b[bufnr].changedtick,
+ version = 0,
uri = vim.uri_from_bufnr(bufnr),
languageId = self.get_language_id(bufnr, filetype),
text = lsp._buf_get_full_text(bufnr),
},
}
self.notify(ms.textDocument_didOpen, params)
+ lsp.util.buf_versions[bufnr] = params.textDocument.version
-- Next chance we get, we should re-do the diagnostics
vim.schedule(function()
@@ -941,7 +940,6 @@ function Client:_text_document_did_open_handler(bufnr)
end)
end
---- @package
--- Runs the on_attach function from the client's config if it was defined.
--- @param bufnr integer Buffer number
function Client:_on_attach(bufnr)
@@ -1064,7 +1062,6 @@ function Client:_on_exit(code, signal)
)
end
---- @package
--- Add a directory to the workspace folders.
--- @param dir string?
function Client:_add_workspace_folder(dir)
@@ -1087,7 +1084,6 @@ function Client:_add_workspace_folder(dir)
vim.list_extend(self.workspace_folders, wf)
end
---- @package
--- Remove a directory to the workspace folders.
--- @param dir string?
function Client:_remove_workspace_folder(dir)
diff --git a/runtime/lua/vim/lsp/completion.lua b/runtime/lua/vim/lsp/completion.lua
index 39c0c5fa29..4b7deabf41 100644
--- a/runtime/lua/vim/lsp/completion.lua
+++ b/runtime/lua/vim/lsp/completion.lua
@@ -30,7 +30,7 @@ local buf_handles = {}
--- @nodoc
--- @class vim.lsp.completion.Context
local Context = {
- cursor = nil, --- @type { [1]: integer, [2]: integer }?
+ cursor = nil, --- @type [integer, integer]?
last_request_time = nil, --- @type integer?
pending_requests = {}, --- @type function[]
isIncomplete = false,
@@ -153,7 +153,8 @@ local function get_completion_word(item)
return item.label
end
elseif item.textEdit then
- return item.textEdit.newText
+ local word = item.textEdit.newText
+ return word:match('^(%S*)') or word
elseif item.insertText and item.insertText ~= '' then
return item.insertText
end
@@ -201,6 +202,24 @@ local function get_items(result)
end
end
+---@param item lsp.CompletionItem
+---@return string
+local function get_doc(item)
+ local doc = item.documentation
+ if not doc then
+ return ''
+ end
+ if type(doc) == 'string' then
+ return doc
+ end
+ if type(doc) == 'table' and type(doc.value) == 'string' then
+ return doc.value
+ end
+
+ vim.notify('invalid documentation value: ' .. vim.inspect(doc), vim.log.levels.WARN)
+ return ''
+end
+
--- Turns the result of a `textDocument/completion` request into vim-compatible
--- |complete-items|.
---
@@ -216,58 +235,48 @@ function M._lsp_to_complete_items(result, prefix, client_id)
return {}
end
- if prefix ~= '' then
- ---@param item lsp.CompletionItem
- local function match_prefix(item)
- if item.filterText then
- return next(vim.fn.matchfuzzy({ item.filterText }, prefix))
- end
- return true
+ local matches = prefix == '' and function()
+ return true
+ end or function(item)
+ if item.filterText then
+ return next(vim.fn.matchfuzzy({ item.filterText }, prefix))
end
-
- items = vim.tbl_filter(match_prefix, items) --[[@as lsp.CompletionItem[]|]]
+ return true
end
- table.sort(items, function(a, b)
- return (a.sortText or a.label) < (b.sortText or b.label)
- end)
-
- local matches = {}
+ local candidates = {}
for _, item in ipairs(items) do
- local info = ''
- local documentation = item.documentation
- if documentation then
- if type(documentation) == 'string' and documentation ~= '' then
- info = documentation
- elseif type(documentation) == 'table' and type(documentation.value) == 'string' then
- info = documentation.value
- else
- vim.notify(
- ('invalid documentation value %s'):format(vim.inspect(documentation)),
- vim.log.levels.WARN
- )
- end
- end
- local word = get_completion_word(item)
- table.insert(matches, {
- word = word,
- abbr = item.label,
- kind = protocol.CompletionItemKind[item.kind] or 'Unknown',
- menu = item.detail or '',
- info = #info > 0 and info or '',
- icase = 1,
- dup = 1,
- empty = 1,
- user_data = {
- nvim = {
- lsp = {
- completion_item = item,
- client_id = client_id,
+ if matches(item) then
+ local word = get_completion_word(item)
+ table.insert(candidates, {
+ word = word,
+ abbr = item.label,
+ kind = protocol.CompletionItemKind[item.kind] or 'Unknown',
+ menu = item.detail or '',
+ info = get_doc(item),
+ icase = 1,
+ dup = 1,
+ empty = 1,
+ user_data = {
+ nvim = {
+ lsp = {
+ completion_item = item,
+ client_id = client_id,
+ },
},
},
- },
- })
+ })
+ end
end
- return matches
+ ---@diagnostic disable-next-line: no-unknown
+ table.sort(candidates, function(a, b)
+ ---@type lsp.CompletionItem
+ local itema = a.user_data.nvim.lsp.completion_item
+ ---@type lsp.CompletionItem
+ local itemb = b.user_data.nvim.lsp.completion_item
+ return (itema.sortText or itema.label) < (itemb.sortText or itemb.label)
+ end)
+
+ return candidates
end
--- @param lnum integer 0-indexed
@@ -340,79 +349,7 @@ function M._convert_results(
return matches, server_start_boundary
end
---- Implements 'omnifunc' compatible LSP completion.
----
---- @see |complete-functions|
---- @see |complete-items|
---- @see |CompleteDone|
----
---- @param findstart integer 0 or 1, decides behavior
---- @param base integer findstart=0, text to match against
----
---- @return integer|table Decided by {findstart}:
---- - findstart=0: column where the completion starts, or -2 or -3
---- - findstart=1: list of matches (actually just calls |complete()|)
-function M._omnifunc(findstart, base)
- vim.lsp.log.debug('omnifunc.findstart', { findstart = findstart, base = base })
- assert(base) -- silence luals
- local bufnr = api.nvim_get_current_buf()
- local clients = lsp.get_clients({ bufnr = bufnr, method = ms.textDocument_completion })
- local remaining = #clients
- if remaining == 0 then
- return findstart == 1 and -1 or {}
- end
-
- local win = api.nvim_get_current_win()
- local cursor = api.nvim_win_get_cursor(win)
- local lnum = cursor[1] - 1
- local cursor_col = cursor[2]
- local line = api.nvim_get_current_line()
- local line_to_cursor = line:sub(1, cursor_col)
- local client_start_boundary = vim.fn.match(line_to_cursor, '\\k*$') --[[@as integer]]
- local server_start_boundary = nil
- local items = {}
-
- local function on_done()
- local mode = api.nvim_get_mode()['mode']
- if mode == 'i' or mode == 'ic' then
- vim.fn.complete((server_start_boundary or client_start_boundary) + 1, items)
- end
- end
-
- local util = vim.lsp.util
- for _, client in ipairs(clients) do
- local params = util.make_position_params(win, client.offset_encoding)
- client.request(ms.textDocument_completion, params, function(err, result)
- if err then
- lsp.log.warn(err.message)
- end
- if result and vim.fn.mode() == 'i' then
- local matches
- matches, server_start_boundary = M._convert_results(
- line,
- lnum,
- cursor_col,
- client.id,
- client_start_boundary,
- server_start_boundary,
- result,
- client.offset_encoding
- )
- vim.list_extend(items, matches)
- end
- remaining = remaining - 1
- if remaining == 0 then
- vim.schedule(on_done)
- end
- end, bufnr)
- end
-
- -- Return -2 to signal that we should continue completion so that we can
- -- async complete.
- return -2
-end
-
---- @param clients table<integer, vim.lsp.Client>
+--- @param clients table<integer, vim.lsp.Client> # keys != client_id
--- @param bufnr integer
--- @param win integer
--- @param callback fun(responses: table<integer, { err: lsp.ResponseError, result: vim.lsp.CompletionResult }>)
@@ -422,7 +359,8 @@ local function request(clients, bufnr, win, callback)
local request_ids = {} --- @type table<integer, integer>
local remaining_requests = vim.tbl_count(clients)
- for client_id, client in pairs(clients) do
+ for _, client in pairs(clients) do
+ local client_id = client.id
local params = lsp.util.make_position_params(win, client.offset_encoding)
local ok, request_id = client.request(ms.textDocument_completion, params, function(err, result)
responses[client_id] = { err = err, result = result }
@@ -447,6 +385,64 @@ local function request(clients, bufnr, win, callback)
end
end
+local function trigger(bufnr, clients)
+ reset_timer()
+ Context:cancel_pending()
+
+ local win = api.nvim_get_current_win()
+ local cursor_row, cursor_col = unpack(api.nvim_win_get_cursor(win)) --- @type integer, integer
+ local line = api.nvim_get_current_line()
+ local line_to_cursor = line:sub(1, cursor_col)
+ local word_boundary = vim.fn.match(line_to_cursor, '\\k*$')
+ local start_time = vim.uv.hrtime()
+ Context.last_request_time = start_time
+
+ local cancel_request = request(clients, bufnr, win, function(responses)
+ local end_time = vim.uv.hrtime()
+ rtt_ms = compute_new_average((end_time - start_time) * ns_to_ms)
+
+ Context.pending_requests = {}
+ Context.isIncomplete = false
+
+ local row_changed = api.nvim_win_get_cursor(win)[1] ~= cursor_row
+ local mode = api.nvim_get_mode().mode
+ if row_changed or not (mode == 'i' or mode == 'ic') then
+ return
+ end
+
+ local matches = {}
+ local server_start_boundary --- @type integer?
+ for client_id, response in pairs(responses) do
+ if response.err then
+ vim.notify_once(response.err.message, vim.log.levels.warn)
+ end
+
+ local result = response.result
+ if result then
+ Context.isIncomplete = Context.isIncomplete or result.isIncomplete
+ local client = lsp.get_client_by_id(client_id)
+ local encoding = client and client.offset_encoding or 'utf-16'
+ local client_matches
+ client_matches, server_start_boundary = M._convert_results(
+ line,
+ cursor_row - 1,
+ cursor_col,
+ client_id,
+ word_boundary,
+ nil,
+ result,
+ encoding
+ )
+ vim.list_extend(matches, client_matches)
+ end
+ end
+ local start_col = (server_start_boundary or word_boundary) + 1
+ vim.fn.complete(start_col, matches)
+ end)
+
+ table.insert(Context.pending_requests, cancel_request)
+end
+
--- @param handle vim.lsp.completion.BufHandle
local function on_insert_char_pre(handle)
if tonumber(vim.fn.pumvisible()) == 1 then
@@ -581,8 +577,10 @@ end
---@param bufnr integer
---@param opts vim.lsp.completion.BufferOpts
local function enable_completions(client_id, bufnr, opts)
- if not buf_handles[bufnr] then
- buf_handles[bufnr] = { clients = {}, triggers = {} }
+ local buf_handle = buf_handles[bufnr]
+ if not buf_handle then
+ buf_handle = { clients = {}, triggers = {} }
+ buf_handles[bufnr] = buf_handle
-- Attach to buffer events.
api.nvim_buf_attach(bufnr, false, {
@@ -623,12 +621,12 @@ local function enable_completions(client_id, bufnr, opts)
end
end
- if not buf_handles[bufnr].clients[client_id] then
+ if not buf_handle.clients[client_id] then
local client = lsp.get_client_by_id(client_id)
assert(client, 'invalid client ID')
-- Add the new client to the buffer's clients.
- buf_handles[bufnr].clients[client_id] = client
+ buf_handle.clients[client_id] = client
-- Add the new client to the clients that should be triggered by its trigger characters.
--- @type string[]
@@ -638,10 +636,10 @@ local function enable_completions(client_id, bufnr, opts)
'triggerCharacters'
) or {}
for _, char in ipairs(triggers) do
- local clients_for_trigger = buf_handles[bufnr].triggers[char]
+ local clients_for_trigger = buf_handle.triggers[char]
if not clients_for_trigger then
clients_for_trigger = {}
- buf_handles[bufnr].triggers[char] = clients_for_trigger
+ buf_handle.triggers[char] = clients_for_trigger
end
local client_exists = vim.iter(clients_for_trigger):any(function(c)
return c.id == client_id
@@ -693,63 +691,38 @@ end
--- Trigger LSP completion in the current buffer.
function M.trigger()
- reset_timer()
- Context:cancel_pending()
-
- local win = api.nvim_get_current_win()
local bufnr = api.nvim_get_current_buf()
- local cursor_row, cursor_col = unpack(api.nvim_win_get_cursor(win)) --- @type integer, integer
- local line = api.nvim_get_current_line()
- local line_to_cursor = line:sub(1, cursor_col)
local clients = (buf_handles[bufnr] or {}).clients or {}
- local word_boundary = vim.fn.match(line_to_cursor, '\\k*$')
- local start_time = vim.uv.hrtime()
- Context.last_request_time = start_time
-
- local cancel_request = request(clients, bufnr, win, function(responses)
- local end_time = vim.uv.hrtime()
- rtt_ms = compute_new_average((end_time - start_time) * ns_to_ms)
-
- Context.pending_requests = {}
- Context.isIncomplete = false
-
- local row_changed = api.nvim_win_get_cursor(win)[1] ~= cursor_row
- local mode = api.nvim_get_mode().mode
- if row_changed or not (mode == 'i' or mode == 'ic') then
- return
- end
+ trigger(bufnr, clients)
+end
- local matches = {}
- local server_start_boundary --- @type integer?
- for client_id, response in pairs(responses) do
- if response.err then
- vim.notify_once(response.err.message, vim.log.levels.warn)
- end
+--- Implements 'omnifunc' compatible LSP completion.
+---
+--- @see |complete-functions|
+--- @see |complete-items|
+--- @see |CompleteDone|
+---
+--- @param findstart integer 0 or 1, decides behavior
+--- @param base integer findstart=0, text to match against
+---
+--- @return integer|table Decided by {findstart}:
+--- - findstart=0: column where the completion starts, or -2 or -3
+--- - findstart=1: list of matches (actually just calls |complete()|)
+function M._omnifunc(findstart, base)
+ vim.lsp.log.debug('omnifunc.findstart', { findstart = findstart, base = base })
+ assert(base) -- silence luals
+ local bufnr = api.nvim_get_current_buf()
+ local clients = lsp.get_clients({ bufnr = bufnr, method = ms.textDocument_completion })
+ local remaining = #clients
+ if remaining == 0 then
+ return findstart == 1 and -1 or {}
+ end
- local result = response.result
- if result then
- Context.isIncomplete = Context.isIncomplete or result.isIncomplete
- local client = lsp.get_client_by_id(client_id)
- local encoding = client and client.offset_encoding or 'utf-16'
- local client_matches
- client_matches, server_start_boundary = M._convert_results(
- line,
- cursor_row - 1,
- cursor_col,
- client_id,
- word_boundary,
- nil,
- result,
- encoding
- )
- vim.list_extend(matches, client_matches)
- end
- end
- local start_col = (server_start_boundary or word_boundary) + 1
- vim.fn.complete(start_col, matches)
- end)
+ trigger(bufnr, clients)
- table.insert(Context.pending_requests, cancel_request)
+ -- Return -2 to signal that we should continue completion so that we can
+ -- async complete.
+ return -2
end
return M
diff --git a/runtime/lua/vim/lsp/handlers.lua b/runtime/lua/vim/lsp/handlers.lua
index 38c43893eb..44548fec92 100644
--- a/runtime/lua/vim/lsp/handlers.lua
+++ b/runtime/lua/vim/lsp/handlers.lua
@@ -646,6 +646,7 @@ M[ms.window_showMessage] = function(_, result, ctx, _)
if message_type == protocol.MessageType.Error then
err_message('LSP[', client_name, '] ', message)
else
+ --- @type string
local message_type_name = protocol.MessageType[message_type]
api.nvim_out_write(string.format('LSP[%s][%s] %s\n', client_name, message_type_name, message))
end
diff --git a/runtime/lua/vim/lsp/inlay_hint.lua b/runtime/lua/vim/lsp/inlay_hint.lua
index 78f309abf7..2d784816cb 100644
--- a/runtime/lua/vim/lsp/inlay_hint.lua
+++ b/runtime/lua/vim/lsp/inlay_hint.lua
@@ -43,7 +43,7 @@ function M.on_inlayhint(err, result, ctx, _)
return
end
local bufnr = assert(ctx.bufnr)
- if vim.b[bufnr].changedtick ~= ctx.version then
+ if util.buf_versions[bufnr] ~= ctx.version then
return
end
local client_id = ctx.client_id
@@ -324,7 +324,7 @@ api.nvim_set_decoration_provider(namespace, {
return
end
- if bufstate.version ~= vim.b[bufnr].changedtick then
+ if bufstate.version ~= util.buf_versions[bufnr] then
return
end
@@ -348,7 +348,7 @@ api.nvim_set_decoration_provider(namespace, {
text = text .. part.value
end
end
- local vt = {} --- @type {[1]: string, [2]: string?}[]
+ local vt = {} --- @type [string, string?][]
if hint.paddingLeft then
vt[#vt + 1] = { ' ' }
end
diff --git a/runtime/lua/vim/lsp/log.lua b/runtime/lua/vim/lsp/log.lua
index 9f2bd71158..0438ca84af 100644
--- a/runtime/lua/vim/lsp/log.lua
+++ b/runtime/lua/vim/lsp/log.lua
@@ -9,7 +9,7 @@ local log_levels = vim.log.levels
--- Can be used to lookup the number from the name or the name from the number.
--- Levels by name: "TRACE", "DEBUG", "INFO", "WARN", "ERROR", "OFF"
--- Level numbers begin with "TRACE" at 0
---- @type table<string|integer, string|integer>
+--- @type table<string,integer> | table<integer, string>
--- @nodoc
log.levels = vim.deepcopy(log_levels)
diff --git a/runtime/lua/vim/lsp/protocol.lua b/runtime/lua/vim/lsp/protocol.lua
index 8ac4cc794b..eb18043843 100644
--- a/runtime/lua/vim/lsp/protocol.lua
+++ b/runtime/lua/vim/lsp/protocol.lua
@@ -12,9 +12,6 @@ end
local sysname = vim.uv.os_uname().sysname
--- Protocol for the Microsoft Language Server Protocol (mslsp)
-local protocol = {}
-
local constants = {
--- @enum lsp.DiagnosticSeverity
DiagnosticSeverity = {
@@ -46,6 +43,8 @@ local constants = {
Info = 3,
-- A log message.
Log = 4,
+ -- A debug message.
+ Debug = 5,
},
-- The file event type.
@@ -308,326 +307,18 @@ local constants = {
},
}
-for k1, v1 in pairs(constants) do
- local tbl = vim.deepcopy(v1, true)
- for _, k2 in ipairs(vim.tbl_keys(tbl)) do
- local v2 = tbl[k2]
- tbl[v2] = k2
+-- Protocol for the Microsoft Language Server Protocol (mslsp)
+local protocol = {}
+
+--- @diagnostic disable:no-unknown
+for k1, v1 in pairs(vim.deepcopy(constants, true)) do
+ for _, k2 in ipairs(vim.tbl_keys(v1)) do
+ local v2 = v1[k2]
+ v1[v2] = k2
end
- protocol[k1] = tbl
+ protocol[k1] = v1
end
-
---[=[
---Text document specific client capabilities.
-export interface TextDocumentClientCapabilities {
- synchronization?: {
- --Whether text document synchronization supports dynamic registration.
- dynamicRegistration?: boolean;
- --The client supports sending will save notifications.
- willSave?: boolean;
- --The client supports sending a will save request and
- --waits for a response providing text edits which will
- --be applied to the document before it is saved.
- willSaveWaitUntil?: boolean;
- --The client supports did save notifications.
- didSave?: boolean;
- }
- --Capabilities specific to the `textDocument/completion`
- completion?: {
- --Whether completion supports dynamic registration.
- dynamicRegistration?: boolean;
- --The client supports the following `CompletionItem` specific
- --capabilities.
- completionItem?: {
- --The client supports snippets as insert text.
- --
- --A snippet can define tab stops and placeholders with `$1`, `$2`
- --and `${3:foo}`. `$0` defines the final tab stop, it defaults to
- --the end of the snippet. Placeholders with equal identifiers are linked,
- --that is typing in one will update others too.
- snippetSupport?: boolean;
- --The client supports commit characters on a completion item.
- commitCharactersSupport?: boolean
- --The client supports the following content formats for the documentation
- --property. The order describes the preferred format of the client.
- documentationFormat?: MarkupKind[];
- --The client supports the deprecated property on a completion item.
- deprecatedSupport?: boolean;
- --The client supports the preselect property on a completion item.
- preselectSupport?: boolean;
- }
- completionItemKind?: {
- --The completion item kind values the client supports. When this
- --property exists the client also guarantees that it will
- --handle values outside its set gracefully and falls back
- --to a default value when unknown.
- --
- --If this property is not present the client only supports
- --the completion items kinds from `Text` to `Reference` as defined in
- --the initial version of the protocol.
- valueSet?: CompletionItemKind[];
- },
- --The client supports to send additional context information for a
- --`textDocument/completion` request.
- contextSupport?: boolean;
- };
- --Capabilities specific to the `textDocument/hover`
- hover?: {
- --Whether hover supports dynamic registration.
- dynamicRegistration?: boolean;
- --The client supports the follow content formats for the content
- --property. The order describes the preferred format of the client.
- contentFormat?: MarkupKind[];
- };
- --Capabilities specific to the `textDocument/signatureHelp`
- signatureHelp?: {
- --Whether signature help supports dynamic registration.
- dynamicRegistration?: boolean;
- --The client supports the following `SignatureInformation`
- --specific properties.
- signatureInformation?: {
- --The client supports the follow content formats for the documentation
- --property. The order describes the preferred format of the client.
- documentationFormat?: MarkupKind[];
- --Client capabilities specific to parameter information.
- parameterInformation?: {
- --The client supports processing label offsets instead of a
- --simple label string.
- --
- --Since 3.14.0
- labelOffsetSupport?: boolean;
- }
- };
- };
- --Capabilities specific to the `textDocument/references`
- references?: {
- --Whether references supports dynamic registration.
- dynamicRegistration?: boolean;
- };
- --Capabilities specific to the `textDocument/documentHighlight`
- documentHighlight?: {
- --Whether document highlight supports dynamic registration.
- dynamicRegistration?: boolean;
- };
- --Capabilities specific to the `textDocument/documentSymbol`
- documentSymbol?: {
- --Whether document symbol supports dynamic registration.
- dynamicRegistration?: boolean;
- --Specific capabilities for the `SymbolKind`.
- symbolKind?: {
- --The symbol kind values the client supports. When this
- --property exists the client also guarantees that it will
- --handle values outside its set gracefully and falls back
- --to a default value when unknown.
- --
- --If this property is not present the client only supports
- --the symbol kinds from `File` to `Array` as defined in
- --the initial version of the protocol.
- valueSet?: SymbolKind[];
- }
- --The client supports hierarchical document symbols.
- hierarchicalDocumentSymbolSupport?: boolean;
- };
- --Capabilities specific to the `textDocument/formatting`
- formatting?: {
- --Whether formatting supports dynamic registration.
- dynamicRegistration?: boolean;
- };
- --Capabilities specific to the `textDocument/rangeFormatting`
- rangeFormatting?: {
- --Whether range formatting supports dynamic registration.
- dynamicRegistration?: boolean;
- };
- --Capabilities specific to the `textDocument/onTypeFormatting`
- onTypeFormatting?: {
- --Whether on type formatting supports dynamic registration.
- dynamicRegistration?: boolean;
- };
- --Capabilities specific to the `textDocument/declaration`
- declaration?: {
- --Whether declaration supports dynamic registration. If this is set to `true`
- --the client supports the new `(TextDocumentRegistrationOptions & StaticRegistrationOptions)`
- --return value for the corresponding server capability as well.
- dynamicRegistration?: boolean;
- --The client supports additional metadata in the form of declaration links.
- --
- --Since 3.14.0
- linkSupport?: boolean;
- };
- --Capabilities specific to the `textDocument/definition`.
- --
- --Since 3.14.0
- definition?: {
- --Whether definition supports dynamic registration.
- dynamicRegistration?: boolean;
- --The client supports additional metadata in the form of definition links.
- linkSupport?: boolean;
- };
- --Capabilities specific to the `textDocument/typeDefinition`
- --
- --Since 3.6.0
- typeDefinition?: {
- --Whether typeDefinition supports dynamic registration. If this is set to `true`
- --the client supports the new `(TextDocumentRegistrationOptions & StaticRegistrationOptions)`
- --return value for the corresponding server capability as well.
- dynamicRegistration?: boolean;
- --The client supports additional metadata in the form of definition links.
- --
- --Since 3.14.0
- linkSupport?: boolean;
- };
- --Capabilities specific to the `textDocument/implementation`.
- --
- --Since 3.6.0
- implementation?: {
- --Whether implementation supports dynamic registration. If this is set to `true`
- --the client supports the new `(TextDocumentRegistrationOptions & StaticRegistrationOptions)`
- --return value for the corresponding server capability as well.
- dynamicRegistration?: boolean;
- --The client supports additional metadata in the form of definition links.
- --
- --Since 3.14.0
- linkSupport?: boolean;
- };
- --Capabilities specific to the `textDocument/codeAction`
- codeAction?: {
- --Whether code action supports dynamic registration.
- dynamicRegistration?: boolean;
- --The client support code action literals as a valid
- --response of the `textDocument/codeAction` request.
- --
- --Since 3.8.0
- codeActionLiteralSupport?: {
- --The code action kind is support with the following value
- --set.
- codeActionKind: {
- --The code action kind values the client supports. When this
- --property exists the client also guarantees that it will
- --handle values outside its set gracefully and falls back
- --to a default value when unknown.
- valueSet: CodeActionKind[];
- };
- };
- };
- --Capabilities specific to the `textDocument/codeLens`
- codeLens?: {
- --Whether code lens supports dynamic registration.
- dynamicRegistration?: boolean;
- };
- --Capabilities specific to the `textDocument/documentLink`
- documentLink?: {
- --Whether document link supports dynamic registration.
- dynamicRegistration?: boolean;
- };
- --Capabilities specific to the `textDocument/documentColor` and the
- --`textDocument/colorPresentation` request.
- --
- --Since 3.6.0
- colorProvider?: {
- --Whether colorProvider supports dynamic registration. If this is set to `true`
- --the client supports the new `(ColorProviderOptions & TextDocumentRegistrationOptions & StaticRegistrationOptions)`
- --return value for the corresponding server capability as well.
- dynamicRegistration?: boolean;
- }
- --Capabilities specific to the `textDocument/rename`
- rename?: {
- --Whether rename supports dynamic registration.
- dynamicRegistration?: boolean;
- --The client supports testing for validity of rename operations
- --before execution.
- prepareSupport?: boolean;
- };
- --Capabilities specific to `textDocument/publishDiagnostics`.
- publishDiagnostics?: {
- --Whether the clients accepts diagnostics with related information.
- relatedInformation?: boolean;
- --Client supports the tag property to provide meta data about a diagnostic.
- --Clients supporting tags have to handle unknown tags gracefully.
- --Since 3.15.0
- tagSupport?: {
- --The tags supported by this client
- valueSet: DiagnosticTag[];
- };
- };
- --Capabilities specific to `textDocument/foldingRange` requests.
- --
- --Since 3.10.0
- foldingRange?: {
- --Whether implementation supports dynamic registration for folding range providers. If this is set to `true`
- --the client supports the new `(FoldingRangeProviderOptions & TextDocumentRegistrationOptions & StaticRegistrationOptions)`
- --return value for the corresponding server capability as well.
- dynamicRegistration?: boolean;
- --The maximum number of folding ranges that the client prefers to receive per document. The value serves as a
- --hint, servers are free to follow the limit.
- rangeLimit?: number;
- --If set, the client signals that it only supports folding complete lines. If set, client will
- --ignore specified `startCharacter` and `endCharacter` properties in a FoldingRange.
- lineFoldingOnly?: boolean;
- };
-}
---]=]
-
---[=[
---Workspace specific client capabilities.
-export interface WorkspaceClientCapabilities {
- --The client supports applying batch edits to the workspace by supporting
- --the request 'workspace/applyEdit'
- applyEdit?: boolean;
- --Capabilities specific to `WorkspaceEdit`s
- workspaceEdit?: {
- --The client supports versioned document changes in `WorkspaceEdit`s
- documentChanges?: boolean;
- --The resource operations the client supports. Clients should at least
- --support 'create', 'rename' and 'delete' files and folders.
- resourceOperations?: ResourceOperationKind[];
- --The failure handling strategy of a client if applying the workspace edit
- --fails.
- failureHandling?: FailureHandlingKind;
- };
- --Capabilities specific to the `workspace/didChangeConfiguration` notification.
- didChangeConfiguration?: {
- --Did change configuration notification supports dynamic registration.
- dynamicRegistration?: boolean;
- };
- --Capabilities specific to the `workspace/didChangeWatchedFiles` notification.
- didChangeWatchedFiles?: {
- --Did change watched files notification supports dynamic registration. Please note
- --that the current protocol doesn't support static configuration for file changes
- --from the server side.
- dynamicRegistration?: boolean;
- };
- --Capabilities specific to the `workspace/symbol` request.
- symbol?: {
- --Symbol request supports dynamic registration.
- dynamicRegistration?: boolean;
- --Specific capabilities for the `SymbolKind` in the `workspace/symbol` request.
- symbolKind?: {
- --The symbol kind values the client supports. When this
- --property exists the client also guarantees that it will
- --handle values outside its set gracefully and falls back
- --to a default value when unknown.
- --
- --If this property is not present the client only supports
- --the symbol kinds from `File` to `Array` as defined in
- --the initial version of the protocol.
- valueSet?: SymbolKind[];
- }
- };
- --Capabilities specific to the `workspace/executeCommand` request.
- executeCommand?: {
- --Execute command supports dynamic registration.
- dynamicRegistration?: boolean;
- };
- --The client has support for workspace folders.
- --
- --Since 3.6.0
- workspaceFolders?: boolean;
- --The client supports `workspace/configuration` requests.
- --
- --Since 3.6.0
- configuration?: boolean;
-}
---]=]
+--- @diagnostic enable:no-unknown
--- Gets a new ClientCapabilities object describing the LSP client
--- capabilities.
@@ -1250,14 +941,5 @@ protocol.Methods = {
--- The `workspace/workspaceFolders` is sent from the server to the client to fetch the open workspace folders.
workspace_workspaceFolders = 'workspace/workspaceFolders',
}
-local function freeze(t)
- return setmetatable({}, {
- __index = t,
- __newindex = function()
- error('cannot modify immutable table')
- end,
- })
-end
-protocol.Methods = freeze(protocol.Methods)
return protocol
diff --git a/runtime/lua/vim/lsp/rpc.lua b/runtime/lua/vim/lsp/rpc.lua
index 3c63a12da2..5e2b041a0a 100644
--- a/runtime/lua/vim/lsp/rpc.lua
+++ b/runtime/lua/vim/lsp/rpc.lua
@@ -140,7 +140,7 @@ local client_errors = {
SERVER_RESULT_CALLBACK_ERROR = 7,
}
---- @type table<string|integer, string|integer>
+--- @type table<string,integer> | table<integer,string>
--- @nodoc
M.client_errors = vim.deepcopy(client_errors)
for k, v in pairs(client_errors) do
@@ -502,7 +502,7 @@ function Client:handle_body(body)
if decoded.error then
decoded.error = setmetatable(decoded.error, {
__tostring = M.format_rpc_error,
- }) --- @type table
+ })
end
self:try_call(
M.client_errors.SERVER_RESULT_CALLBACK_ERROR,
diff --git a/runtime/lua/vim/lsp/semantic_tokens.lua b/runtime/lua/vim/lsp/semantic_tokens.lua
index 278014a4ea..f92c0eb2e6 100644
--- a/runtime/lua/vim/lsp/semantic_tokens.lua
+++ b/runtime/lua/vim/lsp/semantic_tokens.lua
@@ -116,7 +116,7 @@ local function tokens_to_ranges(data, bufnr, client, request)
if elapsed_ns > yield_interval_ns then
vim.schedule(function()
- coroutine.resume(co, vim.b[bufnr].changedtick)
+ coroutine.resume(co, util.buf_versions[bufnr])
end)
if request.version ~= coroutine.yield() then
-- request became stale since the last time the coroutine ran.
@@ -197,12 +197,6 @@ function STHighlighter.new(bufnr)
highlighter:send_request()
end
end,
- on_detach = function(_, buf)
- local highlighter = STHighlighter.active[buf]
- if highlighter then
- highlighter:destroy()
- end
- end,
})
api.nvim_create_autocmd({ 'BufWinEnter', 'InsertLeave' }, {
@@ -275,7 +269,7 @@ end
---
---@package
function STHighlighter:send_request()
- local version = vim.b[self.bufnr].changedtick
+ local version = util.buf_versions[self.bufnr]
self:reset_timer()
@@ -418,7 +412,7 @@ end
function STHighlighter:on_win(topline, botline)
for client_id, state in pairs(self.client_state) do
local current_result = state.current_result
- if current_result.version and current_result.version == vim.b[self.bufnr].changedtick then
+ if current_result.version and current_result.version == util.buf_versions[self.bufnr] then
if not current_result.namespace_cleared then
api.nvim_buf_clear_namespace(self.bufnr, state.namespace, 0, -1)
current_result.namespace_cleared = true
@@ -779,7 +773,6 @@ function M.highlight_token(token, bufnr, client_id, hl_group, opts)
})
end
---- @package
--- |lsp-handler| for the method `workspace/semanticTokens/refresh`
---
--- Refresh requests are sent by the server to indicate a project-wide change
diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua
index d1f0e97065..ae6de591b3 100644
--- a/runtime/lua/vim/lsp/util.lua
+++ b/runtime/lua/vim/lsp/util.lua
@@ -173,11 +173,11 @@ local _str_byteindex_enc = M._str_byteindex_enc
--- CAUTION: Changes in-place!
---
---@deprecated
----@param lines (table) Original list of strings
----@param A (table) Start position; a 2-tuple of {line,col} numbers
----@param B (table) End position; a 2-tuple of {line,col} numbers
----@param new_lines (table) list of strings to replace the original
----@return table The modified {lines} object
+---@param lines string[] Original list of strings
+---@param A [integer, integer] Start position; a 2-tuple of {line,col} numbers
+---@param B [integer, integer] End position; a 2-tuple {line,col} numbers
+---@param new_lines string[] list of strings to replace the original
+---@return string[] The modified {lines} object
function M.set_lines(lines, A, B, new_lines)
vim.deprecate('vim.lsp.util.set_lines()', 'nil', '0.12')
-- 0-indexing to 1-indexing
@@ -238,6 +238,7 @@ end
---@param rows integer[] zero-indexed line numbers
---@return table<integer, string>|string a table mapping rows to lines
local function get_lines(bufnr, rows)
+ --- @type integer[]
rows = type(rows) == 'table' and rows or { rows }
-- This is needed for bufload and bufloaded
@@ -246,7 +247,7 @@ local function get_lines(bufnr, rows)
end
local function buf_lines()
- local lines = {}
+ local lines = {} --- @type table<integer,string>
for _, row in ipairs(rows) do
lines[row] = (api.nvim_buf_get_lines(bufnr, row, row + 1, false) or { '' })[1]
end
@@ -274,11 +275,11 @@ local function get_lines(bufnr, rows)
if not fd then
return ''
end
- local stat = uv.fs_fstat(fd)
- local data = uv.fs_read(fd, stat.size, 0)
+ local stat = assert(uv.fs_fstat(fd))
+ local data = assert(uv.fs_read(fd, stat.size, 0))
uv.fs_close(fd)
- local lines = {} -- rows we need to retrieve
+ local lines = {} --- @type table<integer,true|string> rows we need to retrieve
local need = 0 -- keep track of how many unique rows we need
for _, row in pairs(rows) do
if not lines[row] then
@@ -307,7 +308,7 @@ local function get_lines(bufnr, rows)
lines[i] = ''
end
end
- return lines
+ return lines --[[@as table<integer,string>]]
end
--- Gets the zero-indexed line from the given buffer.
@@ -322,7 +323,8 @@ local function get_line(bufnr, row)
end
--- Position is a https://microsoft.github.io/language-server-protocol/specifications/specification-current/#position
----@param offset_encoding string|nil utf-8|utf-16|utf-32
+---@param position lsp.Position
+---@param offset_encoding? string utf-8|utf-16|utf-32
---@return integer
local function get_line_byte_from_position(bufnr, position, offset_encoding)
-- LSP's line and characters are 0-indexed
@@ -343,7 +345,7 @@ local function get_line_byte_from_position(bufnr, position, offset_encoding)
end
--- Applies a list of text edits to a buffer.
----@param text_edits table list of `TextEdit` objects
+---@param text_edits lsp.TextEdit[]
---@param bufnr integer Buffer id
---@param offset_encoding string utf-8|utf-16|utf-32
---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textEdit
@@ -366,6 +368,7 @@ function M.apply_text_edits(text_edits, bufnr, offset_encoding)
-- Fix reversed range and indexing each text_edits
local index = 0
+ --- @param text_edit lsp.TextEdit
text_edits = vim.tbl_map(function(text_edit)
index = index + 1
text_edit._index = index
@@ -383,6 +386,9 @@ function M.apply_text_edits(text_edits, bufnr, offset_encoding)
end, text_edits)
-- Sort text_edits
+ ---@param a lsp.TextEdit | { _index: integer }
+ ---@param b lsp.TextEdit | { _index: integer }
+ ---@return boolean
table.sort(text_edits, function(a, b)
if a.range.start.line ~= b.range.start.line then
return a.range.start.line > b.range.start.line
@@ -391,12 +397,13 @@ function M.apply_text_edits(text_edits, bufnr, offset_encoding)
return a.range.start.character > b.range.start.character
end
if a._index ~= b._index then
- return a._index > b._index
+ return a._index < b._index
end
+ return false
end)
-- save and restore local marks since they get deleted by nvim_buf_set_lines
- local marks = {}
+ local marks = {} --- @type table<string,[integer,integer]>
for _, m in pairs(vim.fn.getmarklist(bufnr)) do
if m.mark:match("^'[a-z]$") then
marks[m.mark:sub(2, 2)] = { m.pos[2], m.pos[3] - 1 } -- api-indexed
@@ -481,8 +488,8 @@ end
--- Applies a `TextDocumentEdit`, which is a list of changes to a single
--- document.
---
----@param text_document_edit table: a `TextDocumentEdit` object
----@param index integer: Optional index of the edit, if from a list of edits (or nil, if not from a list)
+---@param text_document_edit lsp.TextDocumentEdit
+---@param index? integer: Optional index of the edit, if from a list of edits (or nil, if not from a list)
---@param offset_encoding? string
---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocumentEdit
function M.apply_text_document_edit(text_document_edit, index, offset_encoding)
@@ -509,7 +516,8 @@ function M.apply_text_document_edit(text_document_edit, index, offset_encoding)
and (
text_document.version
and text_document.version > 0
- and vim.b[bufnr].changedtick > text_document.version
+ and M.buf_versions[bufnr]
+ and M.buf_versions[bufnr] > text_document.version
)
then
print('Buffer ', text_document.uri, ' newer than edits.')
@@ -533,6 +541,7 @@ local function path_under_prefix(path, prefix)
end
--- Get list of buffers whose filename matches the given path prefix (normalized full path)
+---@param prefix string
---@return integer[]
local function get_bufs_with_prefix(prefix)
prefix = path_components(prefix)
@@ -677,7 +686,7 @@ end
--- Applies a `WorkspaceEdit`.
---
----@param workspace_edit table `WorkspaceEdit`
+---@param workspace_edit lsp.WorkspaceEdit
---@param offset_encoding string utf-8|utf-16|utf-32 (required)
---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#workspace_applyEdit
function M.apply_workspace_edit(workspace_edit, offset_encoding)
@@ -723,8 +732,8 @@ end
--- Note that if the input is of type `MarkupContent` and its kind is `plaintext`,
--- then the corresponding value is returned without further modifications.
---
----@param input (lsp.MarkedString | lsp.MarkedString[] | lsp.MarkupContent)
----@param contents (table|nil) List of strings to extend with converted lines. Defaults to {}.
+---@param input lsp.MarkedString|lsp.MarkedString[]|lsp.MarkupContent
+---@param contents string[]|nil List of strings to extend with converted lines. Defaults to {}.
---@return string[] extended with lines of converted markdown.
---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_hover
function M.convert_input_to_markdown_lines(input, contents)
@@ -759,11 +768,11 @@ end
--- Converts `textDocument/signatureHelp` response to markdown lines.
---
----@param signature_help table Response of `textDocument/SignatureHelp`
+---@param signature_help lsp.SignatureHelp Response of `textDocument/SignatureHelp`
---@param ft string|nil filetype that will be use as the `lang` for the label markdown code block
---@param triggers table|nil list of trigger characters from the lsp server. used to better determine parameter offsets
----@return table|nil table list of lines of converted markdown.
----@return table|nil table of active hl
+---@return string[]|nil table list of lines of converted markdown.
+---@return number[]|nil table of active hl
---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_signatureHelp
function M.convert_signature_help_to_markdown_lines(signature_help, ft, triggers)
if not signature_help.signatures then
@@ -960,7 +969,7 @@ end
--- Shows document and optionally jumps to the location.
---
----@param location table (`Location`|`LocationLink`)
+---@param location lsp.Location|lsp.LocationLink
---@param offset_encoding string|nil utf-8|utf-16|utf-32
---@param opts table|nil options
--- - reuse_win (boolean) Jump to existing window if buffer is already open.
@@ -1017,7 +1026,7 @@ end
--- Jumps to a location.
---
----@param location table (`Location`|`LocationLink`)
+---@param location lsp.Location|lsp.LocationLink
---@param offset_encoding string|nil utf-8|utf-16|utf-32
---@param reuse_win boolean|nil Jump to existing window if buffer is already open.
---@return boolean `true` if the jump succeeded
@@ -1038,7 +1047,7 @@ end
--- - for Location, range is shown (e.g., function definition)
--- - for LocationLink, targetRange is shown (e.g., body of function definition)
---
----@param location table a single `Location` or `LocationLink`
+---@param location lsp.Location|lsp.LocationLink
---@param opts table
---@return integer|nil buffer id of float window
---@return integer|nil window id of float window
@@ -1154,7 +1163,7 @@ end
--- If you want to open a popup with fancy markdown, use `open_floating_preview` instead
---
---@param bufnr integer
----@param contents table of lines to show in window
+---@param contents string[] of lines to show in window
---@param opts table with optional fields
--- - height of floating window
--- - width of floating window
@@ -1669,7 +1678,7 @@ do --[[ References ]]
--- Shows a list of document highlights for a certain buffer.
---
---@param bufnr integer Buffer id
- ---@param references table List of `DocumentHighlight` objects to highlight
+ ---@param references lsp.DocumentHighlight[] objects to highlight
---@param offset_encoding string One of "utf-8", "utf-16", "utf-32".
---@see https://microsoft.github.io/language-server-protocol/specification/#textDocumentContentChangeEvent
function M.buf_highlight_references(bufnr, references, offset_encoding)
@@ -1720,7 +1729,9 @@ end)
---@inlinedoc
---@field filename string
---@field lnum integer 1-indexed line number
+---@field end_lnum integer 1-indexed end line number
---@field col integer 1-indexed column
+---@field end_col integer 1-indexed end column
---@field text string
---@field user_data lsp.Location|lsp.LocationLink
@@ -1747,7 +1758,7 @@ function M.locations_to_items(locations, offset_encoding)
end
local items = {}
- ---@type table<string, {start: lsp.Position, location: lsp.Location|lsp.LocationLink}[]>
+ ---@type table<string, {start: lsp.Position, end: lsp.Position, location: lsp.Location|lsp.LocationLink}[]>
local grouped = setmetatable({}, {
__index = function(t, k)
local v = {}
@@ -1759,7 +1770,7 @@ function M.locations_to_items(locations, offset_encoding)
-- locations may be Location or LocationLink
local uri = d.uri or d.targetUri
local range = d.range or d.targetSelectionRange
- table.insert(grouped[uri], { start = range.start, location = d })
+ table.insert(grouped[uri], { start = range.start, ['end'] = range['end'], location = d })
end
---@type string[]
@@ -1774,6 +1785,9 @@ function M.locations_to_items(locations, offset_encoding)
local line_numbers = {}
for _, temp in ipairs(rows) do
table.insert(line_numbers, temp.start.line)
+ if temp.start.line ~= temp['end'].line then
+ table.insert(line_numbers, temp['end'].line)
+ end
end
-- get all the lines for this uri
@@ -1781,13 +1795,18 @@ function M.locations_to_items(locations, offset_encoding)
for _, temp in ipairs(rows) do
local pos = temp.start
+ local end_pos = temp['end']
local row = pos.line
+ local end_row = end_pos.line
local line = lines[row] or ''
local col = M._str_byteindex_enc(line, pos.character, offset_encoding)
+ local end_col = M._str_byteindex_enc(lines[end_row] or '', end_pos.character, offset_encoding)
table.insert(items, {
filename = filename,
lnum = row + 1,
+ end_lnum = end_row + 1,
col = col + 1,
+ end_col = end_col + 1,
text = line,
user_data = temp.location,
})
@@ -1873,7 +1892,7 @@ end
--- CAUTION: Modifies the input in-place!
---
---@deprecated
----@param lines table list of lines
+---@param lines string[] list of lines
---@return string filetype or "markdown" if it was unchanged.
function M.try_trim_markdown_code_blocks(lines)
vim.deprecate('vim.lsp.util.try_trim_markdown_code_blocks()', 'nil', '0.12')
@@ -1898,7 +1917,7 @@ function M.try_trim_markdown_code_blocks(lines)
end
---@param window integer|nil: window handle or 0 for current, defaults to current
----@param offset_encoding string utf-8|utf-16|utf-32|nil defaults to `offset_encoding` of first client of buffer of `window`
+---@param offset_encoding? string utf-8|utf-16|utf-32|nil defaults to `offset_encoding` of first client of buffer of `window`
local function make_position_param(window, offset_encoding)
window = window or 0
local buf = api.nvim_win_get_buf(window)
@@ -1919,7 +1938,7 @@ end
---
---@param window integer|nil: window handle or 0 for current, defaults to current
---@param offset_encoding string|nil utf-8|utf-16|utf-32|nil defaults to `offset_encoding` of first client of buffer of `window`
----@return table `TextDocumentPositionParams` object
+---@return lsp.TextDocumentPositionParams
---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocumentPositionParams
function M.make_position_params(window, offset_encoding)
window = window or 0
@@ -1932,7 +1951,7 @@ function M.make_position_params(window, offset_encoding)
end
--- Utility function for getting the encoding of the first LSP client on the given buffer.
----@param bufnr (integer) buffer handle or 0 for current, defaults to current
+---@param bufnr integer buffer handle or 0 for current, defaults to current
---@return string encoding first client if there is one, nil otherwise
function M._get_offset_encoding(bufnr)
validate({
@@ -2033,15 +2052,16 @@ end
--- Creates a `TextDocumentIdentifier` object for the current buffer.
---
---@param bufnr integer|nil: Buffer handle, defaults to current
----@return table `TextDocumentIdentifier`
+---@return lsp.TextDocumentIdentifier
---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocumentIdentifier
function M.make_text_document_params(bufnr)
return { uri = vim.uri_from_bufnr(bufnr or 0) }
end
--- Create the workspace params
----@param added table
----@param removed table
+---@param added lsp.WorkspaceFolder[]
+---@param removed lsp.WorkspaceFolder[]
+---@return lsp.WorkspaceFoldersChangeEvent
function M.make_workspace_params(added, removed)
return { event = { added = added, removed = removed } }
end
@@ -2049,8 +2069,8 @@ end
--- Returns indentation size.
---
---@see 'shiftwidth'
----@param bufnr (integer|nil): Buffer handle, defaults to current
----@return (integer) indentation size
+---@param bufnr integer|nil: Buffer handle, defaults to current
+---@return integer indentation size
function M.get_effective_tabstop(bufnr)
validate({ bufnr = { bufnr, 'n', true } })
local bo = bufnr and vim.bo[bufnr] or vim.bo
@@ -2060,7 +2080,7 @@ end
--- Creates a `DocumentFormattingParams` object for the current buffer and cursor position.
---
----@param options table|nil with valid `FormattingOptions` entries
+---@param options lsp.FormattingOptions|nil with valid `FormattingOptions` entries
---@return lsp.DocumentFormattingParams object
---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_formatting
function M.make_formatting_params(options)
@@ -2199,16 +2219,9 @@ function M._refresh(method, opts)
end
end
----@nodoc
----@deprecated
----@type table<integer,integer>
-M.buf_versions = setmetatable({}, {
- __index = function(_, bufnr)
- vim.deprecate('vim.lsp.util.buf_versions', 'vim.b.changedtick', '0.13')
- return vim.b[bufnr].changedtick
- end,
-})
-
M._get_line_byte_from_position = get_line_byte_from_position
+---@nodoc
+M.buf_versions = {} ---@type table<integer,integer>
+
return M
diff --git a/runtime/lua/vim/provider/health.lua b/runtime/lua/vim/provider/health.lua
index fa2c452268..860f839f23 100644
--- a/runtime/lua/vim/provider/health.lua
+++ b/runtime/lua/vim/provider/health.lua
@@ -353,7 +353,7 @@ end
--- their respective paths. If either of those is invalid, return two empty
--- strings, effectively ignoring pyenv.
---
---- @return {[1]: string, [2]: string}
+--- @return [string, string]
local function check_for_pyenv()
local pyenv_path = vim.fn.resolve(vim.fn.exepath('pyenv'))
diff --git a/runtime/lua/vim/shared.lua b/runtime/lua/vim/shared.lua
index 0ec79e1dc7..7fd29d5f7b 100644
--- a/runtime/lua/vim/shared.lua
+++ b/runtime/lua/vim/shared.lua
@@ -789,7 +789,7 @@ do
}
--- @nodoc
- --- @class vim.validate.Spec {[1]: any, [2]: string|string[], [3]: boolean }
+ --- @class vim.validate.Spec [any, string|string[], boolean]
--- @field [1] any Argument value
--- @field [2] string|string[]|fun(v:any):boolean, string? Type name, or callable
--- @field [3]? boolean
@@ -1139,4 +1139,82 @@ function vim._defer_require(root, mod)
})
end
+--- @nodoc
+--- @class vim.context.mods
+--- @field buf? integer
+--- @field emsg_silent? boolean
+--- @field hide? boolean
+--- @field horizontal? boolean
+--- @field keepalt? boolean
+--- @field keepjumps? boolean
+--- @field keepmarks? boolean
+--- @field keeppatterns? boolean
+--- @field lockmarks? boolean
+--- @field noautocmd? boolean
+--- @field options? table<string, any>
+--- @field sandbox? boolean
+--- @field silent? boolean
+--- @field unsilent? boolean
+--- @field win? integer
+
+--- Executes function `f` with the given context specification.
+---
+--- @param context vim.context.mods
+function vim._with(context, f)
+ vim.validate('context', context, 'table')
+ vim.validate('f', f, 'function')
+
+ vim.validate('context.buf', context.buf, 'number', true)
+ vim.validate('context.emsg_silent', context.emsg_silent, 'boolean', true)
+ vim.validate('context.hide', context.hide, 'boolean', true)
+ vim.validate('context.horizontal', context.horizontal, 'boolean', true)
+ vim.validate('context.keepalt', context.keepalt, 'boolean', true)
+ vim.validate('context.keepjumps', context.keepjumps, 'boolean', true)
+ vim.validate('context.keepmarks', context.keepmarks, 'boolean', true)
+ vim.validate('context.keeppatterns', context.keeppatterns, 'boolean', true)
+ vim.validate('context.lockmarks', context.lockmarks, 'boolean', true)
+ vim.validate('context.noautocmd', context.noautocmd, 'boolean', true)
+ vim.validate('context.options', context.options, 'table', true)
+ vim.validate('context.sandbox', context.sandbox, 'boolean', true)
+ vim.validate('context.silent', context.silent, 'boolean', true)
+ vim.validate('context.unsilent', context.unsilent, 'boolean', true)
+ vim.validate('context.win', context.win, 'number', true)
+
+ -- Check buffer exists
+ if context.buf then
+ if not vim.api.nvim_buf_is_valid(context.buf) then
+ error('Invalid buffer id: ' .. context.buf)
+ end
+ end
+
+ -- Check window exists
+ if context.win then
+ if not vim.api.nvim_win_is_valid(context.win) then
+ error('Invalid window id: ' .. context.win)
+ end
+ end
+
+ -- Store original options
+ local previous_options ---@type table<string, any>
+ if context.options then
+ previous_options = {}
+ for k, v in pairs(context.options) do
+ previous_options[k] =
+ vim.api.nvim_get_option_value(k, { win = context.win, buf = context.buf })
+ vim.api.nvim_set_option_value(k, v, { win = context.win, buf = context.buf })
+ end
+ end
+
+ local retval = { vim._with_c(context, f) }
+
+ -- Restore original options
+ if previous_options then
+ for k, v in pairs(previous_options) do
+ vim.api.nvim_set_option_value(k, v, { win = context.win, buf = context.buf })
+ end
+ end
+
+ return unpack(retval)
+end
+
return vim
diff --git a/runtime/lua/vim/treesitter.lua b/runtime/lua/vim/treesitter.lua
index db544c1ab1..e36aacfd94 100644
--- a/runtime/lua/vim/treesitter.lua
+++ b/runtime/lua/vim/treesitter.lua
@@ -335,7 +335,7 @@ end
---
--- 0-indexed (row, col) tuple. Defaults to cursor position in the
--- current window. Required if {bufnr} is not the current buffer
---- @field pos { [1]: integer, [2]: integer }?
+--- @field pos [integer, integer]?
---
--- Parser language. (default: from buffer filetype)
--- @field lang string?
diff --git a/runtime/lua/vim/treesitter/_fold.lua b/runtime/lua/vim/treesitter/_fold.lua
index eecf1ad6b1..04a3c62cf1 100644
--- a/runtime/lua/vim/treesitter/_fold.lua
+++ b/runtime/lua/vim/treesitter/_fold.lua
@@ -383,7 +383,6 @@ local function on_bytes(bufnr, foldinfo, start_row, start_col, old_row, old_col,
end
end
----@package
---@param lnum integer|nil
---@return string
function M.foldexpr(lnum)
diff --git a/runtime/lua/vim/treesitter/_meta.lua b/runtime/lua/vim/treesitter/_meta.lua
index 177699a207..2aedf5754e 100644
--- a/runtime/lua/vim/treesitter/_meta.lua
+++ b/runtime/lua/vim/treesitter/_meta.lua
@@ -33,6 +33,7 @@ error('Cannot require a meta file')
---@field iter_children fun(self: TSNode): fun(): TSNode, string
---@field field fun(self: TSNode, name: string): TSNode[]
---@field byte_length fun(self: TSNode): integer
+---@field __has_ancestor fun(self: TSNode, node_types: string[]): boolean
local TSNode = {}
---@alias TSLoggerCallback fun(logtype: 'parse'|'lex', msg: string)
@@ -62,6 +63,7 @@ local TSNode = {}
---@field patterns table<integer, (integer|string)[][]>
--- @param lang string
+--- @return table
vim._ts_inspect_language = function(lang) end
---@return integer
diff --git a/runtime/lua/vim/treesitter/dev.lua b/runtime/lua/vim/treesitter/dev.lua
index ca8cf85eda..56608bbf14 100644
--- a/runtime/lua/vim/treesitter/dev.lua
+++ b/runtime/lua/vim/treesitter/dev.lua
@@ -174,7 +174,7 @@ end
--- @param source_buf integer
--- @param inspect_buf integer
--- @param inspect_win integer
---- @param pos? { [1]: integer, [2]: integer }
+--- @param pos? [integer, integer]
local function set_inspector_cursor(treeview, lang, source_buf, inspect_buf, inspect_win, pos)
api.nvim_buf_clear_namespace(inspect_buf, treeview.ns, 0, -1)
diff --git a/runtime/lua/vim/treesitter/highlighter.lua b/runtime/lua/vim/treesitter/highlighter.lua
index d2f986b874..003f7e0169 100644
--- a/runtime/lua/vim/treesitter/highlighter.lua
+++ b/runtime/lua/vim/treesitter/highlighter.lua
@@ -47,7 +47,7 @@ function TSHighlighterQuery:get_hl_from_capture(capture)
return self.hl_cache[capture]
end
----@package
+---@nodoc
function TSHighlighterQuery:query()
return self._query
end
@@ -75,7 +75,7 @@ local TSHighlighter = {
TSHighlighter.__index = TSHighlighter
----@package
+---@nodoc
---
--- Creates a highlighter for `tree`.
---
@@ -232,7 +232,7 @@ function TSHighlighter:on_changedtree(changes)
end
--- Gets the query used for @param lang
----@package
+---@nodoc
---@param lang string Language used by the highlighter.
---@return vim.treesitter.highlighter.Query
function TSHighlighter:get_query(lang)
diff --git a/runtime/lua/vim/treesitter/languagetree.lua b/runtime/lua/vim/treesitter/languagetree.lua
index b0812123b9..3523ea95e0 100644
--- a/runtime/lua/vim/treesitter/languagetree.lua
+++ b/runtime/lua/vim/treesitter/languagetree.lua
@@ -98,9 +98,9 @@ local LanguageTree = {}
LanguageTree.__index = LanguageTree
---- @package
+--- @nodoc
---
---- |LanguageTree| contains a tree of parsers: the root treesitter parser for {lang} and any
+--- LanguageTree contains a tree of parsers: the root treesitter parser for {lang} and any
--- "injected" language parsers, which themselves may inject other languages, recursively.
---
---@param source (integer|string) Buffer or text string to parse
@@ -951,7 +951,7 @@ function LanguageTree:_edit(
end
end
----@package
+---@nodoc
---@param bufnr integer
---@param changed_tick integer
---@param start_row integer
@@ -1023,12 +1023,12 @@ function LanguageTree:_on_bytes(
)
end
----@package
+---@nodoc
function LanguageTree:_on_reload()
self:invalidate(true)
end
----@package
+---@nodoc
function LanguageTree:_on_detach(...)
self:invalidate(true)
self:_do_callback('detach', ...)
diff --git a/runtime/lua/vim/ui.lua b/runtime/lua/vim/ui.lua
index 99b9b78e2a..f168da4955 100644
--- a/runtime/lua/vim/ui.lua
+++ b/runtime/lua/vim/ui.lua
@@ -179,7 +179,13 @@ function M._get_url()
current_node = current_node:parent()
end
end
- return vim.fn.expand('<cfile>')
+
+ local old_isfname = vim.o.isfname
+ vim.cmd [[set isfname+=@-@]]
+ local url = vim.fn.expand('<cfile>')
+ vim.o.isfname = old_isfname
+
+ return url
end
return M
diff --git a/runtime/lua/vim/vimhelp.lua b/runtime/lua/vim/vimhelp.lua
index 4af6866d48..33324602c9 100644
--- a/runtime/lua/vim/vimhelp.lua
+++ b/runtime/lua/vim/vimhelp.lua
@@ -30,4 +30,42 @@ function M.highlight_groups(patterns)
vim.fn.setpos('.', save_cursor)
end
+--- Show a table of contents for the help buffer in a loclist
+function M.show_toc()
+ local bufnr = vim.api.nvim_get_current_buf()
+ local parser = vim.treesitter.get_parser(bufnr, 'vimdoc')
+ local query = vim.treesitter.query.parse(
+ parser:lang(),
+ [[
+ (h1 (heading) @h1)
+ (h2 (heading) @h2)
+ (h3 (heading) @h3)
+ (column_heading (heading) @h4)
+ ]]
+ )
+ local root = parser:parse()[1]:root()
+ local headings = {}
+ for id, node, _, _ in query:iter_captures(root, bufnr) do
+ local text = vim.treesitter.get_node_text(node, bufnr)
+ local capture = query.captures[id]
+ local row, col = node:start()
+ -- only column_headings at col 1 are headings, otherwise it's code examples
+ local is_code = (capture == 'h4' and col > 0)
+ -- ignore tabular material
+ local is_table = (capture == 'h4' and (text:find('\t') or text:find(' ')))
+ -- ignore tag-only headings
+ local is_tag = node:child_count() == 1 and node:child(0):type() == 'tag'
+ if not (is_code or is_table or is_tag) then
+ table.insert(headings, {
+ bufnr = bufnr,
+ lnum = row + 1,
+ text = (capture == 'h3' or capture == 'h4') and '  ' .. text or text,
+ })
+ end
+ end
+ vim.fn.setloclist(0, headings, ' ')
+ vim.fn.setloclist(0, {}, 'a', { title = 'Help TOC' })
+ vim.cmd.lopen()
+end
+
return M
diff --git a/runtime/optwin.vim b/runtime/optwin.vim
index 5b5b33e4ad..3b874f4cda 100644
--- a/runtime/optwin.vim
+++ b/runtime/optwin.vim
@@ -1,7 +1,7 @@
" These commands create the option window.
"
" Maintainer: The Vim Project <https://github.com/vim/vim>
-" Last Change: 2023 Aug 31
+" Last Change: 2024 Jun 05
" Former Maintainer: Bram Moolenaar <Bram@vim.org>
" If there already is an option window, jump to that one.
@@ -723,7 +723,7 @@ if has("insert_expand")
call append("$", "\t" .. s:local_to_buffer)
call <SID>OptionL("cpt")
call <SID>AddOption("completeopt", gettext("whether to use a popup menu for Insert mode completion"))
- call <SID>OptionG("cot", &cot)
+ call <SID>OptionL("cot")
call <SID>AddOption("pumheight", gettext("maximum height of the popup menu"))
call <SID>OptionG("ph", &ph)
call <SID>AddOption("pumwidth", gettext("minimum width of the popup menu"))
diff --git a/runtime/queries/vimdoc/highlights.scm b/runtime/queries/vimdoc/highlights.scm
index 70a3a2f206..194c80362c 100644
--- a/runtime/queries/vimdoc/highlights.scm
+++ b/runtime/queries/vimdoc/highlights.scm
@@ -1,13 +1,19 @@
-(h1) @markup.heading.1
+(h1
+ (delimiter) @markup.heading.1
+ (heading) @markup.heading.1)
-(h2) @markup.heading.2
+(h2
+ (delimiter) @markup.heading.2
+ (heading) @markup.heading.2)
-(h3) @markup.heading.3
+(h3
+ (heading) @markup.heading.3)
-(column_heading) @markup.heading.4
+(column_heading
+ (heading) @markup.heading.4)
(column_heading
- "~" @markup.heading.4
+ (delimiter) @markup.heading.4
(#set! conceal ""))
(tag
diff --git a/runtime/syntax/deb822sources.vim b/runtime/syntax/deb822sources.vim
index f7d337fce9..ec45605905 100644
--- a/runtime/syntax/deb822sources.vim
+++ b/runtime/syntax/deb822sources.vim
@@ -40,7 +40,7 @@ syn match deb822sourcesUri '\(https\?://\|ftp://\|[rs]sh://\|debtorre
syn region deb822sourcesStrictField matchgroup=deb822sourcesEntryField start="^\%(Types\|URIs\|Suites\|Components\): *" end="$" contains=deb822sourcesType,deb822sourcesUri,deb822sourcesSupportedSuites,deb822sourcesUnsupportedSuites,deb822sourcesFreeComponent,deb822sourcesNonFreeComponent oneline
syn region deb822sourcesField matchgroup=deb822sourcesOptionField start="^\%(Signed-By\|Check-Valid-Until\|Valid-Until-Min\|Valid-Until-Max\|Date-Max-Future\|InRelease-Path\): *" end="$" oneline
syn region deb822sourcesField matchgroup=deb822sourcesMultiValueOptionField start="^\%(Architectures\|Languages\|Targets\)\%(-Add\|-Remove\)\?: *" end="$" oneline
-syn region deb822sourcesStrictField matchgroup=deb822sourcesBooleanOptionField start="^\%(PDiffs\|Allow-Insecure\|Allow-Weak\|Allow-Downgrade-To-Insecure\|Trusted\|Check-Date\): *" end="$" contains=deb822sourcesYesNo oneline
+syn region deb822sourcesStrictField matchgroup=deb822sourcesBooleanOptionField start="^\%(PDiffs\|Allow-Insecure\|Allow-Weak\|Allow-Downgrade-To-Insecure\|Trusted\|Check-Date\|Enabled\): *" end="$" contains=deb822sourcesYesNo oneline
syn region deb822sourcesStrictField matchgroup=deb822sourcesForceBooleanOptionField start="^\%(By-Hash\): *" end="$" contains=deb822sourcesForce,deb822sourcesYesNo oneline
hi def link deb822sourcesField Default
diff --git a/runtime/syntax/java.vim b/runtime/syntax/java.vim
index 9867b147c2..f5910a8557 100644
--- a/runtime/syntax/java.vim
+++ b/runtime/syntax/java.vim
@@ -3,7 +3,7 @@
" Maintainer: Aliaksei Budavei <0x000c70 AT gmail DOT com>
" Former Maintainer: Claudio Fleiner <claudio@fleiner.com>
" Repository: https://github.com/zzzyxwvut/java-vim.git
-" Last Change: 2024 May 10
+" Last Change: 2024 Jun 08
" Please check :help java.vim for comments on some of the options available.
@@ -215,7 +215,7 @@ syn keyword javaLabelVarType contained var
syn keyword javaLabelCastType contained char byte short int
" Allow for the contingency of the enclosing region not being able to
" _keep_ its _end_, e.g. case ':':.
-syn region javaLabelWhenClause contained transparent matchgroup=javaLabel start="\<when\>" matchgroup=NONE end=":"me=e-1 end="->"me=e-2 contains=TOP,javaExternal
+syn region javaLabelWhenClause contained transparent matchgroup=javaLabel start="\<when\>" matchgroup=NONE end=":"me=e-1 end="->"me=e-2 contains=TOP,javaExternal,javaLambdaDef
syn match javaLabelNumber contained "\<0\>[lL]\@!"
syn match javaLabelNumber contained "\<\%(0\%([xX]\x\%(_*\x\)*\|_*\o\%(_*\o\)*\|[bB][01]\%(_*[01]\)*\)\|[1-9]\%(_*\d\)*\)\>[lL]\@!"
hi def link javaLabelDefault javaLabel
@@ -348,7 +348,6 @@ if exists("java_highlight_functions")
exec 'syn region javaFuncDef start=/' . s:ff.Engine('\%#=2', '') . '^\s\+\%(\%(@\%(\K\k*\.\)*\K\k*\>\)\s\+\)*\%(p\%(ublic\|rotected\|rivate\)\s\+\)\=\%(\%(abstract\|default\)\s\+\|\%(\%(final\|\%(native\|strictfp\)\|s\%(tatic\|ynchronized\)\)\s\+\)*\)\=\%(<.*[[:space:]-]\@' . s:ff.Peek('1', '') . '<!>\s\+\)\=\%(void\|\%(b\%(oolean\|yte\)\|char\|short\|int\|long\|float\|double\|\%(\<\K\k*\>\.\)*\<' . s:ff.UpperCase('[$_[:upper:]]', '[^a-z0-9]') . '\k*\>\%(<[^(){}]*[[:space:]-]\@' . s:ff.Peek('1', '') . '<!>\)\=\)\%(\[\]\)*\)\s\+\<' . s:ff.LowerCase('[$_[:lower:]]', '[^A-Z0-9]') . '\k*\>\s*(/ end=/)/ skip=/\/\*.\{-}\*\/\|\/\/.*$/ contains=@javaFuncParams'
endif
- exec 'syn match javaLambdaDef "\<\K\k*\>\%(\<default\>\)\@' . s:ff.Peek('7', '') . '<!\s*->"'
syn match javaBraces "[{}]"
endif
@@ -421,9 +420,26 @@ syn match javaParenError "\]"
hi def link javaParenError javaError
+" Lambda expressions (JLS-17, §15.27).
if exists("java_highlight_functions")
" Make ()-matching definitions after the parenthesis error catcher.
- exec 'syn match javaLambdaDef "\k\@' . s:ff.Peek('4', '') . '<!(\%(\k\|[[:space:]<>?\[\]@,.]\)*)\s*->"'
+ "
+ " Match: ([@A [@B ...] final] var a[, var b, ...]) ->
+ " | ([@A [@B ...] final] T[<α>][[][]] a[, T b, ...]) ->
+ " There is no recognition of expressions interspersed with comments
+ " or of expressions whose parameterised parameter types are written
+ " across multiple lines.
+ exec 'syn match javaLambdaDef "\k\@' . s:ff.Peek('4', '') . '<!([[:space:]\n]*\%(\%(@\%(\K\k*\.\)*\K\k*\>\%((\_.\{-1,})\)\{-,1}[[:space:]\n]\+\)*\%(final[[:space:]\n]\+\)\=\%(\<\K\k*\>\.\)*\<\K\k*\>\%(<[^(){}]*[[:space:]-]\@' . s:ff.Peek('1', '') . '<!>\)\=\%(\%(\%(\[\]\)\+\|\.\.\.\)\)\=[[:space:]\n]\+\<\K\k*\>\%(\[\]\)*\%(,[[:space:]\n]*\)\=\)\+)[[:space:]\n]*->" contains=javaAnnotation,javaParamModifier,javaLambdaVarType,javaType,@javaClasses,javaVarArg'
+ " Match: () ->
+ " | (a[, b, ...]) ->
+ exec 'syn match javaLambdaDef "\k\@' . s:ff.Peek('4', '') . '<!([[:space:]\n]*\%(\<\K\k*\>\%(,[[:space:]\n]*\)\=\)*)[[:space:]\n]*->"'
+ " Match: a ->
+ exec 'syn match javaLambdaDef "\<\K\k*\>\%(\<default\>\)\@' . s:ff.Peek('7', '') . '<![[:space:]\n]*->"'
+
+ syn keyword javaParamModifier contained final
+ hi def link javaParamModifier javaConceptKind
+ syn keyword javaLambdaVarType contained var
+ hi def link javaLambdaVarType javaOperator
endif
" The @javaTop cluster comprises non-contained Java syntax groups.
diff --git a/runtime/syntax/kdl.vim b/runtime/syntax/kdl.vim
new file mode 100644
index 0000000000..a36bb9e927
--- /dev/null
+++ b/runtime/syntax/kdl.vim
@@ -0,0 +1,45 @@
+" Vim syntax file
+" Language: KDL
+" Maintainer: Aram Drevekenin <aram@poor.dev>
+" Maintainer: Yinzuo Jiang <jiangyinzuo@foxmail.com>
+" Latest Revision: 2024-06-10
+
+" quit when a syntax file was already loaded
+if exists("b:current_syntax")
+ finish
+endif
+
+syn match kdlNode '\v(\w|-|\=)' display
+syn match kdlBool '\v(true|false)' display
+
+syn keyword kdlTodo contained TODO FIXME XXX NOTE
+syn match kdlComment "//.*$" contains=kdlTodo
+
+" Regular int like number with - + or nothing in front
+syn match kdlNumber '\d\+'
+syn match kdlNumber '[-+]\d\+'
+
+" Floating point number with decimal no E or e (+,-)
+syn match kdlNumber '\d\+\.\d*' contained display
+syn match kdlNumber '[-+]\d\+\.\d*' contained display
+
+" Floating point like number with E and no decimal point (+,-)
+syn match kdlNumber '[-+]\=\d[[:digit:]]*[eE][\-+]\=\d\+' contained display
+syn match kdlNumber '\d[[:digit:]]*[eE][\-+]\=\d\+' contained display
+
+" Floating point like number with E and decimal point (+,-)
+syn match kdlNumber '[-+]\=\d[[:digit:]]*\.\d*[eE][\-+]\=\d\+' contained display
+syn match kdlNumber '\d[[:digit:]]*\.\d*[eE][\-+]\=\d\+' contained display
+
+syn region kdlString start='"' end='"' skip='\\\\\|\\"' display
+
+syn region kdlChildren start="{" end="}" contains=kdlString,kdlNumber,kdlNode,kdlBool,kdlComment
+
+hi def link kdlTodo Todo
+hi def link kdlComment Comment
+hi def link kdlNode Statement
+hi def link kdlBool Boolean
+hi def link kdlString String
+hi def link kdlNumber Number
+
+let b:current_syntax = "kdl"
diff --git a/runtime/syntax/lc.vim b/runtime/syntax/lc.vim
index a334529385..1991c1b582 100644
--- a/runtime/syntax/lc.vim
+++ b/runtime/syntax/lc.vim
@@ -2,6 +2,7 @@
" Language: Elsa
" Maintainer: Miles Glapa-Grossklag <miles@glapa-grossklag.com>
" Last Change: 2023-01-29
+" 2024 May 25 by Riley Bruins <ribru17@gmail.com> (move 'commentstring' to ftplugin)
if exists('b:current_syntax')
finish
@@ -13,7 +14,6 @@ syntax match elsaKeyword "\v:"
highlight link elsaKeyword Keyword
" Comments
-setlocal commentstring=--%s
syntax match elsaComment "\v--.*$"
highlight link elsaComment Comment
diff --git a/runtime/syntax/mma.vim b/runtime/syntax/mma.vim
index d2f22e9be5..802cbe5538 100644
--- a/runtime/syntax/mma.vim
+++ b/runtime/syntax/mma.vim
@@ -2,6 +2,7 @@
" Language: Mathematica
" Maintainer: steve layland <layland@wolfram.com>
" Last Change: 2012 Feb 03 by Thilo Six
+" 2024 May 24 by Riley Bruins <ribru17@gmail.com> (remove 'commentstring')
" Source: http://members.wri.com/layland/vim/syntax/mma.vim
" http://vim.sourceforge.net/scripts/script.php?script_id=1273
" Id: $Id: mma.vim,v 1.4 2006/04/14 20:40:38 vimboss Exp $
@@ -248,7 +249,6 @@ syntax match mmaBoring "[(){}]" contained
"syntax region mmaRegion start="(\*\+[^<]*<!--[^>]*\*\+)" end="--> \*)" containedin=ALLBUT,@mmaStrings transparent fold keepend
" show fold text
-set commentstring='(*%s*)'
"set foldtext=MmaFoldText()
"function MmaFoldText()
diff --git a/runtime/syntax/rasi.vim b/runtime/syntax/rasi.vim
new file mode 100644
index 0000000000..40c3393fc5
--- /dev/null
+++ b/runtime/syntax/rasi.vim
@@ -0,0 +1,298 @@
+" Vim syntax file
+" Language: rasi (Rofi Advanced Style Information)
+" Maintainer: Pierrick Guillaume <pierguill@gmail.com>
+" Last Change: 2024 May 21
+"
+" Syntax support for rasi config file
+
+" This file is based on syntax defined in rofi-theme man page
+" https://man.archlinux.org/man/community/rofi/rofi-theme.5.en
+
+if exists('b:current_syntax')
+ finish
+endif
+let b:current_syntax = 'rasi'
+
+" String {{{
+syn region rasiString start=+"+ skip=+\\"+ end=+"+ oneline contained
+syn match rasiCharacter +L\='[^\\]'+ contained
+
+syn cluster rasiPropertyVals add=rasiString,rasiCharacter
+" }}}
+
+" Integer/Real {{{
+syn match rasiNumber display contained '[+-]\?\d\+\(\.\d\+\)\?'
+
+syn cluster rasiPropertyVals add=rasiNumber
+" }}}
+
+" Boolean {{{
+syn keyword rasiBool contained true false
+
+syn cluster rasiPropertyVals add=rasiBool
+" }}}
+
+" Image {{{
+syn match rasiInvImage display contained 'url([^)]*)'
+syn keyword rasiImageK contained url linear-gradient
+
+syn match rasiImage display contained transparent 'url(\s*"\([^"]\|\\"\)\+"\(\s*,\s*\(none\|both\|width\|height\)\)\?\s*)' contains=rasiImageScale,rasiString,rasiImageK
+syn keyword rasiImageScale contained none both width height
+
+syn match rasiImage display contained transparent 'linear-gradient(\s*\(\(top\|left\|right\|bottom\)\s*,\s*\)\?[^,)]\+\s*\(,\s*[^,)]\+\s*\)\+)' contains=rasiImageDirection,@rasiColors,rasiImageK
+syn keyword rasiImageDirection contained top left right bottom
+
+syn match rasiImage display contained transparent 'linear-gradient(\s*\d\+\(rad\|grad\|deg\)\s*,\s*[^,)]\+\s*\(,\s*[^,)]\+\s*\)\+)' contains=rasiImageUnit,@rasiColor,@rasiInvColor,rasiNumber,rasiImageK
+syn match rasiImageUnit display contained '\(rad\|grad\|deg\)\>'
+
+syn cluster rasiPropertyVals add=rasiInvImage,rasiImage
+" }}}
+
+" Reference {{{
+syn match rasiReference display contained '@[a-zA-Z0-9-]\+'
+
+syn keyword rasiVarReferenceK contained var
+
+syn match rasiInvVarReference display contained 'var([^)]*)'
+syn match rasiVarReference display contained transparent 'var(\s*[a-zA-Z0-9-]\+\s*,\s*\(\a\+\s*([^)]*)\)\?[^),]*)' contains=rasiVarReferenceK,rasiPropertyIdRef,@rasiPropertyVals
+syn match rasiPropertyIdRef display contained '\a[a-zA-Z0-9-]*'
+
+syn cluster rasiPropertyVals add=rasiReference,rasiInvVarReference,rasiVarReference
+" }}}
+
+" Env variable {{{
+syn match rasiInvEnv display contained '${[^}]*}'
+syn match rasiEnv display contained '${\w\+}'hs=s+2,he=e-1
+
+syn keyword rasiEnvVarK contained env
+
+syn match rasiInvEnvVar display contained 'env([^)]*)'
+syn match rasiEnvVar display contained transparent 'env(\s*\w\+\s*,\s*\(\a\+([^)]*)\)\?[^),]*)' contains=rasiEnvVarK,rasiEnvRef,@rasiPropertyVals
+syn match rasiEnvRef display contained '\a\w*'
+
+syn cluster rasiPropertyVals add=rasiEnv,rasiInvEnv,rasiInvEnvVar,rasiEnvVar
+" }}}
+
+" Color {{{
+syn keyword rasiColorK contained rgb[a] hsl[a] hwb[a] cmyk
+
+syn match rasiHexColor display contained '#\x\{3,4}'
+syn match rasiHexColor display contained '#\x\{6}'
+syn match rasiHexColor display contained '#\x\{8}'
+syn match rasiInvHexColor display contained '#\x\{5}\X'he=e-1,me=e-1
+syn match rasiInvHexColor display contained '#\x\{7}\X'he=e-1,me=e-1
+
+syn match rasiInvRGBColor display contained 'rgb\(a\)\?([^)]*)'
+syn match rasiRGBColor display contained transparent 'rgb\(a\)\?(\s*\d\+\s*\(%\)\?\s*,\(\s*\d\+\s*\(%\)\?\s*\){2}\(,\s*\(\d\(\.\d*\)\?\|\d\{,3}%\)\s*\)\?)' contains=rasiColorK,rasiNumber,rasiDistance
+
+syn match rasiInvHSLColor display contained 'h\(sl\|wb\)\(a\)\?([^)]*)'
+syn match rasiHSLColor display contained transparent 'h\(sl\|wb\)\(a\)\?(\s*\d\+\(\.\d*\)\?\(deg\|rad\|grad\|turn\)\?\s*\(,\s*\(\d\(\.\d*\)\?\|\d\{,3}%\)\s*\)\{2,3})' contains=rasiColorK,rasiNumber,rasiDistance
+
+
+"this matches doesn't works properly (too long ?)
+syn match rasiInvCMYKColor display contained 'cmyk([^)]*)'
+syn match rasiCMYKColor display contained transparent 'cmyk(\s*\(\d\(\.\d*\)\?\|\d\{,3}%\)\s*\(,\s*\(\d\(\.\d*\)\?\|\d\{,3}%\)\s*\)\{3,4})' contains=rasiColorK,rasiNumber,rasiDistance
+
+syn case ignore
+syn keyword rasiNamedColor contained
+ \ AliceBlue AntiqueWhite Aqua Aquamarine Azure Beige Bisque Black BlanchedAlmond Blue
+ \ BlueViolet Brown BurlyWood CadetBlue Chartreuse Chocolate Coral CornflowerBlue Cornsilk
+ \ Crimson Cyan DarkBlue DarkCyan DarkGoldenRod DarkGray DarkGrey DarkGreen DarkKhaki DarkMagenta
+ \ DarkOliveGreen DarkOrange DarkOrchid DarkRed DarkSalmon DarkSeaGreen Dark SlateBlue
+ \ DarkSlateGray DarkSlateGrey DarkTurquoise DarkViolet DeepPink DeepSkyBlue DimGray DimGrey
+ \ DodgerBlue FireBrick FloralWhite ForestGreen Fuchsia Gainsboro GhostWhite Gold GoldenRod
+ \ Gray Grey Green GreenYellow HoneyDew HotPink IndianRed Indigo Ivory Khaki Lavender
+ \ LavenderBlush LawnGreen LemonChiffon LightBlue LightCoral LightCyan LightGoldenRodYellow
+ \ LightGray LightGrey LightGreen LightPink LightSalmon LightSeaGreen LightSkyBlue LightSlateGray
+ \ LightSlateGrey LightSteelBlue LightYellow Lime LimeGreen Linen Magenta Maroon MediumAquaMarine
+ \ MediumBlue MediumOrchid MediumPurple MediumSeaGreen MediumSlateBlue MediumSpringGreen
+ \ MediumTurquoise MediumVioletRed MidnightBlue MintCream MistyRose Moccasin NavajoWhite Navy
+ \ OldLace Olive OliveDrab Orange OrangeRed Orchid PaleGoldenRod PaleGreen PaleTurquoise
+ \ PaleVioletRed PapayaWhip PeachPuff Peru Pink Plum PowderBlue Purple RebeccaPurple Red
+ \ RosyBrown RoyalBlue SaddleBrown Salmon SandyBrown SeaGreen SeaShell Sienna Silver SkyBlue
+ \ SlateBlue SlateGray SlateGrey Snow SpringGreen SteelBlue Tan Teal Thistle Tomato Turquoise
+ \ Violet Wheat White WhiteSmoke Yellow YellowGreen transparent[] "uses `[]` to escape keyword
+
+syn cluster rasiColors add=rasiHexColor,rasiRGBColor,rasiHSLColor,rasiCMYKColor,rasiNamedColor
+syn cluster rasiColors add=rasiInvHexColor,rasiInvRGBColor,rasiInvHSLColor,rasiInvCMYKColor
+
+syn cluster rasiPropertyVals add=@rasiColors
+" }}}
+
+" Text-Style {{{
+syn keyword rasiTextStyle contained bold italic underline strikethrough none
+
+syn cluster rasiPropertyVals add=rasiTextStyle
+" }}}
+
+" Line-Style {{{
+syn keyword rasiLineStyle contained dash solid
+
+syn cluster rasiPropertyVals add=rasiLineStyle
+" }}}
+
+" Distance {{{
+syn match rasiDistanceUnit display contained '\(px\|em\|ch\|%\|mm\)'
+
+syn match rasiInvDistance display contained '[+-]\?\d\+\.\d\+\(px\|mm\)'
+syn match rasiDistance display contained transparent '[-+]\?\d\+\(px\|mm\)' contains=rasiDistanceUnit,rasiNumber
+syn match rasiDistance display contained transparent '[+-]\?\d\+\(\.\d\+\)\?\(em\|ch\|%\)' contains=rasiDistanceUnit,rasiNumber
+
+syn keyword rasiDistanceCalc contained calc nextgroup=rasiDistanceCalcBody
+syn region rasiDistanceCalcBody display contained start=+(+ end=+)+ contains=rasiDistanceCalcOp,rasiDistance,rasiInvDistance
+syn match rasiDistanceCalcOp display contained '\(+\|-\|/\|\*\|%\|min\|max\)'
+
+syn cluster rasiPropertyVals add=rasiInvDistance,rasiDistance,rasiDistanceCalc
+" }}}
+
+" Position {{{
+syn keyword rasiPosition contained center east north west south
+
+syn cluster rasiPropertyVals add=rasiPosition
+" }}}
+
+" Orientation {{{
+syn keyword rasiOrientation contained horizontal vertical
+
+syn cluster rasiPropertyVals add=rasiOrientation
+" }}}
+
+" Cursor {{{
+syn keyword rasiCursor contained default pointer text
+
+syn cluster rasiPropertyVals add=rasiCursor
+" }}}
+
+" Keyword List {{{
+syn region rasiKeywordList contained start=+\[+ end=+\]+ contains=rasiPropertyIdRef
+
+syn cluster rasiPropertyVals add=rasiKeywordList
+" }}}
+
+" Inherit {{{
+syn keyword rasiInherit contained inherit children
+
+syn cluster rasiPropertyVals add=rasiInherit
+" }}}
+
+syn match rasiGlobalImport display '^\s*@\(import\|theme\)' nextgroup=rasiString skipwhite
+
+" Section {{{
+" syn region rasiSection transparent start='^[^{]\+{'me=e-1 end='}' contains=rasiSectionOpenning,rasiSectionContent
+syn match rasiSectionOpenning transparent '^[^{]\+{'me=e-1 contains=rasiGlobalSection,rasiWidgetName,rasiGlobalMedia nextgroup=rasiThemeSectionContent
+" syn match rasiThemeInnerSectionOpenning transparent '^[^:${]\+{'me=e-1 contains=rasiWidgetName nextgroup=rasiThemeInnerSectionContent contained
+
+syn match rasiGlobalMedia display contained '^\s*@media' nextgroup=rasiInvMediaBody,rasiMediaBody skipwhite
+syn match rasiInvMediaBody display contained '([^)]*)'
+syn match rasiMediaBody display contained '(\s*[a-z-]\+\s*:\s*\d\+\(px\|mm\)\?\s*)' contains=rasiMediaK,rasiNumber,rasiDistance
+syn keyword rasiMediaK contained min-width max-width min-height max-height min-aspect-ratio max-aspect-ratio monitor-id
+
+syn match rasiGlobalSection display contained '^*'
+syn match rasiWidgetName display contained '[a-zA-Z0-9-]\+' nextgroup=rasiVisibleMod skipwhite
+
+syn keyword rasiVisibleMod contained normal selected alternate nextgroup=rasiVisibleMod,rasiStateWrapper skipwhite
+syn match rasiStateWrapper display contained transparent '\.\(normal\|active\|urgent\)' contains=rasiState
+syn keyword rasiState contained normal active urgent
+
+
+syn region rasiThemeSectionContent transparent start="{" end="}" contains=rasiProperty,rasiComment,rasiCommentL,rasiSectionOpenning contained
+" syn region rasiThemeInnerSectionContent transparent start="{" end="}" contains=rasiProperty,rasiComment,rasiCommentL,rasiThemeInnerSectionOpenning contained
+
+syn match rasiProperty transparent '^\s*\S\+\s*:.*;\s*$' keepend contained contains=rasiPropertyId,rasiInvPropertyId,rasiPropertyVal,rasiComment,rasiCommentL
+syn match rasiInvPropertyId '^\([^:]\&[^/]\{2}\)*:'me=e-1 contained
+syn match rasiPropertyId '^\s*[0-9a-zA-Z-]\+\s*:'me=e-1 contained
+syn match rasiInvPropertyVal ':[^;];\s*\S\+\s*$'ms=s+1,hs=s+1
+syn match rasiPropertyVal ':\s*[^;]\+;\s*$'ms=s+1,hs=s+1 contained contains=@rasiPropertyVals
+" }}}
+
+" Comment {{{
+syn cluster rasiCommentGroup contains=rasiTodo,rasiBadContinuation
+
+syn region rasiCommentL start="//" skip="\\$" end="$" keepend contains=@rasiCommentGroup,@Spell
+syn region rasiComment start="/\*" end="\*/" contains=@rasiCommentGroup,rasiCommentStartError,@Spell fold extend
+
+syn match rasiCommentError display '\*/'
+
+syn keyword rasiTodo contained TODO FIXME XXX NOTE
+
+if exists("rasi_minlines")
+ let b:rasi_minlines = rasi_minlines
+else
+ let b:rasi_minlines = 50
+endif
+exec "syn sync ccomment rasiComment minlines=" . b:rasi_minlines
+" }}}
+
+
+
+" Highlighting: {{{
+hi def link rasiError Error
+
+hi def link rasiTodo Todo
+hi def link rasiComment Comment
+hi def link rasiCommentStart rasiComment
+hi def link rasiCommentL rasiComment
+hi def link rasiCommentError rasiError
+
+hi def link rasiString String
+hi def link rasiNumber Number
+hi def link rasiBool Boolean
+
+hi def link rasiImageK Function
+hi def link rasiImageScale Keyword
+hi def link rasiImageDirection Keyword
+hi def link rasiImageUnit Type
+hi def link rasiInvImage rasiError
+
+hi def link rasiHexColor Number
+hi def link rasiColorK Function
+hi def link rasiNamedColor Number
+hi def link rasiInvColor rasiError
+hi def link rasiInvHexColor rasiInvColor
+hi def link rasiInvRGBColor rasiInvColor
+hi def link rasiInvHSLColor rasiInvColor
+hi def link rasiInvCMYKColor rasiInvColor
+
+hi def link rasiTextStyle Keyword
+hi def link rasiLineStyle Keyword
+
+hi def link rasiDistanceUnit Type
+hi def link rasiDistanceCalc Function
+hi def link rasiDistanceCalcOp Operator
+hi def link rasiInvDistance rasiError
+
+hi def link rasiPosition Keyword
+hi def link rasiOrientation Keyword
+hi def link rasiCursor Keyword
+
+hi def link rasiReference Identifier
+hi def link rasiPropertyIdRef Identifier
+hi def link rasiVarReferenceK Function
+hi def link rasiInvVarReference rasiError
+
+hi def link rasiEnv Identifier
+hi def link rasiEnvRef Identifier
+hi def link rasiEnvVarK Function
+hi def link rasiInvEnv rasiError
+hi def link rasiInvEnvVar rasiError
+
+hi def link rasiWidgetName StorageClass
+hi def link rasiGlobalSection StorageClass
+hi def link rasiVisibleMod Type
+hi def link rasiState Tag
+
+hi def link rasiInherit Identifier
+
+hi def link rasiGlobalImport Include
+
+hi def link rasiGlobalMedia Preproc
+hi def link rasiMediaK Keyword
+hi def link rasiInvMediaBody rasiError
+
+hi def link rasiPropertyId Identifier
+hi def link rasiInvProperty rasiError
+hi def link rasiInvPropertyId rasiError
+hi def link rasiInvPropertyVal rasiError
+" }}}
+
+" vim:ts=8
diff --git a/runtime/syntax/vim.vim b/runtime/syntax/vim.vim
index 22c1e16a30..d16d62dc4a 100644
--- a/runtime/syntax/vim.vim
+++ b/runtime/syntax/vim.vim
@@ -359,7 +359,9 @@ syn region vimUserCmdBlock contained matchgroup=vimSep start="{" end="}" contain
" Lower Priority Comments: after some vim commands... {{{2
" =======================
-syn region vimCommentString contained oneline start='\S\s\+"'ms=e end='"'
+if get(g:, "vimsyn_comment_strings", 1)
+ syn region vimCommentString contained oneline start='\S\s\+"'ms=e end='"'
+endif
if s:vim9script
syn match vimComment excludenl +\s"[^\-:.%#=*].*$+lc=1 contains=@vimCommentGroup,vimCommentString contained
@@ -428,12 +430,10 @@ syn match vimStringInterpolationBrace contained "}}"
syn cluster vimSubstList contains=vimPatSep,vimPatRegion,vimPatSepErr,vimSubstTwoBS,vimSubstRange,vimNotation
syn cluster vimSubstRepList contains=vimSubstSubstr,vimSubstTwoBS,vimNotation
syn cluster vimSubstList add=vimCollection
-syn match vimSubst "^\s*\%(s\%[ubstitute]\|sm\%[agic]\|sno\%[magic]\)\>[\"#|]\@!" nextgroup=vimSubstPat
-syn match vimSubst "^\s*\%(s\%[ubstitute]\|sm\%[agic]\|sno\%[magic]\)_\@=" nextgroup=vimSubstPat
-syn match vimSubst "^\s*\%(s\%[ubstitute]\|sm\%[agic]\>\|sno\%[magic]\)\ze#.\{-}#.\{-}#" nextgroup=vimSubstPat
-syn match vimSubst1 contained "\%(s\%[ubstitute]\|sm\%[agic]\>\|sno\%[magic]\)\>[\"#|]\@!" nextgroup=vimSubstPat
-syn match vimSubst1 contained "\%(s\%[ubstitute]\|sm\%[agic]\>\|sno\%[magic]\)_\@=" nextgroup=vimSubstPat
-syn match vimSubst1 contained "\%(s\%[ubstitute]\|sm\%[agic]\>\|sno\%[magic]\)\ze#.\{-}#.\{-}#" nextgroup=vimSubstPat
+syn match vimSubst "^\s*\%(s\%[ubstitute]\|sm\%[agic]\|sno\%[magic]\)\>" skipwhite nextgroup=vimSubstPat
+syn match vimSubst "^\s*\%(s\%[ubstitute]\|sm\%[agic]\|sno\%[magic]\)[_#]\@=" skipwhite nextgroup=vimSubstPat
+syn match vimSubst1 contained "\%(s\%[ubstitute]\|sm\%[agic]\>\|sno\%[magic]\)\>" skipwhite nextgroup=vimSubstPat
+syn match vimSubst1 contained "\%(s\%[ubstitute]\|sm\%[agic]\>\|sno\%[magic]\)[_#]\@=" skipwhite nextgroup=vimSubstPat
" TODO: Vim9 illegal separators for abbreviated :s form are [-.:], :su\%[...] required
" : # is allowed but "not recommended" (see :h pattern-delimiter)
syn region vimSubstPat contained matchgroup=vimSubstDelim start="\z([!#$%&'()*+,-./:;<=>?@[\]^_`{}~]\)"rs=s+1 skip="\\\\\|\\\z1" end="\z1"re=e-1,me=e-1 contains=@vimSubstList nextgroup=vimSubstRep4 oneline
@@ -446,6 +446,10 @@ syn match vimSubstTwoBS contained "\\\\"
syn match vimSubstFlagErr contained "[^< \t\r|]\+" contains=vimSubstFlags
syn match vimSubstFlags contained "[&cegiIlnpr#]\+"
+" Vi compatibility
+syn match vimSubstDelim contained "\\"
+syn match vimSubstPat contained "\\\ze[/?&]" contains=vimSubstDelim nextgroup=vimSubstRep4
+
" 'String': {{{2
syn match vimString "[^(,]'[^']\{-}\zs'"
@@ -804,16 +808,17 @@ syn match vimCtrlChar "[- -]"
" Beginners - Patterns that involve ^ {{{2
" =========
if s:vim9script
- syn match vimLineComment +^[ \t:]*".*$+ contains=@vimCommentGroup,vimCommentString,vimCommentTitle contained
- syn match vim9LineComment +^[ \t:]*#.*$+ contains=@vimCommentGroup,vimCommentString,vim9CommentTitle
+ syn region vim9LineComment start=+^[ \t:]*\zs#.*$+ skip=+\n\s*\\\|\n\s*#\\ + end="$" contains=@vimCommentGroup,vimCommentString,vim9CommentTitle
+ syn region vimLineComment start=+^[ \t:]*\zs".*$+ skip=+\n\s*\\\|\n\s*"\\ + end="$" contains=@vimCommentGroup,vimCommentString,vimCommentTitle contained
else
- syn match vimLineComment +^[ \t:]*".*$+ contains=@vimCommentGroup,vimCommentString,vimCommentTitle
- syn match vim9LineComment +^[ \t:]*#.*$+ contains=@vimCommentGroup,vimCommentString,vim9CommentTitle contained
+ syn region vimLineComment start=+^[ \t:]*\zs".*$+ skip=+\n\s*\\\|\n\s*"\\ + end="$" contains=@vimCommentGroup,vimCommentString,vimCommentTitle
+ syn region vim9LineComment start=+^[ \t:]*\zs#.*$+ skip=+\n\s*\\\|\n\s*#\\ + end="$" contains=@vimCommentGroup,vimCommentString,vim9CommentTitle contained
endif
syn match vimCommentTitle '"\s*\%([sS]:\|\h\w*#\)\=\u\w*\(\s\+\u\w*\)*:'hs=s+1 contained contains=vimCommentTitleLeader,vimTodo,@vimCommentGroup
syn match vim9CommentTitle '#\s*\%([sS]:\|\h\w*#\)\=\u\w*\(\s\+\u\w*\)*:'hs=s+1 contained contains=vim9CommentTitleLeader,vimTodo,@vimCommentGroup
+
syn match vimContinue "^\s*\zs\\"
-syn match vimContinueComment '^\s*\zs["#]\\ .*' contained
+syn match vimContinueComment '^\s*\zs["#]\\ .*'
syn cluster vimContinue contains=vimContinue,vimContinueComment
syn region vimString start="^\s*\\\z(['"]\)" skip='\\\\\|\\\z1' end="\z1" oneline keepend contains=@vimStringGroup,vimContinue
syn match vimCommentTitleLeader '"\s\+'ms=s+1 contained
diff --git a/runtime/tutor/en/vim-01-beginner.tutor b/runtime/tutor/en/vim-01-beginner.tutor
index 622eb7cc06..e6b81d63b9 100644
--- a/runtime/tutor/en/vim-01-beginner.tutor
+++ b/runtime/tutor/en/vim-01-beginner.tutor
@@ -888,7 +888,7 @@ NOTE: If you want to ignore case for just one search command, use [\c](/\c)
Neovim has a comprehensive online help system.
-To get started, try one of these three:
+To get started, try one of these two:
- press the `<F1>`{normal} key (if you have one)
- type `:help`{vim}
diff --git a/scripts/gen_eval_files.lua b/scripts/gen_eval_files.lua
index f1bba5c0a2..76092f8b39 100755
--- a/scripts/gen_eval_files.lua
+++ b/scripts/gen_eval_files.lua
@@ -6,7 +6,7 @@ local DEP_API_METADATA = 'build/funcs_metadata.mpack'
--- @class vim.api.metadata
--- @field name string
---- @field parameters {[1]:string,[2]:string}[]
+--- @field parameters [string,string][]
--- @field return_type string
--- @field deprecated_since integer
--- @field eval boolean
@@ -149,7 +149,7 @@ local function api_type(t)
end
--- @param f string
---- @param params {[1]:string,[2]:string}[]|true
+--- @param params [string,string][]|true
--- @return string
local function render_fun_sig(f, params)
local param_str --- @type string
@@ -158,7 +158,7 @@ local function render_fun_sig(f, params)
else
param_str = table.concat(
vim.tbl_map(
- --- @param v {[1]:string,[2]:string}
+ --- @param v [string,string]
--- @return string
function(v)
return v[1]
@@ -178,8 +178,8 @@ end
--- Uniquify names
--- Fix any names that are lua keywords
---- @param params {[1]:string,[2]:string,[3]:string}[]
---- @return {[1]:string,[2]:string,[3]:string}[]
+--- @param params [string,string,string][]
+--- @return [string,string,string][]
local function process_params(params)
local seen = {} --- @type table<string,true>
local sfx = 1
@@ -245,7 +245,7 @@ local function get_api_meta()
for _, fun in pairs(functions) do
local deprecated = fun.deprecated_since ~= nil
- local params = {} --- @type {[1]:string,[2]:string}[]
+ local params = {} --- @type [string,string][]
for _, p in ipairs(fun.params) do
params[#params + 1] = {
p.name,
diff --git a/scripts/gen_lsp.lua b/scripts/gen_lsp.lua
index 04d19f22e6..1706b39864 100644
--- a/scripts/gen_lsp.lua
+++ b/scripts/gen_lsp.lua
@@ -297,13 +297,13 @@ function M.gen(opt)
-- TupleType
elseif type.kind == 'tuple' then
- local tuple = '{ '
- for i, value in ipairs(type.items) do
- tuple = tuple .. '[' .. i .. ']: ' .. parse_type(value, prefix) .. ', '
+ local tuple = '['
+ for _, value in ipairs(type.items) do
+ tuple = tuple .. parse_type(value, prefix) .. ', '
end
-- remove , at the end
tuple = tuple:sub(0, -3)
- return tuple .. ' }'
+ return tuple .. ']'
end
vim.print('WARNING: Unknown type ', type)
diff --git a/scripts/gen_vimdoc.lua b/scripts/gen_vimdoc.lua
index dac6c6f461..dc384c12f5 100755
--- a/scripts/gen_vimdoc.lua
+++ b/scripts/gen_vimdoc.lua
@@ -421,8 +421,11 @@ local function render_type(ty, generics, default)
end
--- @param p nvim.luacats.parser.param|nvim.luacats.parser.field
-local function should_render_param(p)
- return not p.access and not contains(p.name, { '_', 'self' })
+local function should_render_field_or_param(p)
+ return not p.nodoc
+ and not p.access
+ and not contains(p.name, { '_', 'self' })
+ and not vim.startswith(p.name, '_')
end
--- @param desc? string
@@ -524,7 +527,7 @@ end
local function render_fields_or_params(xs, generics, classes, exclude_types)
local ret = {} --- @type string[]
- xs = vim.tbl_filter(should_render_param, xs)
+ xs = vim.tbl_filter(should_render_field_or_param, xs)
local indent = 0
for _, p in ipairs(xs) do
@@ -935,7 +938,7 @@ local function gen_target(cfg)
expand_files(cfg.files)
- --- @type table<string,{[1]:table<string,nvim.luacats.parser.class>, [2]: nvim.luacats.parser.fun[], [3]: string[]}>
+ --- @type table<string,[table<string,nvim.luacats.parser.class>, nvim.luacats.parser.fun[], string[]]>
local file_results = {}
--- @type table<string,nvim.luacats.parser.class>
diff --git a/scripts/lintcommit.lua b/scripts/lintcommit.lua
index 96f6304247..f0e2feaab3 100644
--- a/scripts/lintcommit.lua
+++ b/scripts/lintcommit.lua
@@ -41,12 +41,6 @@ end
-- Returns nil if the given commit message is valid, or returns a string
-- message explaining why it is invalid.
local function validate_commit(commit_message)
- -- Return nil if the commit message starts with "fixup" as it signifies it's
- -- a work in progress and shouldn't be linted yet.
- if vim.startswith(commit_message, 'fixup') then
- return nil
- end
-
local commit_split = vim.split(commit_message, ':', { plain = true })
-- Return nil if the type is vim-patch since most of the normal rules don't
-- apply.
@@ -229,9 +223,9 @@ function M._test()
['vim-patch:8.2.3374: Pyret files are not recognized (#15642)'] = true,
['vim-patch:8.1.1195,8.2.{3417,3419}'] = true,
['revert: "ci: use continue-on-error instead of "|| true""'] = true,
- ['fixup'] = true,
- ['fixup: commit message'] = true,
- ['fixup! commit message'] = true,
+ ['fixup'] = false,
+ ['fixup: commit message'] = false,
+ ['fixup! commit message'] = false,
[':no type before colon 1'] = false,
[' :no type before colon 2'] = false,
[' :no type before colon 3'] = false,
diff --git a/scripts/luacats_grammar.lua b/scripts/luacats_grammar.lua
index 29f3bda5aa..ebb0183fd9 100644
--- a/scripts/luacats_grammar.lua
+++ b/scripts/luacats_grammar.lua
@@ -170,7 +170,7 @@ local grammar = P {
ltype = parenOpt(v.ty_union),
ty_union = v.ty_opt * rep(Pf('|') * v.ty_opt),
- ty = v.ty_fun + ident + v.ty_table + literal + paren(v.ty) + v.ty_generic,
+ ty = v.ty_fun + ident + v.ty_table + literal + paren(v.ty) + v.ty_generic + v.ty_tuple,
ty_param = Pf('<') * comma1(v.ltype) * fill * P('>'),
ty_opt = v.ty * opt(v.ty_param) * opt(P('[]')) * opt(P('?')),
ty_index = (Pf('[') * (v.ltype + ident + rep1(num)) * fill * P(']')),
@@ -178,8 +178,10 @@ local grammar = P {
table_elem = v.table_key * colon * v.ltype,
ty_table = Pf('{') * comma1(v.table_elem) * fill * P('}'),
fun_param = lname * opt(colon * v.ltype),
- ty_fun = Pf('fun') * paren(comma(lname * opt(colon * v.ltype))) * opt(colon * comma1(v.ltype)),
+ fun_ret = v.ltype + (ident * colon * v.ltype) + (P('...') * opt(colon * v.ltype)),
+ ty_fun = Pf('fun') * paren(comma(lname * opt(colon * v.ltype))) * opt(colon * comma1(v.fun_ret)),
ty_generic = P('`') * letter * P('`'),
+ ty_tuple = Pf('[') * comma(v.ltype) * fill * P(']'),
}
return grammar --[[@as nvim.luacats.grammar]]
diff --git a/scripts/luacats_parser.lua b/scripts/luacats_parser.lua
index 66fe8ed616..e73a42111d 100644
--- a/scripts/luacats_parser.lua
+++ b/scripts/luacats_parser.lua
@@ -46,6 +46,7 @@ local luacats_grammar = require('scripts.luacats_grammar')
--- @field type string
--- @field desc string
--- @field access? 'private'|'package'|'protected'
+--- @field nodoc? true
--- @class nvim.luacats.parser.class
--- @field kind 'class'
@@ -270,6 +271,7 @@ local function fun2field(fun)
type = table.concat(parts, ''),
access = fun.access,
desc = fun.desc,
+ nodoc = fun.nodoc,
}
end
diff --git a/src/clint.py b/src/clint.py
index 41058469b1..051f0e91e5 100755
--- a/src/clint.py
+++ b/src/clint.py
@@ -1995,7 +1995,7 @@ def CheckLanguage(filename, clean_lines, linenum, error):
if match:
error(filename, linenum, 'runtime/printf', 4,
'Use xstrlcpy, xmemcpyz or snprintf instead of %s' % match.group(1))
- match = Search(r'\b(STRNCAT|strncat|strcat|vim_strcat)\b', line)
+ match = Search(r'\b(STRNCAT|strncat|vim_strcat)\b', line)
if match:
error(filename, linenum, 'runtime/printf', 4,
'Use xstrlcat or snprintf instead of %s' % match.group(1))
diff --git a/src/man/nvim.1 b/src/man/nvim.1
index 4dc099f98c..9b7680d011 100644
--- a/src/man/nvim.1
+++ b/src/man/nvim.1
@@ -387,10 +387,10 @@ features like
.El
.Sh FILES
.Bl -tag -width "~/.config/nvim/init.vim"
-.It Pa ~/.config/nvim/init.vim
+.It Pa ~/.config/nvim/init.lua
User-local
.Nm
-configuration file.
+Lua configuration file.
.It Pa ~/.config/nvim
User-local
.Nm
diff --git a/src/nvim/api/buffer.c b/src/nvim/api/buffer.c
index 7e64808709..a0678dc3e4 100644
--- a/src/nvim/api/buffer.c
+++ b/src/nvim/api/buffer.c
@@ -1183,12 +1183,12 @@ ArrayOf(Integer, 2) nvim_buf_get_mark(Buffer buffer, String name, Arena *arena,
return rv;
}
-/// call a function with buffer as temporary current buffer
+/// Call a function with buffer as temporary current buffer.
///
/// This temporarily switches current buffer to "buffer".
-/// If the current window already shows "buffer", the window is not switched
+/// If the current window already shows "buffer", the window is not switched.
/// If a window inside the current tabpage (including a float) already shows the
-/// buffer One of these windows will be set as current window temporarily.
+/// buffer, then one of these windows will be set as current window temporarily.
/// Otherwise a temporary scratch window (called the "autocmd window" for
/// historical reasons) will be used.
///
@@ -1375,7 +1375,7 @@ static inline void init_line_array(lua_State *lstate, Array *a, size_t size, Are
/// @param s String to push
/// @param len Size of string
/// @param idx 0-based index to place s (only used for Lua)
-/// @param replace_nl Replace newlines ('\n') with null ('\0')
+/// @param replace_nl Replace newlines ('\n') with null (NUL)
static void push_linestr(lua_State *lstate, Array *a, const char *s, size_t len, int idx,
bool replace_nl, Arena *arena)
{
@@ -1384,7 +1384,7 @@ static void push_linestr(lua_State *lstate, Array *a, const char *s, size_t len,
if (s && replace_nl && strchr(s, '\n')) {
// TODO(bfredl): could manage scratch space in the arena, for the NUL case
char *tmp = xmemdupz(s, len);
- strchrsub(tmp, '\n', '\0');
+ strchrsub(tmp, '\n', NUL);
lua_pushlstring(lstate, tmp, len);
xfree(tmp);
} else {
@@ -1397,7 +1397,7 @@ static void push_linestr(lua_State *lstate, Array *a, const char *s, size_t len,
str = CBUF_TO_ARENA_STR(arena, s, len);
if (replace_nl) {
// Vim represents NULs as NLs, but this may confuse clients.
- strchrsub(str.data, '\n', '\0');
+ strchrsub(str.data, '\n', NUL);
}
}
diff --git a/src/nvim/api/command.c b/src/nvim/api/command.c
index 779e216c74..5ad439af9c 100644
--- a/src/nvim/api/command.c
+++ b/src/nvim/api/command.c
@@ -193,7 +193,7 @@ Dict(cmd) nvim_parse_cmd(String str, Dict(empty) *opts, Arena *arena, Error *err
} else {
nargs[0] = '0';
}
- nargs[1] = '\0';
+ nargs[1] = NUL;
PUT_KEY(result, cmd, nargs, CSTR_TO_ARENA_OBJ(arena, nargs));
char *addr;
@@ -391,7 +391,7 @@ String nvim_cmd(uint64_t channel_id, Dict(cmd) *cmd, Dict(cmd_opts) *opts, Arena
case kObjectTypeBoolean:
data_str = arena_alloc(arena, 2, false);
data_str[0] = elem.data.boolean ? '1' : '0';
- data_str[1] = '\0';
+ data_str[1] = NUL;
ADD_C(args, CSTR_AS_OBJ(data_str));
break;
case kObjectTypeBuffer:
diff --git a/src/nvim/api/deprecated.c b/src/nvim/api/deprecated.c
index af3bfe2c03..a1af354577 100644
--- a/src/nvim/api/deprecated.c
+++ b/src/nvim/api/deprecated.c
@@ -170,7 +170,7 @@ Integer nvim_buf_set_virtual_text(Buffer buffer, Integer src_id, Integer line, A
DecorInline decor = { .ext = true, .data.ext.vt = vt, .data.ext.sh_idx = DECOR_ID_INVALID };
extmark_set(buf, ns_id, NULL, (int)line, 0, -1, -1, decor, 0, true,
- false, false, false, false, NULL);
+ false, false, false, NULL);
return src_id;
}
diff --git a/src/nvim/api/extmark.c b/src/nvim/api/extmark.c
index 85cce45560..ab6ff5ff1f 100644
--- a/src/nvim/api/extmark.c
+++ b/src/nvim/api/extmark.c
@@ -18,6 +18,7 @@
#include "nvim/decoration_provider.h"
#include "nvim/drawscreen.h"
#include "nvim/extmark.h"
+#include "nvim/globals.h"
#include "nvim/grid.h"
#include "nvim/highlight_group.h"
#include "nvim/map_defs.h"
@@ -41,6 +42,7 @@ void api_extmark_free_all_mem(void)
xfree(name.data);
})
map_destroy(String, &namespace_ids);
+ set_destroy(uint32_t, &namespace_localscope);
}
/// Creates a new namespace or gets an existing one. [namespace]()
@@ -179,10 +181,6 @@ static Array extmark_to_array(MTPair extmark, bool id, bool add_dict, bool hl_na
PUT_C(dict, "invalid", BOOLEAN_OBJ(true));
}
- if (mt_scoped(start)) {
- PUT_C(dict, "scoped", BOOLEAN_OBJ(true));
- }
-
decor_to_dict_legacy(&dict, mt_decor(start), hl_name, arena);
ADD_C(rv, DICTIONARY_OBJ(dict));
@@ -489,8 +487,6 @@ Array nvim_buf_get_extmarks(Buffer buffer, Integer ns_id, Object start, Object e
/// used together with virt_text.
/// - url: A URL to associate with this extmark. In the TUI, the OSC 8 control
/// sequence is used to generate a clickable hyperlink to this URL.
-/// - scoped: boolean (EXPERIMENTAL) enables "scoping" for the extmark. See
-/// |nvim__win_add_ns()|
///
/// @param[out] err Error details, if any
/// @return Id of the created/updated extmark
@@ -749,11 +745,6 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer
}
if (opts->ephemeral && decor_state.win && decor_state.win->w_buffer == buf) {
- if (opts->scoped) {
- api_set_error(err, kErrorTypeException, "not yet implemented");
- goto error;
- }
-
int r = (int)line;
int c = (int)col;
if (line2 == -1) {
@@ -834,7 +825,7 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer
extmark_set(buf, (uint32_t)ns_id, &id, (int)line, (colnr_T)col, line2, col2,
decor, decor_flags, right_gravity, opts->end_right_gravity,
!GET_BOOL_OR_TRUE(opts, set_extmark, undo_restore),
- opts->invalidate, opts->scoped, err);
+ opts->invalidate, err);
if (ERROR_SET(err)) {
decor_free(decor);
return 0;
@@ -960,7 +951,7 @@ Integer nvim_buf_add_highlight(Buffer buffer, Integer ns_id, String hl_group, In
decor.data.hl.hl_id = hl_id;
extmark_set(buf, ns, NULL, (int)line, (colnr_T)col_start, end_line, (colnr_T)col_end,
- decor, MT_FLAG_DECOR_HL, true, false, false, false, false, NULL);
+ decor, MT_FLAG_DECOR_HL, true, false, false, false, NULL);
return ns_id;
}
@@ -1038,7 +1029,7 @@ void nvim_buf_clear_namespace(Buffer buffer, Integer ns_id, Integer line_start,
/// ```
/// - on_win: called when starting to redraw a specific window.
/// ```
-/// ["win", winid, bufnr, topline, botline]
+/// ["win", winid, bufnr, toprow, botrow]
/// ```
/// - on_line: called for each buffer line being redrawn.
/// (The interaction with fold lines is subject to change)
@@ -1217,77 +1208,119 @@ String nvim__buf_debug_extmarks(Buffer buffer, Boolean keys, Boolean dot, Error
/// EXPERIMENTAL: this API will change in the future.
///
-/// Scopes a namespace to the a window, so extmarks in the namespace will be active only in the
-/// given window.
+/// Set some properties for namespace
///
-/// @param window Window handle, or 0 for current window
/// @param ns_id Namespace
-/// @return true if the namespace was added, else false
-Boolean nvim__win_add_ns(Window window, Integer ns_id, Error *err)
+/// @param opts Optional parameters to set:
+/// - wins: a list of windows to be scoped in
+///
+void nvim__ns_set(Integer ns_id, Dict(ns_opts) *opts, Error *err)
{
- win_T *win = find_window_by_handle(window, err);
- if (!win) {
- return false;
- }
-
VALIDATE_INT(ns_initialized((uint32_t)ns_id), "ns_id", ns_id, {
- return false;
+ return;
});
- set_put(uint32_t, &win->w_ns_set, (uint32_t)ns_id);
+ bool set_scoped = true;
- if (map_has(uint32_t, win->w_buffer->b_extmark_ns, (uint32_t)ns_id)) {
- changed_window_setting(win);
- }
+ if (HAS_KEY(opts, ns_opts, wins)) {
+ if (opts->wins.size == 0) {
+ set_scoped = false;
+ }
- return true;
-}
+ Set(ptr_t) windows = SET_INIT;
+ for (size_t i = 0; i < opts->wins.size; i++) {
+ Integer win = opts->wins.items[i].data.integer;
-/// EXPERIMENTAL: this API will change in the future.
-///
-/// Gets the namespace scopes for a given window.
-///
-/// @param window Window handle, or 0 for current window
-/// @return a list of namespaces ids
-ArrayOf(Integer) nvim__win_get_ns(Window window, Arena *arena, Error *err)
-{
- win_T *win = find_window_by_handle(window, err);
- if (!win) {
- return (Array)ARRAY_DICT_INIT;
+ win_T *wp = find_window_by_handle((Window)win, err);
+ if (!wp) {
+ return;
+ }
+
+ set_put(ptr_t, &windows, wp);
+ }
+
+ FOR_ALL_TAB_WINDOWS(tp, wp) {
+ if (set_has(ptr_t, &windows, wp) && !set_has(uint32_t, &wp->w_ns_set, (uint32_t)ns_id)) {
+ set_put(uint32_t, &wp->w_ns_set, (uint32_t)ns_id);
+
+ if (map_has(uint32_t, wp->w_buffer->b_extmark_ns, (uint32_t)ns_id)) {
+ changed_window_setting(wp);
+ }
+ }
+
+ if (set_has(uint32_t, &wp->w_ns_set, (uint32_t)ns_id) && !set_has(ptr_t, &windows, wp)) {
+ set_del(uint32_t, &wp->w_ns_set, (uint32_t)ns_id);
+
+ if (map_has(uint32_t, wp->w_buffer->b_extmark_ns, (uint32_t)ns_id)) {
+ changed_window_setting(wp);
+ }
+ }
+ }
+
+ set_destroy(ptr_t, &windows);
}
- Array rv = arena_array(arena, set_size(&win->w_ns_set));
- uint32_t i;
- set_foreach(&win->w_ns_set, i, {
- ADD_C(rv, INTEGER_OBJ((Integer)(i)));
- });
+ if (set_scoped && !set_has(uint32_t, &namespace_localscope, (uint32_t)ns_id)) {
+ set_put(uint32_t, &namespace_localscope, (uint32_t)ns_id);
- return rv;
+ // When a namespace becomes scoped, any window which contains
+ // elements associated with namespace needs to be redrawn
+ FOR_ALL_TAB_WINDOWS(tp, wp) {
+ if (map_has(uint32_t, wp->w_buffer->b_extmark_ns, (uint32_t)ns_id)) {
+ changed_window_setting(wp);
+ }
+ }
+ } else if (!set_scoped && set_has(uint32_t, &namespace_localscope, (uint32_t)ns_id)) {
+ set_del(uint32_t, &namespace_localscope, (uint32_t)ns_id);
+
+ // When a namespace becomes unscoped, any window which does not
+ // contain elements associated with namespace needs to be redrawn
+ FOR_ALL_TAB_WINDOWS(tp, wp) {
+ if (map_has(uint32_t, wp->w_buffer->b_extmark_ns, (uint32_t)ns_id)) {
+ changed_window_setting(wp);
+ }
+ }
+ }
}
/// EXPERIMENTAL: this API will change in the future.
///
-/// Unscopes a namespace (un-binds it from the given scope).
+/// Get the properties for namespace
///
-/// @param window Window handle, or 0 for current window
-/// @param ns_id the namespace to remove
-/// @return true if the namespace was removed, else false
-Boolean nvim__win_del_ns(Window window, Integer ns_id, Error *err)
+/// @param ns_id Namespace
+/// @return Map defining the namespace properties, see |nvim__ns_set()|
+Dict(ns_opts) nvim__ns_get(Integer ns_id, Arena *arena, Error *err)
{
- win_T *win = find_window_by_handle(window, err);
- if (!win) {
- return false;
+ Dict(ns_opts) opts = KEYDICT_INIT;
+
+ Array windows = ARRAY_DICT_INIT;
+
+ PUT_KEY(opts, ns_opts, wins, windows);
+
+ VALIDATE_INT(ns_initialized((uint32_t)ns_id), "ns_id", ns_id, {
+ return opts;
+ });
+
+ if (!set_has(uint32_t, &namespace_localscope, (uint32_t)ns_id)) {
+ return opts;
}
- if (!set_has(uint32_t, &win->w_ns_set, (uint32_t)ns_id)) {
- return false;
+ size_t count = 0;
+ FOR_ALL_TAB_WINDOWS(tp, wp) {
+ if (set_has(uint32_t, &wp->w_ns_set, (uint32_t)ns_id)) {
+ count++;
+ }
}
- set_del(uint32_t, &win->w_ns_set, (uint32_t)ns_id);
+ windows = arena_array(arena, count);
- if (map_has(uint32_t, win->w_buffer->b_extmark_ns, (uint32_t)ns_id)) {
- changed_window_setting(win);
+ FOR_ALL_TAB_WINDOWS(tp, wp) {
+ if (set_has(uint32_t, &wp->w_ns_set, (uint32_t)ns_id)) {
+ ADD(windows, INTEGER_OBJ(wp->handle));
+ }
}
- return true;
+ PUT_KEY(opts, ns_opts, wins, windows);
+
+ return opts;
}
diff --git a/src/nvim/api/extmark.h b/src/nvim/api/extmark.h
index 124feaabfb..af2d51c95c 100644
--- a/src/nvim/api/extmark.h
+++ b/src/nvim/api/extmark.h
@@ -4,14 +4,29 @@
#include "nvim/api/keysets_defs.h" // IWYU pragma: keep
#include "nvim/api/private/defs.h" // IWYU pragma: keep
+#include "nvim/buffer_defs.h"
#include "nvim/decoration_defs.h" // IWYU pragma: keep
#include "nvim/macros_defs.h"
#include "nvim/map_defs.h"
#include "nvim/types_defs.h"
EXTERN Map(String, int) namespace_ids INIT( = MAP_INIT);
+/// Non-global namespaces. A locally-scoped namespace may be "orphaned" if all
+/// window(s) it was scoped to, are destroyed. Such orphans are tracked here to
+/// avoid being mistaken as "global scope".
+EXTERN Set(uint32_t) namespace_localscope INIT( = SET_INIT);
EXTERN handle_T next_namespace_id INIT( = 1);
+/// Returns true if the namespace is global or scoped in the given window.
+static inline bool ns_in_win(uint32_t ns_id, win_T *wp)
+{
+ if (!set_has(uint32_t, &namespace_localscope, ns_id)) {
+ return true;
+ }
+
+ return set_has(uint32_t, &wp->w_ns_set, ns_id);
+}
+
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "api/extmark.h.generated.h"
#endif
diff --git a/src/nvim/api/keysets_defs.h b/src/nvim/api/keysets_defs.h
index 00d8aa8428..cc2ef981b5 100644
--- a/src/nvim/api/keysets_defs.h
+++ b/src/nvim/api/keysets_defs.h
@@ -387,3 +387,8 @@ typedef struct {
Window win;
Buffer buf;
} Dict(redraw);
+
+typedef struct {
+ OptionalKeys is_set__ns_opts_;
+ Array wins;
+} Dict(ns_opts);
diff --git a/src/nvim/api/options.c b/src/nvim/api/options.c
index d9bc0ccc92..5adaff8449 100644
--- a/src/nvim/api/options.c
+++ b/src/nvim/api/options.c
@@ -54,6 +54,10 @@ static int validate_option_value_args(Dict(option) *opts, char *name, OptIndex *
}
if (HAS_KEY_X(opts, buf)) {
+ VALIDATE(!(HAS_KEY_X(opts, scope) && *scope == OPT_GLOBAL), "%s",
+ "cannot use both global 'scope' and 'buf'", {
+ return FAIL;
+ });
*scope = OPT_LOCAL;
*req_scope = kOptReqBuf;
*from = find_buffer_by_handle(opts->buf, err);
@@ -68,11 +72,6 @@ static int validate_option_value_args(Dict(option) *opts, char *name, OptIndex *
return FAIL;
});
- VALIDATE((!HAS_KEY_X(opts, scope) || !HAS_KEY_X(opts, buf)), "%s",
- "cannot use both 'scope' and 'buf'", {
- return FAIL;
- });
-
VALIDATE((!HAS_KEY_X(opts, win) || !HAS_KEY_X(opts, buf)),
"%s", "cannot use both 'buf' and 'win'", {
return FAIL;
diff --git a/src/nvim/api/private/validate.c b/src/nvim/api/private/validate.c
index e198c671eb..9fd7d3bfa6 100644
--- a/src/nvim/api/private/validate.c
+++ b/src/nvim/api/private/validate.c
@@ -17,7 +17,7 @@ void api_err_invalid(Error *err, const char *name, const char *val_s, int64_t va
char *has_space = strchr(name, ' ');
// No value.
- if (val_s && val_s[0] == '\0') {
+ if (val_s && val_s[0] == NUL) {
api_set_error(err, errtype, has_space ? "Invalid %s" : "Invalid '%s'", name);
return;
}
diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c
index 52ab18cbff..26dc223948 100644
--- a/src/nvim/api/vim.c
+++ b/src/nvim/api/vim.c
@@ -28,6 +28,7 @@
#include "nvim/cursor.h"
#include "nvim/decoration.h"
#include "nvim/drawscreen.h"
+#include "nvim/errors.h"
#include "nvim/eval.h"
#include "nvim/eval/typval.h"
#include "nvim/eval/typval_defs.h"
@@ -313,7 +314,7 @@ void nvim_feedkeys(String keys, String mode, Boolean escape_ks)
keys_esc = keys.data;
}
if (lowlevel) {
- input_enqueue_raw(cstr_as_string(keys_esc));
+ input_enqueue_raw(keys_esc, strlen(keys_esc));
} else {
ins_typebuf(keys_esc, (remap ? REMAP_YES : REMAP_NONE),
insert ? 0 : typebuf.tb_len, !typed, false);
diff --git a/src/nvim/api/vimscript.c b/src/nvim/api/vimscript.c
index 477cbe2428..124c26d175 100644
--- a/src/nvim/api/vimscript.c
+++ b/src/nvim/api/vimscript.c
@@ -109,7 +109,7 @@ String exec_impl(uint64_t channel_id, String src, Dict(exec_opts) *opts, Error *
// redir usually (except :echon) prepends a newline.
if (s.data[0] == '\n') {
memmove(s.data, s.data + 1, s.size - 1);
- s.data[s.size - 1] = '\0';
+ s.data[s.size - 1] = NUL;
s.size = s.size - 1;
}
return s; // Caller will free the memory.
diff --git a/src/nvim/api/win_config.c b/src/nvim/api/win_config.c
index 70235d8db6..f0b90d8512 100644
--- a/src/nvim/api/win_config.c
+++ b/src/nvim/api/win_config.c
@@ -17,6 +17,7 @@
#include "nvim/decoration.h"
#include "nvim/decoration_defs.h"
#include "nvim/drawscreen.h"
+#include "nvim/errors.h"
#include "nvim/eval/window.h"
#include "nvim/extmark_defs.h"
#include "nvim/globals.h"
diff --git a/src/nvim/api/window.c b/src/nvim/api/window.c
index 54a19513db..92dc9dc7e3 100644
--- a/src/nvim/api/window.c
+++ b/src/nvim/api/window.c
@@ -13,6 +13,7 @@
#include "nvim/buffer_defs.h"
#include "nvim/cursor.h"
#include "nvim/drawscreen.h"
+#include "nvim/errors.h"
#include "nvim/eval/window.h"
#include "nvim/ex_docmd.h"
#include "nvim/gettext_defs.h"
diff --git a/src/nvim/arglist.c b/src/nvim/arglist.c
index 4d493c9d03..700bfc1655 100644
--- a/src/nvim/arglist.c
+++ b/src/nvim/arglist.c
@@ -13,6 +13,7 @@
#include "nvim/buffer_defs.h"
#include "nvim/charset.h"
#include "nvim/cmdexpand_defs.h"
+#include "nvim/errors.h"
#include "nvim/eval/typval.h"
#include "nvim/eval/typval_defs.h"
#include "nvim/eval/window.h"
diff --git a/src/nvim/autocmd.c b/src/nvim/autocmd.c
index c5d81d4cd2..ebed3e6f03 100644
--- a/src/nvim/autocmd.c
+++ b/src/nvim/autocmd.c
@@ -15,6 +15,7 @@
#include "nvim/charset.h"
#include "nvim/cmdexpand_defs.h"
#include "nvim/cursor.h"
+#include "nvim/errors.h"
#include "nvim/eval.h"
#include "nvim/eval/typval.h"
#include "nvim/eval/userfunc.h"
@@ -710,7 +711,7 @@ char *au_event_disable(char *what)
if (*what == ',' && *p_ei == NUL) {
STRCPY(new_ei, what + 1);
} else {
- STRCAT(new_ei, what);
+ strcat(new_ei, what);
}
set_option_direct(kOptEventignore, CSTR_AS_OPTVAL(new_ei), 0, SID_NONE);
xfree(new_ei);
@@ -823,11 +824,11 @@ void do_autocmd(exarg_T *eap, char *arg_in, int forceit)
continue;
}
- invalid_flags |= arg_autocmd_flag_get(&once, &cmd, "++once", 6);
- invalid_flags |= arg_autocmd_flag_get(&nested, &cmd, "++nested", 8);
+ invalid_flags |= arg_autocmd_flag_get(&once, &cmd, S_LEN("++once"));
+ invalid_flags |= arg_autocmd_flag_get(&nested, &cmd, S_LEN("++nested"));
// Check the deprecated "nested" flag.
- invalid_flags |= arg_autocmd_flag_get(&nested, &cmd, "nested", 6);
+ invalid_flags |= arg_autocmd_flag_get(&nested, &cmd, S_LEN("nested"));
}
if (invalid_flags) {
@@ -1244,7 +1245,7 @@ void ex_doautoall(exarg_T *eap)
bool check_nomodeline(char **argp)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
{
- if (strncmp(*argp, "<nomodeline>", 12) == 0) {
+ if (strncmp(*argp, S_LEN("<nomodeline>")) == 0) {
*argp = skipwhite(*argp + 12);
return false;
}
@@ -2358,7 +2359,7 @@ theend:
bool aupat_is_buflocal(const char *pat, int patlen)
FUNC_ATTR_PURE
{
- return patlen >= 8 && strncmp(pat, "<buffer", 7) == 0 && (pat)[patlen - 1] == '>';
+ return patlen >= 8 && strncmp(pat, S_LEN("<buffer")) == 0 && (pat)[patlen - 1] == '>';
}
int aupat_get_buflocal_nr(const char *pat, int patlen)
diff --git a/src/nvim/base64.c b/src/nvim/base64.c
index a645c64fe3..99d3c5a33e 100644
--- a/src/nvim/base64.c
+++ b/src/nvim/base64.c
@@ -4,6 +4,7 @@
#include <string.h>
#include "auto/config.h" // IWYU pragma: keep
+#include "nvim/ascii_defs.h"
#include "nvim/base64.h"
#include "nvim/memory.h"
@@ -125,7 +126,7 @@ char *base64_encode(const char *src, size_t src_len)
dest[out_i] = '=';
}
- dest[out_len] = '\0';
+ dest[out_len] = NUL;
return dest;
}
@@ -141,6 +142,7 @@ char *base64_encode(const char *src, size_t src_len)
/// @param [out] out_lenp Returns the length of the decoded string
/// @return Decoded string
char *base64_decode(const char *src, size_t src_len, size_t *out_lenp)
+ FUNC_ATTR_NONNULL_ALL
{
assert(src != NULL);
assert(out_lenp != NULL);
diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c
index 39d0d24d47..3f4e7047f9 100644
--- a/src/nvim/buffer.c
+++ b/src/nvim/buffer.c
@@ -43,6 +43,7 @@
#include "nvim/diff.h"
#include "nvim/digraph.h"
#include "nvim/drawscreen.h"
+#include "nvim/errors.h"
#include "nvim/eval.h"
#include "nvim/eval/typval.h"
#include "nvim/eval/vars.h"
@@ -2076,6 +2077,7 @@ void free_buf_options(buf_T *buf, bool free_p_ff)
clear_string_option(&buf->b_p_lop);
clear_string_option(&buf->b_p_cinsd);
clear_string_option(&buf->b_p_cinw);
+ clear_string_option(&buf->b_p_cot);
clear_string_option(&buf->b_p_cpt);
clear_string_option(&buf->b_p_cfu);
callback_free(&buf->b_cfu_cb);
@@ -3848,8 +3850,8 @@ static int chk_modeline(linenr_T lnum, int flags)
int prev = -1;
for (s = ml_get(lnum); *s != NUL; s++) {
if (prev == -1 || ascii_isspace(prev)) {
- if ((prev != -1 && strncmp(s, "ex:", 3) == 0)
- || strncmp(s, "vi:", 3) == 0) {
+ if ((prev != -1 && strncmp(s, S_LEN("ex:")) == 0)
+ || strncmp(s, S_LEN("vi:")) == 0) {
break;
}
// Accept both "vim" and "Vim".
@@ -3865,7 +3867,7 @@ static int chk_modeline(linenr_T lnum, int flags)
if (*e == ':'
&& (s[0] != 'V'
- || strncmp(skipwhite(e + 1), "set", 3) == 0)
+ || strncmp(skipwhite(e + 1), S_LEN("set")) == 0)
&& (s[3] == ':'
|| (VIM_VERSION_100 >= vers && isdigit((uint8_t)s[3]))
|| (VIM_VERSION_100 < vers && s[3] == '<')
@@ -3914,8 +3916,8 @@ static int chk_modeline(linenr_T lnum, int flags)
// "vi:set opt opt opt: foo" -- foo not interpreted
// "vi:opt opt opt: foo" -- foo interpreted
// Accept "se" for compatibility with Elvis.
- if (strncmp(s, "set ", 4) == 0
- || strncmp(s, "se ", 3) == 0) {
+ if (strncmp(s, S_LEN("set ")) == 0
+ || strncmp(s, S_LEN("se ")) == 0) {
if (*e != ':') { // no terminating ':'?
break;
}
@@ -4207,7 +4209,7 @@ int buf_open_scratch(handle_T bufnr, char *bufname)
bool buf_is_empty(buf_T *buf)
{
- return buf->b_ml.ml_line_count == 1 && *ml_get_buf(buf, 1) == '\0';
+ return buf->b_ml.ml_line_count == 1 && *ml_get_buf(buf, 1) == NUL;
}
/// Increment b:changedtick value
diff --git a/src/nvim/buffer_defs.h b/src/nvim/buffer_defs.h
index 512247047c..221a86a907 100644
--- a/src/nvim/buffer_defs.h
+++ b/src/nvim/buffer_defs.h
@@ -533,6 +533,8 @@ struct file_buffer {
char *b_p_cinsd; ///< 'cinscopedecls'
char *b_p_com; ///< 'comments'
char *b_p_cms; ///< 'commentstring'
+ char *b_p_cot; ///< 'completeopt' local value
+ unsigned b_cot_flags; ///< flags for 'completeopt'
char *b_p_cpt; ///< 'complete'
#ifdef BACKSLASH_IN_FILENAME
char *b_p_csl; ///< 'completeslash'
diff --git a/src/nvim/bufwrite.c b/src/nvim/bufwrite.c
index 27de03954a..5522ab1ca3 100644
--- a/src/nvim/bufwrite.c
+++ b/src/nvim/bufwrite.c
@@ -18,6 +18,7 @@
#include "nvim/bufwrite.h"
#include "nvim/change.h"
#include "nvim/drawscreen.h"
+#include "nvim/errors.h"
#include "nvim/eval.h"
#include "nvim/eval/typval_defs.h"
#include "nvim/ex_cmds.h"
@@ -1065,7 +1066,7 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en
bool whole = (start == 1 && end == buf->b_ml.ml_line_count);
bool write_undo_file = false;
context_sha256_T sha_ctx;
- unsigned bkc = get_bkc_value(buf);
+ unsigned bkc = get_bkc_flags(buf);
if (fname == NULL || *fname == NUL) { // safety check
return FAIL;
diff --git a/src/nvim/change.c b/src/nvim/change.c
index 05772d39e9..6c979df1fe 100644
--- a/src/nvim/change.c
+++ b/src/nvim/change.c
@@ -1723,12 +1723,12 @@ bool open_line(int dir, int flags, int second_line_indent, bool *did_do_comment)
// Below, set_indent(newindent, SIN_INSERT) will insert the
// whitespace needed before the comment char.
for (int i = 0; i < padding; i++) {
- STRCAT(leader, " ");
+ strcat(leader, " ");
less_cols--;
newcol++;
}
}
- STRCAT(leader, p_extra);
+ strcat(leader, p_extra);
p_extra = leader;
did_ai = true; // So truncating blanks works with comments
less_cols -= lead_len;
diff --git a/src/nvim/channel.c b/src/nvim/channel.c
index 41635747f8..e3df12abbe 100644
--- a/src/nvim/channel.c
+++ b/src/nvim/channel.c
@@ -13,6 +13,7 @@
#include "nvim/autocmd_defs.h"
#include "nvim/buffer_defs.h"
#include "nvim/channel.h"
+#include "nvim/errors.h"
#include "nvim/eval.h"
#include "nvim/eval/encode.h"
#include "nvim/eval/typval.h"
@@ -38,8 +39,6 @@
#include "nvim/os/os_defs.h"
#include "nvim/os/shell.h"
#include "nvim/path.h"
-#include "nvim/rbuffer.h"
-#include "nvim/rbuffer_defs.h"
#include "nvim/terminal.h"
#include "nvim/types_defs.h"
@@ -126,19 +125,19 @@ bool channel_close(uint64_t id, ChannelPart part, const char **error)
*error = e_invstream;
return false;
}
- stream_may_close(&chan->stream.socket);
+ rstream_may_close(&chan->stream.socket);
break;
case kChannelStreamProc:
proc = &chan->stream.proc;
if (part == kChannelPartStdin || close_main) {
- stream_may_close(&proc->in);
+ wstream_may_close(&proc->in);
}
if (part == kChannelPartStdout || close_main) {
- stream_may_close(&proc->out);
+ rstream_may_close(&proc->out);
}
if (part == kChannelPartStderr || part == kChannelPartAll) {
- stream_may_close(&proc->err);
+ rstream_may_close(&proc->err);
}
if (proc->type == kProcessTypePty && part == kChannelPartAll) {
pty_process_close_master(&chan->stream.pty);
@@ -148,10 +147,10 @@ bool channel_close(uint64_t id, ChannelPart part, const char **error)
case kChannelStreamStdio:
if (part == kChannelPartStdin || close_main) {
- stream_may_close(&chan->stream.stdio.in);
+ rstream_may_close(&chan->stream.stdio.in);
}
if (part == kChannelPartStdout || close_main) {
- stream_may_close(&chan->stream.stdio.out);
+ wstream_may_close(&chan->stream.stdio.out);
}
if (part == kChannelPartStderr) {
*error = e_invstream;
@@ -431,7 +430,7 @@ Channel *channel_job_start(char **argv, const char *exepath, CallbackReader on_s
wstream_init(&proc->in, 0);
}
if (has_out) {
- rstream_init(&proc->out, 0);
+ rstream_init(&proc->out);
}
if (rpc) {
@@ -446,7 +445,7 @@ Channel *channel_job_start(char **argv, const char *exepath, CallbackReader on_s
if (has_err) {
callback_reader_start(&chan->on_stderr, "stderr");
- rstream_init(&proc->err, 0);
+ rstream_init(&proc->err);
rstream_start(&proc->err, on_job_stderr, chan);
}
@@ -480,10 +479,10 @@ uint64_t channel_connect(bool tcp, const char *address, bool rpc, CallbackReader
return 0;
}
- channel->stream.socket.internal_close_cb = close_cb;
- channel->stream.socket.internal_data = channel;
- wstream_init(&channel->stream.socket, 0);
- rstream_init(&channel->stream.socket, 0);
+ channel->stream.socket.s.internal_close_cb = close_cb;
+ channel->stream.socket.s.internal_data = channel;
+ wstream_init(&channel->stream.socket.s, 0);
+ rstream_init(&channel->stream.socket);
if (rpc) {
rpc_start(channel);
@@ -505,10 +504,10 @@ void channel_from_connection(SocketWatcher *watcher)
{
Channel *channel = channel_alloc(kChannelStreamSocket);
socket_watcher_accept(watcher, &channel->stream.socket);
- channel->stream.socket.internal_close_cb = close_cb;
- channel->stream.socket.internal_data = channel;
- wstream_init(&channel->stream.socket, 0);
- rstream_init(&channel->stream.socket, 0);
+ channel->stream.socket.s.internal_close_cb = close_cb;
+ channel->stream.socket.s.internal_data = channel;
+ wstream_init(&channel->stream.socket.s, 0);
+ rstream_init(&channel->stream.socket);
rpc_start(channel);
channel_create_event(channel, watcher->addr);
}
@@ -553,7 +552,7 @@ uint64_t channel_from_stdio(bool rpc, CallbackReader on_output, const char **err
dup2(STDERR_FILENO, STDIN_FILENO);
}
#endif
- rstream_init_fd(&main_loop, &channel->stream.stdio.in, stdin_dup_fd, 0);
+ rstream_init_fd(&main_loop, &channel->stream.stdio.in, stdin_dup_fd);
wstream_init_fd(&main_loop, &channel->stream.stdio.out, stdout_dup_fd, 0);
if (rpc) {
@@ -640,58 +639,45 @@ static inline list_T *buffer_to_tv_list(const char *const buf, const size_t len)
list_T *const l = tv_list_alloc(kListLenMayKnow);
// Empty buffer should be represented by [''], encode_list_write() thinks
// empty list is fine for the case.
- tv_list_append_string(l, "", 0);
+ tv_list_append_string(l, S_LEN(""));
if (len > 0) {
encode_list_write(l, buf, len);
}
return l;
}
-void on_channel_data(Stream *stream, RBuffer *buf, size_t count, void *data, bool eof)
+size_t on_channel_data(RStream *stream, const char *buf, size_t count, void *data, bool eof)
{
Channel *chan = data;
- on_channel_output(stream, chan, buf, eof, &chan->on_data);
+ return on_channel_output(stream, chan, buf, count, eof, &chan->on_data);
}
-void on_job_stderr(Stream *stream, RBuffer *buf, size_t count, void *data, bool eof)
+size_t on_job_stderr(RStream *stream, const char *buf, size_t count, void *data, bool eof)
{
Channel *chan = data;
- on_channel_output(stream, chan, buf, eof, &chan->on_stderr);
+ return on_channel_output(stream, chan, buf, count, eof, &chan->on_stderr);
}
-static void on_channel_output(Stream *stream, Channel *chan, RBuffer *buf, bool eof,
- CallbackReader *reader)
+static size_t on_channel_output(RStream *stream, Channel *chan, const char *buf, size_t count,
+ bool eof, CallbackReader *reader)
{
- size_t count;
- char *output = rbuffer_read_ptr(buf, &count);
-
if (chan->term) {
- if (!eof) {
- char *p = output;
- char *end = output + count;
+ if (count) {
+ const char *p = buf;
+ const char *end = buf + count;
while (p < end) {
// Don't pass incomplete UTF-8 sequences to libvterm. #16245
// Composing chars can be passed separately, so utf_ptr2len_len() is enough.
int clen = utf_ptr2len_len(p, (int)(end - p));
if (clen > end - p) {
- count = (size_t)(p - output);
+ count = (size_t)(p - buf);
break;
}
p += clen;
}
}
- terminal_receive(chan->term, output, count);
- }
-
- if (count) {
- rbuffer_consumed(buf, count);
- }
- // Move remaining data to start of buffer, so the buffer can never wrap around.
- rbuffer_reset(buf);
-
- if (callback_reader_set(*reader)) {
- ga_concat_len(&reader->buffer, output, count);
+ terminal_receive(chan->term, buf, count);
}
if (eof) {
@@ -699,8 +685,11 @@ static void on_channel_output(Stream *stream, Channel *chan, RBuffer *buf, bool
}
if (callback_reader_set(*reader)) {
+ ga_concat_len(&reader->buffer, buf, count);
schedule_channel_event(chan);
}
+
+ return count;
}
/// schedule the necessary callbacks to be invoked as a deferred event
@@ -864,7 +853,7 @@ static void term_resize(uint16_t width, uint16_t height, void *data)
static inline void term_delayed_free(void **argv)
{
Channel *chan = argv[0];
- if (chan->stream.proc.in.pending_reqs || chan->stream.proc.out.pending_reqs) {
+ if (chan->stream.proc.in.pending_reqs || chan->stream.proc.out.s.pending_reqs) {
multiqueue_put(chan->events, term_delayed_free, chan);
return;
}
diff --git a/src/nvim/channel.h b/src/nvim/channel.h
index 35d369e513..72480db0d5 100644
--- a/src/nvim/channel.h
+++ b/src/nvim/channel.h
@@ -30,7 +30,7 @@ struct Channel {
Process proc;
LibuvProcess uv;
PtyProcess pty;
- Stream socket;
+ RStream socket;
StdioPair stdio;
StderrState err;
InternalState internal;
@@ -73,7 +73,7 @@ static inline Stream *channel_instream(Channel *chan)
return &chan->stream.proc.in;
case kChannelStreamSocket:
- return &chan->stream.socket;
+ return &chan->stream.socket.s;
case kChannelStreamStdio:
return &chan->stream.stdio.out;
@@ -85,10 +85,10 @@ static inline Stream *channel_instream(Channel *chan)
abort();
}
-static inline Stream *channel_outstream(Channel *chan)
+static inline RStream *channel_outstream(Channel *chan)
REAL_FATTR_NONNULL_ALL;
-static inline Stream *channel_outstream(Channel *chan)
+static inline RStream *channel_outstream(Channel *chan)
{
switch (chan->streamtype) {
case kChannelStreamProc:
diff --git a/src/nvim/channel_defs.h b/src/nvim/channel_defs.h
index d4f1895420..2df6edea7a 100644
--- a/src/nvim/channel_defs.h
+++ b/src/nvim/channel_defs.h
@@ -30,7 +30,7 @@ typedef enum {
} ChannelStdinMode;
typedef struct {
- Stream in;
+ RStream in;
Stream out;
} StdioPair;
diff --git a/src/nvim/charset.c b/src/nvim/charset.c
index c611d4cfd6..430f6b15fe 100644
--- a/src/nvim/charset.c
+++ b/src/nvim/charset.c
@@ -1470,7 +1470,7 @@ start:
*dst++ = *p++;
}
}
- *dst = '\0';
+ *dst = NUL;
}
}
@@ -1492,6 +1492,6 @@ char *backslash_halve_save(const char *p)
*dst++ = *p++;
}
}
- *dst = '\0';
+ *dst = NUL;
return res;
}
diff --git a/src/nvim/cmdexpand.c b/src/nvim/cmdexpand.c
index 808df44941..fdb452aee4 100644
--- a/src/nvim/cmdexpand.c
+++ b/src/nvim/cmdexpand.c
@@ -19,6 +19,7 @@
#include "nvim/cmdexpand.h"
#include "nvim/cmdhist.h"
#include "nvim/drawscreen.h"
+#include "nvim/errors.h"
#include "nvim/eval.h"
#include "nvim/eval/funcs.h"
#include "nvim/eval/typval.h"
@@ -2246,7 +2247,7 @@ static const char *set_one_cmd_context(expand_T *xp, const char *buff)
// Does command allow "++argopt" argument?
if (ea.argt & EX_ARGOPT) {
- while (*arg != NUL && strncmp(arg, "++", 2) == 0) {
+ while (*arg != NUL && strncmp(arg, S_LEN("++")) == 0) {
p = arg + 2;
while (*p && !ascii_isspace(*p)) {
MB_PTR_ADV(p);
@@ -2773,7 +2774,7 @@ static int ExpandFromContext(expand_T *xp, char *pat, char ***matches, int *numM
// When expanding a function name starting with s:, match the <SNR>nr_
// prefix.
char *tofree = NULL;
- if (xp->xp_context == EXPAND_USER_FUNC && strncmp(pat, "^s:", 3) == 0) {
+ if (xp->xp_context == EXPAND_USER_FUNC && strncmp(pat, S_LEN("^s:")) == 0) {
const size_t len = strlen(pat) + 20;
tofree = xmalloc(len);
@@ -3074,7 +3075,7 @@ static void *call_user_expand_func(user_expand_func_T user_expand_func, expand_T
typval_T args[4];
const sctx_T save_current_sctx = current_sctx;
- if (xp->xp_arg == NULL || xp->xp_arg[0] == '\0' || xp->xp_line == NULL) {
+ if (xp->xp_arg == NULL || xp->xp_arg[0] == NUL || xp->xp_line == NULL) {
return NULL;
}
@@ -3256,7 +3257,7 @@ void globpath(char *path, char *file, garray_T *ga, int expand_options, bool dir
copy_option_part(&path, buf, MAXPATHL, ",");
if (strlen(buf) + strlen(file) + 2 < MAXPATHL) {
add_pathsep(buf);
- STRCAT(buf, file);
+ strcat(buf, file);
char **p;
int num_p = 0;
@@ -3563,7 +3564,7 @@ void f_getcompletion(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
if (xpc.xp_context == EXPAND_USER_DEFINED) {
// Must be "custom,funcname" pattern
- if (strncmp(type, "custom,", 7) != 0) {
+ if (strncmp(type, S_LEN("custom,")) != 0) {
semsg(_(e_invarg2), type);
return;
}
@@ -3573,7 +3574,7 @@ void f_getcompletion(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
if (xpc.xp_context == EXPAND_USER_LIST) {
// Must be "customlist,funcname" pattern
- if (strncmp(type, "customlist,", 11) != 0) {
+ if (strncmp(type, S_LEN("customlist,")) != 0) {
semsg(_(e_invarg2), type);
return;
}
diff --git a/src/nvim/cmdhist.c b/src/nvim/cmdhist.c
index 983ab8b59b..ab05ae1cfc 100644
--- a/src/nvim/cmdhist.c
+++ b/src/nvim/cmdhist.c
@@ -11,6 +11,7 @@
#include "nvim/charset.h"
#include "nvim/cmdexpand_defs.h"
#include "nvim/cmdhist.h"
+#include "nvim/errors.h"
#include "nvim/eval/typval.h"
#include "nvim/ex_cmds.h"
#include "nvim/ex_cmds_defs.h"
diff --git a/src/nvim/context.c b/src/nvim/context.c
index 95e2618f62..b8eecfbb16 100644
--- a/src/nvim/context.c
+++ b/src/nvim/context.c
@@ -261,7 +261,7 @@ static inline void ctx_save_funcs(Context *ctx, bool scriptonly)
HASHTAB_ITER(func_tbl_get(), hi, {
const char *const name = hi->hi_key;
- bool islambda = (strncmp(name, "<lambda>", 8) == 0);
+ bool islambda = (strncmp(name, S_LEN("<lambda>")) == 0);
bool isscript = ((uint8_t)name[0] == K_SPECIAL);
if (!islambda && (!scriptonly || isscript)) {
@@ -299,7 +299,7 @@ static inline void ctx_restore_funcs(Context *ctx)
static inline Array sbuf_to_array(msgpack_sbuffer sbuf, Arena *arena)
{
list_T *const list = tv_list_alloc(kListLenMayKnow);
- tv_list_append_string(list, "", 0);
+ tv_list_append_string(list, S_LEN(""));
if (sbuf.size > 0) {
encode_list_write(list, sbuf.data, sbuf.size);
}
diff --git a/src/nvim/debugger.c b/src/nvim/debugger.c
index 7d87b61ce5..ffbeee7f7a 100644
--- a/src/nvim/debugger.c
+++ b/src/nvim/debugger.c
@@ -13,6 +13,7 @@
#include "nvim/cmdexpand_defs.h"
#include "nvim/debugger.h"
#include "nvim/drawscreen.h"
+#include "nvim/errors.h"
#include "nvim/eval.h"
#include "nvim/eval/typval.h"
#include "nvim/eval/typval_defs.h"
@@ -520,18 +521,18 @@ static int dbg_parsearg(char *arg, garray_T *gap)
struct debuggy *bp = &DEBUGGY(gap, gap->ga_len);
// Find "func" or "file".
- if (strncmp(p, "func", 4) == 0) {
+ if (strncmp(p, S_LEN("func")) == 0) {
bp->dbg_type = DBG_FUNC;
- } else if (strncmp(p, "file", 4) == 0) {
+ } else if (strncmp(p, S_LEN("file")) == 0) {
bp->dbg_type = DBG_FILE;
- } else if (gap != &prof_ga && strncmp(p, "here", 4) == 0) {
+ } else if (gap != &prof_ga && strncmp(p, S_LEN("here")) == 0) {
if (curbuf->b_ffname == NULL) {
emsg(_(e_noname));
return FAIL;
}
bp->dbg_type = DBG_FILE;
here = true;
- } else if (gap != &prof_ga && strncmp(p, "expr", 4) == 0) {
+ } else if (gap != &prof_ga && strncmp(p, S_LEN("expr")) == 0) {
bp->dbg_type = DBG_EXPR;
} else {
semsg(_(e_invarg2), p);
@@ -558,7 +559,7 @@ static int dbg_parsearg(char *arg, garray_T *gap)
}
if (bp->dbg_type == DBG_FUNC) {
- bp->dbg_name = xstrdup(strncmp(p, "g:", 2) == 0 ? p + 2 : p);
+ bp->dbg_name = xstrdup(strncmp(p, S_LEN("g:")) == 0 ? p + 2 : p);
} else if (here) {
bp->dbg_name = xstrdup(curbuf->b_ffname);
} else if (bp->dbg_type == DBG_EXPR) {
diff --git a/src/nvim/decoration.c b/src/nvim/decoration.c
index 303d0318b5..0cf02d96da 100644
--- a/src/nvim/decoration.c
+++ b/src/nvim/decoration.c
@@ -15,6 +15,7 @@
#include "nvim/drawscreen.h"
#include "nvim/extmark.h"
#include "nvim/fold.h"
+#include "nvim/globals.h"
#include "nvim/grid.h"
#include "nvim/grid_defs.h"
#include "nvim/highlight.h"
@@ -88,7 +89,7 @@ void bufhl_add_hl_pos_offset(buf_T *buf, int src_id, int hl_id, lpos_T pos_start
extmark_set(buf, (uint32_t)src_id, NULL,
(int)lnum - 1, hl_start, (int)lnum - 1 + end_off, hl_end,
- decor, MT_FLAG_DECOR_HL, true, false, true, false, false, NULL);
+ decor, MT_FLAG_DECOR_HL, true, false, true, false, NULL);
}
}
@@ -184,6 +185,21 @@ void buf_put_decor(buf_T *buf, DecorInline decor, int row, int row2)
}
}
+/// When displaying signs in the 'number' column, if the width of the number
+/// column is less than 2, then force recomputing the width after placing or
+/// unplacing the first sign in "buf".
+static void may_force_numberwidth_recompute(buf_T *buf, bool unplace)
+{
+ FOR_ALL_TAB_WINDOWS(tp, wp) {
+ if (wp->w_buffer == buf
+ && wp->w_minscwidth == SCL_NUM
+ && (wp->w_p_nu || wp->w_p_rnu)
+ && (unplace || wp->w_nrwidth_width < 2)) {
+ wp->w_nrwidth_line_count = 0;
+ }
+ }
+}
+
static int sign_add_id = 0;
void buf_put_decor_sh(buf_T *buf, DecorSignHighlight *sh, int row1, int row2)
{
@@ -191,6 +207,7 @@ void buf_put_decor_sh(buf_T *buf, DecorSignHighlight *sh, int row1, int row2)
sh->sign_add_id = sign_add_id++;
if (sh->text[0]) {
buf_signcols_count_range(buf, row1, row2, 1, kFalse);
+ may_force_numberwidth_recompute(buf, false);
}
}
}
@@ -218,6 +235,7 @@ void buf_remove_decor_sh(buf_T *buf, int row1, int row2, DecorSignHighlight *sh)
if (buf_meta_total(buf, kMTMetaSignText)) {
buf_signcols_count_range(buf, row1, row2, -1, kFalse);
} else {
+ may_force_numberwidth_recompute(buf, true);
buf->b_signcols.resized = true;
buf->b_signcols.max = buf->b_signcols.count[0] = 0;
}
@@ -580,7 +598,7 @@ int decor_redraw_col(win_T *wp, int col, int win_col, bool hidden, DecorState *s
break;
}
- if (!mt_scoped_in_win(mark, wp)) {
+ if (!ns_in_win(mark.ns, wp)) {
goto next_mark;
}
@@ -729,7 +747,7 @@ void decor_redraw_signs(win_T *wp, buf_T *buf, int row, SignTextAttrs sattrs[],
break;
}
if (!mt_end(mark) && !mt_invalid(mark) && mt_decor_sign(mark)
- && mt_scoped_in_win(mark, wp)) {
+ && ns_in_win(mark.ns, wp)) {
DecorSignHighlight *sh = decor_find_sign(mt_decor(mark));
num_text += (sh->text[0] != NUL);
kv_push(signs, ((SignItem){ sh, mark.id }));
@@ -909,7 +927,7 @@ int decor_virt_lines(win_T *wp, linenr_T lnum, VirtLines *lines, TriState has_fo
while (true) {
MTKey mark = marktree_itr_current(itr);
DecorVirtText *vt = mt_decor_virt(mark);
- if (mt_scoped_in_win(mark, wp)) {
+ if (ns_in_win(mark.ns, wp)) {
while (vt) {
if (vt->flags & kVTIsLines) {
bool above = vt->flags & kVTLinesAbove;
diff --git a/src/nvim/diff.c b/src/nvim/diff.c
index ea846b46ec..750f0c3525 100644
--- a/src/nvim/diff.c
+++ b/src/nvim/diff.c
@@ -26,6 +26,7 @@
#include "nvim/cursor.h"
#include "nvim/diff.h"
#include "nvim/drawscreen.h"
+#include "nvim/errors.h"
#include "nvim/eval.h"
#include "nvim/ex_cmds.h"
#include "nvim/ex_cmds_defs.h"
@@ -1019,7 +1020,7 @@ static int check_external_diff(diffio_T *diffio)
if (fd == NULL) {
io_error = true;
} else {
- if (fwrite("line1\n", 6, 1, fd) != 1) {
+ if (fwrite(S_LEN("line1\n"), 1, fd) != 1) {
io_error = true;
}
fclose(fd);
@@ -1028,7 +1029,7 @@ static int check_external_diff(diffio_T *diffio)
if (fd == NULL) {
io_error = true;
} else {
- if (fwrite("line2\n", 6, 1, fd) != 1) {
+ if (fwrite(S_LEN("line2\n"), 1, fd) != 1) {
io_error = true;
}
fclose(fd);
@@ -1049,8 +1050,8 @@ static int check_external_diff(diffio_T *diffio)
break;
}
- if (strncmp(linebuf, "1c1", 3) == 0
- || strncmp(linebuf, "@@ -1 +1 @@", 11) == 0) {
+ if (strncmp(linebuf, S_LEN("1c1")) == 0
+ || strncmp(linebuf, S_LEN("@@ -1 +1 @@")) == 0) {
ok = kTrue;
}
}
@@ -1272,10 +1273,10 @@ void ex_diffpatch(exarg_T *eap)
// Delete any .orig or .rej file created.
STRCPY(buf, tmp_new);
- STRCAT(buf, ".orig");
+ strcat(buf, ".orig");
os_remove(buf);
STRCPY(buf, tmp_new);
- STRCAT(buf, ".rej");
+ strcat(buf, ".rej");
os_remove(buf);
// Only continue if the output file was created.
@@ -1287,7 +1288,7 @@ void ex_diffpatch(exarg_T *eap)
} else {
if (curbuf->b_fname != NULL) {
newname = xstrnsave(curbuf->b_fname, strlen(curbuf->b_fname) + 4);
- STRCAT(newname, ".new");
+ strcat(newname, ".new");
}
// don't use a new tab page, each tab page has its own diffs
@@ -1582,13 +1583,13 @@ static bool extract_hunk(FILE *fd, diffhunk_T *hunk, diffstyle_T *diffstyle)
// @@ -1,3 +1,5 @@
if (isdigit((uint8_t)(*line))) {
*diffstyle = DIFF_ED;
- } else if ((strncmp(line, "@@ ", 3) == 0)) {
+ } else if ((strncmp(line, S_LEN("@@ ")) == 0)) {
*diffstyle = DIFF_UNIFIED;
- } else if ((strncmp(line, "--- ", 4) == 0)
+ } else if ((strncmp(line, S_LEN("--- ")) == 0)
&& (vim_fgets(line, LBUFLEN, fd) == 0)
- && (strncmp(line, "+++ ", 4) == 0)
+ && (strncmp(line, S_LEN("+++ ")) == 0)
&& (vim_fgets(line, LBUFLEN, fd) == 0)
- && (strncmp(line, "@@ ", 3) == 0)) {
+ && (strncmp(line, S_LEN("@@ ")) == 0)) {
*diffstyle = DIFF_UNIFIED;
} else {
// Format not recognized yet, skip over this line. Cygwin diff
@@ -1606,7 +1607,7 @@ static bool extract_hunk(FILE *fd, diffhunk_T *hunk, diffstyle_T *diffstyle)
}
} else {
assert(*diffstyle == DIFF_UNIFIED);
- if (strncmp(line, "@@ ", 3) != 0) {
+ if (strncmp(line, S_LEN("@@ ")) != 0) {
continue; // not the start of a diff block
}
if (parse_diff_unified(line, hunk) == FAIL) {
@@ -2472,70 +2473,70 @@ int diffopt_changed(void)
char *p = p_dip;
while (*p != NUL) {
// Note: Keep this in sync with p_dip_values
- if (strncmp(p, "filler", 6) == 0) {
+ if (strncmp(p, S_LEN("filler")) == 0) {
p += 6;
diff_flags_new |= DIFF_FILLER;
- } else if ((strncmp(p, "context:", 8) == 0) && ascii_isdigit(p[8])) {
+ } else if ((strncmp(p, S_LEN("context:")) == 0) && ascii_isdigit(p[8])) {
p += 8;
diff_context_new = getdigits_int(&p, false, diff_context_new);
- } else if (strncmp(p, "iblank", 6) == 0) {
+ } else if (strncmp(p, S_LEN("iblank")) == 0) {
p += 6;
diff_flags_new |= DIFF_IBLANK;
- } else if (strncmp(p, "icase", 5) == 0) {
+ } else if (strncmp(p, S_LEN("icase")) == 0) {
p += 5;
diff_flags_new |= DIFF_ICASE;
- } else if (strncmp(p, "iwhiteall", 9) == 0) {
+ } else if (strncmp(p, S_LEN("iwhiteall")) == 0) {
p += 9;
diff_flags_new |= DIFF_IWHITEALL;
- } else if (strncmp(p, "iwhiteeol", 9) == 0) {
+ } else if (strncmp(p, S_LEN("iwhiteeol")) == 0) {
p += 9;
diff_flags_new |= DIFF_IWHITEEOL;
- } else if (strncmp(p, "iwhite", 6) == 0) {
+ } else if (strncmp(p, S_LEN("iwhite")) == 0) {
p += 6;
diff_flags_new |= DIFF_IWHITE;
- } else if (strncmp(p, "horizontal", 10) == 0) {
+ } else if (strncmp(p, S_LEN("horizontal")) == 0) {
p += 10;
diff_flags_new |= DIFF_HORIZONTAL;
- } else if (strncmp(p, "vertical", 8) == 0) {
+ } else if (strncmp(p, S_LEN("vertical")) == 0) {
p += 8;
diff_flags_new |= DIFF_VERTICAL;
- } else if ((strncmp(p, "foldcolumn:", 11) == 0) && ascii_isdigit(p[11])) {
+ } else if ((strncmp(p, S_LEN("foldcolumn:")) == 0) && ascii_isdigit(p[11])) {
p += 11;
diff_foldcolumn_new = getdigits_int(&p, false, diff_foldcolumn_new);
- } else if (strncmp(p, "hiddenoff", 9) == 0) {
+ } else if (strncmp(p, S_LEN("hiddenoff")) == 0) {
p += 9;
diff_flags_new |= DIFF_HIDDEN_OFF;
- } else if (strncmp(p, "closeoff", 8) == 0) {
+ } else if (strncmp(p, S_LEN("closeoff")) == 0) {
p += 8;
diff_flags_new |= DIFF_CLOSE_OFF;
- } else if (strncmp(p, "followwrap", 10) == 0) {
+ } else if (strncmp(p, S_LEN("followwrap")) == 0) {
p += 10;
diff_flags_new |= DIFF_FOLLOWWRAP;
- } else if (strncmp(p, "indent-heuristic", 16) == 0) {
+ } else if (strncmp(p, S_LEN("indent-heuristic")) == 0) {
p += 16;
diff_indent_heuristic = XDF_INDENT_HEURISTIC;
- } else if (strncmp(p, "internal", 8) == 0) {
+ } else if (strncmp(p, S_LEN("internal")) == 0) {
p += 8;
diff_flags_new |= DIFF_INTERNAL;
- } else if (strncmp(p, "algorithm:", 10) == 0) {
+ } else if (strncmp(p, S_LEN("algorithm:")) == 0) {
// Note: Keep this in sync with p_dip_algorithm_values.
p += 10;
- if (strncmp(p, "myers", 5) == 0) {
+ if (strncmp(p, S_LEN("myers")) == 0) {
p += 5;
diff_algorithm_new = 0;
- } else if (strncmp(p, "minimal", 7) == 0) {
+ } else if (strncmp(p, S_LEN("minimal")) == 0) {
p += 7;
diff_algorithm_new = XDF_NEED_MINIMAL;
- } else if (strncmp(p, "patience", 8) == 0) {
+ } else if (strncmp(p, S_LEN("patience")) == 0) {
p += 8;
diff_algorithm_new = XDF_PATIENCE_DIFF;
- } else if (strncmp(p, "histogram", 9) == 0) {
+ } else if (strncmp(p, S_LEN("histogram")) == 0) {
p += 9;
diff_algorithm_new = XDF_HISTOGRAM_DIFF;
} else {
return FAIL;
}
- } else if ((strncmp(p, "linematch:", 10) == 0) && ascii_isdigit(p[10])) {
+ } else if ((strncmp(p, S_LEN("linematch:")) == 0) && ascii_isdigit(p[10])) {
p += 10;
linematch_lines_new = getdigits_int(&p, false, linematch_lines_new);
diff_flags_new |= DIFF_LINEMATCH;
diff --git a/src/nvim/digraph.c b/src/nvim/digraph.c
index a358a1723a..26fb77df30 100644
--- a/src/nvim/digraph.c
+++ b/src/nvim/digraph.c
@@ -12,6 +12,7 @@
#include "nvim/charset.h"
#include "nvim/digraph.h"
#include "nvim/drawscreen.h"
+#include "nvim/errors.h"
#include "nvim/eval.h"
#include "nvim/eval/typval.h"
#include "nvim/ex_cmds_defs.h"
diff --git a/src/nvim/drawline.c b/src/nvim/drawline.c
index 4d534d78a2..4247705896 100644
--- a/src/nvim/drawline.c
+++ b/src/nvim/drawline.c
@@ -465,6 +465,7 @@ static void draw_sign(bool nrcol, win_T *wp, winlinevars_T *wlv, int sign_idx, i
int fill = nrcol ? number_width(wp) + 1 : SIGN_WIDTH;
draw_col_fill(wlv, schar_from_ascii(' '), fill, attr);
int sign_pos = wlv->off - SIGN_WIDTH - (int)nrcol;
+ assert(sign_pos >= 0);
linebuf_char[sign_pos] = sattr.text[0];
linebuf_char[sign_pos + 1] = sattr.text[1];
} else {
@@ -1421,7 +1422,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s
line = ml_get_buf(wp->w_buffer, lnum);
ptr = line + linecol;
- if (len == 0 || (int)wp->w_cursor.col > ptr - line) {
+ if (len == 0 || wp->w_cursor.col > linecol) {
// no bad word found at line start, don't check until end of a
// word
spell_hlf = HLF_COUNT;
diff --git a/src/nvim/drawscreen.c b/src/nvim/drawscreen.c
index 039bbd219c..88e1f302da 100644
--- a/src/nvim/drawscreen.c
+++ b/src/nvim/drawscreen.c
@@ -931,13 +931,7 @@ int showmode(void)
msg_ext_clear(true);
}
- // Don't make non-flushed message part of the showmode and reset global
- // variables before flushing to to avoid recursiveness.
- bool draw_mode = redraw_mode;
- bool clear_cmd = clear_cmdline;
- redraw_cmdline = false;
- redraw_mode = false;
- clear_cmdline = false;
+ // Don't make non-flushed message part of the showmode.
msg_ext_ui_flush();
msg_grid_validate();
@@ -960,8 +954,8 @@ int showmode(void)
msg_check_for_delay(false);
// if the cmdline is more than one line high, erase top lines
- bool need_clear = clear_cmd;
- if (clear_cmd && cmdline_row < Rows - 1) {
+ bool need_clear = clear_cmdline;
+ if (clear_cmdline && cmdline_row < Rows - 1) {
msg_clr_cmdline(); // will reset clear_cmdline
}
@@ -1083,7 +1077,7 @@ int showmode(void)
}
mode_displayed = true;
- if (need_clear || clear_cmd || draw_mode) {
+ if (need_clear || clear_cmdline || redraw_mode) {
msg_clr_eos();
}
msg_didout = false; // overwrite this message
@@ -1092,10 +1086,10 @@ int showmode(void)
msg_no_more = false;
lines_left = save_lines_left;
need_wait_return = nwr_save; // never ask for hit-return for this
- } else if (clear_cmd && msg_silent == 0) {
+ } else if (clear_cmdline && msg_silent == 0) {
// Clear the whole command line. Will reset "clear_cmdline".
msg_clr_cmdline();
- } else if (draw_mode) {
+ } else if (redraw_mode) {
msg_pos_mode();
msg_clr_eos();
}
@@ -1118,6 +1112,10 @@ int showmode(void)
grid_line_flush();
}
+ redraw_cmdline = false;
+ redraw_mode = false;
+ clear_cmdline = false;
+
return length;
}
@@ -1548,6 +1546,7 @@ static void win_update(win_T *wp)
// Force redraw when width of 'number' or 'relativenumber' column changes.
if (wp->w_nrwidth != nrwidth_new) {
type = UPD_NOT_VALID;
+ changed_line_abv_curs_win(wp);
wp->w_nrwidth = nrwidth_new;
} else {
// Set mod_top to the first line that needs displaying because of
diff --git a/src/nvim/edit.c b/src/nvim/edit.c
index 220b92d099..889f445c3d 100644
--- a/src/nvim/edit.c
+++ b/src/nvim/edit.c
@@ -18,6 +18,7 @@
#include "nvim/digraph.h"
#include "nvim/drawscreen.h"
#include "nvim/edit.h"
+#include "nvim/errors.h"
#include "nvim/eval.h"
#include "nvim/eval/typval_defs.h"
#include "nvim/ex_cmds_defs.h"
@@ -473,7 +474,8 @@ static int insert_check(VimState *state)
if (curwin->w_wcol < s->mincol - tabstop_at(get_nolist_virtcol(),
curbuf->b_p_ts,
- curbuf->b_p_vts_array)
+ curbuf->b_p_vts_array,
+ false)
&& curwin->w_wrow == curwin->w_height_inner - 1 - get_scrolloff_value(curwin)
&& (curwin->w_cursor.lnum != curwin->w_topline
|| curwin->w_topfill > 0)) {
@@ -3093,7 +3095,7 @@ bool in_cinkeys(int keytyped, int when, bool line_is_empty)
if (try_match && keytyped == 'e' && curwin->w_cursor.col >= 4) {
p = get_cursor_line_ptr();
if (skipwhite(p) == p + curwin->w_cursor.col - 4
- && strncmp(p + curwin->w_cursor.col - 4, "else", 4) == 0) {
+ && strncmp(p + curwin->w_cursor.col - 4, S_LEN("else")) == 0) {
return true;
}
}
@@ -4419,18 +4421,30 @@ static bool ins_tab(void)
// Delete following spaces.
int i = cursor->col - fpos.col;
if (i > 0) {
- STRMOVE(ptr, ptr + i);
+ if (!(State & VREPLACE_FLAG)) {
+ char *newp = xmalloc((size_t)(curbuf->b_ml.ml_line_len - i));
+ ptrdiff_t col = ptr - curbuf->b_ml.ml_line_ptr;
+ if (col > 0) {
+ memmove(newp, ptr - col, (size_t)col);
+ }
+ memmove(newp + col, ptr + i, (size_t)(curbuf->b_ml.ml_line_len - col - i));
+ if (curbuf->b_ml.ml_flags & (ML_LINE_DIRTY | ML_ALLOCATED)) {
+ xfree(curbuf->b_ml.ml_line_ptr);
+ }
+ curbuf->b_ml.ml_line_ptr = newp;
+ curbuf->b_ml.ml_line_len -= i;
+ curbuf->b_ml.ml_flags = (curbuf->b_ml.ml_flags | ML_LINE_DIRTY) & ~ML_EMPTY;
+ inserted_bytes(fpos.lnum, change_col,
+ cursor->col - change_col, fpos.col - change_col);
+ } else {
+ STRMOVE(ptr, ptr + i);
+ }
// correct replace stack.
if ((State & REPLACE_FLAG) && !(State & VREPLACE_FLAG)) {
for (temp = i; --temp >= 0;) {
replace_join(repl_off);
}
}
- if (!(State & VREPLACE_FLAG)) {
- curbuf->b_ml.ml_line_len -= i;
- inserted_bytes(fpos.lnum, change_col,
- cursor->col - change_col, fpos.col - change_col);
- }
}
cursor->col -= i;
diff --git a/src/nvim/errors.h b/src/nvim/errors.h
new file mode 100644
index 0000000000..39095db952
--- /dev/null
+++ b/src/nvim/errors.h
@@ -0,0 +1,193 @@
+#pragma once
+
+#include "nvim/gettext_defs.h"
+#include "nvim/macros_defs.h"
+
+//
+// Shared error messages. Excludes errors only used once and debugging messages.
+//
+// uncrustify:off
+EXTERN const char e_abort[] INIT(= N_("E470: Command aborted"));
+EXTERN const char e_afterinit[] INIT(= N_("E905: Cannot set this option after startup"));
+EXTERN const char e_api_spawn_failed[] INIT(= N_("E903: Could not spawn API job"));
+EXTERN const char e_argreq[] INIT(= N_("E471: Argument required"));
+EXTERN const char e_backslash[] INIT(= N_("E10: \\ should be followed by /, ? or &"));
+EXTERN const char e_cmdwin[] INIT(= N_("E11: Invalid in command-line window; <CR> executes, CTRL-C quits"));
+EXTERN const char e_curdir[] INIT(= N_("E12: Command not allowed in secure mode in current dir or tag search"));
+EXTERN const char e_invalid_buffer_name_str[] INIT(= N_("E158: Invalid buffer name: %s"));
+EXTERN const char e_command_too_recursive[] INIT(= N_("E169: Command too recursive"));
+EXTERN const char e_buffer_is_not_loaded[] INIT(= N_("E681: Buffer is not loaded"));
+EXTERN const char e_endif[] INIT(= N_("E171: Missing :endif"));
+EXTERN const char e_endtry[] INIT(= N_("E600: Missing :endtry"));
+EXTERN const char e_endwhile[] INIT(= N_("E170: Missing :endwhile"));
+EXTERN const char e_endfor[] INIT(= N_("E170: Missing :endfor"));
+EXTERN const char e_while[] INIT(= N_("E588: :endwhile without :while"));
+EXTERN const char e_for[] INIT(= N_("E588: :endfor without :for"));
+EXTERN const char e_exists[] INIT(= N_("E13: File exists (add ! to override)"));
+EXTERN const char e_failed[] INIT(= N_("E472: Command failed"));
+EXTERN const char e_internal[] INIT(= N_("E473: Internal error"));
+EXTERN const char e_intern2[] INIT(= N_("E685: Internal error: %s"));
+EXTERN const char e_interr[] INIT(= N_("Interrupted"));
+EXTERN const char e_invarg[] INIT(= N_("E474: Invalid argument"));
+EXTERN const char e_invarg2[] INIT(= N_("E475: Invalid argument: %s"));
+EXTERN const char e_invargval[] INIT(= N_("E475: Invalid value for argument %s"));
+EXTERN const char e_invargNval[] INIT(= N_("E475: Invalid value for argument %s: %s"));
+EXTERN const char e_duparg2[] INIT(= N_("E983: Duplicate argument: %s"));
+EXTERN const char e_invexpr2[] INIT(= N_("E15: Invalid expression: \"%s\""));
+EXTERN const char e_invrange[] INIT(= N_("E16: Invalid range"));
+EXTERN const char e_invcmd[] INIT(= N_("E476: Invalid command"));
+EXTERN const char e_isadir2[] INIT(= N_("E17: \"%s\" is a directory"));
+EXTERN const char e_no_spell[] INIT(= N_("E756: Spell checking is not possible"));
+EXTERN const char e_invchan[] INIT(= N_("E900: Invalid channel id"));
+EXTERN const char e_invchanjob[] INIT(= N_("E900: Invalid channel id: not a job"));
+EXTERN const char e_jobtblfull[] INIT(= N_("E901: Job table is full"));
+EXTERN const char e_jobspawn[] INIT(= N_("E903: Process failed to start: %s: \"%s\""));
+EXTERN const char e_channotpty[] INIT(= N_("E904: channel is not a pty"));
+EXTERN const char e_stdiochan2[] INIT(= N_("E905: Couldn't open stdio channel: %s"));
+EXTERN const char e_invstream[] INIT(= N_("E906: invalid stream for channel"));
+EXTERN const char e_invstreamrpc[] INIT(= N_("E906: invalid stream for rpc channel, use 'rpc'"));
+EXTERN const char e_streamkey[] INIT(= N_("E5210: dict key '%s' already set for buffered stream in channel %" PRIu64));
+EXTERN const char e_libcall[] INIT(= N_("E364: Library call failed for \"%s()\""));
+EXTERN const char e_fsync[] INIT(= N_("E667: Fsync failed: %s"));
+EXTERN const char e_mkdir[] INIT(= N_("E739: Cannot create directory %s: %s"));
+EXTERN const char e_markinval[] INIT(= N_("E19: Mark has invalid line number"));
+EXTERN const char e_marknotset[] INIT(= N_("E20: Mark not set"));
+EXTERN const char e_modifiable[] INIT(= N_("E21: Cannot make changes, 'modifiable' is off"));
+EXTERN const char e_nesting[] INIT(= N_("E22: Scripts nested too deep"));
+EXTERN const char e_noalt[] INIT(= N_("E23: No alternate file"));
+EXTERN const char e_noabbr[] INIT(= N_("E24: No such abbreviation"));
+EXTERN const char e_nobang[] INIT(= N_("E477: No ! allowed"));
+EXTERN const char e_nogroup[] INIT(= N_("E28: No such highlight group name: %s"));
+EXTERN const char e_noinstext[] INIT(= N_("E29: No inserted text yet"));
+EXTERN const char e_nolastcmd[] INIT(= N_("E30: No previous command line"));
+EXTERN const char e_nomap[] INIT(= N_("E31: No such mapping"));
+EXTERN const char e_nomatch[] INIT(= N_("E479: No match"));
+EXTERN const char e_nomatch2[] INIT(= N_("E480: No match: %s"));
+EXTERN const char e_noname[] INIT(= N_("E32: No file name"));
+EXTERN const char e_nopresub[] INIT(= N_("E33: No previous substitute regular expression"));
+EXTERN const char e_noprev[] INIT(= N_("E34: No previous command"));
+EXTERN const char e_noprevre[] INIT(= N_("E35: No previous regular expression"));
+EXTERN const char e_norange[] INIT(= N_("E481: No range allowed"));
+EXTERN const char e_noroom[] INIT(= N_("E36: Not enough room"));
+EXTERN const char e_notmp[] INIT(= N_("E483: Can't get temp file name"));
+EXTERN const char e_notopen[] INIT(= N_("E484: Can't open file %s"));
+EXTERN const char e_notopen_2[] INIT(= N_("E484: Can't open file %s: %s"));
+EXTERN const char e_notread[] INIT(= N_("E485: Can't read file %s"));
+EXTERN const char e_null[] INIT(= N_("E38: Null argument"));
+EXTERN const char e_number_exp[] INIT(= N_("E39: Number expected"));
+EXTERN const char e_openerrf[] INIT(= N_("E40: Can't open errorfile %s"));
+EXTERN const char e_outofmem[] INIT(= N_("E41: Out of memory!"));
+EXTERN const char e_patnotf[] INIT(= N_("Pattern not found"));
+EXTERN const char e_patnotf2[] INIT(= N_("E486: Pattern not found: %s"));
+EXTERN const char e_positive[] INIT(= N_("E487: Argument must be positive"));
+EXTERN const char e_prev_dir[] INIT(= N_("E459: Cannot go back to previous directory"));
+
+EXTERN const char e_no_errors[] INIT(= N_("E42: No Errors"));
+EXTERN const char e_loclist[] INIT(= N_("E776: No location list"));
+EXTERN const char e_re_damg[] INIT(= N_("E43: Damaged match string"));
+EXTERN const char e_re_corr[] INIT(= N_("E44: Corrupted regexp program"));
+EXTERN const char e_readonly[] INIT(= N_("E45: 'readonly' option is set (add ! to override)"));
+EXTERN const char e_letwrong[] INIT(= N_("E734: Wrong variable type for %s="));
+EXTERN const char e_illvar[] INIT(= N_("E461: Illegal variable name: %s"));
+EXTERN const char e_cannot_mod[] INIT(= N_("E995: Cannot modify existing variable"));
+EXTERN const char e_readonlyvar[] INIT(= N_("E46: Cannot change read-only variable \"%.*s\""));
+EXTERN const char e_stringreq[] INIT(= N_("E928: String required"));
+EXTERN const char e_dictreq[] INIT(= N_("E715: Dictionary required"));
+EXTERN const char e_blobidx[] INIT(= N_("E979: Blob index out of range: %" PRId64));
+EXTERN const char e_invalblob[] INIT(= N_("E978: Invalid operation for Blob"));
+EXTERN const char e_toomanyarg[] INIT(= N_("E118: Too many arguments for function: %s"));
+EXTERN const char e_toofewarg[] INIT(= N_("E119: Not enough arguments for function: %s"));
+EXTERN const char e_dictkey[] INIT(= N_("E716: Key not present in Dictionary: \"%s\""));
+EXTERN const char e_dictkey_len[] INIT(= N_("E716: Key not present in Dictionary: \"%.*s\""));
+EXTERN const char e_listreq[] INIT(= N_("E714: List required"));
+EXTERN const char e_listblobreq[] INIT(= N_("E897: List or Blob required"));
+EXTERN const char e_listdictarg[] INIT(= N_("E712: Argument of %s must be a List or Dictionary"));
+EXTERN const char e_listdictblobarg[] INIT(= N_("E896: Argument of %s must be a List, Dictionary or Blob"));
+EXTERN const char e_readerrf[] INIT(= N_("E47: Error while reading errorfile"));
+EXTERN const char e_sandbox[] INIT(= N_("E48: Not allowed in sandbox"));
+EXTERN const char e_secure[] INIT(= N_("E523: Not allowed here"));
+EXTERN const char e_textlock[] INIT(= N_("E565: Not allowed to change text or change window"));
+EXTERN const char e_screenmode[] INIT(= N_("E359: Screen mode setting not supported"));
+EXTERN const char e_scroll[] INIT(= N_("E49: Invalid scroll size"));
+EXTERN const char e_shellempty[] INIT(= N_("E91: 'shell' option is empty"));
+EXTERN const char e_signdata[] INIT(= N_("E255: Couldn't read in sign data!"));
+EXTERN const char e_swapclose[] INIT(= N_("E72: Close error on swap file"));
+EXTERN const char e_toocompl[] INIT(= N_("E74: Command too complex"));
+EXTERN const char e_longname[] INIT(= N_("E75: Name too long"));
+EXTERN const char e_toomsbra[] INIT(= N_("E76: Too many ["));
+EXTERN const char e_toomany[] INIT(= N_("E77: Too many file names"));
+EXTERN const char e_trailing[] INIT(= N_("E488: Trailing characters"));
+EXTERN const char e_trailing_arg[] INIT(= N_("E488: Trailing characters: %s"));
+EXTERN const char e_umark[] INIT(= N_("E78: Unknown mark"));
+EXTERN const char e_wildexpand[] INIT(= N_("E79: Cannot expand wildcards"));
+EXTERN const char e_winheight[] INIT(= N_("E591: 'winheight' cannot be smaller than 'winminheight'"));
+EXTERN const char e_winwidth[] INIT(= N_("E592: 'winwidth' cannot be smaller than 'winminwidth'"));
+EXTERN const char e_write[] INIT(= N_("E80: Error while writing"));
+EXTERN const char e_zerocount[] INIT(= N_("E939: Positive count required"));
+EXTERN const char e_usingsid[] INIT(= N_("E81: Using <SID> not in a script context"));
+EXTERN const char e_missingparen[] INIT(= N_("E107: Missing parentheses: %s"));
+EXTERN const char e_empty_buffer[] INIT(= N_("E749: Empty buffer"));
+EXTERN const char e_nobufnr[] INIT(= N_("E86: Buffer %" PRId64 " does not exist"));
+
+EXTERN const char e_str_not_inside_function[] INIT(= N_("E193: %s not inside a function"));
+
+EXTERN const char e_invalpat[] INIT(= N_("E682: Invalid search pattern or delimiter"));
+EXTERN const char e_bufloaded[] INIT(= N_("E139: File is loaded in another buffer"));
+EXTERN const char e_notset[] INIT(= N_("E764: Option '%s' is not set"));
+EXTERN const char e_invalidreg[] INIT(= N_("E850: Invalid register name"));
+EXTERN const char e_dirnotf[] INIT(= N_("E919: Directory not found in '%s': \"%s\""));
+EXTERN const char e_au_recursive[] INIT(= N_("E952: Autocommand caused recursive behavior"));
+EXTERN const char e_menu_only_exists_in_another_mode[]
+INIT(= N_("E328: Menu only exists in another mode"));
+EXTERN const char e_autocmd_close[] INIT(= N_("E813: Cannot close autocmd window"));
+EXTERN const char e_listarg[] INIT(= N_("E686: Argument of %s must be a List"));
+EXTERN const char e_unsupportedoption[] INIT(= N_("E519: Option not supported"));
+EXTERN const char e_fnametoolong[] INIT(= N_("E856: Filename too long"));
+EXTERN const char e_using_float_as_string[] INIT(= N_("E806: Using a Float as a String"));
+EXTERN const char e_cannot_edit_other_buf[] INIT(= N_("E788: Not allowed to edit another buffer now"));
+EXTERN const char e_using_number_as_bool_nr[] INIT(= N_("E1023: Using a Number as a Bool: %d"));
+EXTERN const char e_not_callable_type_str[] INIT(= N_("E1085: Not a callable type: %s"));
+EXTERN const char e_auabort[] INIT(= N_("E855: Autocommands caused command to abort"));
+
+EXTERN const char e_api_error[] INIT(= N_("E5555: API call: %s"));
+
+EXTERN const char e_luv_api_disabled[] INIT(= N_("E5560: %s must not be called in a lua loop callback"));
+
+EXTERN const char e_floatonly[] INIT(= N_("E5601: Cannot close window, only floating window would remain"));
+EXTERN const char e_floatexchange[] INIT(= N_("E5602: Cannot exchange or rotate float"));
+
+EXTERN const char e_cannot_define_autocommands_for_all_events[] INIT(= N_("E1155: Cannot define autocommands for ALL events"));
+
+EXTERN const char e_resulting_text_too_long[] INIT(= N_("E1240: Resulting text too long"));
+
+EXTERN const char e_line_number_out_of_range[] INIT(= N_("E1247: Line number out of range"));
+
+EXTERN const char e_highlight_group_name_invalid_char[] INIT(= N_("E5248: Invalid character in group name"));
+
+EXTERN const char e_highlight_group_name_too_long[] INIT(= N_("E1249: Highlight group name too long"));
+
+EXTERN const char e_invalid_column_number_nr[] INIT( = N_("E964: Invalid column number: %ld"));
+EXTERN const char e_invalid_line_number_nr[] INIT(= N_("E966: Invalid line number: %ld"));
+
+EXTERN const char e_stray_closing_curly_str[]
+INIT(= N_("E1278: Stray '}' without a matching '{': %s"));
+EXTERN const char e_missing_close_curly_str[]
+INIT(= N_("E1279: Missing '}': %s"));
+
+EXTERN const char e_val_too_large[] INIT(= N_("E1510: Value too large: %s"));
+
+EXTERN const char e_undobang_cannot_redo_or_move_branch[]
+INIT(= N_("E5767: Cannot use :undo! to redo or move to a different undo branch"));
+
+EXTERN const char e_winfixbuf_cannot_go_to_buffer[]
+INIT(= N_("E1513: Cannot switch buffer. 'winfixbuf' is enabled"));
+
+EXTERN const char e_trustfile[] INIT(= N_("E5570: Cannot update trust file: %s"));
+
+EXTERN const char e_unknown_option2[] INIT(= N_("E355: Unknown option: %s"));
+
+EXTERN const char top_bot_msg[] INIT(= N_("search hit TOP, continuing at BOTTOM"));
+EXTERN const char bot_top_msg[] INIT(= N_("search hit BOTTOM, continuing at TOP"));
+
+EXTERN const char line_msg[] INIT(= N_(" line "));
+// uncrustify:on
diff --git a/src/nvim/eval.c b/src/nvim/eval.c
index 48a58228ae..4cff5e1582 100644
--- a/src/nvim/eval.c
+++ b/src/nvim/eval.c
@@ -24,6 +24,7 @@
#include "nvim/cmdhist.h"
#include "nvim/cursor.h"
#include "nvim/edit.h"
+#include "nvim/errors.h"
#include "nvim/eval.h"
#include "nvim/eval/encode.h"
#include "nvim/eval/executor.h"
@@ -1218,7 +1219,7 @@ int call_vim_function(const char *func, int argc, typval_T *argv, typval_T *rett
int len = (int)strlen(func);
partial_T *pt = NULL;
- if (len >= 6 && !memcmp(func, "v:lua.", 6)) {
+ if (len >= 6 && !memcmp(func, S_LEN("v:lua."))) {
func += 6;
len = check_luafunc_name(func, false);
if (len == 0) {
@@ -2160,7 +2161,7 @@ void del_menutrans_vars(void)
{
hash_lock(&globvarht);
HASHTAB_ITER(&globvarht, hi, {
- if (strncmp(hi->hi_key, "menutrans_", 10) == 0) {
+ if (strncmp(hi->hi_key, S_LEN("menutrans_")) == 0) {
delete_var(&globvarht, hi);
}
});
@@ -3273,7 +3274,7 @@ static int eval7(char **arg, typval_T *rettv, evalarg_T *const evalarg, bool wan
check_vars(s, (size_t)len);
// If evaluate is false rettv->v_type was not set, but it's needed
// in handle_subscript() to parse v:lua, so set it here.
- if (rettv->v_type == VAR_UNKNOWN && !evaluate && strnequal(s, "v:lua.", 6)) {
+ if (rettv->v_type == VAR_UNKNOWN && !evaluate && strnequal(s, S_LEN("v:lua."))) {
rettv->v_type = VAR_PARTIAL;
rettv->vval.v_partial = vvlua_partial;
rettv->vval.v_partial->pt_refcount++;
@@ -3482,7 +3483,7 @@ static int eval_method(char **const arg, typval_T *const rettv, evalarg_T *const
int len;
char *name = *arg;
char *lua_funcname = NULL;
- if (strnequal(name, "v:lua.", 6)) {
+ if (strnequal(name, S_LEN("v:lua."))) {
lua_funcname = name + 6;
*arg = (char *)skip_luafunc_name(lua_funcname);
*arg = skipwhite(*arg); // to detect trailing whitespace later
@@ -5617,7 +5618,7 @@ void common_function(typval_T *argvars, typval_T *rettv, bool is_funcref)
int dict_idx = 0;
int arg_idx = 0;
list_T *list = NULL;
- if (strncmp(s, "s:", 2) == 0 || strncmp(s, "<SID>", 5) == 0) {
+ if (strncmp(s, S_LEN("s:")) == 0 || strncmp(s, S_LEN("<SID>")) == 0) {
// Expand s: and <SID> into <SNR>nr_, so that the function can
// also be called from another script. Using trans_function_name()
// would also work, but some plugins depend on the name being
@@ -6191,7 +6192,7 @@ bool callback_call(Callback *const callback, const int argcount_in, typval_T *co
case kCallbackFuncref:
name = callback->data.funcref;
int len = (int)strlen(name);
- if (len >= 6 && !memcmp(name, "v:lua.", 6)) {
+ if (len >= 6 && !memcmp(name, S_LEN("v:lua."))) {
name += 6;
len = check_luafunc_name(name, false);
if (len == 0) {
@@ -6459,7 +6460,7 @@ bool write_list(FileDescriptor *const fp, const list_T *const list, const bool b
}
}
if (!binary || TV_LIST_ITEM_NEXT(list, li) != NULL) {
- const ptrdiff_t written = file_write(fp, "\n", 1);
+ const ptrdiff_t written = file_write(fp, S_LEN("\n"));
if (written < 0) {
error = (int)written;
goto write_list_error;
@@ -7153,8 +7154,8 @@ static char *make_expanded_name(const char *in_start, char *expr_start, char *ex
retval = xmalloc(strlen(temp_result) + (size_t)(expr_start - in_start)
+ (size_t)(in_end - expr_end) + 1);
STRCPY(retval, in_start);
- STRCAT(retval, temp_result);
- STRCAT(retval, expr_end + 1);
+ strcat(retval, temp_result);
+ strcat(retval, expr_end + 1);
}
xfree(temp_result);
@@ -8909,7 +8910,7 @@ bool eval_has_provider(const char *feat, bool throw_if_fast)
char name[32]; // Normalized: "python3_compiled" => "python3".
snprintf(name, sizeof(name), "%s", feat);
- strchrsub(name, '_', '\0'); // Chop any "_xx" suffix.
+ strchrsub(name, '_', NUL); // Chop any "_xx" suffix.
char buf[256];
typval_T tv;
diff --git a/src/nvim/eval.lua b/src/nvim/eval.lua
index ceaba11f41..f5706f9553 100644
--- a/src/nvim/eval.lua
+++ b/src/nvim/eval.lua
@@ -19,7 +19,7 @@
--- @field returns_desc? string
--- @field signature? string
--- @field desc? string
---- @field params {[1]:string, [2]:string, [3]:string}[]
+--- @field params [string, string, string][]
--- @field lua? false Do not render type information
--- @field tags? string[] Extra tags
--- @field data? string Used by gen_eval.lua
@@ -3448,7 +3448,7 @@ M.funcs = {
<
]=],
name = 'getchar',
- params = {},
+ params = { { 'expr', '0|1' } },
returns = 'integer',
signature = 'getchar([{expr}])',
},
@@ -3537,7 +3537,7 @@ M.funcs = {
result is converted to a string.
]=],
name = 'getcharstr',
- params = {},
+ params = { { 'expr', '0|1' } },
returns = 'string',
signature = 'getcharstr([{expr}])',
},
@@ -4047,8 +4047,9 @@ M.funcs = {
]=],
name = 'getmarklist',
- params = { { 'buf', 'any' } },
+ params = { { 'buf', 'integer?' } },
signature = 'getmarklist([{buf}])',
+ returns = 'vim.fn.getmarklist.ret.item[]',
},
getmatches = {
args = { 0, 1 },
@@ -6080,10 +6081,21 @@ M.funcs = {
display isn't updated, e.g. in silent Ex mode)
w$ last line visible in current window (this is one
less than "w0" if no lines are visible)
- v In Visual mode: the start of the Visual area (the
- cursor is the end). When not in Visual mode
- returns the cursor position. Differs from |'<| in
- that it's updated right away.
+ v When not in Visual mode, returns the cursor
+ position. In Visual mode, returns the other end
+ of the Visual area. A good way to think about
+ this is that in Visual mode "v" and "." complement
+ each other. While "." refers to the cursor
+ position, "v" refers to where |v_o| would move the
+ cursor. As a result, you can use "v" and "."
+ together to work on all of a selection in
+ characterwise visual mode. If the cursor is at
+ the end of a characterwise visual area, "v" refers
+ to the start of the same visual area. And if the
+ cursor is at the start of a characterwise visual
+ area, "v" refers to the end of the same visual
+ area. "v" differs from |'<| and |'>| in that it's
+ updated right away.
Note that a mark in another file can be used. The line number
then applies to another buffer.
To get the column number use |col()|. To get both use
@@ -6481,7 +6493,8 @@ M.funcs = {
echo printf("Operator-pending mode bit: 0x%x", op_bit)
]],
name = 'maplist',
- params = {},
+ params = { { 'abbr', '0|1' } },
+ returns = 'table[]',
signature = 'maplist([{abbr}])',
},
mapnew = {
@@ -9142,7 +9155,16 @@ M.funcs = {
<
]=],
name = 'searchpair',
- params = {},
+ params = {
+ { 'start', 'any' },
+ { 'middle', 'any' },
+ { 'end', 'any' },
+ { 'flags', 'string' },
+ { 'skip', 'any' },
+ { 'stopline', 'any' },
+ { 'timeout', 'integer' },
+ },
+ returns = 'integer',
signature = 'searchpair({start}, {middle}, {end} [, {flags} [, {skip} [, {stopline} [, {timeout}]]]])',
},
searchpairpos = {
@@ -9159,7 +9181,16 @@ M.funcs = {
See |match-parens| for a bigger and more useful example.
]=],
name = 'searchpairpos',
- params = {},
+ params = {
+ { 'start', 'any' },
+ { 'middle', 'any' },
+ { 'end', 'any' },
+ { 'flags', 'string' },
+ { 'skip', 'any' },
+ { 'stopline', 'any' },
+ { 'timeout', 'integer' },
+ },
+ returns = '[integer, integer]',
signature = 'searchpairpos({start}, {middle}, {end} [, {flags} [, {skip} [, {stopline} [, {timeout}]]]])',
},
searchpos = {
@@ -11672,7 +11703,7 @@ M.funcs = {
]=],
name = 'synconcealed',
params = { { 'lnum', 'integer' }, { 'col', 'integer' } },
- returns = '{[1]: integer, [2]: string, [3]: integer}',
+ returns = '[integer, string, integer]',
signature = 'synconcealed({lnum}, {col})',
},
synstack = {
diff --git a/src/nvim/eval/encode.c b/src/nvim/eval/encode.c
index d35ac4eb7b..e216dbdaa6 100644
--- a/src/nvim/eval/encode.c
+++ b/src/nvim/eval/encode.c
@@ -855,7 +855,7 @@ char *encode_tv2string(typval_T *tv, size_t *len)
if (len != NULL) {
*len = (size_t)ga.ga_len;
}
- ga_append(&ga, '\0');
+ ga_append(&ga, NUL);
return (char *)ga.ga_data;
}
@@ -883,7 +883,7 @@ char *encode_tv2echo(typval_T *tv, size_t *len)
if (len != NULL) {
*len = (size_t)ga.ga_len;
}
- ga_append(&ga, '\0');
+ ga_append(&ga, NUL);
return (char *)ga.ga_data;
}
@@ -908,7 +908,7 @@ char *encode_tv2json(typval_T *tv, size_t *len)
if (len != NULL) {
*len = (size_t)ga.ga_len;
}
- ga_append(&ga, '\0');
+ ga_append(&ga, NUL);
return (char *)ga.ga_data;
}
diff --git a/src/nvim/eval/executor.c b/src/nvim/eval/executor.c
index 1b8c057d7c..3255e78d09 100644
--- a/src/nvim/eval/executor.c
+++ b/src/nvim/eval/executor.c
@@ -1,6 +1,7 @@
#include <inttypes.h>
#include <stdlib.h>
+#include "nvim/errors.h"
#include "nvim/eval.h"
#include "nvim/eval/executor.h"
#include "nvim/eval/typval.h"
diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c
index 8b22c7a797..9a1ed7dea9 100644
--- a/src/nvim/eval/funcs.c
+++ b/src/nvim/eval/funcs.c
@@ -38,6 +38,7 @@
#include "nvim/cursor.h"
#include "nvim/diff.h"
#include "nvim/edit.h"
+#include "nvim/errors.h"
#include "nvim/eval.h"
#include "nvim/eval/buffer.h"
#include "nvim/eval/decode.h"
@@ -4317,7 +4318,7 @@ static dict_T *create_environment(const dictitem_T *job_env, const bool clear_en
// Set $NVIM (in the child process) to v:servername. #3118
char *nvim_addr = get_vim_var_str(VV_SEND_SERVER);
- if (nvim_addr[0] != '\0') {
+ if (nvim_addr[0] != NUL) {
dictitem_T *dv = tv_dict_find(env, S_LEN("NVIM"));
if (dv) {
tv_dict_item_remove(env, dv);
@@ -5094,7 +5095,7 @@ static void get_matches_in_str(const char *str, regmatch_T *rmp, list_T *mlist,
// return a list with the submatches
for (int i = 1; i < NSUBEXP; i++) {
if (rmp->endp[i] == NULL) {
- tv_list_append_string(sml, "", 0);
+ tv_list_append_string(sml, S_LEN(""));
} else {
tv_list_append_string(sml, rmp->startp[i], rmp->endp[i] - rmp->startp[i]);
}
@@ -8301,7 +8302,7 @@ static void f_shiftwidth(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
if (col < 0) {
return; // type error; errmsg already given
}
- rettv->vval.v_number = get_sw_value_col(curbuf, col);
+ rettv->vval.v_number = get_sw_value_col(curbuf, col, false);
return;
}
rettv->vval.v_number = get_sw_value(curbuf);
@@ -9173,13 +9174,13 @@ static void f_termopen(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
size_t len = home_replace(NULL, NameBuff, IObuff, sizeof(IObuff), true);
// Trim slash.
if (len != 1 && (IObuff[len - 1] == '\\' || IObuff[len - 1] == '/')) {
- IObuff[len - 1] = '\0';
+ IObuff[len - 1] = NUL;
}
if (len == 1 && IObuff[0] == '/') {
// Avoid ambiguity in the URI when CWD is root directory.
IObuff[1] = '.';
- IObuff[2] = '\0';
+ IObuff[2] = NUL;
}
// Terminal URI: "term://$CWD//$PID:$CMD"
diff --git a/src/nvim/eval/typval.c b/src/nvim/eval/typval.c
index eb8c89c36e..13b31ab30f 100644
--- a/src/nvim/eval/typval.c
+++ b/src/nvim/eval/typval.c
@@ -10,6 +10,7 @@
#include "nvim/ascii_defs.h"
#include "nvim/assert_defs.h"
#include "nvim/charset.h"
+#include "nvim/errors.h"
#include "nvim/eval.h"
#include "nvim/eval/encode.h"
#include "nvim/eval/executor.h"
@@ -1823,7 +1824,7 @@ char *callback_to_string(Callback *cb, Arena *arena)
snprintf(msg, msglen, "<vim partial: %s>", cb->data.partial->pt_name);
break;
default:
- *msg = '\0';
+ *msg = NUL;
break;
}
return msg;
diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c
index 39bd63462c..122a1ac8ab 100644
--- a/src/nvim/eval/userfunc.c
+++ b/src/nvim/eval/userfunc.c
@@ -15,6 +15,7 @@
#include "nvim/charset.h"
#include "nvim/cmdexpand_defs.h"
#include "nvim/debugger.h"
+#include "nvim/errors.h"
#include "nvim/eval.h"
#include "nvim/eval/encode.h"
#include "nvim/eval/funcs.h"
@@ -264,7 +265,7 @@ static void set_ufunc_name(ufunc_T *fp, char *name)
if ((uint8_t)name[0] == K_SPECIAL) {
fp->uf_name_exp = xmalloc(strlen(name) + 3);
STRCPY(fp->uf_name_exp, "<SNR>");
- STRCAT(fp->uf_name_exp, fp->uf_name + 3);
+ strcat(fp->uf_name_exp, fp->uf_name + 3);
}
}
@@ -2061,7 +2062,7 @@ char *get_scriptlocal_funcname(char *funcname)
const int off = *funcname == 's' ? 2 : 5;
char *newname = xmalloc(strlen(sid_buf) + strlen(funcname + off) + 1);
STRCPY(newname, sid_buf);
- STRCAT(newname, funcname + off);
+ strcat(newname, funcname + off);
return newname;
}
diff --git a/src/nvim/eval/vars.c b/src/nvim/eval/vars.c
index 1c15274acc..7b93a291c4 100644
--- a/src/nvim/eval/vars.c
+++ b/src/nvim/eval/vars.c
@@ -15,6 +15,7 @@
#include "nvim/buffer_defs.h"
#include "nvim/charset.h"
#include "nvim/drawscreen.h"
+#include "nvim/errors.h"
#include "nvim/eval.h"
#include "nvim/eval/encode.h"
#include "nvim/eval/funcs.h"
diff --git a/src/nvim/eval/window.c b/src/nvim/eval/window.c
index 68de40f983..86495f1cb6 100644
--- a/src/nvim/eval/window.c
+++ b/src/nvim/eval/window.c
@@ -10,6 +10,7 @@
#include "nvim/autocmd.h"
#include "nvim/buffer.h"
#include "nvim/cursor.h"
+#include "nvim/errors.h"
#include "nvim/eval/funcs.h"
#include "nvim/eval/typval.h"
#include "nvim/eval/typval_defs.h"
@@ -271,7 +272,7 @@ static int get_winnr(tabpage_T *tp, typval_T *argvar)
// if count is not specified, default to 1
count = 1;
}
- if (endp != NULL && *endp != '\0') {
+ if (endp != NULL && *endp != NUL) {
if (strequal(endp, "j")) {
twin = win_vert_neighbor(tp, twin, false, count);
} else if (strequal(endp, "k")) {
diff --git a/src/nvim/event/defs.h b/src/nvim/event/defs.h
index 9b7d8708be..41690ead88 100644
--- a/src/nvim/event/defs.h
+++ b/src/nvim/event/defs.h
@@ -6,7 +6,6 @@
#include <uv.h>
#include "nvim/eval/typval_defs.h"
-#include "nvim/rbuffer_defs.h"
#include "nvim/types_defs.h"
enum { EVENT_HANDLER_MAX_ARGC = 10, };
@@ -55,14 +54,17 @@ struct wbuffer {
};
typedef struct stream Stream;
-/// Type of function called when the Stream buffer is filled with data
+typedef struct rstream RStream;
+/// Type of function called when the RStream buffer is filled with data
///
/// @param stream The Stream instance
-/// @param buf The associated RBuffer instance
+/// @param read_data data that was read
/// @param count Number of bytes that was read.
/// @param data User-defined data
/// @param eof If the stream reached EOF.
-typedef void (*stream_read_cb)(Stream *stream, RBuffer *buf, size_t count, void *data, bool eof);
+/// @return number of bytes which were consumed
+typedef size_t (*stream_read_cb)(RStream *stream, const char *read_data, size_t count, void *data,
+ bool eof);
/// Type of function called when the Stream has information about a write
/// request.
@@ -71,11 +73,11 @@ typedef void (*stream_read_cb)(Stream *stream, RBuffer *buf, size_t count, void
/// @param data User-defined data
/// @param status 0 on success, anything else indicates failure
typedef void (*stream_write_cb)(Stream *stream, void *data, int status);
+
typedef void (*stream_close_cb)(Stream *stream, void *data);
struct stream {
bool closed;
- bool did_eof;
union {
uv_pipe_t pipe;
uv_tcp_t tcp;
@@ -85,20 +87,32 @@ struct stream {
#endif
} uv;
uv_stream_t *uvstream;
- uv_buf_t uvbuf;
- RBuffer *buffer;
uv_file fd;
- stream_read_cb read_cb;
- stream_write_cb write_cb;
void *cb_data;
stream_close_cb close_cb, internal_close_cb;
void *close_cb_data, *internal_data;
- size_t fpos;
+ size_t pending_reqs;
+ MultiQueue *events;
+
+ // only used for writing:
+ stream_write_cb write_cb;
size_t curmem;
size_t maxmem;
- size_t pending_reqs;
+};
+
+struct rstream {
+ Stream s;
+ bool did_eof;
+ bool want_read;
+ bool pending_read;
+ bool paused_full;
+ char *buffer; // ARENA_BLOCK_SIZE
+ char *read_pos;
+ char *write_pos;
+ uv_buf_t uvbuf;
+ stream_read_cb read_cb;
size_t num_bytes;
- MultiQueue *events;
+ int64_t fpos;
};
#define ADDRESS_MAX_SIZE 256
@@ -147,7 +161,8 @@ struct process {
char **argv;
const char *exepath;
dict_T *env;
- Stream in, out, err;
+ Stream in;
+ RStream out, err;
/// Exit handler. If set, user must call process_free().
process_exit_cb cb;
internal_process_cb internal_exit_cb, internal_close_cb;
diff --git a/src/nvim/event/libuv_process.c b/src/nvim/event/libuv_process.c
index f77d686c10..0dead1f9b4 100644
--- a/src/nvim/event/libuv_process.c
+++ b/src/nvim/event/libuv_process.c
@@ -70,19 +70,19 @@ int libuv_process_spawn(LibuvProcess *uvproc)
uvproc->uvstdio[0].data.stream = (uv_stream_t *)(&proc->in.uv.pipe);
}
- if (!proc->out.closed) {
+ if (!proc->out.s.closed) {
uvproc->uvstdio[1].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE;
#ifdef MSWIN
// pipe must be readable for IOCP to work on Windows.
uvproc->uvstdio[1].flags |= proc->overlapped
? (UV_READABLE_PIPE | UV_OVERLAPPED_PIPE) : 0;
#endif
- uvproc->uvstdio[1].data.stream = (uv_stream_t *)(&proc->out.uv.pipe);
+ uvproc->uvstdio[1].data.stream = (uv_stream_t *)(&proc->out.s.uv.pipe);
}
- if (!proc->err.closed) {
+ if (!proc->err.s.closed) {
uvproc->uvstdio[2].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE;
- uvproc->uvstdio[2].data.stream = (uv_stream_t *)(&proc->err.uv.pipe);
+ uvproc->uvstdio[2].data.stream = (uv_stream_t *)(&proc->err.s.uv.pipe);
} else if (proc->fwd_err) {
uvproc->uvstdio[2].flags = UV_INHERIT_FD;
uvproc->uvstdio[2].data.fd = STDERR_FILENO;
diff --git a/src/nvim/event/process.c b/src/nvim/event/process.c
index 7460e92766..70fc31ba21 100644
--- a/src/nvim/event/process.c
+++ b/src/nvim/event/process.c
@@ -8,7 +8,9 @@
#include "nvim/event/loop.h"
#include "nvim/event/multiqueue.h"
#include "nvim/event/process.h"
+#include "nvim/event/rstream.h"
#include "nvim/event/stream.h"
+#include "nvim/event/wstream.h"
#include "nvim/globals.h"
#include "nvim/log.h"
#include "nvim/main.h"
@@ -16,7 +18,6 @@
#include "nvim/os/pty_process.h"
#include "nvim/os/shell.h"
#include "nvim/os/time.h"
-#include "nvim/rbuffer_defs.h"
#include "nvim/ui_client.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
@@ -51,15 +52,15 @@ int process_spawn(Process *proc, bool in, bool out, bool err)
}
if (out) {
- uv_pipe_init(&proc->loop->uv, &proc->out.uv.pipe, 0);
+ uv_pipe_init(&proc->loop->uv, &proc->out.s.uv.pipe, 0);
} else {
- proc->out.closed = true;
+ proc->out.s.closed = true;
}
if (err) {
- uv_pipe_init(&proc->loop->uv, &proc->err.uv.pipe, 0);
+ uv_pipe_init(&proc->loop->uv, &proc->err.s.uv.pipe, 0);
} else {
- proc->err.closed = true;
+ proc->err.s.closed = true;
}
#ifdef USE_GCOV
@@ -82,10 +83,10 @@ int process_spawn(Process *proc, bool in, bool out, bool err)
uv_close((uv_handle_t *)&proc->in.uv.pipe, NULL);
}
if (out) {
- uv_close((uv_handle_t *)&proc->out.uv.pipe, NULL);
+ uv_close((uv_handle_t *)&proc->out.s.uv.pipe, NULL);
}
if (err) {
- uv_close((uv_handle_t *)&proc->err.uv.pipe, NULL);
+ uv_close((uv_handle_t *)&proc->err.s.uv.pipe, NULL);
}
if (proc->type == kProcessTypeUv) {
@@ -106,16 +107,16 @@ int process_spawn(Process *proc, bool in, bool out, bool err)
}
if (out) {
- stream_init(NULL, &proc->out, -1, (uv_stream_t *)&proc->out.uv.pipe);
- proc->out.internal_data = proc;
- proc->out.internal_close_cb = on_process_stream_close;
+ stream_init(NULL, &proc->out.s, -1, (uv_stream_t *)&proc->out.s.uv.pipe);
+ proc->out.s.internal_data = proc;
+ proc->out.s.internal_close_cb = on_process_stream_close;
proc->refcount++;
}
if (err) {
- stream_init(NULL, &proc->err, -1, (uv_stream_t *)&proc->err.uv.pipe);
- proc->err.internal_data = proc;
- proc->err.internal_close_cb = on_process_stream_close;
+ stream_init(NULL, &proc->err.s, -1, (uv_stream_t *)&proc->err.s.uv.pipe);
+ proc->err.s.internal_data = proc;
+ proc->err.s.internal_close_cb = on_process_stream_close;
proc->refcount++;
}
@@ -148,9 +149,9 @@ void process_teardown(Loop *loop) FUNC_ATTR_NONNULL_ALL
void process_close_streams(Process *proc) FUNC_ATTR_NONNULL_ALL
{
- stream_may_close(&proc->in);
- stream_may_close(&proc->out);
- stream_may_close(&proc->err);
+ wstream_may_close(&proc->in);
+ rstream_may_close(&proc->out);
+ rstream_may_close(&proc->err);
}
/// Synchronously wait for a process to finish
@@ -337,10 +338,10 @@ static void process_close(Process *proc)
///
/// @param proc Process, for which an output stream should be flushed.
/// @param stream Stream to flush.
-static void flush_stream(Process *proc, Stream *stream)
+static void flush_stream(Process *proc, RStream *stream)
FUNC_ATTR_NONNULL_ARG(1)
{
- if (!stream || stream->closed) {
+ if (!stream || stream->s.closed) {
return;
}
@@ -350,23 +351,23 @@ static void flush_stream(Process *proc, Stream *stream)
// keeps sending data, we only accept as much data as the system buffer size.
// Otherwise this would block cleanup/teardown.
int system_buffer_size = 0;
- int err = uv_recv_buffer_size((uv_handle_t *)&stream->uv.pipe,
+ int err = uv_recv_buffer_size((uv_handle_t *)&stream->s.uv.pipe,
&system_buffer_size);
if (err) {
- system_buffer_size = (int)rbuffer_capacity(stream->buffer);
+ system_buffer_size = ARENA_BLOCK_SIZE;
}
size_t max_bytes = stream->num_bytes + (size_t)system_buffer_size;
// Read remaining data.
- while (!stream->closed && stream->num_bytes < max_bytes) {
+ while (!stream->s.closed && stream->num_bytes < max_bytes) {
// Remember number of bytes before polling
size_t num_bytes = stream->num_bytes;
// Poll for data and process the generated events.
loop_poll_events(proc->loop, 0);
- if (stream->events) {
- multiqueue_process_events(stream->events);
+ if (stream->s.events) {
+ multiqueue_process_events(stream->s.events);
}
// Stream can be closed if it is empty.
@@ -374,7 +375,7 @@ static void flush_stream(Process *proc, Stream *stream)
if (stream->read_cb && !stream->did_eof) {
// Stream callback could miss EOF handling if a child keeps the stream
// open. But only send EOF if we haven't already.
- stream->read_cb(stream, stream->buffer, 0, stream->cb_data, true);
+ stream->read_cb(stream, stream->buffer, 0, stream->s.cb_data, true);
}
break;
}
diff --git a/src/nvim/event/process.h b/src/nvim/event/process.h
index 421a470244..74b52cbbb1 100644
--- a/src/nvim/event/process.h
+++ b/src/nvim/event/process.h
@@ -21,8 +21,8 @@ static inline Process process_init(Loop *loop, ProcessType type, void *data)
.argv = NULL,
.exepath = NULL,
.in = { .closed = false },
- .out = { .closed = false },
- .err = { .closed = false },
+ .out = { .s.closed = false },
+ .err = { .s.closed = false },
.cb = NULL,
.closed = false,
.internal_close_cb = NULL,
diff --git a/src/nvim/event/rstream.c b/src/nvim/event/rstream.c
index 6b4ab472e4..71290d0c0d 100644
--- a/src/nvim/event/rstream.c
+++ b/src/nvim/event/rstream.c
@@ -11,75 +11,81 @@
#include "nvim/macros_defs.h"
#include "nvim/main.h"
#include "nvim/os/os_defs.h"
-#include "nvim/rbuffer.h"
-#include "nvim/rbuffer_defs.h"
#include "nvim/types_defs.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "event/rstream.c.generated.h"
#endif
-void rstream_init_fd(Loop *loop, Stream *stream, int fd, size_t bufsize)
+void rstream_init_fd(Loop *loop, RStream *stream, int fd)
FUNC_ATTR_NONNULL_ARG(1, 2)
{
- stream_init(loop, stream, fd, NULL);
- rstream_init(stream, bufsize);
+ stream_init(loop, &stream->s, fd, NULL);
+ rstream_init(stream);
}
-void rstream_init_stream(Stream *stream, uv_stream_t *uvstream, size_t bufsize)
+void rstream_init_stream(RStream *stream, uv_stream_t *uvstream)
FUNC_ATTR_NONNULL_ARG(1, 2)
{
- stream_init(NULL, stream, -1, uvstream);
- rstream_init(stream, bufsize);
+ stream_init(NULL, &stream->s, -1, uvstream);
+ rstream_init(stream);
}
-void rstream_init(Stream *stream, size_t bufsize)
+void rstream_init(RStream *stream)
FUNC_ATTR_NONNULL_ARG(1)
{
- stream->buffer = rbuffer_new(bufsize);
- stream->buffer->data = stream;
- stream->buffer->full_cb = on_rbuffer_full;
- stream->buffer->nonfull_cb = on_rbuffer_nonfull;
+ stream->fpos = 0;
+ stream->read_cb = NULL;
+ stream->num_bytes = 0;
+ stream->buffer = alloc_block();
+ stream->read_pos = stream->write_pos = stream->buffer;
+}
+
+void rstream_start_inner(RStream *stream)
+ FUNC_ATTR_NONNULL_ARG(1)
+{
+ if (stream->s.uvstream) {
+ uv_read_start(stream->s.uvstream, alloc_cb, read_cb);
+ } else {
+ uv_idle_start(&stream->s.uv.idle, fread_idle_cb);
+ }
}
/// Starts watching for events from a `Stream` instance.
///
/// @param stream The `Stream` instance
-void rstream_start(Stream *stream, stream_read_cb cb, void *data)
+void rstream_start(RStream *stream, stream_read_cb cb, void *data)
FUNC_ATTR_NONNULL_ARG(1)
{
stream->read_cb = cb;
- stream->cb_data = data;
- if (stream->uvstream) {
- uv_read_start(stream->uvstream, alloc_cb, read_cb);
- } else {
- uv_idle_start(&stream->uv.idle, fread_idle_cb);
+ stream->s.cb_data = data;
+ stream->want_read = true;
+ if (!stream->paused_full) {
+ rstream_start_inner(stream);
}
}
/// Stops watching for events from a `Stream` instance.
///
/// @param stream The `Stream` instance
-void rstream_stop(Stream *stream)
+void rstream_stop_inner(RStream *stream)
FUNC_ATTR_NONNULL_ALL
{
- if (stream->uvstream) {
- uv_read_stop(stream->uvstream);
+ if (stream->s.uvstream) {
+ uv_read_stop(stream->s.uvstream);
} else {
- uv_idle_stop(&stream->uv.idle);
+ uv_idle_stop(&stream->s.uv.idle);
}
}
-static void on_rbuffer_full(RBuffer *buf, void *data)
-{
- rstream_stop(data);
-}
-
-static void on_rbuffer_nonfull(RBuffer *buf, void *data)
+/// Stops watching for events from a `Stream` instance.
+///
+/// @param stream The `Stream` instance
+void rstream_stop(RStream *stream)
+ FUNC_ATTR_NONNULL_ALL
{
- Stream *stream = data;
- assert(stream->read_cb);
- rstream_start(stream, stream->read_cb, stream->cb_data);
+ rstream_stop_inner(stream);
+ stream->want_read = false;
}
// Callbacks used by libuv
@@ -87,11 +93,10 @@ static void on_rbuffer_nonfull(RBuffer *buf, void *data)
/// Called by libuv to allocate memory for reading.
static void alloc_cb(uv_handle_t *handle, size_t suggested, uv_buf_t *buf)
{
- Stream *stream = handle->data;
- // `uv_buf_t.len` happens to have different size on Windows.
- size_t write_count;
- buf->base = rbuffer_write_ptr(stream->buffer, &write_count);
- buf->len = UV_BUF_LEN(write_count);
+ RStream *stream = handle->data;
+ buf->base = stream->write_pos;
+ // `uv_buf_t.len` happens to have different size on Windows (as a treat)
+ buf->len = UV_BUF_LEN(rstream_space(stream));
}
/// Callback invoked by libuv after it copies the data into the buffer provided
@@ -99,27 +104,27 @@ static void alloc_cb(uv_handle_t *handle, size_t suggested, uv_buf_t *buf)
/// 0-length buffer.
static void read_cb(uv_stream_t *uvstream, ssize_t cnt, const uv_buf_t *buf)
{
- Stream *stream = uvstream->data;
+ RStream *stream = uvstream->data;
if (cnt <= 0) {
// cnt == 0 means libuv asked for a buffer and decided it wasn't needed:
// http://docs.libuv.org/en/latest/stream.html#c.uv_read_start.
//
- // We don't need to do anything with the RBuffer because the next call
+ // We don't need to do anything with the buffer because the next call
// to `alloc_cb` will return the same unused pointer (`rbuffer_produced`
// won't be called)
if (cnt == UV_ENOBUFS || cnt == 0) {
return;
} else if (cnt == UV_EOF && uvstream->type == UV_TTY) {
// The TTY driver might signal EOF without closing the stream
- invoke_read_cb(stream, 0, true);
+ invoke_read_cb(stream, true);
} else {
DLOG("closing Stream (%p): %s (%s)", (void *)stream,
uv_err_name((int)cnt), os_strerror((int)cnt));
// Read error or EOF, either way stop the stream and invoke the callback
// with eof == true
uv_read_stop(uvstream);
- invoke_read_cb(stream, 0, true);
+ invoke_read_cb(stream, true);
}
return;
}
@@ -127,10 +132,13 @@ static void read_cb(uv_stream_t *uvstream, ssize_t cnt, const uv_buf_t *buf)
// at this point we're sure that cnt is positive, no error occurred
size_t nread = (size_t)cnt;
stream->num_bytes += nread;
- // Data was already written, so all we need is to update 'wpos' to reflect
- // the space actually used in the buffer.
- rbuffer_produced(stream->buffer, nread);
- invoke_read_cb(stream, nread, false);
+ stream->write_pos += cnt;
+ invoke_read_cb(stream, false);
+}
+
+static size_t rstream_space(RStream *stream)
+{
+ return (size_t)((stream->buffer + ARENA_BLOCK_SIZE) - stream->write_pos);
}
/// Called by the by the 'idle' handle to emulate a reading event
@@ -141,66 +149,91 @@ static void read_cb(uv_stream_t *uvstream, ssize_t cnt, const uv_buf_t *buf)
static void fread_idle_cb(uv_idle_t *handle)
{
uv_fs_t req;
- Stream *stream = handle->data;
+ RStream *stream = handle->data;
+ stream->uvbuf.base = stream->write_pos;
// `uv_buf_t.len` happens to have different size on Windows.
- size_t write_count;
- stream->uvbuf.base = rbuffer_write_ptr(stream->buffer, &write_count);
- stream->uvbuf.len = UV_BUF_LEN(write_count);
-
- // the offset argument to uv_fs_read is int64_t, could someone really try
- // to read more than 9 quintillion (9e18) bytes?
- // upcast is meant to avoid tautological condition warning on 32 bits
- uintmax_t fpos_intmax = stream->fpos;
- if (fpos_intmax > INT64_MAX) {
- ELOG("stream offset overflow");
- preserve_exit("stream offset overflow");
- }
+ stream->uvbuf.len = UV_BUF_LEN(rstream_space(stream));
// Synchronous read
- uv_fs_read(handle->loop,
- &req,
- stream->fd,
- &stream->uvbuf,
- 1,
- (int64_t)stream->fpos,
- NULL);
+ uv_fs_read(handle->loop, &req, stream->s.fd, &stream->uvbuf, 1, stream->fpos, NULL);
uv_fs_req_cleanup(&req);
if (req.result <= 0) {
- uv_idle_stop(&stream->uv.idle);
- invoke_read_cb(stream, 0, true);
+ uv_idle_stop(&stream->s.uv.idle);
+ invoke_read_cb(stream, true);
return;
}
- // no errors (req.result (ssize_t) is positive), it's safe to cast.
- size_t nread = (size_t)req.result;
- rbuffer_produced(stream->buffer, nread);
- stream->fpos += nread;
- invoke_read_cb(stream, nread, false);
+ // no errors (req.result (ssize_t) is positive), it's safe to use.
+ stream->write_pos += req.result;
+ stream->fpos += req.result;
+ invoke_read_cb(stream, false);
}
static void read_event(void **argv)
{
- Stream *stream = argv[0];
+ RStream *stream = argv[0];
+ stream->pending_read = false;
if (stream->read_cb) {
- size_t count = (uintptr_t)argv[1];
- bool eof = (uintptr_t)argv[2];
- stream->did_eof = eof;
- stream->read_cb(stream, stream->buffer, count, stream->cb_data, eof);
+ size_t available = rstream_available(stream);
+ size_t consumed = stream->read_cb(stream, stream->read_pos, available, stream->s.cb_data,
+ stream->did_eof);
+ assert(consumed <= available);
+ rstream_consume(stream, consumed);
+ }
+ stream->s.pending_reqs--;
+ if (stream->s.closed && !stream->s.pending_reqs) {
+ stream_close_handle(&stream->s, true);
+ }
+}
+
+size_t rstream_available(RStream *stream)
+{
+ return (size_t)(stream->write_pos - stream->read_pos);
+}
+
+void rstream_consume(RStream *stream, size_t consumed)
+{
+ stream->read_pos += consumed;
+ size_t remaining = (size_t)(stream->write_pos - stream->read_pos);
+ if (remaining > 0 && stream->read_pos > stream->buffer) {
+ memmove(stream->buffer, stream->read_pos, remaining);
+ stream->read_pos = stream->buffer;
+ stream->write_pos = stream->buffer + remaining;
+ } else if (remaining == 0) {
+ stream->read_pos = stream->write_pos = stream->buffer;
}
- stream->pending_reqs--;
- if (stream->closed && !stream->pending_reqs) {
- stream_close_handle(stream);
+
+ if (stream->want_read && stream->paused_full && rstream_space(stream)) {
+ assert(stream->read_cb);
+ stream->paused_full = false;
+ rstream_start_inner(stream);
}
}
-static void invoke_read_cb(Stream *stream, size_t count, bool eof)
+static void invoke_read_cb(RStream *stream, bool eof)
{
+ stream->did_eof |= eof;
+
+ if (!rstream_space(stream)) {
+ rstream_stop_inner(stream);
+ stream->paused_full = true;
+ }
+
+ // we cannot use pending_reqs as a socket can have both pending reads and writes
+ if (stream->pending_read) {
+ return;
+ }
+
// Don't let the stream be closed before the event is processed.
- stream->pending_reqs++;
+ stream->s.pending_reqs++;
+ stream->pending_read = true;
+ CREATE_EVENT(stream->s.events, read_event, stream);
+}
- CREATE_EVENT(stream->events, read_event,
- stream, (void *)(uintptr_t *)count, (void *)(uintptr_t)eof);
+void rstream_may_close(RStream *stream)
+{
+ stream_may_close(&stream->s, true);
}
diff --git a/src/nvim/event/socket.c b/src/nvim/event/socket.c
index 4e878a2ecf..1214c3e336 100644
--- a/src/nvim/event/socket.c
+++ b/src/nvim/event/socket.c
@@ -35,7 +35,7 @@ int socket_watcher_init(Loop *loop, SocketWatcher *watcher, const char *endpoint
if (host_end && addr != host_end) {
// Split user specified address into two strings, addr(hostname) and port.
// The port part in watcher->addr will be updated later.
- *host_end = '\0';
+ *host_end = NUL;
char *port = host_end + 1;
intmax_t iport;
@@ -135,17 +135,17 @@ int socket_watcher_start(SocketWatcher *watcher, int backlog, socket_cb cb)
return 0;
}
-int socket_watcher_accept(SocketWatcher *watcher, Stream *stream)
+int socket_watcher_accept(SocketWatcher *watcher, RStream *stream)
FUNC_ATTR_NONNULL_ARG(1) FUNC_ATTR_NONNULL_ARG(2)
{
uv_stream_t *client;
if (watcher->stream->type == UV_TCP) {
- client = (uv_stream_t *)(&stream->uv.tcp);
+ client = (uv_stream_t *)(&stream->s.uv.tcp);
uv_tcp_init(watcher->uv.tcp.handle.loop, (uv_tcp_t *)client);
uv_tcp_nodelay((uv_tcp_t *)client, true);
} else {
- client = (uv_stream_t *)&stream->uv.pipe;
+ client = (uv_stream_t *)&stream->s.uv.pipe;
uv_pipe_init(watcher->uv.pipe.handle.loop, (uv_pipe_t *)client, 0);
}
@@ -156,7 +156,7 @@ int socket_watcher_accept(SocketWatcher *watcher, Stream *stream)
return result;
}
- stream_init(NULL, stream, -1, client);
+ stream_init(NULL, &stream->s, -1, client);
return 0;
}
@@ -197,7 +197,7 @@ static void connect_cb(uv_connect_t *req, int status)
}
}
-bool socket_connect(Loop *loop, Stream *stream, bool is_tcp, const char *address, int timeout,
+bool socket_connect(Loop *loop, RStream *stream, bool is_tcp, const char *address, int timeout,
const char **error)
{
bool success = false;
@@ -206,7 +206,7 @@ bool socket_connect(Loop *loop, Stream *stream, bool is_tcp, const char *address
req.data = &status;
uv_stream_t *uv_stream;
- uv_tcp_t *tcp = &stream->uv.tcp;
+ uv_tcp_t *tcp = &stream->s.uv.tcp;
uv_getaddrinfo_t addr_req;
addr_req.addrinfo = NULL;
const struct addrinfo *addrinfo = NULL;
@@ -237,7 +237,7 @@ tcp_retry:
uv_tcp_connect(&req, tcp, addrinfo->ai_addr, connect_cb);
uv_stream = (uv_stream_t *)tcp;
} else {
- uv_pipe_t *pipe = &stream->uv.pipe;
+ uv_pipe_t *pipe = &stream->s.uv.pipe;
uv_pipe_init(&loop->uv, pipe, 0);
uv_pipe_connect(&req, pipe, address, connect_cb);
uv_stream = (uv_stream_t *)pipe;
@@ -245,7 +245,7 @@ tcp_retry:
status = 1;
LOOP_PROCESS_EVENTS_UNTIL(&main_loop, NULL, timeout, status != 1);
if (status == 0) {
- stream_init(NULL, stream, -1, uv_stream);
+ stream_init(NULL, &stream->s, -1, uv_stream);
success = true;
} else if (is_tcp && addrinfo->ai_next) {
addrinfo = addrinfo->ai_next;
diff --git a/src/nvim/event/stream.c b/src/nvim/event/stream.c
index 0b9ed4f25b..bc1b503f4c 100644
--- a/src/nvim/event/stream.c
+++ b/src/nvim/event/stream.c
@@ -8,7 +8,6 @@
#include "nvim/event/loop.h"
#include "nvim/event/stream.h"
#include "nvim/log.h"
-#include "nvim/rbuffer.h"
#include "nvim/types_defs.h"
#ifdef MSWIN
# include "nvim/os/os_win_console.h"
@@ -85,21 +84,17 @@ void stream_init(Loop *loop, Stream *stream, int fd, uv_stream_t *uvstream)
}
stream->internal_data = NULL;
- stream->fpos = 0;
stream->curmem = 0;
stream->maxmem = 0;
stream->pending_reqs = 0;
- stream->read_cb = NULL;
stream->write_cb = NULL;
stream->close_cb = NULL;
stream->internal_close_cb = NULL;
stream->closed = false;
- stream->buffer = NULL;
stream->events = NULL;
- stream->num_bytes = 0;
}
-void stream_close(Stream *stream, stream_close_cb on_stream_close, void *data)
+void stream_close(Stream *stream, stream_close_cb on_stream_close, void *data, bool rstream)
FUNC_ATTR_NONNULL_ARG(1)
{
assert(!stream->closed);
@@ -116,18 +111,18 @@ void stream_close(Stream *stream, stream_close_cb on_stream_close, void *data)
#endif
if (!stream->pending_reqs) {
- stream_close_handle(stream);
+ stream_close_handle(stream, rstream);
}
}
-void stream_may_close(Stream *stream)
+void stream_may_close(Stream *stream, bool rstream)
{
if (!stream->closed) {
- stream_close(stream, NULL, NULL);
+ stream_close(stream, NULL, NULL, rstream);
}
}
-void stream_close_handle(Stream *stream)
+void stream_close_handle(Stream *stream, bool rstream)
FUNC_ATTR_NONNULL_ALL
{
uv_handle_t *handle = NULL;
@@ -145,16 +140,22 @@ void stream_close_handle(Stream *stream)
assert(handle != NULL);
if (!uv_is_closing(handle)) {
- uv_close(handle, close_cb);
+ uv_close(handle, rstream ? rstream_close_cb : close_cb);
}
}
-static void close_cb(uv_handle_t *handle)
+static void rstream_close_cb(uv_handle_t *handle)
{
- Stream *stream = handle->data;
+ RStream *stream = handle->data;
if (stream->buffer) {
- rbuffer_free(stream->buffer);
+ free_block(stream->buffer);
}
+ close_cb(handle);
+}
+
+static void close_cb(uv_handle_t *handle)
+{
+ Stream *stream = handle->data;
if (stream->close_cb) {
stream->close_cb(stream, stream->close_cb_data);
}
diff --git a/src/nvim/event/wstream.c b/src/nvim/event/wstream.c
index c67a9b96ed..07aab87e4d 100644
--- a/src/nvim/event/wstream.c
+++ b/src/nvim/event/wstream.c
@@ -141,7 +141,7 @@ static void write_cb(uv_write_t *req, int status)
if (data->stream->closed && data->stream->pending_reqs == 0) {
// Last pending write, free the stream;
- stream_close_handle(data->stream);
+ stream_close_handle(data->stream, false);
}
xfree(data);
@@ -158,3 +158,8 @@ void wstream_release_wbuffer(WBuffer *buffer)
xfree(buffer);
}
}
+
+void wstream_may_close(Stream *stream)
+{
+ stream_may_close(stream, false);
+}
diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c
index 834cc6698a..7858e44f17 100644
--- a/src/nvim/ex_cmds.c
+++ b/src/nvim/ex_cmds.c
@@ -34,6 +34,7 @@
#include "nvim/digraph.h"
#include "nvim/drawscreen.h"
#include "nvim/edit.h"
+#include "nvim/errors.h"
#include "nvim/eval.h"
#include "nvim/eval/typval.h"
#include "nvim/eval/typval_defs.h"
@@ -969,13 +970,13 @@ void do_bang(int addr_count, exarg_T *eap, bool forceit, bool do_in, bool do_out
char *t = xmalloc(len);
*t = NUL;
if (newcmd != NULL) {
- STRCAT(t, newcmd);
+ strcat(t, newcmd);
}
if (ins_prevcmd) {
- STRCAT(t, prevcmd);
+ strcat(t, prevcmd);
}
char *p = t + strlen(t);
- STRCAT(t, trailarg);
+ strcat(t, trailarg);
xfree(newcmd);
newcmd = t;
@@ -1028,8 +1029,8 @@ void do_bang(int addr_count, exarg_T *eap, bool forceit, bool do_in, bool do_out
}
newcmd = xmalloc(strlen(prevcmd) + 2 * strlen(p_shq) + 1);
STRCPY(newcmd, p_shq);
- STRCAT(newcmd, prevcmd);
- STRCAT(newcmd, p_shq);
+ strcat(newcmd, prevcmd);
+ strcat(newcmd, p_shq);
free_newcmd = true;
}
if (addr_count == 0) { // :!
@@ -1359,11 +1360,11 @@ char *make_filter_cmd(char *cmd, char *itmp, char *otmp)
{
bool is_fish_shell =
#if defined(UNIX)
- strncmp(invocation_path_tail(p_sh, NULL), "fish", 4) == 0;
+ strncmp(invocation_path_tail(p_sh, NULL), S_LEN("fish")) == 0;
#else
false;
#endif
- bool is_pwsh = strncmp(invocation_path_tail(p_sh, NULL), "pwsh", 4) == 0
+ bool is_pwsh = strncmp(invocation_path_tail(p_sh, NULL), S_LEN("pwsh")) == 0
|| strncmp(invocation_path_tail(p_sh, NULL), "powershell",
10) == 0;
@@ -4107,7 +4108,7 @@ skip:
// the line as reference, because the substitute may
// have changed the number of characters. Same for
// "prev_matchcol".
- STRCAT(new_start, sub_firstline + copycol);
+ strcat(new_start, sub_firstline + copycol);
matchcol = (colnr_T)strlen(sub_firstline) - matchcol;
prev_matchcol = (colnr_T)strlen(sub_firstline)
- prev_matchcol;
diff --git a/src/nvim/ex_cmds2.c b/src/nvim/ex_cmds2.c
index f4a6e61831..a602719f6d 100644
--- a/src/nvim/ex_cmds2.c
+++ b/src/nvim/ex_cmds2.c
@@ -17,6 +17,7 @@
#include "nvim/bufwrite.h"
#include "nvim/change.h"
#include "nvim/channel.h"
+#include "nvim/errors.h"
#include "nvim/eval.h"
#include "nvim/eval/typval.h"
#include "nvim/eval/typval_defs.h"
diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c
index 1fcfc505df..9a6a845958 100644
--- a/src/nvim/ex_docmd.c
+++ b/src/nvim/ex_docmd.c
@@ -29,6 +29,7 @@
#include "nvim/digraph.h"
#include "nvim/drawscreen.h"
#include "nvim/edit.h"
+#include "nvim/errors.h"
#include "nvim/eval.h"
#include "nvim/eval/typval.h"
#include "nvim/eval/typval_defs.h"
@@ -1728,12 +1729,6 @@ int execute_cmd(exarg_T *eap, CmdParseInfo *cmdinfo, bool preview)
}
const char *errormsg = NULL;
-#undef ERROR
-#define ERROR(msg) \
- do { \
- errormsg = msg; \
- goto end; \
- } while (0)
cmdmod_T save_cmdmod = cmdmod;
cmdmod = cmdinfo->cmdmod;
@@ -1744,16 +1739,19 @@ int execute_cmd(exarg_T *eap, CmdParseInfo *cmdinfo, bool preview)
if (!MODIFIABLE(curbuf) && (eap->argt & EX_MODIFY)
// allow :put in terminals
&& !(curbuf->terminal && eap->cmdidx == CMD_put)) {
- ERROR(_(e_modifiable));
+ errormsg = _(e_modifiable);
+ goto end;
}
if (!IS_USER_CMDIDX(eap->cmdidx)) {
if (cmdwin_type != 0 && !(eap->argt & EX_CMDWIN)) {
// Command not allowed in the command line window
- ERROR(_(e_cmdwin));
+ errormsg = _(e_cmdwin);
+ goto end;
}
if (text_locked() && !(eap->argt & EX_LOCK_OK)) {
// Command not allowed when text is locked
- ERROR(_(get_text_locked_msg()));
+ errormsg = _(get_text_locked_msg());
+ goto end;
}
}
// Disallow editing another buffer when "curbuf->b_ro_locked" is set.
@@ -1801,7 +1799,6 @@ end:
do_cmdline_end();
return retv;
-#undef ERROR
}
static void profile_cmd(const exarg_T *eap, cstack_T *cstack, LineGetter fgetline, void *cookie)
@@ -2695,7 +2692,7 @@ int parse_command_modifiers(exarg_T *eap, const char **errormsg, cmdmod_T *cmod,
/// Apply the command modifiers. Saves current state in "cmdmod", call
/// undo_cmdmod() later.
-static void apply_cmdmod(cmdmod_T *cmod)
+void apply_cmdmod(cmdmod_T *cmod)
{
if ((cmod->cmod_flags & CMOD_SANDBOX) && !cmod->cmod_did_sandbox) {
sandbox++;
@@ -3829,8 +3826,8 @@ char *replace_makeprg(exarg_T *eap, char *arg, char **cmdlinep)
// No $* in arg, build "<makeprg> <arg>" instead
new_cmdline = xmalloc(strlen(program) + strlen(arg) + 2);
STRCPY(new_cmdline, program);
- STRCAT(new_cmdline, " ");
- STRCAT(new_cmdline, arg);
+ strcat(new_cmdline, " ");
+ strcat(new_cmdline, arg);
}
msg_make(arg);
@@ -4117,7 +4114,7 @@ static char *getargcmd(char **argp)
if (*arg == '+') { // +[command]
arg++;
- if (ascii_isspace(*arg) || *arg == '\0') {
+ if (ascii_isspace(*arg) || *arg == NUL) {
command = dollar_command;
} else {
command = arg;
@@ -4194,7 +4191,7 @@ static int getargopt(exarg_T *eap)
// Note: Keep this in sync with get_argopt_name.
// ":edit ++[no]bin[ary] file"
- if (strncmp(arg, "bin", 3) == 0 || strncmp(arg, "nobin", 5) == 0) {
+ if (strncmp(arg, S_LEN("bin")) == 0 || strncmp(arg, S_LEN("nobin")) == 0) {
if (*arg == 'n') {
arg += 2;
eap->force_bin = FORCE_NOBIN;
@@ -4209,33 +4206,33 @@ static int getargopt(exarg_T *eap)
}
// ":read ++edit file"
- if (strncmp(arg, "edit", 4) == 0) {
+ if (strncmp(arg, S_LEN("edit")) == 0) {
eap->read_edit = true;
eap->arg = skipwhite(arg + 4);
return OK;
}
// ":write ++p foo/bar/file
- if (strncmp(arg, "p", 1) == 0) {
+ if (strncmp(arg, S_LEN("p")) == 0) {
eap->mkdir_p = true;
eap->arg = skipwhite(arg + 1);
return OK;
}
- if (strncmp(arg, "ff", 2) == 0) {
+ if (strncmp(arg, S_LEN("ff")) == 0) {
arg += 2;
pp = &eap->force_ff;
- } else if (strncmp(arg, "fileformat", 10) == 0) {
+ } else if (strncmp(arg, S_LEN("fileformat")) == 0) {
arg += 10;
pp = &eap->force_ff;
- } else if (strncmp(arg, "enc", 3) == 0) {
- if (strncmp(arg, "encoding", 8) == 0) {
+ } else if (strncmp(arg, S_LEN("enc")) == 0) {
+ if (strncmp(arg, S_LEN("encoding")) == 0) {
arg += 8;
} else {
arg += 3;
}
pp = &eap->force_enc;
- } else if (strncmp(arg, "bad", 3) == 0) {
+ } else if (strncmp(arg, S_LEN("bad")) == 0) {
arg += 3;
pp = &bad_char_idx;
}
@@ -4299,19 +4296,19 @@ int expand_argopt(char *pat, expand_T *xp, regmatch_T *rmp, char ***matches, int
char *name_end = xp->xp_pattern - 1;
if (name_end - xp->xp_line >= 2
- && strncmp(name_end - 2, "ff", 2) == 0) {
+ && strncmp(name_end - 2, S_LEN("ff")) == 0) {
cb = get_fileformat_name;
} else if (name_end - xp->xp_line >= 10
- && strncmp(name_end - 10, "fileformat", 10) == 0) {
+ && strncmp(name_end - 10, S_LEN("fileformat")) == 0) {
cb = get_fileformat_name;
} else if (name_end - xp->xp_line >= 3
- && strncmp(name_end - 3, "enc", 3) == 0) {
+ && strncmp(name_end - 3, S_LEN("enc")) == 0) {
cb = get_encoding_name;
} else if (name_end - xp->xp_line >= 8
- && strncmp(name_end - 8, "encoding", 8) == 0) {
+ && strncmp(name_end - 8, S_LEN("encoding")) == 0) {
cb = get_encoding_name;
} else if (name_end - xp->xp_line >= 3
- && strncmp(name_end - 3, "bad", 3) == 0) {
+ && strncmp(name_end - 3, S_LEN("bad")) == 0) {
cb = get_bad_name;
}
@@ -7216,7 +7213,7 @@ char *expand_sfile(char *arg)
char *result = xstrdup(arg);
for (char *p = result; *p;) {
- if (strncmp(p, "<sfile>", 7) != 0) {
+ if (strncmp(p, S_LEN("<sfile>")) != 0) {
p++;
} else {
// replace "<sfile>" with the sourced file name, and do ":" stuff
@@ -7239,7 +7236,7 @@ char *expand_sfile(char *arg)
memmove(newres, result, (size_t)(p - result));
STRCPY(newres + (p - result), repl);
len = strlen(newres);
- STRCAT(newres, p + srclen);
+ strcat(newres, p + srclen);
xfree(repl);
xfree(result);
result = newres;
@@ -7303,12 +7300,12 @@ static void ex_filetype(exarg_T *eap)
// Accept "plugin" and "indent" in any order.
while (true) {
- if (strncmp(arg, "plugin", 6) == 0) {
+ if (strncmp(arg, S_LEN("plugin")) == 0) {
plugin = true;
arg = skipwhite(arg + 6);
continue;
}
- if (strncmp(arg, "indent", 6) == 0) {
+ if (strncmp(arg, S_LEN("indent")) == 0) {
indent = true;
arg = skipwhite(arg + 6);
continue;
@@ -7387,7 +7384,7 @@ static void ex_setfiletype(exarg_T *eap)
}
char *arg = eap->arg;
- if (strncmp(arg, "FALLBACK ", 9) == 0) {
+ if (strncmp(arg, S_LEN("FALLBACK ")) == 0) {
arg += 9;
}
diff --git a/src/nvim/ex_eval.c b/src/nvim/ex_eval.c
index 472741d537..0f4f31df02 100644
--- a/src/nvim/ex_eval.c
+++ b/src/nvim/ex_eval.c
@@ -11,6 +11,7 @@
#include "nvim/ascii_defs.h"
#include "nvim/charset.h"
#include "nvim/debugger.h"
+#include "nvim/errors.h"
#include "nvim/eval.h"
#include "nvim/eval/typval.h"
#include "nvim/eval/typval_defs.h"
@@ -253,7 +254,7 @@ bool cause_errthrow(const char *mesg, bool multiline, bool severe, bool *ignore)
if (plist == msg_list || severe) {
// Skip the extra "Vim " prefix for message "E458".
char *tmsg = elem->msg;
- if (strncmp(tmsg, "Vim E", 5) == 0
+ if (strncmp(tmsg, S_LEN("Vim E")) == 0
&& ascii_isdigit(tmsg[5])
&& ascii_isdigit(tmsg[6])
&& ascii_isdigit(tmsg[7])
@@ -405,7 +406,7 @@ char *get_exception_string(void *value, except_type_T type, char *cmdname, bool
|| (ascii_isdigit(p[3])
&& p[4] == ':')))))) {
if (*p == NUL || p == mesg) {
- STRCAT(val, mesg); // 'E123' missing or at beginning
+ strcat(val, mesg); // 'E123' missing or at beginning
} else {
// '"filename" E123: message text'
if (mesg[0] != '"' || p - 2 < &mesg[1]
@@ -414,7 +415,7 @@ char *get_exception_string(void *value, except_type_T type, char *cmdname, bool
continue;
}
- STRCAT(val, p);
+ strcat(val, p);
p[-2] = NUL;
snprintf(val + strlen(p), strlen(" (%s)"), " (%s)", &mesg[1]);
p[-2] = '"';
@@ -442,7 +443,7 @@ static int throw_exception(void *value, except_type_T type, char *cmdname)
// would be treated differently from real interrupt or error exceptions
// when no active try block is found, see do_cmdline().
if (type == ET_USER) {
- if (strncmp(value, "Vim", 3) == 0
+ if (strncmp(value, S_LEN("Vim")) == 0
&& (((char *)value)[3] == NUL || ((char *)value)[3] == ':'
|| ((char *)value)[3] == '(')) {
emsg(_("E608: Cannot :throw exceptions with 'Vim' prefix"));
diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c
index cc2608433d..74e6e3422e 100644
--- a/src/nvim/ex_getln.c
+++ b/src/nvim/ex_getln.c
@@ -28,6 +28,7 @@
#include "nvim/digraph.h"
#include "nvim/drawscreen.h"
#include "nvim/edit.h"
+#include "nvim/errors.h"
#include "nvim/eval.h"
#include "nvim/eval/typval.h"
#include "nvim/eval/vars.h"
@@ -2798,13 +2799,13 @@ int check_opt_wim(void)
if (p[i] != NUL && p[i] != ',' && p[i] != ':') {
return FAIL;
}
- if (i == 7 && strncmp(p, "longest", 7) == 0) {
+ if (i == 7 && strncmp(p, S_LEN("longest")) == 0) {
new_wim_flags[idx] |= WIM_LONGEST;
- } else if (i == 4 && strncmp(p, "full", 4) == 0) {
+ } else if (i == 4 && strncmp(p, S_LEN("full")) == 0) {
new_wim_flags[idx] |= WIM_FULL;
- } else if (i == 4 && strncmp(p, "list", 4) == 0) {
+ } else if (i == 4 && strncmp(p, S_LEN("list")) == 0) {
new_wim_flags[idx] |= WIM_LIST;
- } else if (i == 8 && strncmp(p, "lastused", 8) == 0) {
+ } else if (i == 8 && strncmp(p, S_LEN("lastused")) == 0) {
new_wim_flags[idx] |= WIM_BUFLASTUSED;
} else {
return FAIL;
@@ -3454,11 +3455,9 @@ void cmdline_screen_cleared(void)
/// called by ui_flush, do what redraws necessary to keep cmdline updated.
void cmdline_ui_flush(void)
{
- static bool flushing = false;
- if (!ui_has(kUICmdline) || flushing) {
+ if (!ui_has(kUICmdline)) {
return;
}
- flushing = true;
int level = ccline.level;
CmdlineInfo *line = &ccline;
while (level > 0 && line) {
@@ -3473,7 +3472,6 @@ void cmdline_ui_flush(void)
}
line = line->prev_ccline;
}
- flushing = false;
}
// Put a character on the command line. Shifts the following text to the
diff --git a/src/nvim/ex_session.c b/src/nvim/ex_session.c
index 0e5d2fe4f5..50ee197ef4 100644
--- a/src/nvim/ex_session.c
+++ b/src/nvim/ex_session.c
@@ -15,6 +15,7 @@
#include "nvim/autocmd.h"
#include "nvim/buffer.h"
#include "nvim/buffer_defs.h"
+#include "nvim/errors.h"
#include "nvim/eval.h"
#include "nvim/eval/typval.h"
#include "nvim/eval/typval_defs.h"
diff --git a/src/nvim/extmark.c b/src/nvim/extmark.c
index 4e47fa76fe..b592283d92 100644
--- a/src/nvim/extmark.c
+++ b/src/nvim/extmark.c
@@ -54,12 +54,12 @@
/// must not be used during iteration!
void extmark_set(buf_T *buf, uint32_t ns_id, uint32_t *idp, int row, colnr_T col, int end_row,
colnr_T end_col, DecorInline decor, uint16_t decor_flags, bool right_gravity,
- bool end_right_gravity, bool no_undo, bool invalidate, bool scoped, Error *err)
+ bool end_right_gravity, bool no_undo, bool invalidate, Error *err)
{
uint32_t *ns = map_put_ref(uint32_t, uint32_t)(buf->b_extmark_ns, ns_id, NULL, NULL);
uint32_t id = idp ? *idp : 0;
- uint16_t flags = mt_flags(right_gravity, no_undo, invalidate, decor.ext, scoped) | decor_flags;
+ uint16_t flags = mt_flags(right_gravity, no_undo, invalidate, decor.ext) | decor_flags;
if (id == 0) {
id = ++*ns;
} else {
diff --git a/src/nvim/file_search.c b/src/nvim/file_search.c
index a8b0dbddee..50031eedee 100644
--- a/src/nvim/file_search.c
+++ b/src/nvim/file_search.c
@@ -399,7 +399,7 @@ void *vim_findfile_init(char *path, char *filename, char *stopdirs, int level, i
emsg(_(e_path_too_long_for_completion));
break;
}
- if (strncmp(wc_part, "**", 2) == 0) {
+ if (strncmp(wc_part, S_LEN("**")) == 0) {
ff_expand_buffer[len++] = *wc_part++;
ff_expand_buffer[len++] = *wc_part++;
@@ -451,7 +451,7 @@ void *vim_findfile_init(char *path, char *filename, char *stopdirs, int level, i
STRCPY(buf, ff_expand_buffer);
STRCPY(buf + eb_len, search_ctx->ffsc_fix_path);
if (os_isdir(buf)) {
- STRCAT(ff_expand_buffer, search_ctx->ffsc_fix_path);
+ strcat(ff_expand_buffer, search_ctx->ffsc_fix_path);
add_pathsep(ff_expand_buffer);
} else {
char *p = path_tail(search_ctx->ffsc_fix_path);
@@ -462,7 +462,7 @@ void *vim_findfile_init(char *path, char *filename, char *stopdirs, int level, i
if (p > search_ctx->ffsc_fix_path) {
// do not add '..' to the path and start upwards searching
len = (int)(p - search_ctx->ffsc_fix_path) - 1;
- if ((len >= 2 && strncmp(search_ctx->ffsc_fix_path, "..", 2) == 0)
+ if ((len >= 2 && strncmp(search_ctx->ffsc_fix_path, S_LEN("..")) == 0)
&& (len == 2 || search_ctx->ffsc_fix_path[2] == PATHSEP)) {
xfree(buf);
goto error_return;
@@ -479,7 +479,7 @@ void *vim_findfile_init(char *path, char *filename, char *stopdirs, int level, i
+ strlen(search_ctx->ffsc_fix_path + len)
+ 1);
STRCPY(temp, search_ctx->ffsc_fix_path + len);
- STRCAT(temp, search_ctx->ffsc_wc_path);
+ strcat(temp, search_ctx->ffsc_wc_path);
xfree(search_ctx->ffsc_wc_path);
xfree(wc_path);
search_ctx->ffsc_wc_path = temp;
@@ -505,24 +505,36 @@ error_return:
/// @return the stopdir string. Check that ';' is not escaped.
char *vim_findfile_stopdir(char *buf)
{
- char *r_ptr = buf;
-
- while (*r_ptr != NUL && *r_ptr != ';') {
- if (r_ptr[0] == '\\' && r_ptr[1] == ';') {
- // Overwrite the escape char,
- // use strlen(r_ptr) to move the trailing '\0'.
- STRMOVE(r_ptr, r_ptr + 1);
- r_ptr++;
+ for (; *buf != NUL && *buf != ';' && (buf[0] != '\\' || buf[1] != ';'); buf++) {}
+ char *dst = buf;
+ if (*buf == ';') {
+ goto is_semicolon;
+ }
+ if (*buf == NUL) {
+ goto is_nul;
+ }
+ goto start;
+ while (*buf != NUL && *buf != ';') {
+ if (buf[0] == '\\' && buf[1] == ';') {
+start:
+ // Overwrite the escape char.
+ *dst++ = ';';
+ buf += 2;
+ } else {
+ *dst++ = *buf++;
}
- r_ptr++;
}
- if (*r_ptr == ';') {
- *r_ptr = 0;
- r_ptr++;
- } else if (*r_ptr == NUL) {
- r_ptr = NULL;
+ assert(dst < buf);
+ *dst = NUL;
+ if (*buf == ';') {
+is_semicolon:
+ *buf = NUL;
+ buf++;
+ } else { // if (*buf == NUL)
+is_nul:
+ buf = NULL;
}
- return r_ptr;
+ return buf;
}
/// Clean up the given search context. Can handle a NULL pointer.
@@ -669,7 +681,7 @@ char *vim_findfile(void *search_ctx_arg)
ff_free_stack_element(stackp);
goto fail;
}
- STRCAT(file_path, stackp->ffs_fix_path);
+ strcat(file_path, stackp->ffs_fix_path);
if (!add_pathsep(file_path)) {
ff_free_stack_element(stackp);
goto fail;
@@ -678,7 +690,7 @@ char *vim_findfile(void *search_ctx_arg)
rest_of_wildcards = stackp->ffs_wc_path;
if (*rest_of_wildcards != NUL) {
len = strlen(file_path);
- if (strncmp(rest_of_wildcards, "**", 2) == 0) {
+ if (strncmp(rest_of_wildcards, S_LEN("**")) == 0) {
// pointer to the restrict byte
// The restrict byte is not a character!
p = rest_of_wildcards + 2;
@@ -769,7 +781,7 @@ char *vim_findfile(void *search_ctx_arg)
ff_free_stack_element(stackp);
goto fail;
}
- STRCAT(file_path, search_ctx->ffsc_file_to_search);
+ strcat(file_path, search_ctx->ffsc_file_to_search);
// Try without extra suffix and then with suffixes
// from 'suffixesadd'.
@@ -855,7 +867,7 @@ char *vim_findfile(void *search_ctx_arg)
// if wildcards contains '**' we have to descent till we reach the
// leaves of the directory tree.
- if (strncmp(stackp->ffs_wc_path, "**", 2) == 0) {
+ if (strncmp(stackp->ffs_wc_path, S_LEN("**")) == 0) {
for (int i = stackp->ffs_filearray_cur;
i < stackp->ffs_filearray_size; i++) {
if (path_fnamecmp(stackp->ffs_filearray[i],
@@ -910,7 +922,7 @@ char *vim_findfile(void *search_ctx_arg)
if (!add_pathsep(file_path)) {
goto fail;
}
- STRCAT(file_path, search_ctx->ffsc_fix_path);
+ strcat(file_path, search_ctx->ffsc_fix_path);
// create a new stack entry
sptr = ff_create_stack_element(file_path,
diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c
index df9c4928c9..4b8121b423 100644
--- a/src/nvim/fileio.c
+++ b/src/nvim/fileio.c
@@ -27,6 +27,7 @@
#include "nvim/diff.h"
#include "nvim/drawscreen.h"
#include "nvim/edit.h"
+#include "nvim/errors.h"
#include "nvim/eval.h"
#include "nvim/ex_cmds_defs.h"
#include "nvim/ex_eval.h"
@@ -1895,7 +1896,7 @@ theend:
bool is_dev_fd_file(char *fname)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
{
- return strncmp(fname, "/dev/fd/", 8) == 0
+ return strncmp(fname, S_LEN("/dev/fd/")) == 0
&& ascii_isdigit((uint8_t)fname[8])
&& *skipdigits(fname + 9) == NUL
&& (fname[9] != NUL
@@ -2418,7 +2419,7 @@ char *modname(const char *fname, const char *ext, bool prepend_dot)
// the file name has at most BASENAMELEN characters.
if (strlen(ptr) > BASENAMELEN) {
- ptr[BASENAMELEN] = '\0';
+ ptr[BASENAMELEN] = NUL;
}
char *s = ptr + strlen(ptr);
@@ -3329,7 +3330,7 @@ static void vim_mktempdir(void)
#endif
// If our "root" tempdir is invalid or fails, proceed without "<user>/".
// Else user1 could break user2 by creating "/tmp/nvim.user2/".
- tmp[strlen(tmp) - strlen(user)] = '\0';
+ tmp[strlen(tmp) - strlen(user)] = NUL;
}
// Now try to create "/tmp/nvim.<user>/XXXXXX".
diff --git a/src/nvim/fold.c b/src/nvim/fold.c
index 59a4dc6aad..78fe33cc78 100644
--- a/src/nvim/fold.c
+++ b/src/nvim/fold.c
@@ -22,6 +22,7 @@
#include "nvim/decoration.h"
#include "nvim/diff.h"
#include "nvim/drawscreen.h"
+#include "nvim/errors.h"
#include "nvim/eval.h"
#include "nvim/eval/typval.h"
#include "nvim/ex_session.h"
@@ -3314,7 +3315,7 @@ void f_foldtext(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
char *r = xmalloc(len);
snprintf(r, len, txt, dashes, count);
len = strlen(r);
- STRCAT(r, s);
+ strcat(r, s);
// remove 'foldmarker' and 'commentstring'
foldtext_cleanup(r + len);
rettv->vval.v_string = r;
diff --git a/src/nvim/generators/gen_api_dispatch.lua b/src/nvim/generators/gen_api_dispatch.lua
index 62c99ce082..61c80a3d2e 100644
--- a/src/nvim/generators/gen_api_dispatch.lua
+++ b/src/nvim/generators/gen_api_dispatch.lua
@@ -306,6 +306,7 @@ local keysets_defs = assert(io.open(keysets_outputf, 'wb'))
-- so that the dispatcher can find the C functions that you are creating!
-- ===========================================================================
output:write([[
+#include "nvim/errors.h"
#include "nvim/ex_docmd.h"
#include "nvim/ex_getln.h"
#include "nvim/globals.h"
diff --git a/src/nvim/generators/gen_api_ui_events.lua b/src/nvim/generators/gen_api_ui_events.lua
index 516b5ad5ae..c5b37672bf 100644
--- a/src/nvim/generators/gen_api_ui_events.lua
+++ b/src/nvim/generators/gen_api_ui_events.lua
@@ -128,8 +128,16 @@ for i = 1, #events do
write_signature(call_output, ev, '')
call_output:write('\n{\n')
if ev.remote_only then
+ -- Lua callbacks may emit other events or the same event again. Avoid the latter
+ -- by adding a recursion guard to each generated function that may call a Lua callback.
+ call_output:write(' static bool entered = false;\n')
+ call_output:write(' if (entered) {\n')
+ call_output:write(' return;\n')
+ call_output:write(' }\n')
+ call_output:write(' entered = true;\n')
write_arglist(call_output, ev)
call_output:write(' ui_call_event("' .. ev.name .. '", ' .. args .. ');\n')
+ call_output:write(' entered = false;\n')
elseif ev.compositor_impl then
call_output:write(' ui_comp_' .. ev.name)
write_signature(call_output, ev, '', true)
diff --git a/src/nvim/generators/gen_options.lua b/src/nvim/generators/gen_options.lua
index 0718d965c6..591a6b93df 100644
--- a/src/nvim/generators/gen_options.lua
+++ b/src/nvim/generators/gen_options.lua
@@ -148,7 +148,7 @@ local get_defaults = function(d, n)
return value_dumpers[type(d)](d)
end
---- @type {[1]:string,[2]:string}[]
+--- @type [string,string][]
local defines = {}
--- @param i integer
diff --git a/src/nvim/getchar.c b/src/nvim/getchar.c
index 9b19644b7e..6167418052 100644
--- a/src/nvim/getchar.c
+++ b/src/nvim/getchar.c
@@ -19,6 +19,7 @@
#include "nvim/cursor.h"
#include "nvim/drawscreen.h"
#include "nvim/edit.h"
+#include "nvim/errors.h"
#include "nvim/eval.h"
#include "nvim/eval/typval.h"
#include "nvim/eval/typval_defs.h"
@@ -565,7 +566,7 @@ void AppendToRedobuffLit(const char *str, int len)
// CTRL-V '0' must be inserted as CTRL-V 048.
if (*s == NUL && c == '0') {
- add_buff(&redobuff, "048", 3);
+ add_buff(&redobuff, S_LEN("048"));
} else {
add_char_buff(&redobuff, c);
}
@@ -776,7 +777,7 @@ int start_redo(int count, bool old_redo)
// copy the buffer name, if present
if (c == '"') {
- add_buff(&readbuf2, "\"", 1);
+ add_buff(&readbuf2, S_LEN("\""));
c = read_redo(false, old_redo);
// if a numbered buffer is used, increment the number
diff --git a/src/nvim/globals.h b/src/nvim/globals.h
index 83fef1fe75..410e8f2e7c 100644
--- a/src/nvim/globals.h
+++ b/src/nvim/globals.h
@@ -793,195 +793,7 @@ EXTERN disptick_T display_tick INIT( = 0);
// cursor position in Insert mode.
EXTERN linenr_T spell_redraw_lnum INIT( = 0);
-// uncrustify:off
-
-// The error messages that can be shared are included here.
-// Excluded are errors that are only used once and debugging messages.
-EXTERN const char e_abort[] INIT(= N_("E470: Command aborted"));
-EXTERN const char e_afterinit[] INIT(= N_("E905: Cannot set this option after startup"));
-EXTERN const char e_api_spawn_failed[] INIT(= N_("E903: Could not spawn API job"));
-EXTERN const char e_argreq[] INIT(= N_("E471: Argument required"));
-EXTERN const char e_backslash[] INIT(= N_("E10: \\ should be followed by /, ? or &"));
-EXTERN const char e_cmdwin[] INIT(= N_("E11: Invalid in command-line window; <CR> executes, CTRL-C quits"));
-EXTERN const char e_curdir[] INIT(= N_("E12: Command not allowed in secure mode in current dir or tag search"));
-EXTERN const char e_invalid_buffer_name_str[] INIT(= N_("E158: Invalid buffer name: %s"));
-EXTERN const char e_command_too_recursive[] INIT(= N_("E169: Command too recursive"));
-EXTERN const char e_buffer_is_not_loaded[] INIT(= N_("E681: Buffer is not loaded"));
-EXTERN const char e_endif[] INIT(= N_("E171: Missing :endif"));
-EXTERN const char e_endtry[] INIT(= N_("E600: Missing :endtry"));
-EXTERN const char e_endwhile[] INIT(= N_("E170: Missing :endwhile"));
-EXTERN const char e_endfor[] INIT(= N_("E170: Missing :endfor"));
-EXTERN const char e_while[] INIT(= N_("E588: :endwhile without :while"));
-EXTERN const char e_for[] INIT(= N_("E588: :endfor without :for"));
-EXTERN const char e_exists[] INIT(= N_("E13: File exists (add ! to override)"));
-EXTERN const char e_failed[] INIT(= N_("E472: Command failed"));
-EXTERN const char e_internal[] INIT(= N_("E473: Internal error"));
-EXTERN const char e_intern2[] INIT(= N_("E685: Internal error: %s"));
-EXTERN const char e_interr[] INIT(= N_("Interrupted"));
-EXTERN const char e_invarg[] INIT(= N_("E474: Invalid argument"));
-EXTERN const char e_invarg2[] INIT(= N_("E475: Invalid argument: %s"));
-EXTERN const char e_invargval[] INIT(= N_("E475: Invalid value for argument %s"));
-EXTERN const char e_invargNval[] INIT(= N_("E475: Invalid value for argument %s: %s"));
-EXTERN const char e_duparg2[] INIT(= N_("E983: Duplicate argument: %s"));
-EXTERN const char e_invexpr2[] INIT(= N_("E15: Invalid expression: \"%s\""));
-EXTERN const char e_invrange[] INIT(= N_("E16: Invalid range"));
-EXTERN const char e_invcmd[] INIT(= N_("E476: Invalid command"));
-EXTERN const char e_isadir2[] INIT(= N_("E17: \"%s\" is a directory"));
-EXTERN const char e_no_spell[] INIT(= N_("E756: Spell checking is not possible"));
-EXTERN const char e_invchan[] INIT(= N_("E900: Invalid channel id"));
-EXTERN const char e_invchanjob[] INIT(= N_("E900: Invalid channel id: not a job"));
-EXTERN const char e_jobtblfull[] INIT(= N_("E901: Job table is full"));
-EXTERN const char e_jobspawn[] INIT(= N_("E903: Process failed to start: %s: \"%s\""));
-EXTERN const char e_channotpty[] INIT(= N_("E904: channel is not a pty"));
-EXTERN const char e_stdiochan2[] INIT(= N_("E905: Couldn't open stdio channel: %s"));
-EXTERN const char e_invstream[] INIT(= N_("E906: invalid stream for channel"));
-EXTERN const char e_invstreamrpc[] INIT(= N_("E906: invalid stream for rpc channel, use 'rpc'"));
-EXTERN const char e_streamkey[] INIT(= N_("E5210: dict key '%s' already set for buffered stream in channel %" PRIu64));
-EXTERN const char e_libcall[] INIT(= N_("E364: Library call failed for \"%s()\""));
-EXTERN const char e_fsync[] INIT(= N_("E667: Fsync failed: %s"));
-EXTERN const char e_mkdir[] INIT(= N_("E739: Cannot create directory %s: %s"));
-EXTERN const char e_markinval[] INIT(= N_("E19: Mark has invalid line number"));
-EXTERN const char e_marknotset[] INIT(= N_("E20: Mark not set"));
-EXTERN const char e_modifiable[] INIT(= N_("E21: Cannot make changes, 'modifiable' is off"));
-EXTERN const char e_nesting[] INIT(= N_("E22: Scripts nested too deep"));
-EXTERN const char e_noalt[] INIT(= N_("E23: No alternate file"));
-EXTERN const char e_noabbr[] INIT(= N_("E24: No such abbreviation"));
-EXTERN const char e_nobang[] INIT(= N_("E477: No ! allowed"));
-EXTERN const char e_nogroup[] INIT(= N_("E28: No such highlight group name: %s"));
-EXTERN const char e_noinstext[] INIT(= N_("E29: No inserted text yet"));
-EXTERN const char e_nolastcmd[] INIT(= N_("E30: No previous command line"));
-EXTERN const char e_nomap[] INIT(= N_("E31: No such mapping"));
-EXTERN const char e_nomatch[] INIT(= N_("E479: No match"));
-EXTERN const char e_nomatch2[] INIT(= N_("E480: No match: %s"));
-EXTERN const char e_noname[] INIT(= N_("E32: No file name"));
-EXTERN const char e_nopresub[] INIT(= N_("E33: No previous substitute regular expression"));
-EXTERN const char e_noprev[] INIT(= N_("E34: No previous command"));
-EXTERN const char e_noprevre[] INIT(= N_("E35: No previous regular expression"));
-EXTERN const char e_norange[] INIT(= N_("E481: No range allowed"));
-EXTERN const char e_noroom[] INIT(= N_("E36: Not enough room"));
-EXTERN const char e_notmp[] INIT(= N_("E483: Can't get temp file name"));
-EXTERN const char e_notopen[] INIT(= N_("E484: Can't open file %s"));
-EXTERN const char e_notopen_2[] INIT(= N_("E484: Can't open file %s: %s"));
-EXTERN const char e_notread[] INIT(= N_("E485: Can't read file %s"));
-EXTERN const char e_null[] INIT(= N_("E38: Null argument"));
-EXTERN const char e_number_exp[] INIT(= N_("E39: Number expected"));
-EXTERN const char e_openerrf[] INIT(= N_("E40: Can't open errorfile %s"));
-EXTERN const char e_outofmem[] INIT(= N_("E41: Out of memory!"));
-EXTERN const char e_patnotf[] INIT(= N_("Pattern not found"));
-EXTERN const char e_patnotf2[] INIT(= N_("E486: Pattern not found: %s"));
-EXTERN const char e_positive[] INIT(= N_("E487: Argument must be positive"));
-EXTERN const char e_prev_dir[] INIT(= N_("E459: Cannot go back to previous directory"));
-
-EXTERN const char e_no_errors[] INIT(= N_("E42: No Errors"));
-EXTERN const char e_loclist[] INIT(= N_("E776: No location list"));
-EXTERN const char e_re_damg[] INIT(= N_("E43: Damaged match string"));
-EXTERN const char e_re_corr[] INIT(= N_("E44: Corrupted regexp program"));
-EXTERN const char e_readonly[] INIT(= N_("E45: 'readonly' option is set (add ! to override)"));
-EXTERN const char e_letwrong[] INIT(= N_("E734: Wrong variable type for %s="));
-EXTERN const char e_illvar[] INIT(= N_("E461: Illegal variable name: %s"));
-EXTERN const char e_cannot_mod[] INIT(= N_("E995: Cannot modify existing variable"));
-EXTERN const char e_readonlyvar[] INIT(= N_("E46: Cannot change read-only variable \"%.*s\""));
-EXTERN const char e_stringreq[] INIT(= N_("E928: String required"));
-EXTERN const char e_dictreq[] INIT(= N_("E715: Dictionary required"));
-EXTERN const char e_blobidx[] INIT(= N_("E979: Blob index out of range: %" PRId64));
-EXTERN const char e_invalblob[] INIT(= N_("E978: Invalid operation for Blob"));
-EXTERN const char e_toomanyarg[] INIT(= N_("E118: Too many arguments for function: %s"));
-EXTERN const char e_toofewarg[] INIT(= N_("E119: Not enough arguments for function: %s"));
-EXTERN const char e_dictkey[] INIT(= N_("E716: Key not present in Dictionary: \"%s\""));
-EXTERN const char e_dictkey_len[] INIT(= N_("E716: Key not present in Dictionary: \"%.*s\""));
-EXTERN const char e_listreq[] INIT(= N_("E714: List required"));
-EXTERN const char e_listblobreq[] INIT(= N_("E897: List or Blob required"));
-EXTERN const char e_listdictarg[] INIT(= N_("E712: Argument of %s must be a List or Dictionary"));
-EXTERN const char e_listdictblobarg[] INIT(= N_("E896: Argument of %s must be a List, Dictionary or Blob"));
-EXTERN const char e_readerrf[] INIT(= N_("E47: Error while reading errorfile"));
-EXTERN const char e_sandbox[] INIT(= N_("E48: Not allowed in sandbox"));
-EXTERN const char e_secure[] INIT(= N_("E523: Not allowed here"));
-EXTERN const char e_textlock[] INIT(= N_("E565: Not allowed to change text or change window"));
-EXTERN const char e_screenmode[] INIT(= N_("E359: Screen mode setting not supported"));
-EXTERN const char e_scroll[] INIT(= N_("E49: Invalid scroll size"));
-EXTERN const char e_shellempty[] INIT(= N_("E91: 'shell' option is empty"));
-EXTERN const char e_signdata[] INIT(= N_("E255: Couldn't read in sign data!"));
-EXTERN const char e_swapclose[] INIT(= N_("E72: Close error on swap file"));
-EXTERN const char e_toocompl[] INIT(= N_("E74: Command too complex"));
-EXTERN const char e_longname[] INIT(= N_("E75: Name too long"));
-EXTERN const char e_toomsbra[] INIT(= N_("E76: Too many ["));
-EXTERN const char e_toomany[] INIT(= N_("E77: Too many file names"));
-EXTERN const char e_trailing[] INIT(= N_("E488: Trailing characters"));
-EXTERN const char e_trailing_arg[] INIT(= N_("E488: Trailing characters: %s"));
-EXTERN const char e_umark[] INIT(= N_("E78: Unknown mark"));
-EXTERN const char e_wildexpand[] INIT(= N_("E79: Cannot expand wildcards"));
-EXTERN const char e_winheight[] INIT(= N_("E591: 'winheight' cannot be smaller than 'winminheight'"));
-EXTERN const char e_winwidth[] INIT(= N_("E592: 'winwidth' cannot be smaller than 'winminwidth'"));
-EXTERN const char e_write[] INIT(= N_("E80: Error while writing"));
-EXTERN const char e_zerocount[] INIT(= N_("E939: Positive count required"));
-EXTERN const char e_usingsid[] INIT(= N_("E81: Using <SID> not in a script context"));
-EXTERN const char e_missingparen[] INIT(= N_("E107: Missing parentheses: %s"));
-EXTERN const char e_empty_buffer[] INIT(= N_("E749: Empty buffer"));
-EXTERN const char e_nobufnr[] INIT(= N_("E86: Buffer %" PRId64 " does not exist"));
-
-EXTERN const char e_str_not_inside_function[] INIT(= N_("E193: %s not inside a function"));
-
-EXTERN const char e_invalpat[] INIT(= N_("E682: Invalid search pattern or delimiter"));
-EXTERN const char e_bufloaded[] INIT(= N_("E139: File is loaded in another buffer"));
-EXTERN const char e_notset[] INIT(= N_("E764: Option '%s' is not set"));
-EXTERN const char e_invalidreg[] INIT(= N_("E850: Invalid register name"));
-EXTERN const char e_dirnotf[] INIT(= N_("E919: Directory not found in '%s': \"%s\""));
-EXTERN const char e_au_recursive[] INIT(= N_("E952: Autocommand caused recursive behavior"));
-EXTERN const char e_menu_only_exists_in_another_mode[]
-INIT(= N_("E328: Menu only exists in another mode"));
-EXTERN const char e_autocmd_close[] INIT(= N_("E813: Cannot close autocmd window"));
-EXTERN const char e_listarg[] INIT(= N_("E686: Argument of %s must be a List"));
-EXTERN const char e_unsupportedoption[] INIT(= N_("E519: Option not supported"));
-EXTERN const char e_fnametoolong[] INIT(= N_("E856: Filename too long"));
-EXTERN const char e_using_float_as_string[] INIT(= N_("E806: Using a Float as a String"));
-EXTERN const char e_cannot_edit_other_buf[] INIT(= N_("E788: Not allowed to edit another buffer now"));
-EXTERN const char e_using_number_as_bool_nr[] INIT(= N_("E1023: Using a Number as a Bool: %d"));
-EXTERN const char e_not_callable_type_str[] INIT(= N_("E1085: Not a callable type: %s"));
-EXTERN const char e_auabort[] INIT(= N_("E855: Autocommands caused command to abort"));
-
-EXTERN const char e_api_error[] INIT(= N_("E5555: API call: %s"));
-
-EXTERN const char e_luv_api_disabled[] INIT(= N_("E5560: %s must not be called in a lua loop callback"));
-
-EXTERN const char e_floatonly[] INIT(= N_("E5601: Cannot close window, only floating window would remain"));
-EXTERN const char e_floatexchange[] INIT(= N_("E5602: Cannot exchange or rotate float"));
-
-EXTERN const char e_cannot_define_autocommands_for_all_events[] INIT(= N_("E1155: Cannot define autocommands for ALL events"));
-
-EXTERN const char e_resulting_text_too_long[] INIT(= N_("E1240: Resulting text too long"));
-
-EXTERN const char e_line_number_out_of_range[] INIT(= N_("E1247: Line number out of range"));
-
-EXTERN const char e_highlight_group_name_invalid_char[] INIT(= N_("E5248: Invalid character in group name"));
-
-EXTERN const char e_highlight_group_name_too_long[] INIT(= N_("E1249: Highlight group name too long"));
-
-EXTERN const char e_invalid_column_number_nr[] INIT( = N_("E964: Invalid column number: %ld"));
-EXTERN const char e_invalid_line_number_nr[] INIT(= N_("E966: Invalid line number: %ld"));
-
-EXTERN const char e_stray_closing_curly_str[]
-INIT(= N_("E1278: Stray '}' without a matching '{': %s"));
-EXTERN const char e_missing_close_curly_str[]
-INIT(= N_("E1279: Missing '}': %s"));
-
-EXTERN const char e_val_too_large[] INIT(= N_("E1510: Value too large: %s"));
-
-EXTERN const char e_undobang_cannot_redo_or_move_branch[]
-INIT(= N_("E5767: Cannot use :undo! to redo or move to a different undo branch"));
-
-EXTERN const char e_winfixbuf_cannot_go_to_buffer[]
-INIT(= N_("E1513: Cannot switch buffer. 'winfixbuf' is enabled"));
-
-EXTERN const char e_trustfile[] INIT(= N_("E5570: Cannot update trust file: %s"));
-
-EXTERN const char e_unknown_option2[] INIT(= N_("E355: Unknown option: %s"));
-
-EXTERN const char top_bot_msg[] INIT(= N_("search hit TOP, continuing at BOTTOM"));
-EXTERN const char bot_top_msg[] INIT(= N_("search hit BOTTOM, continuing at TOP"));
-
-EXTERN const char line_msg[] INIT(= N_(" line "));
-
-EXTERN FILE *time_fd INIT(= NULL); // Where to write --startuptime report.
+EXTERN FILE *time_fd INIT( = NULL); // Where to write --startuptime report.
// Some compilers warn for not using a return value, but in some situations we
// can't do anything useful with the value. Assign to this variable to avoid
@@ -989,11 +801,9 @@ EXTERN FILE *time_fd INIT(= NULL); // Where to write --startuptime report.
EXTERN int vim_ignored;
// stdio is an RPC channel (--embed).
-EXTERN bool embedded_mode INIT(= false);
+EXTERN bool embedded_mode INIT( = false);
// Do not start UI (--headless, -l) nor read/write to stdio (unless embedding).
-EXTERN bool headless_mode INIT(= false);
-
-// uncrustify:on
+EXTERN bool headless_mode INIT( = false);
/// Only filled for Win32.
EXTERN char windowsVersion[20] INIT( = { 0 });
diff --git a/src/nvim/help.c b/src/nvim/help.c
index e9f67ca3e4..6ba3e17e0b 100644
--- a/src/nvim/help.c
+++ b/src/nvim/help.c
@@ -13,6 +13,7 @@
#include "nvim/charset.h"
#include "nvim/cmdexpand.h"
#include "nvim/cmdexpand_defs.h"
+#include "nvim/errors.h"
#include "nvim/ex_cmds.h"
#include "nvim/ex_cmds_defs.h"
#include "nvim/ex_docmd.h"
@@ -654,7 +655,7 @@ void get_local_additions(void)
// files. This uses the very first line in the help file.
char *const fname = path_tail(curbuf->b_fname);
if (path_fnamecmp(fname, "help.txt") == 0
- || (path_fnamencmp(fname, "help.", 5) == 0
+ || (path_fnamencmp(fname, S_LEN("help.")) == 0
&& ASCII_ISALPHA(fname[5])
&& ASCII_ISALPHA(fname[6])
&& TOLOWER_ASC(fname[7]) == 'x'
@@ -957,8 +958,8 @@ static void helptags_one(char *dir, const char *ext, const char *tagfname, bool
if (s == p2
&& (p1 == IObuff || p1[-1] == ' ' || p1[-1] == '\t')
&& (vim_strchr(" \t\n\r", (uint8_t)s[1]) != NULL
- || s[1] == '\0')) {
- *p2 = '\0';
+ || s[1] == NUL)) {
+ *p2 = NUL;
p1++;
size_t s_len = (size_t)(p2 - p1) + strlen(fname) + 2;
s = xmalloc(s_len);
@@ -1014,7 +1015,7 @@ static void helptags_one(char *dir, const char *ext, const char *tagfname, bool
// Write the tags into the file.
for (int i = 0; i < ga.ga_len; i++) {
s = ((char **)ga.ga_data)[i];
- if (strncmp(s, "help-tags\t", 10) == 0) {
+ if (strncmp(s, S_LEN("help-tags\t")) == 0) {
// help-tags entry was added in formatted form
fputs(s, fd_tags);
} else {
@@ -1148,7 +1149,7 @@ void ex_helptags(exarg_T *eap)
bool add_help_tags = false;
// Check for ":helptags ++t {dir}".
- if (strncmp(eap->arg, "++t", 3) == 0 && ascii_iswhite(eap->arg[3])) {
+ if (strncmp(eap->arg, S_LEN("++t")) == 0 && ascii_iswhite(eap->arg[3])) {
add_help_tags = true;
eap->arg = skipwhite(eap->arg + 3);
}
diff --git a/src/nvim/highlight.h b/src/nvim/highlight.h
index cb3a84bcaf..558727fc51 100644
--- a/src/nvim/highlight.h
+++ b/src/nvim/highlight.h
@@ -78,6 +78,8 @@ EXTERN const char *hlf_names[] INIT( = {
[HLF_CU] = "Cursor",
[HLF_BTITLE] = "FloatTitle",
[HLF_BFOOTER] = "FloatFooter",
+ [HLF_TS] = "StatusLineTerm",
+ [HLF_TSNC] = "StatusLineTermNC",
});
EXTERN int highlight_attr[HLF_COUNT + 1]; // Highl. attr for each context.
diff --git a/src/nvim/highlight_defs.h b/src/nvim/highlight_defs.h
index 25ab9dc2d9..17e3db04da 100644
--- a/src/nvim/highlight_defs.h
+++ b/src/nvim/highlight_defs.h
@@ -125,6 +125,8 @@ typedef enum {
HLF_CU, ///< Cursor
HLF_BTITLE, ///< Float Border Title
HLF_BFOOTER, ///< Float Border Footer
+ HLF_TS, ///< status line for terminal window
+ HLF_TSNC, ///< status line for non-current terminal window
HLF_COUNT, ///< MUST be the last one
} hlf_T;
diff --git a/src/nvim/highlight_group.c b/src/nvim/highlight_group.c
index ccb093c116..cc9e606d1d 100644
--- a/src/nvim/highlight_group.c
+++ b/src/nvim/highlight_group.c
@@ -22,6 +22,7 @@
#include "nvim/cursor_shape.h"
#include "nvim/decoration_provider.h"
#include "nvim/drawscreen.h"
+#include "nvim/errors.h"
#include "nvim/eval.h"
#include "nvim/eval/typval_defs.h"
#include "nvim/eval/vars.h"
@@ -150,34 +151,36 @@ static const char *highlight_init_both[] = {
"lCursor guifg=bg guibg=fg",
// UI
- "default link CursorIM Cursor",
- "default link CursorLineFold FoldColumn",
- "default link CursorLineSign SignColumn",
- "default link EndOfBuffer NonText",
- "default link FloatBorder NormalFloat",
- "default link FloatFooter FloatTitle",
- "default link FloatTitle Title",
- "default link FoldColumn SignColumn",
- "default link IncSearch CurSearch",
- "default link LineNrAbove LineNr",
- "default link LineNrBelow LineNr",
- "default link MsgSeparator StatusLine",
- "default link MsgArea NONE",
- "default link NormalNC NONE",
- "default link PmenuExtra Pmenu",
- "default link PmenuExtraSel PmenuSel",
- "default link PmenuKind Pmenu",
- "default link PmenuKindSel PmenuSel",
- "default link PmenuSbar Pmenu",
- "default link Substitute Search",
- "default link TabLine StatusLineNC",
- "default link TabLineFill TabLine",
- "default link TermCursorNC NONE",
- "default link VertSplit WinSeparator",
- "default link VisualNOS Visual",
- "default link Whitespace NonText",
- "default link WildMenu PmenuSel",
- "default link WinSeparator Normal",
+ "default link CursorIM Cursor",
+ "default link CursorLineFold FoldColumn",
+ "default link CursorLineSign SignColumn",
+ "default link EndOfBuffer NonText",
+ "default link FloatBorder NormalFloat",
+ "default link FloatFooter FloatTitle",
+ "default link FloatTitle Title",
+ "default link FoldColumn SignColumn",
+ "default link IncSearch CurSearch",
+ "default link LineNrAbove LineNr",
+ "default link LineNrBelow LineNr",
+ "default link MsgSeparator StatusLine",
+ "default link MsgArea NONE",
+ "default link NormalNC NONE",
+ "default link PmenuExtra Pmenu",
+ "default link PmenuExtraSel PmenuSel",
+ "default link PmenuKind Pmenu",
+ "default link PmenuKindSel PmenuSel",
+ "default link PmenuSbar Pmenu",
+ "default link Substitute Search",
+ "default link StatusLineTerm StatusLine",
+ "default link StatusLineTermNC StatusLineNC",
+ "default link TabLine StatusLineNC",
+ "default link TabLineFill TabLine",
+ "default link TermCursorNC NONE",
+ "default link VertSplit WinSeparator",
+ "default link VisualNOS Visual",
+ "default link Whitespace NonText",
+ "default link WildMenu PmenuSel",
+ "default link WinSeparator Normal",
// Syntax
"default link Character Constant",
@@ -1056,7 +1059,7 @@ void do_highlight(const char *line, const bool forceit, const bool init)
}
int from_id = syn_check_group(from_start, (size_t)(from_end - from_start));
- if (strncmp(to_start, "NONE", 4) == 0) {
+ if (strncmp(to_start, S_LEN("NONE")) == 0) {
to_id = 0;
} else {
to_id = syn_check_group(to_start, (size_t)(to_end - to_start));
@@ -1173,7 +1176,7 @@ void do_highlight(const char *line, const bool forceit, const bool init)
break;
}
vim_memcpy_up(key, key_start, key_len);
- key[key_len] = '\0';
+ key[key_len] = NUL;
linep = skipwhite(linep);
if (strcmp(key, "NONE") == 0) {
@@ -1966,7 +1969,7 @@ int syn_name2id_len(const char *name, size_t len)
// Avoid using stricmp() too much, it's slow on some systems
// Avoid alloc()/free(), these are slow too.
vim_memcpy_up(name_u, name, len);
- name_u[len] = '\0';
+ name_u[len] = NUL;
// map_get(..., int) returns 0 when no key is present, which is
// the expected value for missing highlight group.
diff --git a/src/nvim/indent.c b/src/nvim/indent.c
index d635c7d7bf..a4964db465 100644
--- a/src/nvim/indent.c
+++ b/src/nvim/indent.c
@@ -13,6 +13,7 @@
#include "nvim/cursor.h"
#include "nvim/drawscreen.h"
#include "nvim/edit.h"
+#include "nvim/errors.h"
#include "nvim/eval.h"
#include "nvim/eval/typval_defs.h"
#include "nvim/ex_cmds_defs.h"
@@ -146,25 +147,42 @@ int tabstop_padding(colnr_T col, OptInt ts_arg, const colnr_T *vts)
}
/// Find the size of the tab that covers a particular column.
-int tabstop_at(colnr_T col, OptInt ts, const colnr_T *vts)
+///
+/// If this is being called as part of a shift operation, col is not the cursor
+/// column but is the column number to the left of the first non-whitespace
+/// character in the line. If the shift is to the left (left == true), then
+/// return the size of the tab interval to the left of the column.
+int tabstop_at(colnr_T col, OptInt ts, const colnr_T *vts, bool left)
{
- colnr_T tabcol = 0;
- int t;
- int tab_size = 0;
-
if (vts == NULL || vts[0] == 0) {
return (int)ts;
}
- const int tabcount = vts[0];
+ colnr_T tabcol = 0; // Column of the tab stop under consideration.
+ int t; // Tabstop index in the list of variable tab stops.
+ int tab_size = 0; // Size of the tab stop interval to the right or left of the col.
+ const int tabcount // Number of tab stops in the list of variable tab stops.
+ = vts[0];
for (t = 1; t <= tabcount; t++) {
tabcol += vts[t];
if (tabcol > col) {
- tab_size = vts[t];
+ // If shifting left (left == true), and if the column to the left of
+ // the first first non-blank character (col) in the line is
+ // already to the left of the first tabstop, set the shift amount
+ // (tab_size) to just enough to shift the line to the left margin.
+ // The value doesn't seem to matter as long as it is at least that
+ // distance.
+ if (left && (t == 1)) {
+ tab_size = col;
+ } else {
+ tab_size = vts[t - (left ? 1 : 0)];
+ }
break;
}
}
- if (t > tabcount) {
+ if (t > tabcount) { // If the value of the index t is beyond the
+ // end of the list, use the tab stop value at
+ // the end of the list.
tab_size = vts[tabcount];
}
@@ -311,35 +329,35 @@ int tabstop_first(colnr_T *ts)
/// 'tabstop' value when 'shiftwidth' is zero.
int get_sw_value(buf_T *buf)
{
- int result = get_sw_value_col(buf, 0);
+ int result = get_sw_value_col(buf, 0, false);
return result;
}
/// Idem, using "pos".
-int get_sw_value_pos(buf_T *buf, pos_T *pos)
+int get_sw_value_pos(buf_T *buf, pos_T *pos, bool left)
{
pos_T save_cursor = curwin->w_cursor;
curwin->w_cursor = *pos;
- int sw_value = get_sw_value_col(buf, get_nolist_virtcol());
+ int sw_value = get_sw_value_col(buf, get_nolist_virtcol(), left);
curwin->w_cursor = save_cursor;
return sw_value;
}
/// Idem, using the first non-black in the current line.
-int get_sw_value_indent(buf_T *buf)
+int get_sw_value_indent(buf_T *buf, bool left)
{
pos_T pos = curwin->w_cursor;
pos.col = (colnr_T)getwhitecols_curline();
- return get_sw_value_pos(buf, &pos);
+ return get_sw_value_pos(buf, &pos, left);
}
/// Idem, using virtual column "col".
-int get_sw_value_col(buf_T *buf, colnr_T col)
+int get_sw_value_col(buf_T *buf, colnr_T col, bool left)
{
return buf->b_p_sw ? (int)buf->b_p_sw
- : tabstop_at(col, buf->b_p_ts, buf->b_p_vts_array);
+ : tabstop_at(col, buf->b_p_ts, buf->b_p_vts_array, left);
}
/// Return the effective softtabstop value for the current buffer,
@@ -764,20 +782,20 @@ bool briopt_check(win_T *wp)
char *p = wp->w_p_briopt;
while (*p != NUL) {
// Note: Keep this in sync with p_briopt_values
- if (strncmp(p, "shift:", 6) == 0
+ if (strncmp(p, S_LEN("shift:")) == 0
&& ((p[6] == '-' && ascii_isdigit(p[7])) || ascii_isdigit(p[6]))) {
p += 6;
bri_shift = getdigits_int(&p, true, 0);
- } else if (strncmp(p, "min:", 4) == 0 && ascii_isdigit(p[4])) {
+ } else if (strncmp(p, S_LEN("min:")) == 0 && ascii_isdigit(p[4])) {
p += 4;
bri_min = getdigits_int(&p, true, 0);
- } else if (strncmp(p, "sbr", 3) == 0) {
+ } else if (strncmp(p, S_LEN("sbr")) == 0) {
p += 3;
bri_sbr = true;
- } else if (strncmp(p, "list:", 5) == 0) {
+ } else if (strncmp(p, S_LEN("list:")) == 0) {
p += 5;
bri_list = (int)getdigits(&p, false, 0);
- } else if (strncmp(p, "column:", 7) == 0) {
+ } else if (strncmp(p, S_LEN("column:")) == 0) {
p += 7;
bri_vcol = (int)getdigits(&p, false, 0);
}
diff --git a/src/nvim/insexpand.c b/src/nvim/insexpand.c
index 8b1c09b32f..711e2292b1 100644
--- a/src/nvim/insexpand.c
+++ b/src/nvim/insexpand.c
@@ -22,6 +22,7 @@
#include "nvim/cursor.h"
#include "nvim/drawscreen.h"
#include "nvim/edit.h"
+#include "nvim/errors.h"
#include "nvim/eval.h"
#include "nvim/eval/typval.h"
#include "nvim/eval/typval_defs.h"
@@ -167,6 +168,7 @@ struct compl_S {
///< cp_flags has CP_FREE_FNAME
int cp_flags; ///< CP_ values
int cp_number; ///< sequence number
+ int cp_score; ///< fuzzy match score
};
/// state information used for getting the next set of insert completion
@@ -224,13 +226,6 @@ static char *compl_leader = NULL;
static bool compl_get_longest = false; ///< put longest common string in compl_leader
-static bool compl_no_insert = false; ///< false: select & insert
- ///< true: noinsert
-static bool compl_no_select = false; ///< false: select & insert
- ///< true: noselect
-static bool compl_longest = false; ///< false: insert full match
- ///< true: insert longest prefix
-
/// Selected one of the matches. When false the match was edited or using the
/// longest common string.
static bool compl_used_match;
@@ -287,7 +282,7 @@ static bool compl_opt_refresh_always = false;
static size_t spell_bad_len = 0; // length of located bad word
-static int pum_selected_item = -1;
+static int compl_selected_item = -1;
/// CTRL-X pressed in Insert mode.
void ins_ctrl_x(void)
@@ -1048,22 +1043,10 @@ bool ins_compl_long_shown_match(void)
&& (colnr_T)strlen(compl_shown_match->cp_str) > curwin->w_cursor.col - compl_col;
}
-/// Set variables that store noselect and noinsert behavior from the
-/// 'completeopt' value.
-void completeopt_was_set(void)
+/// Get the local or global value of 'completeopt' flags.
+unsigned get_cot_flags(void)
{
- compl_no_insert = false;
- compl_no_select = false;
- compl_longest = false;
- if (strstr(p_cot, "noselect") != NULL) {
- compl_no_select = true;
- }
- if (strstr(p_cot, "noinsert") != NULL) {
- compl_no_insert = true;
- }
- if (strstr(p_cot, "longest") != NULL) {
- compl_longest = true;
- }
+ return curbuf->b_cot_flags != 0 ? curbuf->b_cot_flags : cot_flags;
}
/// "compl_match_array" points the currently displayed list of entries in the
@@ -1087,7 +1070,7 @@ bool pum_wanted(void)
FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
{
// "completeopt" must contain "menu" or "menuone"
- return vim_strchr(p_cot, 'm') != NULL;
+ return (get_cot_flags() & COT_ANY_MENU) != 0;
}
/// Check that there are two or more matches to be shown in the popup menu.
@@ -1106,7 +1089,7 @@ static bool pum_enough_matches(void)
comp = comp->cp_next;
} while (!is_first_match(comp));
- if (strstr(p_cot, "menuone") != NULL) {
+ if (get_cot_flags() & COT_MENUONE) {
return i >= 1;
}
return i >= 2;
@@ -1160,6 +1143,14 @@ static void trigger_complete_changed_event(int cur)
restore_v_event(v_event, &save_v_event);
}
+/// pumitem qsort compare func
+static int ins_compl_fuzzy_sort(const void *a, const void *b)
+{
+ const int sa = (*(pumitem_T *)a).pum_score;
+ const int sb = (*(pumitem_T *)b).pum_score;
+ return sa == sb ? 0 : sa < sb ? 1 : -1;
+}
+
/// Build a popup menu to show the completion matches.
///
/// @return the popup menu entry that should be selected,
@@ -1177,11 +1168,22 @@ static int ins_compl_build_pum(void)
}
const int lead_len = compl_leader != NULL ? (int)strlen(compl_leader) : 0;
+ int max_fuzzy_score = 0;
+ unsigned cur_cot_flags = get_cot_flags();
+ bool compl_no_select = (cur_cot_flags & COT_NOSELECT) != 0;
+ bool compl_fuzzy_match = (cur_cot_flags & COT_FUZZY) != 0;
do {
+ // When 'completeopt' contains "fuzzy" and leader is not NULL or empty,
+ // set the cp_score for later comparisons.
+ if (compl_fuzzy_match && compl_leader != NULL && lead_len > 0) {
+ comp->cp_score = fuzzy_match_str(comp->cp_str, compl_leader);
+ }
+
if (!match_at_original_text(comp)
&& (compl_leader == NULL
- || ins_compl_equal(comp, compl_leader, (size_t)lead_len))) {
+ || ins_compl_equal(comp, compl_leader, (size_t)lead_len)
+ || (compl_fuzzy_match && comp->cp_score > 0))) {
compl_match_arraysize++;
}
comp = comp->cp_next;
@@ -1210,8 +1212,9 @@ static int ins_compl_build_pum(void)
do {
if (!match_at_original_text(comp)
&& (compl_leader == NULL
- || ins_compl_equal(comp, compl_leader, (size_t)lead_len))) {
- if (!shown_match_ok) {
+ || ins_compl_equal(comp, compl_leader, (size_t)lead_len)
+ || (compl_fuzzy_match && comp->cp_score > 0))) {
+ if (!shown_match_ok && !compl_fuzzy_match) {
if (comp == compl_shown_match || did_find_shown_match) {
// This item is the shown match or this is the
// first displayed item after the shown match.
@@ -1224,6 +1227,26 @@ static int ins_compl_build_pum(void)
shown_compl = comp;
}
cur = i;
+ } else if (compl_fuzzy_match) {
+ // Update the maximum fuzzy score and the shown match
+ // if the current item's score is higher
+ if (comp->cp_score > max_fuzzy_score) {
+ did_find_shown_match = true;
+ max_fuzzy_score = comp->cp_score;
+ compl_shown_match = comp;
+ shown_match_ok = true;
+ }
+
+ // If there is no "no select" condition and the max fuzzy
+ // score is positive, or there is no completion leader or the
+ // leader length is zero, mark the shown match as valid and
+ // reset the current index.
+ if (!compl_no_select
+ && (max_fuzzy_score > 0
+ || (compl_leader == NULL || lead_len == 0))) {
+ shown_match_ok = true;
+ cur = 0;
+ }
}
if (comp->cp_text[CPT_ABBR] != NULL) {
@@ -1233,6 +1256,7 @@ static int ins_compl_build_pum(void)
}
compl_match_array[i].pum_kind = comp->cp_text[CPT_KIND];
compl_match_array[i].pum_info = comp->cp_text[CPT_INFO];
+ compl_match_array[i].pum_score = comp->cp_score;
if (comp->cp_text[CPT_MENU] != NULL) {
compl_match_array[i++].pum_extra = comp->cp_text[CPT_MENU];
} else {
@@ -1240,7 +1264,7 @@ static int ins_compl_build_pum(void)
}
}
- if (comp == compl_shown_match) {
+ if (comp == compl_shown_match && !compl_fuzzy_match) {
did_find_shown_match = true;
// When the original text is the shown match don't set
@@ -1259,6 +1283,12 @@ static int ins_compl_build_pum(void)
comp = comp->cp_next;
} while (comp != NULL && !is_first_match(comp));
+ if (compl_fuzzy_match && compl_leader != NULL && lead_len > 0) {
+ // sort by the largest score of fuzzy match
+ qsort(compl_match_array, (size_t)compl_match_arraysize, sizeof(pumitem_T),
+ ins_compl_fuzzy_sort);
+ }
+
if (!shown_match_ok) { // no displayed match at all
cur = -1;
}
@@ -1310,7 +1340,7 @@ void ins_compl_show_pum(void)
// Use the cursor to get all wrapping and other settings right.
const colnr_T col = curwin->w_cursor.col;
curwin->w_cursor.col = compl_col;
- pum_selected_item = cur;
+ compl_selected_item = cur;
pum_display(compl_match_array, compl_match_arraysize, cur, array_changed, 0);
curwin->w_cursor.col = col;
@@ -2178,7 +2208,7 @@ bool ins_compl_prep(int c)
// Set "compl_get_longest" when finding the first matches.
if (ctrl_x_mode_not_defined_yet()
|| (ctrl_x_mode_normal() && !compl_started)) {
- compl_get_longest = compl_longest;
+ compl_get_longest = (get_cot_flags() & COT_LONGEST) != 0;
compl_used_match = true;
}
@@ -2598,6 +2628,10 @@ static void restore_orig_extmarks(void)
static void set_completion(colnr_T startcol, list_T *list)
{
int flags = CP_ORIGINAL_TEXT;
+ unsigned cur_cot_flags = get_cot_flags();
+ bool compl_longest = (cur_cot_flags & COT_LONGEST) != 0;
+ bool compl_no_insert = (cur_cot_flags & COT_NOINSERT) != 0;
+ bool compl_no_select = (cur_cot_flags & COT_NOSELECT) != 0;
// If already doing completions stop it.
if (ctrl_x_mode_not_default()) {
@@ -3588,6 +3622,42 @@ static void ins_compl_show_filename(void)
redraw_cmdline = false; // don't overwrite!
}
+/// Find a completion item when 'completeopt' contains "fuzzy".
+static compl_T *find_comp_when_fuzzy(void)
+{
+ int target_idx = -1;
+ const bool is_forward = compl_shows_dir_forward();
+ const bool is_backward = compl_shows_dir_backward();
+ compl_T *comp = NULL;
+
+ if (compl_match_array == NULL
+ || (is_forward && compl_selected_item == compl_match_arraysize - 1)
+ || (is_backward && compl_selected_item == 0)) {
+ return compl_first_match;
+ }
+
+ if (is_forward) {
+ target_idx = compl_selected_item + 1;
+ } else if (is_backward) {
+ target_idx = compl_selected_item == -1 ? compl_match_arraysize - 1
+ : compl_selected_item - 1;
+ }
+
+ const int score = compl_match_array[target_idx].pum_score;
+ char *const str = compl_match_array[target_idx].pum_text;
+
+ comp = compl_first_match;
+ do {
+ if (comp->cp_score == score
+ && (str == comp->cp_str || str == comp->cp_text[CPT_ABBR])) {
+ return comp;
+ }
+ comp = comp->cp_next;
+ } while (comp != NULL && !is_first_match(comp));
+
+ return NULL;
+}
+
/// Find the next set of matches for completion. Repeat the completion "todo"
/// times. The number of matches found is returned in 'num_matches'.
///
@@ -3605,17 +3675,22 @@ static int find_next_completion_match(bool allow_get_expansion, int todo, bool a
{
bool found_end = false;
compl_T *found_compl = NULL;
+ unsigned cur_cot_flags = get_cot_flags();
+ bool compl_no_select = (cur_cot_flags & COT_NOSELECT) != 0;
+ bool compl_fuzzy_match = (cur_cot_flags & COT_FUZZY) != 0;
while (--todo >= 0) {
if (compl_shows_dir_forward() && compl_shown_match->cp_next != NULL) {
- compl_shown_match = compl_shown_match->cp_next;
+ compl_shown_match = !compl_fuzzy_match ? compl_shown_match->cp_next
+ : find_comp_when_fuzzy();
found_end = (compl_first_match != NULL
&& (is_first_match(compl_shown_match->cp_next)
|| is_first_match(compl_shown_match)));
} else if (compl_shows_dir_backward()
&& compl_shown_match->cp_prev != NULL) {
found_end = is_first_match(compl_shown_match);
- compl_shown_match = compl_shown_match->cp_prev;
+ compl_shown_match = !compl_fuzzy_match ? compl_shown_match->cp_prev
+ : find_comp_when_fuzzy();
found_end |= is_first_match(compl_shown_match);
} else {
if (!allow_get_expansion) {
@@ -3659,7 +3734,8 @@ static int find_next_completion_match(bool allow_get_expansion, int todo, bool a
if (!match_at_original_text(compl_shown_match)
&& compl_leader != NULL
&& !ins_compl_equal(compl_shown_match,
- compl_leader, strlen(compl_leader))) {
+ compl_leader, strlen(compl_leader))
+ && !(compl_fuzzy_match && compl_shown_match->cp_score > 0)) {
todo++;
} else {
// Remember a matching item.
@@ -3704,6 +3780,9 @@ static int ins_compl_next(bool allow_get_expansion, int count, bool insert_match
int todo = count;
const bool started = compl_started;
buf_T *const orig_curbuf = curbuf;
+ unsigned cur_cot_flags = get_cot_flags();
+ bool compl_no_insert = (cur_cot_flags & COT_NOINSERT) != 0;
+ bool compl_fuzzy_match = (cur_cot_flags & COT_FUZZY) != 0;
// When user complete function return -1 for findstart which is next
// time of 'always', compl_shown_match become NULL.
@@ -3711,7 +3790,9 @@ static int ins_compl_next(bool allow_get_expansion, int count, bool insert_match
return -1;
}
- if (compl_leader != NULL && !match_at_original_text(compl_shown_match)) {
+ if (compl_leader != NULL
+ && !match_at_original_text(compl_shown_match)
+ && !compl_fuzzy_match) {
// Update "compl_shown_match" to the actually shown match
ins_compl_update_shown_match();
}
@@ -3840,7 +3921,7 @@ void ins_compl_check_keys(int frequency, bool in_compl_func)
}
}
}
- if (compl_pending != 0 && !got_int && !compl_no_insert) {
+ if (compl_pending != 0 && !got_int && !(cot_flags & COT_NOINSERT)) {
int todo = compl_pending > 0 ? compl_pending : -compl_pending;
compl_pending = 0;
@@ -3853,7 +3934,7 @@ void ins_compl_check_keys(int frequency, bool in_compl_func)
static int ins_compl_key2dir(int c)
{
if (c == K_EVENT || c == K_COMMAND || c == K_LUA) {
- return pum_want.item < pum_selected_item ? BACKWARD : FORWARD;
+ return pum_want.item < compl_selected_item ? BACKWARD : FORWARD;
}
if (c == Ctrl_P || c == Ctrl_L
|| c == K_PAGEUP || c == K_KPAGEUP
@@ -3879,7 +3960,7 @@ static bool ins_compl_pum_key(int c)
static int ins_compl_key2count(int c)
{
if (c == K_EVENT || c == K_COMMAND || c == K_LUA) {
- int offset = pum_want.item - pum_selected_item;
+ int offset = pum_want.item - compl_selected_item;
return abs(offset);
}
@@ -3978,7 +4059,7 @@ static int get_normal_compl_info(char *line, int startcol, colnr_T curs_col)
compl_pattern = xmalloc(7);
STRCPY(compl_pattern, "\\<");
quote_meta(compl_pattern + 2, line + compl_col, 1);
- STRCAT(compl_pattern, "\\k");
+ strcat(compl_pattern, "\\k");
} else {
compl_pattern = xmalloc(quote_meta(NULL, line + compl_col, compl_length) + 2);
STRCPY(compl_pattern, "\\<");
diff --git a/src/nvim/keycodes.c b/src/nvim/keycodes.c
index 44ddfbba00..a2dffa4602 100644
--- a/src/nvim/keycodes.c
+++ b/src/nvim/keycodes.c
@@ -8,6 +8,7 @@
#include "nvim/ascii_defs.h"
#include "nvim/charset.h"
+#include "nvim/errors.h"
#include "nvim/eval/typval_defs.h"
#include "nvim/eval/vars.h"
#include "nvim/gettext_defs.h"
@@ -903,7 +904,7 @@ char *replace_termcodes(const char *const from, const size_t from_len, char **co
}
// Check for special <> keycodes, like "<C-S-LeftMouse>"
if (do_special && ((flags & REPTERM_DO_LT) || ((end - src) >= 3
- && strncmp(src, "<lt>", 4) != 0))) {
+ && strncmp(src, S_LEN("<lt>")) != 0))) {
// Change <SID>Func to K_SNR <script-nr> _Func. This name is used
// for script-local user functions.
// (room: 5 * 6 = 30 bytes; needed: 3 + <nr> + 1 <= 14)
diff --git a/src/nvim/linematch.c b/src/nvim/linematch.c
index c34b303193..24b2c82381 100644
--- a/src/nvim/linematch.c
+++ b/src/nvim/linematch.c
@@ -5,6 +5,7 @@
#include <stdint.h>
#include <string.h>
+#include "nvim/ascii_defs.h"
#include "nvim/linematch.h"
#include "nvim/macros_defs.h"
#include "nvim/memory.h"
@@ -61,7 +62,7 @@ static int matching_chars_iwhite(const char *s1, const char *s2)
d++;
}
}
- strsproc[k][i] = '\0';
+ strsproc[k][i] = NUL;
}
int matching = matching_chars(strsproc[0], strsproc[1]);
xfree(strsproc[0]);
diff --git a/src/nvim/log.c b/src/nvim/log.c
index fbb3e0385a..774f1c956d 100644
--- a/src/nvim/log.c
+++ b/src/nvim/log.c
@@ -46,7 +46,7 @@ static uv_mutex_t mutex;
static bool log_try_create(char *fname)
{
- if (fname == NULL || fname[0] == '\0') {
+ if (fname == NULL || fname[0] == NUL) {
return false;
}
FILE *log_file = fopen(fname, "a");
@@ -67,7 +67,7 @@ static void log_path_init(void)
size_t size = sizeof(log_file_path);
expand_env("$" ENV_LOGFILE, log_file_path, (int)size - 1);
if (strequal("$" ENV_LOGFILE, log_file_path)
- || log_file_path[0] == '\0'
+ || log_file_path[0] == NUL
|| os_isdir(log_file_path)
|| !log_try_create(log_file_path)) {
// Make $XDG_STATE_HOME if it does not exist.
@@ -88,7 +88,7 @@ static void log_path_init(void)
}
// Fall back to stderr
if (len >= size || !log_try_create(log_file_path)) {
- log_file_path[0] = '\0';
+ log_file_path[0] = NUL;
return;
}
os_setenv(ENV_LOGFILE, log_file_path, true);
@@ -324,7 +324,7 @@ static bool v_do_log_to_file(FILE *log_file, int log_level, const char *context,
// Get a name for this Nvim instance.
// TODO(justinmk): expose this as v:name ?
- if (name[0] == '\0') {
+ if (name[0] == NUL) {
// Parent servername.
const char *parent = path_tail(os_getenv(ENV_NVIM));
// Servername. Empty until starting=false.
@@ -350,7 +350,7 @@ static bool v_do_log_to_file(FILE *log_file, int log_level, const char *context,
func_name, line_num);
if (name[0] == '?') {
// No v:servername yet. Clear `name` so that the next log can try again.
- name[0] = '\0';
+ name[0] = NUL;
}
if (rv < 0) {
diff --git a/src/nvim/lua/api_wrappers.c b/src/nvim/lua/api_wrappers.c
index 2b7b0c6471..36847d1fc9 100644
--- a/src/nvim/lua/api_wrappers.c
+++ b/src/nvim/lua/api_wrappers.c
@@ -5,6 +5,7 @@
#include "nvim/api/private/defs.h"
#include "nvim/api/private/dispatch.h"
#include "nvim/api/private/helpers.h"
+#include "nvim/errors.h"
#include "nvim/ex_docmd.h"
#include "nvim/ex_getln.h"
#include "nvim/func_attr.h"
diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c
index a76b8213e5..6246452b92 100644
--- a/src/nvim/lua/executor.c
+++ b/src/nvim/lua/executor.c
@@ -22,6 +22,7 @@
#include "nvim/cmdexpand_defs.h"
#include "nvim/cursor.h"
#include "nvim/drawscreen.h"
+#include "nvim/errors.h"
#include "nvim/eval.h"
#include "nvim/eval/funcs.h"
#include "nvim/eval/typval.h"
diff --git a/src/nvim/lua/secure.c b/src/nvim/lua/secure.c
index f62e0ace04..61277949c4 100644
--- a/src/nvim/lua/secure.c
+++ b/src/nvim/lua/secure.c
@@ -3,6 +3,7 @@
#include <string.h>
#include "nvim/charset.h"
+#include "nvim/errors.h"
#include "nvim/ex_cmds_defs.h"
#include "nvim/gettext_defs.h"
#include "nvim/globals.h"
@@ -103,12 +104,12 @@ void ex_trust(exarg_T *eap)
action = "deny";
} else if (strcmp(arg1, "++remove") == 0) {
action = "remove";
- } else if (*arg1 != '\0') {
+ } else if (*arg1 != NUL) {
semsg(e_invarg2, arg1);
goto theend;
}
- if (path[0] == '\0') {
+ if (path[0] == NUL) {
path = NULL;
}
diff --git a/src/nvim/lua/spell.c b/src/nvim/lua/spell.c
index ba83239dc5..f4dacd7a55 100644
--- a/src/nvim/lua/spell.c
+++ b/src/nvim/lua/spell.c
@@ -7,6 +7,7 @@
#include "nvim/ascii_defs.h"
#include "nvim/buffer_defs.h"
+#include "nvim/errors.h"
#include "nvim/gettext_defs.h"
#include "nvim/globals.h"
#include "nvim/highlight_defs.h"
diff --git a/src/nvim/lua/stdlib.c b/src/nvim/lua/stdlib.c
index 22ee0a1c98..ee0eabbebb 100644
--- a/src/nvim/lua/stdlib.c
+++ b/src/nvim/lua/stdlib.c
@@ -17,10 +17,13 @@
#include "nvim/api/private/defs.h"
#include "nvim/api/private/helpers.h"
#include "nvim/ascii_defs.h"
+#include "nvim/autocmd.h"
#include "nvim/buffer_defs.h"
#include "nvim/eval/typval.h"
#include "nvim/eval/typval_defs.h"
#include "nvim/eval/vars.h"
+#include "nvim/eval/window.h"
+#include "nvim/ex_docmd.h"
#include "nvim/ex_eval.h"
#include "nvim/fold.h"
#include "nvim/globals.h"
@@ -40,6 +43,7 @@
#include "nvim/runtime.h"
#include "nvim/strings.h"
#include "nvim/types_defs.h"
+#include "nvim/window.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "lua/stdlib.c.generated.h"
@@ -568,6 +572,99 @@ static int nlua_foldupdate(lua_State *lstate)
return 0;
}
+static int nlua_with(lua_State *L)
+{
+ int flags = 0;
+ buf_T *buf = NULL;
+ win_T *win = NULL;
+
+#define APPLY_FLAG(key, flag) \
+ if (strequal((key), k) && (v)) { \
+ flags |= (flag); \
+ }
+
+ luaL_argcheck(L, lua_istable(L, 1), 1, "table expected");
+ lua_pushnil(L); // [dict, ..., nil]
+ while (lua_next(L, 1)) {
+ // [dict, ..., key, value]
+ if (lua_type(L, -2) == LUA_TSTRING) {
+ const char *k = lua_tostring(L, -2);
+ bool v = lua_toboolean(L, -1);
+ if (strequal("buf", k)) { \
+ buf = handle_get_buffer((int)luaL_checkinteger(L, -1));
+ } else if (strequal("win", k)) { \
+ win = handle_get_window((int)luaL_checkinteger(L, -1));
+ } else {
+ APPLY_FLAG("sandbox", CMOD_SANDBOX);
+ APPLY_FLAG("silent", CMOD_SILENT);
+ APPLY_FLAG("emsg_silent", CMOD_ERRSILENT);
+ APPLY_FLAG("unsilent", CMOD_UNSILENT);
+ APPLY_FLAG("noautocmd", CMOD_NOAUTOCMD);
+ APPLY_FLAG("hide", CMOD_HIDE);
+ APPLY_FLAG("keepalt", CMOD_KEEPALT);
+ APPLY_FLAG("keepmarks", CMOD_KEEPMARKS);
+ APPLY_FLAG("keepjumps", CMOD_KEEPJUMPS);
+ APPLY_FLAG("lockmarks", CMOD_LOCKMARKS);
+ APPLY_FLAG("keeppatterns", CMOD_KEEPPATTERNS);
+ }
+ }
+ // pop the value; lua_next will pop the key.
+ lua_pop(L, 1); // [dict, ..., key]
+ }
+ int status = 0;
+ int rets = 0;
+
+ cmdmod_T save_cmdmod = cmdmod;
+ cmdmod.cmod_flags = flags;
+ apply_cmdmod(&cmdmod);
+
+ if (buf || win) {
+ try_start();
+ }
+
+ aco_save_T aco;
+ win_execute_T win_execute_args;
+ Error err = ERROR_INIT;
+
+ if (win) {
+ tabpage_T *tabpage = win_find_tabpage(win);
+ if (!win_execute_before(&win_execute_args, win, tabpage)) {
+ goto end;
+ }
+ } else if (buf) {
+ aucmd_prepbuf(&aco, buf);
+ }
+
+ int s = lua_gettop(L);
+ lua_pushvalue(L, 2);
+ status = lua_pcall(L, 0, LUA_MULTRET, 0);
+ rets = lua_gettop(L) - s;
+
+ if (win) {
+ win_execute_after(&win_execute_args);
+ } else if (buf) {
+ aucmd_restbuf(&aco);
+ }
+
+end:
+ if (buf || win) {
+ try_end(&err);
+ }
+
+ undo_cmdmod(&cmdmod);
+ cmdmod = save_cmdmod;
+
+ if (status) {
+ return lua_error(L);
+ } else if (ERROR_SET(&err)) {
+ nlua_push_errstr(L, "%s", err.msg);
+ api_clear_error(&err);
+ return lua_error(L);
+ }
+
+ return rets;
+}
+
// Access to internal functions. For use in runtime/
static void nlua_state_add_internal(lua_State *const lstate)
{
@@ -582,6 +679,9 @@ static void nlua_state_add_internal(lua_State *const lstate)
// _updatefolds
lua_pushcfunction(lstate, &nlua_foldupdate);
lua_setfield(lstate, -2, "_foldupdate");
+
+ lua_pushcfunction(lstate, &nlua_with);
+ lua_setfield(lstate, -2, "_with_c");
}
void nlua_state_add_stdlib(lua_State *const lstate, bool is_thread)
diff --git a/src/nvim/lua/treesitter.c b/src/nvim/lua/treesitter.c
index e87cf756a8..b13a162074 100644
--- a/src/nvim/lua/treesitter.c
+++ b/src/nvim/lua/treesitter.c
@@ -279,7 +279,7 @@ static const char *input_cb(void *payload, uint32_t byte_index, TSPoint position
memcpy(buf, line + position.column, tocopy);
// Translate embedded \n to NUL
- memchrsub(buf, '\n', '\0', tocopy);
+ memchrsub(buf, '\n', NUL, tocopy);
*bytes_read = (uint32_t)tocopy;
if (tocopy < BUFSIZE) {
// now add the final \n. If it didn't fit, input_cb will be called again
diff --git a/src/nvim/main.c b/src/nvim/main.c
index cf1324d37f..5e243df975 100644
--- a/src/nvim/main.c
+++ b/src/nvim/main.c
@@ -37,6 +37,7 @@
#include "nvim/diff.h"
#include "nvim/drawline.h"
#include "nvim/drawscreen.h"
+#include "nvim/errors.h"
#include "nvim/eval.h"
#include "nvim/eval/typval.h"
#include "nvim/eval/typval_defs.h"
@@ -154,7 +155,6 @@ void event_init(void)
loop_init(&main_loop, NULL);
resize_events = multiqueue_new_child(main_loop.events);
- input_init();
signal_init();
// mspgack-rpc initialization
channel_init();
diff --git a/src/nvim/mapping.c b/src/nvim/mapping.c
index 9320390d68..d02c865328 100644
--- a/src/nvim/mapping.c
+++ b/src/nvim/mapping.c
@@ -19,6 +19,7 @@
#include "nvim/charset.h"
#include "nvim/cmdexpand.h"
#include "nvim/cmdexpand_defs.h"
+#include "nvim/errors.h"
#include "nvim/eval.h"
#include "nvim/eval/typval.h"
#include "nvim/eval/typval_defs.h"
@@ -402,43 +403,43 @@ static int str_to_mapargs(const char *strargs, bool is_unmap, MapArguments *mapa
// Accept <buffer>, <nowait>, <silent>, <expr>, <script>, and <unique> in
// any order.
while (true) {
- if (strncmp(to_parse, "<buffer>", 8) == 0) {
+ if (strncmp(to_parse, S_LEN("<buffer>")) == 0) {
to_parse = skipwhite(to_parse + 8);
mapargs->buffer = true;
continue;
}
- if (strncmp(to_parse, "<nowait>", 8) == 0) {
+ if (strncmp(to_parse, S_LEN("<nowait>")) == 0) {
to_parse = skipwhite(to_parse + 8);
mapargs->nowait = true;
continue;
}
- if (strncmp(to_parse, "<silent>", 8) == 0) {
+ if (strncmp(to_parse, S_LEN("<silent>")) == 0) {
to_parse = skipwhite(to_parse + 8);
mapargs->silent = true;
continue;
}
// Ignore obsolete "<special>" modifier.
- if (strncmp(to_parse, "<special>", 9) == 0) {
+ if (strncmp(to_parse, S_LEN("<special>")) == 0) {
to_parse = skipwhite(to_parse + 9);
continue;
}
- if (strncmp(to_parse, "<script>", 8) == 0) {
+ if (strncmp(to_parse, S_LEN("<script>")) == 0) {
to_parse = skipwhite(to_parse + 8);
mapargs->script = true;
continue;
}
- if (strncmp(to_parse, "<expr>", 6) == 0) {
+ if (strncmp(to_parse, S_LEN("<expr>")) == 0) {
to_parse = skipwhite(to_parse + 6);
mapargs->expr = true;
continue;
}
- if (strncmp(to_parse, "<unique>", 8) == 0) {
+ if (strncmp(to_parse, S_LEN("<unique>")) == 0) {
to_parse = skipwhite(to_parse + 8);
mapargs->unique = true;
continue;
@@ -1251,32 +1252,32 @@ char *set_context_in_map_cmd(expand_T *xp, char *cmd, char *arg, bool forceit, b
xp->xp_context = EXPAND_MAPPINGS;
expand_buffer = false;
while (true) {
- if (strncmp(arg, "<buffer>", 8) == 0) {
+ if (strncmp(arg, S_LEN("<buffer>")) == 0) {
expand_buffer = true;
arg = skipwhite(arg + 8);
continue;
}
- if (strncmp(arg, "<unique>", 8) == 0) {
+ if (strncmp(arg, S_LEN("<unique>")) == 0) {
arg = skipwhite(arg + 8);
continue;
}
- if (strncmp(arg, "<nowait>", 8) == 0) {
+ if (strncmp(arg, S_LEN("<nowait>")) == 0) {
arg = skipwhite(arg + 8);
continue;
}
- if (strncmp(arg, "<silent>", 8) == 0) {
+ if (strncmp(arg, S_LEN("<silent>")) == 0) {
arg = skipwhite(arg + 8);
continue;
}
- if (strncmp(arg, "<special>", 9) == 0) {
+ if (strncmp(arg, S_LEN("<special>")) == 0) {
arg = skipwhite(arg + 9);
continue;
}
- if (strncmp(arg, "<script>", 8) == 0) {
+ if (strncmp(arg, S_LEN("<script>")) == 0) {
arg = skipwhite(arg + 8);
continue;
}
- if (strncmp(arg, "<expr>", 6) == 0) {
+ if (strncmp(arg, S_LEN("<expr>")) == 0) {
arg = skipwhite(arg + 6);
continue;
}
diff --git a/src/nvim/mark.c b/src/nvim/mark.c
index 6ce42bb7fe..16f444a316 100644
--- a/src/nvim/mark.c
+++ b/src/nvim/mark.c
@@ -14,6 +14,7 @@
#include "nvim/cursor.h"
#include "nvim/diff.h"
#include "nvim/edit.h"
+#include "nvim/errors.h"
#include "nvim/eval/typval.h"
#include "nvim/eval/typval_defs.h"
#include "nvim/ex_cmds_defs.h"
diff --git a/src/nvim/marktree.c b/src/nvim/marktree.c
index 34d6cd118f..9e3005b6a3 100644
--- a/src/nvim/marktree.c
+++ b/src/nvim/marktree.c
@@ -2286,7 +2286,7 @@ static void marktree_itr_fix_pos(MarkTree *b, MarkTreeIter *itr)
void marktree_put_test(MarkTree *b, uint32_t ns, uint32_t id, int row, int col, bool right_gravity,
int end_row, int end_col, bool end_right, bool meta_inline)
{
- uint16_t flags = mt_flags(right_gravity, false, false, false, false);
+ uint16_t flags = mt_flags(right_gravity, false, false, false);
// The specific choice is irrelevant here, we pick one counted decor
// type to test the counting and filtering logic.
flags |= meta_inline ? MT_FLAG_DECOR_VIRT_TEXT_INLINE : 0;
diff --git a/src/nvim/marktree.h b/src/nvim/marktree.h
index 8e5cf30ff3..15df57ef63 100644
--- a/src/nvim/marktree.h
+++ b/src/nvim/marktree.h
@@ -35,8 +35,6 @@
#define MT_FLAG_DECOR_VIRT_LINES (((uint16_t)1) << 11)
#define MT_FLAG_DECOR_VIRT_TEXT_INLINE (((uint16_t)1) << 12)
-#define MT_FLAG_SCOPED (((uint16_t)1) << 13)
-
// These _must_ be last to preserve ordering of marks
#define MT_FLAG_RIGHT_GRAVITY (((uint16_t)1) << 14)
#define MT_FLAG_LAST (((uint16_t)1) << 15)
@@ -46,7 +44,7 @@
| MT_FLAG_DECOR_VIRT_TEXT_INLINE)
#define MT_FLAG_EXTERNAL_MASK (MT_FLAG_DECOR_MASK | MT_FLAG_NO_UNDO \
- | MT_FLAG_INVALIDATE | MT_FLAG_INVALID | MT_FLAG_SCOPED)
+ | MT_FLAG_INVALIDATE | MT_FLAG_INVALID)
// this is defined so that start and end of the same range have adjacent ids
#define MARKTREE_END_FLAG ((uint64_t)1)
@@ -110,24 +108,12 @@ static inline bool mt_decor_sign(MTKey key)
return key.flags & (MT_FLAG_DECOR_SIGNTEXT | MT_FLAG_DECOR_SIGNHL);
}
-static inline bool mt_scoped(MTKey key)
-{
- return key.flags & MT_FLAG_SCOPED;
-}
-
-static inline bool mt_scoped_in_win(MTKey key, win_T *wp)
-{
- return !mt_scoped(key) || set_has(uint32_t, &wp->w_ns_set, key.ns);
-}
-
-static inline uint16_t mt_flags(bool right_gravity, bool no_undo, bool invalidate, bool decor_ext,
- bool scoped)
+static inline uint16_t mt_flags(bool right_gravity, bool no_undo, bool invalidate, bool decor_ext)
{
return (uint16_t)((right_gravity ? MT_FLAG_RIGHT_GRAVITY : 0)
| (no_undo ? MT_FLAG_NO_UNDO : 0)
| (invalidate ? MT_FLAG_INVALIDATE : 0)
- | (decor_ext ? MT_FLAG_DECOR_EXT : 0)
- | (scoped ? MT_FLAG_SCOPED : 0));
+ | (decor_ext ? MT_FLAG_DECOR_EXT : 0));
}
static inline MTPair mtpair_from(MTKey start, MTKey end)
diff --git a/src/nvim/match.c b/src/nvim/match.c
index 580d7d1069..6ae4e41147 100644
--- a/src/nvim/match.c
+++ b/src/nvim/match.c
@@ -10,6 +10,7 @@
#include "nvim/buffer_defs.h"
#include "nvim/charset.h"
#include "nvim/drawscreen.h"
+#include "nvim/errors.h"
#include "nvim/eval/funcs.h"
#include "nvim/eval/typval.h"
#include "nvim/eval/window.h"
diff --git a/src/nvim/mbyte.c b/src/nvim/mbyte.c
index a345795bbe..018febb995 100644
--- a/src/nvim/mbyte.c
+++ b/src/nvim/mbyte.c
@@ -43,6 +43,7 @@
#include "nvim/cmdexpand_defs.h"
#include "nvim/cursor.h"
#include "nvim/drawscreen.h"
+#include "nvim/errors.h"
#include "nvim/eval/typval.h"
#include "nvim/eval/typval_defs.h"
#include "nvim/getchar.h"
@@ -370,9 +371,9 @@ int enc_canon_props(const char *name)
int i = enc_canon_search(name);
if (i >= 0) {
return enc_canon_table[i].prop;
- } else if (strncmp(name, "2byte-", 6) == 0) {
+ } else if (strncmp(name, S_LEN("2byte-")) == 0) {
return ENC_DBCS;
- } else if (strncmp(name, "8bit-", 5) == 0 || strncmp(name, "iso-8859-", 9) == 0) {
+ } else if (strncmp(name, S_LEN("8bit-")) == 0 || strncmp(name, S_LEN("iso-8859-")) == 0) {
return ENC_8BIT;
}
return 0;
@@ -392,10 +393,10 @@ int bomb_size(void)
if (*curbuf->b_p_fenc == NUL
|| strcmp(curbuf->b_p_fenc, "utf-8") == 0) {
n = 3;
- } else if (strncmp(curbuf->b_p_fenc, "ucs-2", 5) == 0
- || strncmp(curbuf->b_p_fenc, "utf-16", 6) == 0) {
+ } else if (strncmp(curbuf->b_p_fenc, S_LEN("ucs-2")) == 0
+ || strncmp(curbuf->b_p_fenc, S_LEN("utf-16")) == 0) {
n = 2;
- } else if (strncmp(curbuf->b_p_fenc, "ucs-4", 5) == 0) {
+ } else if (strncmp(curbuf->b_p_fenc, S_LEN("ucs-4")) == 0) {
n = 4;
}
}
@@ -1545,7 +1546,7 @@ int utf16_to_utf8(const wchar_t *utf16, int utf16len, char **utf8)
return uv_translate_sys_error(GetLastError());
}
- (*utf8)[bufsize] = '\0';
+ (*utf8)[bufsize] = NUL;
return 0;
}
@@ -2187,10 +2188,10 @@ const char *mb_unescape(const char **const pp)
/// Skip the Vim specific head of a 'encoding' name.
char *enc_skip(char *p)
{
- if (strncmp(p, "2byte-", 6) == 0) {
+ if (strncmp(p, S_LEN("2byte-")) == 0) {
return p + 6;
}
- if (strncmp(p, "8bit-", 5) == 0) {
+ if (strncmp(p, S_LEN("8bit-")) == 0) {
return p + 5;
}
return p;
@@ -2221,37 +2222,42 @@ char *enc_canonize(char *enc)
}
}
*p = NUL;
+ char *p_e = p;
// Skip "2byte-" and "8bit-".
p = enc_skip(r);
// Change "microsoft-cp" to "cp". Used in some spell files.
- if (strncmp(p, "microsoft-cp", 12) == 0) {
- STRMOVE(p, p + 10);
+ if (strncmp(p, S_LEN("microsoft-cp")) == 0) {
+ memmove(p, p + STRLEN_LITERAL("microsoft-"),
+ (size_t)(p_e - (p + STRLEN_LITERAL("microsoft-"))) + 1);
}
// "iso8859" -> "iso-8859"
- if (strncmp(p, "iso8859", 7) == 0) {
- STRMOVE(p + 4, p + 3);
- p[3] = '-';
+ if (strncmp(p, S_LEN("iso8859")) == 0) {
+ memmove(p + STRLEN_LITERAL("iso-"), p + STRLEN_LITERAL("iso"),
+ (size_t)(p_e - (p + STRLEN_LITERAL("iso"))) + 1);
+ p[STRLEN_LITERAL("iso")] = '-';
}
// "iso-8859n" -> "iso-8859-n"
- if (strncmp(p, "iso-8859", 8) == 0 && p[8] != '-') {
- STRMOVE(p + 9, p + 8);
- p[8] = '-';
+ if (strncmp(p, S_LEN("iso-8859")) == 0 && p[8] != '-') {
+ memmove(p + STRLEN_LITERAL("iso-8859-"), p + STRLEN_LITERAL("iso-8859"),
+ (size_t)(p_e - (p + STRLEN_LITERAL("iso-8859"))) + 1);
+ p[STRLEN_LITERAL("iso-8859")] = '-';
}
// "latin-N" -> "latinN"
- if (strncmp(p, "latin-", 6) == 0) {
- STRMOVE(p + 5, p + 6);
+ if (strncmp(p, S_LEN("latin-")) == 0) {
+ memmove(p + STRLEN_LITERAL("latin"), p + STRLEN_LITERAL("latin-"),
+ (size_t)(p_e - (p + STRLEN_LITERAL("latin-"))) + 1);
}
int i;
if (enc_canon_search(p) >= 0) {
// canonical name can be used unmodified
if (p != r) {
- STRMOVE(r, p);
+ memmove(r, p, (size_t)(p_e - p) + 1);
}
} else if ((i = enc_alias_search(p)) >= 0) {
// alias recognized, get canonical name
@@ -2314,7 +2320,7 @@ char *enc_locale(void)
if (p > s + 2 && !STRNICMP(p + 1, "EUC", 3)
&& !isalnum((uint8_t)p[4]) && p[4] != '-' && p[-3] == '_') {
// Copy "XY.EUC" to "euc-XY" to buf[10].
- memmove(buf, "euc-", 4);
+ memmove(buf, S_LEN("euc-"));
buf[4] = (char)(ASCII_ISALNUM(p[-2]) ? TOLOWER_ASC(p[-2]) : 0);
buf[5] = (char)(ASCII_ISALNUM(p[-1]) ? TOLOWER_ASC(p[-1]) : 0);
buf[6] = NUL;
diff --git a/src/nvim/memfile.c b/src/nvim/memfile.c
index a1713edb66..498d212da3 100644
--- a/src/nvim/memfile.c
+++ b/src/nvim/memfile.c
@@ -46,6 +46,7 @@
#include "nvim/assert_defs.h"
#include "nvim/buffer_defs.h"
+#include "nvim/errors.h"
#include "nvim/fileio.h"
#include "nvim/gettext_defs.h"
#include "nvim/globals.h"
diff --git a/src/nvim/memline.c b/src/nvim/memline.c
index 5acf4f0c37..a21c232a2d 100644
--- a/src/nvim/memline.c
+++ b/src/nvim/memline.c
@@ -864,7 +864,7 @@ void ml_recover(bool checkext)
goto theend;
}
ZeroBlock *b0p = hp->bh_data;
- if (strncmp(b0p->b0_version, "VIM 3.0", 7) == 0) {
+ if (strncmp(b0p->b0_version, S_LEN("VIM 3.0")) == 0) {
msg_start();
msg_outtrans(mfp->mf_fname, MSG_HIST);
msg_puts_attr(_(" cannot be used with this version of Vim.\n"),
@@ -1538,7 +1538,7 @@ static time_t swapfile_info(char *fname)
int fd = os_open(fname, O_RDONLY, 0);
if (fd >= 0) {
if (read_eintr(fd, &b0, sizeof(b0)) == sizeof(b0)) {
- if (strncmp(b0.b0_version, "VIM 3.0", 7) == 0) {
+ if (strncmp(b0.b0_version, S_LEN("VIM 3.0")) == 0) {
msg_puts(_(" [from Vim version 3.0]"));
} else if (ml_check_b0_id(&b0) == FAIL) {
msg_puts(_(" [does not look like a Vim swap file]"));
diff --git a/src/nvim/memory.c b/src/nvim/memory.c
index 789535e270..50860c69d0 100644
--- a/src/nvim/memory.c
+++ b/src/nvim/memory.c
@@ -19,6 +19,7 @@
#include "nvim/context.h"
#include "nvim/decoration_provider.h"
#include "nvim/drawline.h"
+#include "nvim/errors.h"
#include "nvim/eval.h"
#include "nvim/gettext_defs.h"
#include "nvim/globals.h"
@@ -202,7 +203,7 @@ void *xmallocz(size_t size)
}
void *ret = xmalloc(total_size);
- ((char *)ret)[size] = '\0';
+ ((char *)ret)[size] = NUL;
return ret;
}
@@ -232,7 +233,7 @@ void *xmemcpyz(void *dst, const void *src, size_t len)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_RET
{
memcpy(dst, src, len);
- ((char *)dst)[len] = '\0';
+ ((char *)dst)[len] = NUL;
return dst;
}
@@ -240,7 +241,7 @@ void *xmemcpyz(void *dst, const void *src, size_t len)
size_t xstrnlen(const char *s, size_t n)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_PURE
{
- const char *end = memchr(s, '\0', n);
+ const char *end = memchr(s, NUL, n);
if (end == NULL) {
return n;
}
@@ -287,7 +288,7 @@ void *xmemscan(const void *addr, char c, size_t size)
void strchrsub(char *str, char c, char x)
FUNC_ATTR_NONNULL_ALL
{
- assert(c != '\0');
+ assert(c != NUL);
while ((str = strchr(str, c))) {
*str++ = x;
}
@@ -387,7 +388,7 @@ char *xstpcpy(char *restrict dst, const char *restrict src)
char *xstpncpy(char *restrict dst, const char *restrict src, size_t maxlen)
FUNC_ATTR_NONNULL_RET FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL
{
- const char *p = memchr(src, '\0', maxlen);
+ const char *p = memchr(src, NUL, maxlen);
if (p) {
size_t srclen = (size_t)(p - src);
memcpy(dst, src, srclen);
@@ -419,7 +420,7 @@ size_t xstrlcpy(char *restrict dst, const char *restrict src, size_t dsize)
if (dsize) {
size_t len = MIN(slen, dsize - 1);
memcpy(dst, src, len);
- dst[len] = '\0';
+ dst[len] = NUL;
}
return slen; // Does not include NUL.
@@ -449,7 +450,7 @@ size_t xstrlcat(char *const dst, const char *const src, const size_t dsize)
if (slen > dsize - dlen - 1) {
memmove(dst + dlen, src, dsize - dlen - 1);
- dst[dsize - 1] = '\0';
+ dst[dsize - 1] = NUL;
} else {
memmove(dst + dlen, src, slen + 1);
}
@@ -509,7 +510,7 @@ char *xstrndup(const char *str, size_t len)
FUNC_ATTR_MALLOC FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_RET
FUNC_ATTR_NONNULL_ALL
{
- char *p = memchr(str, '\0', len);
+ char *p = memchr(str, NUL, len);
return xmemdupz(str, p ? (size_t)(p - str) : len);
}
@@ -882,7 +883,6 @@ void free_all_mem(void)
decor_free_all_mem();
drawline_free_all_mem();
- input_free_all_mem();
if (ui_client_channel_id) {
ui_client_free_all_mem();
diff --git a/src/nvim/memory.h b/src/nvim/memory.h
index 0788670142..277ffe97aa 100644
--- a/src/nvim/memory.h
+++ b/src/nvim/memory.h
@@ -72,5 +72,3 @@ EXTERN size_t arena_alloc_count INIT( = 0);
// Like strcpy() but allows overlapped source and destination.
#define STRMOVE(d, s) memmove((d), (s), strlen(s) + 1)
-
-#define STRCAT(d, s) strcat((char *)(d), (char *)(s)) // NOLINT(runtime/printf)
diff --git a/src/nvim/menu.c b/src/nvim/menu.c
index ab28eeca1c..aa76b8010d 100644
--- a/src/nvim/menu.c
+++ b/src/nvim/menu.c
@@ -13,6 +13,7 @@
#include "nvim/charset.h"
#include "nvim/cmdexpand_defs.h"
#include "nvim/cursor.h"
+#include "nvim/errors.h"
#include "nvim/eval.h"
#include "nvim/eval/typval.h"
#include "nvim/eval/typval_defs.h"
@@ -60,7 +61,7 @@ static const char e_nomenu[] = N_("E329: No menu \"%s\"");
static bool menu_is_winbar(const char *const name)
FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL
{
- return (strncmp(name, "WinBar", 6) == 0);
+ return (strncmp(name, S_LEN("WinBar")) == 0);
}
static vimmenu_T **get_root_menu(const char *const name)
@@ -89,17 +90,17 @@ void ex_menu(exarg_T *eap)
char *arg = eap->arg;
while (true) {
- if (strncmp(arg, "<script>", 8) == 0) {
+ if (strncmp(arg, S_LEN("<script>")) == 0) {
noremap = REMAP_SCRIPT;
arg = skipwhite(arg + 8);
continue;
}
- if (strncmp(arg, "<silent>", 8) == 0) {
+ if (strncmp(arg, S_LEN("<silent>")) == 0) {
silent = true;
arg = skipwhite(arg + 8);
continue;
}
- if (strncmp(arg, "<special>", 9) == 0) {
+ if (strncmp(arg, S_LEN("<special>")) == 0) {
// Ignore obsolete "<special>" modifier.
arg = skipwhite(arg + 9);
continue;
@@ -109,7 +110,7 @@ void ex_menu(exarg_T *eap)
// Locate an optional "icon=filename" argument
// TODO(nvim): Currently this is only parsed. Should expose it to UIs.
- if (strncmp(arg, "icon=", 5) == 0) {
+ if (strncmp(arg, S_LEN("icon=")) == 0) {
arg += 5;
while (*arg != NUL && *arg != ' ') {
if (*arg == '\\') {
@@ -152,10 +153,10 @@ void ex_menu(exarg_T *eap)
pri_tab[MENUDEPTH] = -1; // mark end of the table
// Check for "disable" or "enable" argument.
- if (strncmp(arg, "enable", 6) == 0 && ascii_iswhite(arg[6])) {
+ if (strncmp(arg, S_LEN("enable")) == 0 && ascii_iswhite(arg[6])) {
enable = kTrue;
arg = skipwhite(arg + 6);
- } else if (strncmp(arg, "disable", 7) == 0 && ascii_iswhite(arg[7])) {
+ } else if (strncmp(arg, S_LEN("disable")) == 0 && ascii_iswhite(arg[7])) {
enable = kFalse;
arg = skipwhite(arg + 7);
}
@@ -888,10 +889,10 @@ char *set_context_in_menu_cmd(expand_T *xp, const char *cmd, char *arg, bool for
}
if (!ascii_iswhite(*p)) {
- if (strncmp(arg, "enable", 6) == 0
+ if (strncmp(arg, S_LEN("enable")) == 0
&& (arg[6] == NUL || ascii_iswhite(arg[6]))) {
p = arg + 6;
- } else if (strncmp(arg, "disable", 7) == 0
+ } else if (strncmp(arg, S_LEN("disable")) == 0
&& (arg[7] == NUL || ascii_iswhite(arg[7]))) {
p = arg + 7;
} else {
@@ -1056,7 +1057,7 @@ char *get_menu_names(expand_T *xp, int idx)
}
// hack on menu separators: use a 'magic' char for the separator
// so that '.' in names gets escaped properly
- STRCAT(tbuffer, "\001");
+ strcat(tbuffer, "\001");
str = tbuffer;
} else {
if (should_advance) {
@@ -1332,14 +1333,14 @@ bool menu_is_menubar(const char *const name)
bool menu_is_popup(const char *const name)
FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL
{
- return strncmp(name, "PopUp", 5) == 0;
+ return strncmp(name, S_LEN("PopUp")) == 0;
}
// Return true if "name" is a toolbar menu name.
bool menu_is_toolbar(const char *const name)
FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL
{
- return strncmp(name, "ToolBar", 7) == 0;
+ return strncmp(name, S_LEN("ToolBar")) == 0;
}
/// @return true if the name is a menu separator identifier: Starts and ends
@@ -1700,7 +1701,7 @@ void ex_menutranslate(exarg_T *eap)
}
// ":menutrans clear": clear all translations.
- if (strncmp(arg, "clear", 5) == 0 && ends_excmd(*skipwhite(arg + 5))) {
+ if (strncmp(arg, S_LEN("clear")) == 0 && ends_excmd(*skipwhite(arg + 5))) {
GA_DEEP_CLEAR(&menutrans_ga, menutrans_T, FREE_MENUTRANS);
// Delete all "menutrans_" global variables.
diff --git a/src/nvim/message.c b/src/nvim/message.c
index 10b90bde29..86e25915a3 100644
--- a/src/nvim/message.c
+++ b/src/nvim/message.c
@@ -18,6 +18,7 @@
#include "nvim/channel.h"
#include "nvim/charset.h"
#include "nvim/drawscreen.h"
+#include "nvim/errors.h"
#include "nvim/eval.h"
#include "nvim/eval/typval.h"
#include "nvim/eval/typval_defs.h"
@@ -472,7 +473,7 @@ void trunc_string(const char *s, char *buf, int room_in, int buflen)
}
} else if (e + 3 < buflen) {
// set the middle and copy the last part
- memmove(buf + e, "...", 3);
+ memmove(buf + e, S_LEN("..."));
len = (int)strlen(s + i) + 1;
if (len >= buflen - e - 3) {
len = buflen - e - 3 - 1;
@@ -2689,7 +2690,7 @@ static void msg_puts_printf(const char *str, const ptrdiff_t maxlen)
*p++ = '\r';
}
memcpy(p, s, (size_t)len);
- *(p + len) = '\0';
+ *(p + len) = NUL;
if (info_message) {
printf("%s", buf);
} else {
@@ -3181,7 +3182,7 @@ static void redir_write(const char *const str, const ptrdiff_t maxlen)
if (*s != '\n' && *s != '\r') {
while (cur_col < msg_col) {
if (capture_ga) {
- ga_concat_len(capture_ga, " ", 1);
+ ga_concat_len(capture_ga, S_LEN(" "));
}
if (redir_reg) {
write_reg_contents(redir_reg, " ", 1, true);
diff --git a/src/nvim/move.c b/src/nvim/move.c
index 418ece09ed..a2bb1b4685 100644
--- a/src/nvim/move.c
+++ b/src/nvim/move.c
@@ -20,6 +20,7 @@
#include "nvim/diff.h"
#include "nvim/drawscreen.h"
#include "nvim/edit.h"
+#include "nvim/errors.h"
#include "nvim/eval/typval.h"
#include "nvim/eval/window.h"
#include "nvim/fold.h"
diff --git a/src/nvim/msgpack_rpc/channel.c b/src/nvim/msgpack_rpc/channel.c
index 5737a0440f..6a0dc10214 100644
--- a/src/nvim/msgpack_rpc/channel.c
+++ b/src/nvim/msgpack_rpc/channel.c
@@ -31,8 +31,6 @@
#include "nvim/msgpack_rpc/packer.h"
#include "nvim/msgpack_rpc/unpacker.h"
#include "nvim/os/input.h"
-#include "nvim/rbuffer.h"
-#include "nvim/rbuffer_defs.h"
#include "nvim/types_defs.h"
#include "nvim/ui.h"
#include "nvim/ui_client.h"
@@ -89,7 +87,7 @@ void rpc_start(Channel *channel)
kv_init(rpc->call_stack);
if (channel->streamtype != kChannelStreamInternal) {
- Stream *out = channel_outstream(channel);
+ RStream *out = channel_outstream(channel);
#ifdef NVIM_LOG_DEBUG
Stream *in = channel_instream(channel);
DLOG("rpc ch %" PRIu64 " in-stream=%p out-stream=%p", channel->id,
@@ -202,10 +200,25 @@ Object rpc_send_call(uint64_t id, const char *method_name, Array args, ArenaMem
return frame.errored ? NIL : frame.result;
}
-static void receive_msgpack(Stream *stream, RBuffer *rbuf, size_t c, void *data, bool eof)
+static size_t receive_msgpack(RStream *stream, const char *rbuf, size_t c, void *data, bool eof)
{
Channel *channel = data;
channel_incref(channel);
+ size_t consumed = 0;
+
+ DLOG("ch %" PRIu64 ": parsing %zu bytes from msgpack Stream: %p",
+ channel->id, c, (void *)stream);
+
+ if (c > 0) {
+ Unpacker *p = channel->rpc.unpacker;
+ p->read_ptr = rbuf;
+ p->read_size = c;
+ parse_msgpack(channel);
+
+ if (!unpacker_closed(p)) {
+ consumed = c - p->read_size;
+ }
+ }
if (eof) {
channel_close(channel->id, kChannelPartRpc, NULL);
@@ -213,25 +226,10 @@ static void receive_msgpack(Stream *stream, RBuffer *rbuf, size_t c, void *data,
snprintf(buf, sizeof(buf), "ch %" PRIu64 " was closed by the client",
channel->id);
chan_close_with_error(channel, buf, LOGLVL_INF);
- goto end;
- }
-
- DLOG("ch %" PRIu64 ": parsing %zu bytes from msgpack Stream: %p",
- channel->id, rbuffer_size(rbuf), (void *)stream);
-
- Unpacker *p = channel->rpc.unpacker;
- size_t size = 0;
- p->read_ptr = rbuffer_read_ptr(rbuf, &size);
- p->read_size = size;
- parse_msgpack(channel);
-
- if (!unpacker_closed(p)) {
- size_t consumed = size - p->read_size;
- rbuffer_consumed_compact(rbuf, consumed);
}
-end:
channel_decref(channel);
+ return consumed;
}
static ChannelCallFrame *find_call_frame(RpcState *rpc, uint32_t request_id)
diff --git a/src/nvim/msgpack_rpc/packer.c b/src/nvim/msgpack_rpc/packer.c
index cac68f76f0..9c0d2910fa 100644
--- a/src/nvim/msgpack_rpc/packer.c
+++ b/src/nvim/msgpack_rpc/packer.c
@@ -113,7 +113,6 @@ void mpack_handle(ObjectType type, handle_T handle, PackerBuffer *packer)
mpack_w(&packer->ptr, 0xc7);
mpack_w(&packer->ptr, packsize);
mpack_w(&packer->ptr, exttype);
- // check_buffer(packer);
memcpy(packer->ptr, buf, (size_t)packsize);
packer->ptr += packsize;
}
diff --git a/src/nvim/msgpack_rpc/server.c b/src/nvim/msgpack_rpc/server.c
index 56b03d67d0..24bd343a34 100644
--- a/src/nvim/msgpack_rpc/server.c
+++ b/src/nvim/msgpack_rpc/server.c
@@ -4,6 +4,7 @@
#include <string.h>
#include <uv.h>
+#include "nvim/ascii_defs.h"
#include "nvim/channel.h"
#include "nvim/eval.h"
#include "nvim/event/defs.h"
@@ -131,7 +132,7 @@ bool server_owns_pipe_address(const char *path)
/// @returns 0: success, 1: validation error, 2: already listening, -errno: failed to bind/listen.
int server_start(const char *addr)
{
- if (addr == NULL || addr[0] == '\0') {
+ if (addr == NULL || addr[0] == NUL) {
WLOG("Empty or NULL address");
return 1;
}
diff --git a/src/nvim/normal.c b/src/nvim/normal.c
index 8ba375f29d..3343803bb1 100644
--- a/src/nvim/normal.c
+++ b/src/nvim/normal.c
@@ -28,6 +28,7 @@
#include "nvim/digraph.h"
#include "nvim/drawscreen.h"
#include "nvim/edit.h"
+#include "nvim/errors.h"
#include "nvim/eval.h"
#include "nvim/ex_cmds.h"
#include "nvim/ex_cmds2.h"
@@ -1986,7 +1987,7 @@ bool add_to_showcmd(int c)
size_t overflow = old_len + extra_len - limit;
memmove(showcmd_buf, showcmd_buf + overflow, old_len - overflow + 1);
}
- STRCAT(showcmd_buf, p);
+ strcat(showcmd_buf, p);
if (char_avail()) {
return false;
diff --git a/src/nvim/ops.c b/src/nvim/ops.c
index 5c1e291ac6..8f8baaf619 100644
--- a/src/nvim/ops.c
+++ b/src/nvim/ops.c
@@ -24,6 +24,7 @@
#include "nvim/cursor.h"
#include "nvim/drawscreen.h"
#include "nvim/edit.h"
+#include "nvim/errors.h"
#include "nvim/eval.h"
#include "nvim/eval/typval.h"
#include "nvim/ex_cmds2.h"
@@ -281,8 +282,10 @@ void op_shift(oparg_T *oap, bool curs_top, int amount)
/// @param call_changed_bytes call changed_bytes()
void shift_line(bool left, bool round, int amount, int call_changed_bytes)
{
- const int sw_val = get_sw_value_indent(curbuf);
-
+ int sw_val = get_sw_value_indent(curbuf, left);
+ if (sw_val == 0) {
+ sw_val = 1; // shouldn't happen, just in case
+ }
int count = get_indent(); // get current indent
if (round) { // round off indent
@@ -327,7 +330,7 @@ static void shift_block(oparg_T *oap, int amount)
const int oldstate = State;
char *newp;
const int oldcol = curwin->w_cursor.col;
- const int sw_val = get_sw_value_indent(curbuf);
+ const int sw_val = get_sw_value_indent(curbuf, left);
const int ts_val = (int)curbuf->b_p_ts;
struct block_def bd;
int incr;
@@ -2663,7 +2666,7 @@ static void op_yank_reg(oparg_T *oap, bool message, yankreg_T *reg, bool append)
char *pnew = xmalloc(strlen(curr->y_array[curr->y_size - 1])
+ strlen(reg->y_array[0]) + 1);
STRCPY(pnew, curr->y_array[--j]);
- STRCAT(pnew, reg->y_array[0]);
+ strcat(pnew, reg->y_array[0]);
xfree(curr->y_array[j]);
xfree(reg->y_array[0]);
curr->y_array[j++] = pnew;
@@ -3428,7 +3431,7 @@ void do_put(int regname, yankreg_T *reg, int dir, int count, int flags)
totlen = strlen(y_array[y_size - 1]);
char *newp = xmalloc((size_t)ml_get_len(lnum) - (size_t)col + totlen + 1);
STRCPY(newp, y_array[y_size - 1]);
- STRCAT(newp, ptr);
+ strcat(newp, ptr);
// insert second line
ml_append(lnum, newp, 0, false);
new_lnum++;
@@ -4722,7 +4725,7 @@ bool do_addsub(int op_type, pos_T *pos, int length, linenr_T Prenum1)
buf2[i++] = ((n >> --bits) & 0x1) ? '1' : '0';
}
- buf2[i] = '\0';
+ buf2[i] = NUL;
} else if (pre == 0) {
vim_snprintf(buf2, ARRAY_SIZE(buf2), "%" PRIu64, (uint64_t)n);
} else if (pre == '0') {
@@ -4744,7 +4747,7 @@ bool do_addsub(int op_type, pos_T *pos, int length, linenr_T Prenum1)
}
}
*ptr = NUL;
- STRCAT(buf1, buf2);
+ strcat(buf1, buf2);
ins_str(buf1); // insert the new number
endpos = curwin->w_cursor;
if (curwin->w_cursor.col) {
diff --git a/src/nvim/option.c b/src/nvim/option.c
index 799513e018..4c68e2bf16 100644
--- a/src/nvim/option.c
+++ b/src/nvim/option.c
@@ -44,6 +44,7 @@
#include "nvim/decoration_provider.h"
#include "nvim/diff.h"
#include "nvim/drawscreen.h"
+#include "nvim/errors.h"
#include "nvim/eval.h"
#include "nvim/eval/typval.h"
#include "nvim/eval/vars.h"
@@ -235,11 +236,11 @@ static void set_init_default_backupskip(void)
== NULL) {
ga_grow(&ga, (int)len);
if (!GA_EMPTY(&ga)) {
- STRCAT(ga.ga_data, ",");
+ strcat(ga.ga_data, ",");
}
- STRCAT(ga.ga_data, p);
+ strcat(ga.ga_data, p);
add_pathsep(ga.ga_data);
- STRCAT(ga.ga_data, "*");
+ strcat(ga.ga_data, "*");
ga.ga_len += (int)len;
}
xfree(item);
@@ -346,7 +347,7 @@ void set_init_1(bool clean_arg)
const size_t backupdir_len = strlen(backupdir);
backupdir = xrealloc(backupdir, backupdir_len + 3);
memmove(backupdir + 2, backupdir, backupdir_len + 1);
- memmove(backupdir, ".,", 2);
+ memmove(backupdir, S_LEN(".,"));
set_string_default(kOptBackupdir, backupdir, true);
set_string_default(kOptViewdir, stdpaths_user_state_subpath("view", 2, true),
true);
@@ -1003,10 +1004,10 @@ static set_op_T get_op(const char *arg)
static set_prefix_T get_option_prefix(char **argp)
{
- if (strncmp(*argp, "no", 2) == 0) {
+ if (strncmp(*argp, S_LEN("no")) == 0) {
*argp += 2;
return PREFIX_NO;
- } else if (strncmp(*argp, "inv", 3) == 0) {
+ } else if (strncmp(*argp, S_LEN("inv")) == 0) {
*argp += 3;
return PREFIX_INV;
}
@@ -1425,7 +1426,7 @@ int do_set(char *arg, int opt_flags)
did_show = true;
} else {
while (*arg != NUL) { // loop to process all options
- if (strncmp(arg, "all", 3) == 0 && !ASCII_ISALPHA(arg[3])
+ if (strncmp(arg, S_LEN("all")) == 0 && !ASCII_ISALPHA(arg[3])
&& !(opt_flags & OPT_MODELINE)) {
// ":set all" show all options.
// ":set all&" set all options to their default value.
@@ -2770,7 +2771,7 @@ static void do_spelllang_source(win_T *win)
char *q = win->w_s->b_p_spl;
// Skip the first name if it is "cjk".
- if (strncmp(q, "cjk,", 4) == 0) {
+ if (strncmp(q, S_LEN("cjk,")) == 0) {
q += 4;
}
@@ -4569,6 +4570,8 @@ void *get_varp_scope_from(vimoption_T *p, int scope, buf_T *buf, win_T *win)
return &(buf->b_p_def);
case PV_INC:
return &(buf->b_p_inc);
+ case PV_COT:
+ return &(buf->b_p_cot);
case PV_DICT:
return &(buf->b_p_dict);
case PV_TSR:
@@ -4652,6 +4655,8 @@ void *get_varp_from(vimoption_T *p, buf_T *buf, win_T *win)
return *buf->b_p_def != NUL ? &(buf->b_p_def) : p->var;
case PV_INC:
return *buf->b_p_inc != NUL ? &(buf->b_p_inc) : p->var;
+ case PV_COT:
+ return *buf->b_p_cot != NUL ? &(buf->b_p_cot) : p->var;
case PV_DICT:
return *buf->b_p_dict != NUL ? &(buf->b_p_dict) : p->var;
case PV_TSR:
@@ -5331,6 +5336,8 @@ void buf_copy_options(buf_T *buf, int flags)
buf->b_p_inc = empty_string_option;
buf->b_p_inex = xstrdup(p_inex);
COPY_OPT_SCTX(buf, BV_INEX);
+ buf->b_p_cot = empty_string_option;
+ buf->b_cot_flags = 0;
buf->b_p_dict = empty_string_option;
buf->b_p_tsr = empty_string_option;
buf->b_p_tsrfu = empty_string_option;
@@ -5443,11 +5450,11 @@ void set_context_in_set_cmd(expand_T *xp, char *arg, int opt_flags)
}
p--;
}
- if (strncmp(p, "no", 2) == 0) {
+ if (strncmp(p, S_LEN("no")) == 0) {
xp->xp_context = EXPAND_BOOL_SETTINGS;
xp->xp_prefix = XP_PREFIX_NO;
p += 2;
- } else if (strncmp(p, "inv", 3) == 0) {
+ } else if (strncmp(p, S_LEN("inv")) == 0) {
xp->xp_context = EXPAND_BOOL_SETTINGS;
xp->xp_prefix = XP_PREFIX_INV;
p += 3;
@@ -5642,7 +5649,7 @@ void set_context_in_set_cmd(expand_T *xp, char *arg, int opt_flags)
// manually handle it here to make sure we have the correct xp_context set.
// for 'spellsuggest' start at "file:"
if (options[opt_idx].var == &p_sps) {
- if (strncmp(xp->xp_pattern, "file:", 5) == 0) {
+ if (strncmp(xp->xp_pattern, S_LEN("file:")) == 0) {
xp->xp_pattern += 5;
return;
} else if (options[expand_option_idx].opt_expand_cb != NULL) {
@@ -6074,16 +6081,16 @@ int fill_culopt_flags(char *val, win_T *wp)
}
while (*p != NUL) {
// Note: Keep this in sync with p_culopt_values.
- if (strncmp(p, "line", 4) == 0) {
+ if (strncmp(p, S_LEN("line")) == 0) {
p += 4;
culopt_flags_new |= CULOPT_LINE;
- } else if (strncmp(p, "both", 4) == 0) {
+ } else if (strncmp(p, S_LEN("both")) == 0) {
p += 4;
culopt_flags_new |= CULOPT_LINE | CULOPT_NBR;
- } else if (strncmp(p, "number", 6) == 0) {
+ } else if (strncmp(p, S_LEN("number")) == 0) {
p += 6;
culopt_flags_new |= CULOPT_NBR;
- } else if (strncmp(p, "screenline", 10) == 0) {
+ } else if (strncmp(p, S_LEN("screenline")) == 0) {
p += 10;
culopt_flags_new |= CULOPT_SCRLINE;
}
@@ -6131,8 +6138,8 @@ int option_set_callback_func(char *optval, Callback *optcb)
typval_T *tv;
if (*optval == '{'
- || (strncmp(optval, "function(", 9) == 0)
- || (strncmp(optval, "funcref(", 8) == 0)) {
+ || (strncmp(optval, S_LEN("function(")) == 0)
+ || (strncmp(optval, S_LEN("funcref(")) == 0)) {
// Lambda expression or a funcref
tv = eval_expr(optval, NULL);
if (tv == NULL) {
@@ -6185,10 +6192,10 @@ bool can_bs(int what)
return vim_strchr(p_bs, what) != NULL;
}
-/// Get the local or global value of 'backupcopy'.
+/// Get the local or global value of 'backupcopy' flags.
///
/// @param buf The buffer.
-unsigned get_bkc_value(buf_T *buf)
+unsigned get_bkc_flags(buf_T *buf)
{
return buf->b_bkc_flags ? buf->b_bkc_flags : bkc_flags;
}
@@ -6204,7 +6211,7 @@ char *get_flp_value(buf_T *buf)
return buf->b_p_flp;
}
-/// Get the local or global value of the 'virtualedit' flags.
+/// Get the local or global value of 'virtualedit' flags.
unsigned get_ve_flags(win_T *wp)
{
return (wp->w_ve_flags ? wp->w_ve_flags : ve_flags) & ~(VE_NONE | VE_NONEU);
diff --git a/src/nvim/option_vars.h b/src/nvim/option_vars.h
index c98c84d34e..bd0fe699d9 100644
--- a/src/nvim/option_vars.h
+++ b/src/nvim/option_vars.h
@@ -430,6 +430,19 @@ EXTERN char *p_cpt; ///< 'complete'
EXTERN OptInt p_columns; ///< 'columns'
EXTERN int p_confirm; ///< 'confirm'
EXTERN char *p_cot; ///< 'completeopt'
+EXTERN unsigned cot_flags; ///< flags from 'completeopt'
+// Keep in sync with p_cot_values in optionstr.c
+#define COT_MENU 0x001
+#define COT_MENUONE 0x002
+#define COT_ANY_MENU 0x003 // combination of menu flags
+#define COT_LONGEST 0x004 // false: insert full match,
+ // true: insert longest prefix
+#define COT_PREVIEW 0x008
+#define COT_POPUP 0x010
+#define COT_ANY_PREVIEW 0x018 // combination of preview flags
+#define COT_NOINSERT 0x020 // false: select & insert, true: noinsert
+#define COT_NOSELECT 0x040 // false: select & insert, true: noselect
+#define COT_FUZZY 0x080 // true: fuzzy match enabled
#ifdef BACKSLASH_IN_FILENAME
EXTERN char *p_csl; ///< 'completeslash'
#endif
diff --git a/src/nvim/options.lua b/src/nvim/options.lua
index 452cc6876b..f323926015 100644
--- a/src/nvim/options.lua
+++ b/src/nvim/options.lua
@@ -1324,8 +1324,8 @@ return {
defaults = { if_true = '' },
desc = [=[
A template for a comment. The "%s" in the value is replaced with the
- comment text. For example, C uses "/*%s*/". Used for |commenting| and to
- add markers for folding, see |fold-marker|.
+ comment text, and should be padded with a space when possible.
+ Used for |commenting| and to add markers for folding, see |fold-marker|.
]=],
full_name = 'commentstring',
redraw = { 'curswant' },
@@ -1443,6 +1443,10 @@ return {
completion in the preview window. Only works in
combination with "menu" or "menuone".
+ popup Show extra information about the currently selected
+ completion in a popup window. Only works in combination
+ with "menu" or "menuone". Overrides "preview".
+
noinsert Do not insert any text for a match until the user selects
a match from the menu. Only works in combination with
"menu" or "menuone". No effect if "longest" is present.
@@ -1451,14 +1455,18 @@ return {
select one from the menu. Only works in combination with
"menu" or "menuone".
- popup Show extra information about the currently selected
- completion in a popup window. Only works in combination
- with "menu" or "menuone". Overrides "preview".
+ fuzzy Enable |fuzzy-matching| for completion candidates. This
+ allows for more flexible and intuitive matching, where
+ characters can be skipped and matches can be found even
+ if the exact sequence is not typed. Only makes a
+ difference how completion candidates are reduced from the
+ list of alternatives, but not how the candidates are
+ collected (using different completion types).
]=],
expand_cb = 'expand_set_completeopt',
full_name = 'completeopt',
list = 'onecomma',
- scope = { 'global' },
+ scope = { 'global', 'buffer' },
short_desc = N_('options for Insert mode completion'),
type = 'string',
varname = 'p_cot',
@@ -7317,8 +7325,8 @@ return {
message; also for quickfix message (e.g., ":cn")
s don't give "search hit BOTTOM, continuing at TOP" or *shm-s*
"search hit TOP, continuing at BOTTOM" messages; when using
- the search count do not show "W" after the count message (see
- S below)
+ the search count do not show "W" before the count message
+ (see |shm-S| below)
t truncate file message at the start if it is too long *shm-t*
to fit on the command-line, "<" will appear in the left most
column; ignored in Ex mode
@@ -7340,7 +7348,11 @@ return {
`:silent` was used for the command; note that this also
affects messages from 'autoread' reloading
S do not show search count message when searching, e.g. *shm-S*
- "[1/5]"
+ "[1/5]". When the "S" flag is not present (e.g. search count
+ is shown), the "search hit BOTTOM, continuing at TOP" and
+ "search hit TOP, continuing at BOTTOM" messages are only
+ indicated by a "W" (Mnemonic: Wrapped) letter before the
+ search count statistics.
This gives you the opportunity to avoid that a change between buffers
requires you to hit <Enter>, but still gives as useful a message as
diff --git a/src/nvim/optionstr.c b/src/nvim/optionstr.c
index 29433ddbb5..503aa7f350 100644
--- a/src/nvim/optionstr.c
+++ b/src/nvim/optionstr.c
@@ -14,6 +14,7 @@
#include "nvim/diff.h"
#include "nvim/digraph.h"
#include "nvim/drawscreen.h"
+#include "nvim/errors.h"
#include "nvim/eval/typval_defs.h"
#include "nvim/eval/userfunc.h"
#include "nvim/eval/vars.h"
@@ -121,8 +122,8 @@ static char *(p_bs_values[]) = { "indent", "eol", "start", "nostop", NULL };
static char *(p_fdm_values[]) = { "manual", "expr", "marker", "indent",
"syntax", "diff", NULL };
static char *(p_fcl_values[]) = { "all", NULL };
-static char *(p_cot_values[]) = { "menu", "menuone", "longest", "preview", "noinsert", "noselect",
- "popup", NULL };
+static char *(p_cot_values[]) = { "menu", "menuone", "longest", "preview", "popup",
+ "noinsert", "noselect", "fuzzy", NULL };
#ifdef BACKSLASH_IN_FILENAME
static char *(p_csl_values[]) = { "slash", "backslash", NULL };
#endif
@@ -157,6 +158,7 @@ void didset_string_options(void)
opt_strings_flags(p_cmp, p_cmp_values, &cmp_flags, true);
opt_strings_flags(p_bkc, p_bkc_values, &bkc_flags, true);
opt_strings_flags(p_bo, p_bo_values, &bo_flags, true);
+ opt_strings_flags(p_cot, p_cot_values, &cot_flags, true);
opt_strings_flags(p_ssop, p_ssop_values, &ssop_flags, true);
opt_strings_flags(p_vop, p_ssop_values, &vop_flags, true);
opt_strings_flags(p_fdo, p_fdo_values, &fdo_flags, true);
@@ -218,6 +220,7 @@ void check_buf_options(buf_T *buf)
check_string_option(&buf->b_p_ft);
check_string_option(&buf->b_p_cinw);
check_string_option(&buf->b_p_cinsd);
+ check_string_option(&buf->b_p_cot);
check_string_option(&buf->b_p_cpt);
check_string_option(&buf->b_p_cfu);
check_string_option(&buf->b_p_ofu);
@@ -285,15 +288,15 @@ int check_signcolumn(win_T *wp)
}
if (check_opt_strings(val, p_scl_values, false) == OK) {
- if (!strncmp(val, "no", 2)) { // no
+ if (!strncmp(val, S_LEN("no"))) { // no
wp->w_minscwidth = wp->w_maxscwidth = SCL_NO;
- } else if (!strncmp(val, "nu", 2) && (wp->w_p_nu || wp->w_p_rnu)) { // number
+ } else if (!strncmp(val, S_LEN("nu")) && (wp->w_p_nu || wp->w_p_rnu)) { // number
wp->w_minscwidth = wp->w_maxscwidth = SCL_NUM;
- } else if (!strncmp(val, "yes:", 4)) { // yes:<NUM>
+ } else if (!strncmp(val, S_LEN("yes:"))) { // yes:<NUM>
wp->w_minscwidth = wp->w_maxscwidth = val[4] - '0';
} else if (*val == 'y') { // yes
wp->w_minscwidth = wp->w_maxscwidth = 1;
- } else if (!strncmp(val, "auto:", 5)) { // auto:<NUM>
+ } else if (!strncmp(val, S_LEN("auto:"))) { // auto:<NUM>
wp->w_minscwidth = 0;
wp->w_maxscwidth = val[5] - '0';
} else { // auto
@@ -303,7 +306,7 @@ int check_signcolumn(win_T *wp)
return OK;
}
- if (strncmp(val, "auto:", 5) != 0
+ if (strncmp(val, S_LEN("auto:")) != 0
|| strlen(val) != 8
|| !ascii_isdigit(val[5])
|| val[6] != '-'
@@ -992,10 +995,23 @@ int expand_set_complete(optexpand_T *args, int *numMatches, char ***matches)
/// The 'completeopt' option is changed.
const char *did_set_completeopt(optset_T *args FUNC_ATTR_UNUSED)
{
- if (check_opt_strings(p_cot, p_cot_values, true) != OK) {
+ buf_T *buf = (buf_T *)args->os_buf;
+ char *cot = p_cot;
+ unsigned *flags = &cot_flags;
+
+ if (args->os_flags & OPT_LOCAL) {
+ cot = buf->b_p_cot;
+ flags = &buf->b_cot_flags;
+ }
+
+ if (check_opt_strings(cot, p_cot_values, true) != OK) {
return e_invarg;
}
- completeopt_was_set();
+
+ if (opt_strings_flags(cot, p_cot_values, flags, true) != OK) {
+ return e_invarg;
+ }
+
return NULL;
}
@@ -1716,9 +1732,9 @@ const char *did_set_mousescroll(optset_T *args FUNC_ATTR_UNUSED)
OptInt *direction;
- if (memcmp(string, "ver:", 4) == 0) {
+ if (memcmp(string, S_LEN("ver:")) == 0) {
direction = &vertical;
- } else if (memcmp(string, "hor:", 4) == 0) {
+ } else if (memcmp(string, S_LEN("hor:")) == 0) {
direction = &horizontal;
} else {
return e_invarg;
diff --git a/src/nvim/os/env.c b/src/nvim/os/env.c
index 5a79004c41..4689414559 100644
--- a/src/nvim/os/env.c
+++ b/src/nvim/os/env.c
@@ -63,13 +63,13 @@ const char *os_getenv(const char *name)
FUNC_ATTR_NONNULL_ALL
{
char *e = NULL;
- if (name[0] == '\0') {
+ if (name[0] == NUL) {
return NULL;
}
int r = 0;
if (map_has(cstr_t, &envmap, name)
&& !!(e = (char *)pmap_get(cstr_t)(&envmap, name))) {
- if (e[0] != '\0') {
+ if (e[0] != NUL) {
// Found non-empty cached env var.
// NOTE: This risks incoherence if an in-process library changes the
// environment without going through our os_setenv() wrapper. If
@@ -85,11 +85,11 @@ const char *os_getenv(const char *name)
if (r == UV_ENOBUFS) {
e = xmalloc(size);
r = uv_os_getenv(name, e, &size);
- if (r != 0 || size == 0 || e[0] == '\0') {
+ if (r != 0 || size == 0 || e[0] == NUL) {
XFREE_CLEAR(e);
goto end;
}
- } else if (r != 0 || size == 0 || buf[0] == '\0') {
+ } else if (r != 0 || size == 0 || buf[0] == NUL) {
e = NULL;
goto end;
} else {
@@ -110,7 +110,7 @@ end:
bool os_env_exists(const char *name)
FUNC_ATTR_NONNULL_ALL
{
- if (name[0] == '\0') {
+ if (name[0] == NUL) {
return false;
}
// Use a tiny buffer because we don't care about the value: if uv_os_getenv()
@@ -134,14 +134,14 @@ bool os_env_exists(const char *name)
int os_setenv(const char *name, const char *value, int overwrite)
FUNC_ATTR_NONNULL_ALL
{
- if (name[0] == '\0') {
+ if (name[0] == NUL) {
return -1;
}
#ifdef MSWIN
if (!overwrite && os_getenv(name) != NULL) {
return 0;
}
- if (value[0] == '\0') {
+ if (value[0] == NUL) {
// Windows (Vim-compat): Empty string undefines the env var.
return os_unsetenv(name);
}
@@ -174,7 +174,7 @@ int os_setenv(const char *name, const char *value, int overwrite)
int os_unsetenv(const char *name)
FUNC_ATTR_NONNULL_ALL
{
- if (name[0] == '\0') {
+ if (name[0] == NUL) {
return -1;
}
pmap_del2(&envmap, name);
@@ -366,7 +366,7 @@ void os_get_hostname(char *hostname, size_t size)
struct utsname vutsname;
if (uname(&vutsname) < 0) {
- *hostname = '\0';
+ *hostname = NUL;
} else {
xstrlcpy(hostname, vutsname.nodename, size);
}
@@ -374,12 +374,12 @@ void os_get_hostname(char *hostname, size_t size)
wchar_t host_utf16[MAX_COMPUTERNAME_LENGTH + 1];
DWORD host_wsize = sizeof(host_utf16) / sizeof(host_utf16[0]);
if (GetComputerNameW(host_utf16, &host_wsize) == 0) {
- *hostname = '\0';
+ *hostname = NUL;
DWORD err = GetLastError();
semsg("GetComputerNameW failed: %d", err);
return;
}
- host_utf16[host_wsize] = '\0';
+ host_utf16[host_wsize] = NUL;
char *host_utf8;
int conversion_result = utf16_to_utf8(host_utf16, -1, &host_utf8);
@@ -391,7 +391,7 @@ void os_get_hostname(char *hostname, size_t size)
xfree(host_utf8);
#else
emsg("os_get_hostname failed: missing uname()");
- *hostname = '\0';
+ *hostname = NUL;
#endif
}
@@ -885,9 +885,9 @@ void vim_get_prefix_from_exepath(char *exe_name)
// but c_grammar.lua does not recognize it (yet).
xstrlcpy(exe_name, get_vim_var_str(VV_PROGPATH), MAXPATHL * sizeof(*exe_name));
char *path_end = path_tail_with_sep(exe_name);
- *path_end = '\0'; // remove the trailing "nvim.exe"
+ *path_end = NUL; // remove the trailing "nvim.exe"
path_end = path_tail(exe_name);
- *path_end = '\0'; // remove the trailing "bin/"
+ *path_end = NUL; // remove the trailing "bin/"
}
/// Vim getenv() wrapper with special handling of $HOME, $VIM, $VIMRUNTIME,
diff --git a/src/nvim/os/fileio.c b/src/nvim/os/fileio.c
index e58eb96c2e..585c4964e2 100644
--- a/src/nvim/os/fileio.c
+++ b/src/nvim/os/fileio.c
@@ -21,8 +21,6 @@
#include "nvim/os/fileio.h"
#include "nvim/os/fs.h"
#include "nvim/os/os_defs.h"
-#include "nvim/rbuffer.h"
-#include "nvim/rbuffer_defs.h"
#include "nvim/types_defs.h"
#ifdef HAVE_SYS_UIO_H
@@ -120,12 +118,9 @@ int file_open_fd(FileDescriptor *const ret_fp, const int fd, const int flags)
assert(!ret_fp->wr || !ret_fp->non_blocking);
ret_fp->fd = fd;
ret_fp->eof = false;
- ret_fp->rv = rbuffer_new(kRWBufferSize);
- ret_fp->_error = 0;
- if (ret_fp->wr) {
- ret_fp->rv->data = ret_fp;
- ret_fp->rv->full_cb = (rbuffer_callback)&file_rb_write_full_cb;
- }
+ ret_fp->buffer = alloc_block();
+ ret_fp->read_pos = ret_fp->buffer;
+ ret_fp->write_pos = ret_fp->buffer;
ret_fp->bytes_read = 0;
return 0;
}
@@ -148,8 +143,9 @@ void file_open_buffer(FileDescriptor *ret_fp, char *data, size_t len)
ret_fp->non_blocking = false;
ret_fp->fd = -1;
ret_fp->eof = true;
- ret_fp->rv = rbuffer_new_wrap_buf(data, len);
- ret_fp->_error = 0;
+ ret_fp->buffer = NULL; // we don't take ownership
+ ret_fp->read_pos = data;
+ ret_fp->write_pos = data + len;
ret_fp->bytes_read = 0;
}
@@ -163,36 +159,18 @@ int file_close(FileDescriptor *const fp, const bool do_fsync)
FUNC_ATTR_NONNULL_ALL
{
if (fp->fd < 0) {
- rbuffer_free(fp->rv);
return 0;
}
const int flush_error = (do_fsync ? file_fsync(fp) : file_flush(fp));
const int close_error = os_close(fp->fd);
- rbuffer_free(fp->rv);
+ free_block(fp->buffer);
if (close_error != 0) {
return close_error;
}
return flush_error;
}
-/// Flush file modifications to disk
-///
-/// @param[in,out] fp File to work with.
-///
-/// @return 0 or error code.
-int file_flush(FileDescriptor *const fp)
- FUNC_ATTR_NONNULL_ALL
-{
- if (!fp->wr) {
- return 0;
- }
- file_rb_write_full_cb(fp->rv, fp);
- const int error = fp->_error;
- fp->_error = 0;
- return error;
-}
-
/// Flush file modifications to disk and run fsync()
///
/// @param[in,out] fp File to work with.
@@ -218,36 +196,29 @@ int file_fsync(FileDescriptor *const fp)
return 0;
}
-/// Buffer used for writing
-///
-/// Like IObuff, but allows file_\* callers not to care about spoiling it.
-static char writebuf[kRWBufferSize];
-
-/// Function run when RBuffer is full when writing to a file
-///
-/// Actually does writing to the file, may also be invoked directly.
+/// Flush file modifications to disk
///
-/// @param[in,out] rv RBuffer instance used.
/// @param[in,out] fp File to work with.
-static void file_rb_write_full_cb(RBuffer *const rv, void *const fp_in)
+///
+/// @return 0 or error code.
+int file_flush(FileDescriptor *fp)
FUNC_ATTR_NONNULL_ALL
{
- FileDescriptor *const fp = fp_in;
- assert(fp->wr);
- assert(rv->data == (void *)fp);
- if (rbuffer_size(rv) == 0) {
- return;
+ if (!fp->wr) {
+ return 0;
+ }
+
+ ptrdiff_t to_write = fp->write_pos - fp->read_pos;
+ if (to_write == 0) {
+ return 0;
}
- const size_t read_bytes = rbuffer_read(rv, writebuf, kRWBufferSize);
- const ptrdiff_t wres = os_write(fp->fd, writebuf, read_bytes,
+ const ptrdiff_t wres = os_write(fp->fd, fp->read_pos, (size_t)to_write,
fp->non_blocking);
- if (wres != (ptrdiff_t)read_bytes) {
- if (wres >= 0) {
- fp->_error = UV_EIO;
- } else {
- fp->_error = (int)wres;
- }
+ fp->read_pos = fp->write_pos = fp->buffer;
+ if (wres != to_write) {
+ return (wres >= 0) ? UV_EIO : (int)wres;
}
+ return 0;
}
/// Read from file
@@ -262,77 +233,78 @@ ptrdiff_t file_read(FileDescriptor *const fp, char *const ret_buf, const size_t
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
{
assert(!fp->wr);
- char *buf = ret_buf;
- size_t read_remaining = size;
- RBuffer *const rv = fp->rv;
+ size_t from_buffer = MIN((size_t)(fp->write_pos - fp->read_pos), size);
+ memcpy(ret_buf, fp->read_pos, from_buffer);
+
+ char *buf = ret_buf + from_buffer;
+ size_t read_remaining = size - from_buffer;
+ if (!read_remaining) {
+ fp->bytes_read += from_buffer;
+ fp->read_pos += from_buffer;
+ return (ptrdiff_t)from_buffer;
+ }
+
+ // at this point, we have consumed all of an existing buffer. restart from the beginning
+ fp->read_pos = fp->write_pos = fp->buffer;
+
+#ifdef HAVE_READV
bool called_read = false;
while (read_remaining) {
- const size_t rv_size = rbuffer_size(rv);
- if (rv_size > 0) {
- const size_t rsize = rbuffer_read(rv, buf, MIN(rv_size, read_remaining));
- buf += rsize;
- read_remaining -= rsize;
- }
- if (fp->eof
- // Allow only at most one os_read[v] call.
- || (called_read && fp->non_blocking)) {
+ // Allow only at most one os_read[v] call.
+ if (fp->eof || (called_read && fp->non_blocking)) {
break;
}
- if (read_remaining) {
- assert(rbuffer_size(rv) == 0);
- rbuffer_reset(rv);
-#ifdef HAVE_READV
- // If there is readv() syscall, then take an opportunity to populate
- // both target buffer and RBuffer at once, …
- size_t write_count;
- struct iovec iov[] = {
- { .iov_base = buf, .iov_len = read_remaining },
- { .iov_base = rbuffer_write_ptr(rv, &write_count),
- .iov_len = kRWBufferSize },
- };
- assert(write_count == kRWBufferSize);
- const ptrdiff_t r_ret = os_readv(fp->fd, &fp->eof, iov,
- ARRAY_SIZE(iov), fp->non_blocking);
- if (r_ret > 0) {
- if (r_ret > (ptrdiff_t)read_remaining) {
- rbuffer_produced(rv, (size_t)(r_ret - (ptrdiff_t)read_remaining));
- read_remaining = 0;
- } else {
- buf += (size_t)r_ret;
- read_remaining -= (size_t)r_ret;
- }
- } else if (r_ret < 0) {
- return r_ret;
- }
-#else
- if (read_remaining >= kRWBufferSize) {
- // …otherwise leave RBuffer empty and populate only target buffer,
- // because filtering information through rbuffer will be more syscalls.
- const ptrdiff_t r_ret = os_read(fp->fd, &fp->eof, buf, read_remaining,
- fp->non_blocking);
- if (r_ret >= 0) {
- read_remaining -= (size_t)r_ret;
- fp->bytes_read += (size - read_remaining);
- return (ptrdiff_t)(size - read_remaining);
- } else if (r_ret < 0) {
- return r_ret;
- }
+ // If there is readv() syscall, then take an opportunity to populate
+ // both target buffer and RBuffer at once, …
+ struct iovec iov[] = {
+ { .iov_base = buf, .iov_len = read_remaining },
+ { .iov_base = fp->write_pos,
+ .iov_len = ARENA_BLOCK_SIZE },
+ };
+ const ptrdiff_t r_ret = os_readv(fp->fd, &fp->eof, iov,
+ ARRAY_SIZE(iov), fp->non_blocking);
+ if (r_ret > 0) {
+ if (r_ret > (ptrdiff_t)read_remaining) {
+ fp->write_pos += (size_t)(r_ret - (ptrdiff_t)read_remaining);
+ read_remaining = 0;
} else {
- size_t write_count;
- const ptrdiff_t r_ret = os_read(fp->fd, &fp->eof,
- rbuffer_write_ptr(rv, &write_count),
- kRWBufferSize, fp->non_blocking);
- assert(write_count == kRWBufferSize);
- if (r_ret > 0) {
- rbuffer_produced(rv, (size_t)r_ret);
- } else if (r_ret < 0) {
- return r_ret;
- }
+ buf += r_ret;
+ read_remaining -= (size_t)r_ret;
}
-#endif
- called_read = true;
+ } else if (r_ret < 0) {
+ return r_ret;
+ }
+ called_read = true;
+ }
+#else
+ if (fp->eof) {
+ // already eof, cannot read more
+ } else if (read_remaining >= ARENA_BLOCK_SIZE) {
+ // …otherwise leave fp->buffer empty and populate only target buffer,
+ // because filtering information through rbuffer will be more syscalls.
+ const ptrdiff_t r_ret = os_read(fp->fd, &fp->eof, buf, read_remaining,
+ fp->non_blocking);
+ if (r_ret >= 0) {
+ read_remaining -= (size_t)r_ret;
+ } else if (r_ret < 0) {
+ return r_ret;
+ }
+ } else {
+ const ptrdiff_t r_ret = os_read(fp->fd, &fp->eof,
+ fp->write_pos,
+ ARENA_BLOCK_SIZE, fp->non_blocking);
+ if (r_ret < 0) {
+ return r_ret;
+ } else {
+ fp->write_pos += r_ret;
+ size_t to_copy = MIN((size_t)r_ret, read_remaining);
+ memcpy(buf, fp->read_pos, to_copy);
+ fp->read_pos += to_copy;
+ read_remaining -= to_copy;
}
}
+#endif
+
fp->bytes_read += (size - read_remaining);
return (ptrdiff_t)(size - read_remaining);
}
@@ -348,40 +320,68 @@ ptrdiff_t file_write(FileDescriptor *const fp, const char *const buf, const size
FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ARG(1)
{
assert(fp->wr);
- const size_t written = rbuffer_write(fp->rv, buf, size);
- if (fp->_error != 0) {
- const int error = fp->_error;
- fp->_error = 0;
- return error;
- } else if (written != size) {
- return UV_EIO;
+ ptrdiff_t space = (fp->buffer + ARENA_BLOCK_SIZE) - fp->write_pos;
+ // includes the trivial case of size==0
+ if (size < (size_t)space) {
+ memcpy(fp->write_pos, buf, size);
+ fp->write_pos += size;
+ return (ptrdiff_t)size;
+ }
+
+ // TODO(bfredl): just as for reading, use iovec to combine fp->buffer with buf
+ int status = file_flush(fp);
+ if (status < 0) {
+ return status;
+ }
+
+ if (size < ARENA_BLOCK_SIZE) {
+ memcpy(fp->write_pos, buf, size);
+ fp->write_pos += size;
+ return (ptrdiff_t)size;
}
- return (ptrdiff_t)written;
-}
-/// Buffer used for skipping. Its contents is undefined and should never be
-/// used.
-static char skipbuf[kRWBufferSize];
+ const ptrdiff_t wres = os_write(fp->fd, buf, size,
+ fp->non_blocking);
+ return (wres != (ptrdiff_t)size && wres >= 0) ? UV_EIO : wres;
+}
/// Skip some bytes
///
/// This is like `fseek(fp, size, SEEK_CUR)`, but actual implementation simply
-/// reads to a buffer and discards the result.
+/// reads to the buffer and discards the result.
ptrdiff_t file_skip(FileDescriptor *const fp, const size_t size)
FUNC_ATTR_NONNULL_ALL
{
assert(!fp->wr);
- size_t read_bytes = 0;
- do {
- const ptrdiff_t new_read_bytes =
- file_read(fp, skipbuf, MIN(size - read_bytes, sizeof(skipbuf)));
- if (new_read_bytes < 0) {
- return new_read_bytes;
- } else if (new_read_bytes == 0) {
+ size_t from_buffer = MIN((size_t)(fp->write_pos - fp->read_pos), size);
+ size_t skip_remaining = size - from_buffer;
+ if (skip_remaining == 0) {
+ fp->read_pos += from_buffer;
+ fp->bytes_read += from_buffer;
+ return (ptrdiff_t)from_buffer;
+ }
+
+ fp->read_pos = fp->write_pos = fp->buffer;
+ bool called_read = false;
+ while (skip_remaining > 0) {
+ // Allow only at most one os_read[v] call.
+ if (fp->eof || (called_read && fp->non_blocking)) {
break;
}
- read_bytes += (size_t)new_read_bytes;
- } while (read_bytes < size && !file_eof(fp));
+ const ptrdiff_t r_ret = os_read(fp->fd, &fp->eof, fp->buffer, ARENA_BLOCK_SIZE,
+ fp->non_blocking);
+ if (r_ret < 0) {
+ return r_ret;
+ } else if ((size_t)r_ret > skip_remaining) {
+ fp->read_pos = fp->buffer + skip_remaining;
+ fp->write_pos = fp->buffer + r_ret;
+ fp->bytes_read += size;
+ return (ptrdiff_t)size;
+ }
+ skip_remaining -= (size_t)r_ret;
+ called_read = true;
+ }
- return (ptrdiff_t)read_bytes;
+ fp->bytes_read += size - skip_remaining;
+ return (ptrdiff_t)(size - skip_remaining);
}
diff --git a/src/nvim/os/fileio_defs.h b/src/nvim/os/fileio_defs.h
index 10277d2a7a..0f76fdb2aa 100644
--- a/src/nvim/os/fileio_defs.h
+++ b/src/nvim/os/fileio_defs.h
@@ -4,13 +4,13 @@
#include <stdint.h>
#include "nvim/func_attr.h"
-#include "nvim/rbuffer_defs.h"
/// Structure used to read from/write to file
typedef struct {
- int fd; ///< File descriptor.
- int _error; ///< Error code for use with RBuffer callbacks or zero.
- RBuffer *rv; ///< Read or write buffer.
+ int fd; ///< File descriptor. Can be -1 if no backing file (file_open_buffer)
+ char *buffer; ///< Read or write buffer. always ARENA_BLOCK_SIZE if allocated
+ char *read_pos; ///< read position in buffer
+ char *write_pos; ///< write position in buffer
bool wr; ///< True if file is in write mode.
bool eof; ///< True if end of file was encountered.
bool non_blocking; ///< True if EAGAIN should not restart syscalls.
@@ -28,7 +28,7 @@ static inline bool file_eof(const FileDescriptor *fp)
/// performed.
static inline bool file_eof(const FileDescriptor *const fp)
{
- return fp->eof && rbuffer_size(fp->rv) == 0;
+ return fp->eof && fp->read_pos == fp->write_pos;
}
static inline int file_fd(const FileDescriptor *fp)
diff --git a/src/nvim/os/fs.c b/src/nvim/os/fs.c
index 19bdf30311..b681b2f832 100644
--- a/src/nvim/os/fs.c
+++ b/src/nvim/os/fs.c
@@ -17,6 +17,7 @@
#endif
#include "auto/config.h"
+#include "nvim/errors.h"
#include "nvim/os/fs.h"
#include "nvim/os/os_defs.h"
@@ -301,7 +302,7 @@ static bool is_executable_ext(const char *name, char **abspath)
char *nameext = strrchr(name, '.');
size_t nameext_len = nameext ? strlen(nameext) : 0;
xstrlcpy(os_buf, name, sizeof(os_buf));
- char *buf_end = xstrchrnul(os_buf, '\0');
+ char *buf_end = xstrchrnul(os_buf, NUL);
const char *pathext = os_getenv("PATHEXT");
if (!pathext) {
pathext = ".com;.exe;.bat;.cmd";
@@ -309,7 +310,7 @@ static bool is_executable_ext(const char *name, char **abspath)
const char *ext = pathext;
while (*ext) {
// If $PATHEXT itself contains dot:
- if (ext[0] == '.' && (ext[1] == '\0' || ext[1] == ENV_SEPCHAR)) {
+ if (ext[0] == '.' && (ext[1] == NUL || ext[1] == ENV_SEPCHAR)) {
if (is_executable(name, abspath)) {
return true;
}
@@ -435,7 +436,7 @@ FILE *os_fopen(const char *path, const char *flags)
assert(flags != NULL && strlen(flags) > 0 && strlen(flags) <= 2);
int iflags = 0;
// Per table in fopen(3) manpage.
- if (flags[1] == '\0' || flags[1] == 'b') {
+ if (flags[1] == NUL || flags[1] == 'b') {
switch (flags[0]) {
case 'r':
iflags = O_RDONLY;
diff --git a/src/nvim/os/input.c b/src/nvim/os/input.c
index 60b5b48745..ea21a32230 100644
--- a/src/nvim/os/input.c
+++ b/src/nvim/os/input.c
@@ -27,13 +27,11 @@
#include "nvim/os/os_defs.h"
#include "nvim/os/time.h"
#include "nvim/profile.h"
-#include "nvim/rbuffer.h"
-#include "nvim/rbuffer_defs.h"
#include "nvim/state.h"
#include "nvim/state_defs.h"
#define READ_BUFFER_SIZE 0xfff
-#define INPUT_BUFFER_SIZE (READ_BUFFER_SIZE * 4)
+#define INPUT_BUFFER_SIZE ((READ_BUFFER_SIZE * 4) + MAX_KEY_CODE_LEN)
typedef enum {
kInputNone,
@@ -41,8 +39,11 @@ typedef enum {
kInputEof,
} InbufPollResult;
-static Stream read_stream = { .closed = true }; // Input before UI starts.
-static RBuffer *input_buffer = NULL;
+static RStream read_stream = { .s.closed = true }; // Input before UI starts.
+static char input_buffer[INPUT_BUFFER_SIZE];
+static char *input_read_pos = input_buffer;
+static char *input_write_pos = input_buffer;
+
static bool input_eof = false;
static bool blocking = false;
static int cursorhold_time = 0; ///< time waiting for CursorHold event
@@ -52,38 +53,26 @@ static int cursorhold_tb_change_cnt = 0; ///< tb_change_cnt when waiting starte
# include "os/input.c.generated.h"
#endif
-void input_init(void)
-{
- input_buffer = rbuffer_new(INPUT_BUFFER_SIZE + MAX_KEY_CODE_LEN);
-}
-
void input_start(void)
{
- if (!read_stream.closed) {
+ if (!read_stream.s.closed) {
return;
}
used_stdin = true;
- rstream_init_fd(&main_loop, &read_stream, STDIN_FILENO, READ_BUFFER_SIZE);
+ rstream_init_fd(&main_loop, &read_stream, STDIN_FILENO);
rstream_start(&read_stream, input_read_cb, NULL);
}
void input_stop(void)
{
- if (read_stream.closed) {
+ if (read_stream.s.closed) {
return;
}
rstream_stop(&read_stream);
- stream_close(&read_stream, NULL, NULL);
-}
-
-#ifdef EXITFREE
-void input_free_all_mem(void)
-{
- rbuffer_free(input_buffer);
+ rstream_may_close(&read_stream);
}
-#endif
static void cursorhold_event(void **argv)
{
@@ -119,9 +108,12 @@ int os_inchar(uint8_t *buf, int maxlen, int ms, int tb_change_cnt, MultiQueue *e
restart_cursorhold_wait(tb_change_cnt);
}
- if (maxlen && rbuffer_size(input_buffer)) {
+ if (maxlen && input_available()) {
restart_cursorhold_wait(tb_change_cnt);
- return (int)rbuffer_read(input_buffer, (char *)buf, (size_t)maxlen);
+ size_t to_read = MIN((size_t)maxlen, input_available());
+ memcpy(buf, input_read_pos, to_read);
+ input_read_pos += to_read;
+ return (int)to_read;
}
// No risk of a UI flood, so disable CTRL-C "interrupt" behavior if it's mapped.
@@ -138,7 +130,7 @@ int os_inchar(uint8_t *buf, int maxlen, int ms, int tb_change_cnt, MultiQueue *e
uint64_t wait_start = os_hrtime();
cursorhold_time = MIN(cursorhold_time, (int)p_ut);
if ((result = inbuf_poll((int)p_ut - cursorhold_time, events)) == kInputNone) {
- if (read_stream.closed && silent_mode) {
+ if (read_stream.s.closed && silent_mode) {
// Drained eventloop & initial input; exit silent/batch-mode (-es/-Es).
read_error_exit();
}
@@ -161,11 +153,14 @@ int os_inchar(uint8_t *buf, int maxlen, int ms, int tb_change_cnt, MultiQueue *e
return 0;
}
- if (maxlen && rbuffer_size(input_buffer)) {
+ if (maxlen && input_available()) {
restart_cursorhold_wait(tb_change_cnt);
- // Safe to convert rbuffer_read to int, it will never overflow since we use
- // relatively small buffers.
- return (int)rbuffer_read(input_buffer, (char *)buf, (size_t)maxlen);
+ // Safe to convert `to_read` to int, it will never overflow since
+ // INPUT_BUFFER_SIZE fits in an int
+ size_t to_read = MIN((size_t)maxlen, input_available());
+ memcpy(buf, input_read_pos, to_read);
+ input_read_pos += to_read;
+ return (int)to_read;
}
// If there are events, return the keys directly
@@ -247,11 +242,28 @@ bool os_isatty(int fd)
return uv_guess_handle(fd) == UV_TTY;
}
-void input_enqueue_raw(String keys)
+size_t input_available(void)
{
- if (keys.size > 0) {
- rbuffer_write(input_buffer, keys.data, keys.size);
+ return (size_t)(input_write_pos - input_read_pos);
+}
+
+static size_t input_space(void)
+{
+ return (size_t)(input_buffer + INPUT_BUFFER_SIZE - input_write_pos);
+}
+
+void input_enqueue_raw(const char *data, size_t size)
+{
+ if (input_read_pos > input_buffer) {
+ size_t available = input_available();
+ memmove(input_buffer, input_read_pos, available);
+ input_read_pos = input_buffer;
+ input_write_pos = input_buffer + available;
}
+
+ size_t to_write = MIN(size, input_space());
+ memcpy(input_write_pos, data, to_write);
+ input_write_pos += to_write;
}
size_t input_enqueue(String keys)
@@ -259,7 +271,7 @@ size_t input_enqueue(String keys)
const char *ptr = keys.data;
const char *end = ptr + keys.size;
- while (rbuffer_space(input_buffer) >= 19 && ptr < end) {
+ while (input_space() >= 19 && ptr < end) {
// A "<x>" form occupies at least 1 characters, and produces up
// to 19 characters (1 + 5 * 3 for the char and 3 for a modifier).
// In the case of K_SPECIAL (0x80), 3 bytes are escaped and needed,
@@ -272,7 +284,7 @@ size_t input_enqueue(String keys)
if (new_size) {
new_size = handle_mouse_event(&ptr, buf, new_size);
- rbuffer_write(input_buffer, (char *)buf, new_size);
+ input_enqueue_raw((char *)buf, new_size);
continue;
}
@@ -293,11 +305,11 @@ size_t input_enqueue(String keys)
// copy the character, escaping K_SPECIAL
if ((uint8_t)(*ptr) == K_SPECIAL) {
- rbuffer_write(input_buffer, (char *)&(uint8_t){ K_SPECIAL }, 1);
- rbuffer_write(input_buffer, (char *)&(uint8_t){ KS_SPECIAL }, 1);
- rbuffer_write(input_buffer, (char *)&(uint8_t){ KE_FILLER }, 1);
+ input_enqueue_raw((char *)&(uint8_t){ K_SPECIAL }, 1);
+ input_enqueue_raw((char *)&(uint8_t){ KS_SPECIAL }, 1);
+ input_enqueue_raw((char *)&(uint8_t){ KE_FILLER }, 1);
} else {
- rbuffer_write(input_buffer, ptr, 1);
+ input_enqueue_raw(ptr, 1);
}
ptr++;
}
@@ -422,7 +434,7 @@ static unsigned handle_mouse_event(const char **ptr, uint8_t *buf, unsigned bufs
return bufsize;
}
-size_t input_enqueue_mouse(int code, uint8_t modifier, int grid, int row, int col)
+void input_enqueue_mouse(int code, uint8_t modifier, int grid, int row, int col)
{
modifier |= check_multiclick(code, grid, row, col);
uint8_t buf[7];
@@ -442,8 +454,7 @@ size_t input_enqueue_mouse(int code, uint8_t modifier, int grid, int row, int co
mouse_col = col;
size_t written = 3 + (size_t)(p - buf);
- rbuffer_write(input_buffer, (char *)buf, written);
- return written;
+ input_enqueue_raw((char *)buf, written);
}
/// @return true if the main loop is blocked and waiting for input.
@@ -484,22 +495,15 @@ static InbufPollResult inbuf_poll(int ms, MultiQueue *events)
return input_eof ? kInputEof : kInputNone;
}
-bool input_available(void)
-{
- return rbuffer_size(input_buffer) != 0;
-}
-
-static void input_read_cb(Stream *stream, RBuffer *buf, size_t c, void *data, bool at_eof)
+static size_t input_read_cb(RStream *stream, const char *buf, size_t c, void *data, bool at_eof)
{
if (at_eof) {
input_eof = true;
}
- assert(rbuffer_space(input_buffer) >= rbuffer_size(buf));
- RBUFFER_UNTIL_EMPTY(buf, ptr, len) {
- (void)rbuffer_write(input_buffer, ptr, len);
- rbuffer_consumed(buf, len);
- }
+ assert(input_space() >= c);
+ input_enqueue_raw(buf, c);
+ return c;
}
static void process_ctrl_c(void)
@@ -508,23 +512,24 @@ static void process_ctrl_c(void)
return;
}
- size_t consume_count = 0;
- RBUFFER_EACH_REVERSE(input_buffer, c, i) {
- if ((uint8_t)c == Ctrl_C
- || ((uint8_t)c == 'C' && i >= 3
- && (uint8_t)(*rbuffer_get(input_buffer, i - 3)) == K_SPECIAL
- && (uint8_t)(*rbuffer_get(input_buffer, i - 2)) == KS_MODIFIER
- && (uint8_t)(*rbuffer_get(input_buffer, i - 1)) == MOD_MASK_CTRL)) {
- *rbuffer_get(input_buffer, i) = Ctrl_C;
+ size_t available = input_available();
+ ssize_t i;
+ for (i = (ssize_t)available - 1; i >= 0; i--) {
+ uint8_t c = (uint8_t)input_read_pos[i];
+ if (c == Ctrl_C
+ || (c == 'C' && i >= 3
+ && (uint8_t)input_read_pos[i - 3] == K_SPECIAL
+ && (uint8_t)input_read_pos[i - 2] == KS_MODIFIER
+ && (uint8_t)input_read_pos[i - 1] == MOD_MASK_CTRL)) {
+ input_read_pos[i] = Ctrl_C;
got_int = true;
- consume_count = i;
break;
}
}
- if (got_int && consume_count) {
+ if (got_int && i > 0) {
// Remove all unprocessed input (typeahead) before the CTRL-C.
- rbuffer_consumed(input_buffer, consume_count);
+ input_read_pos += i;
}
}
@@ -548,7 +553,7 @@ static int push_event_key(uint8_t *buf, int maxlen)
bool os_input_ready(MultiQueue *events)
{
return (typebuf_was_filled // API call filled typeahead
- || rbuffer_size(input_buffer) // Input buffer filled
+ || input_available() // Input buffer filled
|| pending_events(events)); // Events must be processed
}
diff --git a/src/nvim/os/pty_process_unix.c b/src/nvim/os/pty_process_unix.c
index 4d34e8fac4..cfa4dcada7 100644
--- a/src/nvim/os/pty_process_unix.c
+++ b/src/nvim/os/pty_process_unix.c
@@ -169,7 +169,7 @@ int pty_process_spawn(PtyProcess *ptyproc)
int status = 0; // zero or negative error code (libuv convention)
Process *proc = (Process *)ptyproc;
- assert(proc->err.closed);
+ assert(proc->err.s.closed);
uv_signal_start(&proc->loop->children_watcher, chld_handler, SIGCHLD);
ptyproc->winsize = (struct winsize){ ptyproc->height, ptyproc->width, 0, 0 };
uv_disable_stdio_inheritance();
@@ -208,8 +208,8 @@ int pty_process_spawn(PtyProcess *ptyproc)
&& (status = set_duplicating_descriptor(master, &proc->in.uv.pipe))) {
goto error;
}
- if (!proc->out.closed
- && (status = set_duplicating_descriptor(master, &proc->out.uv.pipe))) {
+ if (!proc->out.s.closed
+ && (status = set_duplicating_descriptor(master, &proc->out.s.uv.pipe))) {
goto error;
}
diff --git a/src/nvim/os/pty_process_win.c b/src/nvim/os/pty_process_win.c
index 12831ff05f..39c3966c1c 100644
--- a/src/nvim/os/pty_process_win.c
+++ b/src/nvim/os/pty_process_win.c
@@ -55,7 +55,7 @@ int pty_process_spawn(PtyProcess *ptyproc)
wchar_t *env = NULL;
const char *emsg = NULL;
- assert(proc->err.closed);
+ assert(proc->err.s.closed);
if (!os_has_conpty_working() || (conpty_object = os_conpty_init(&in_name,
&out_name, ptyproc->width,
@@ -72,10 +72,10 @@ int pty_process_spawn(PtyProcess *ptyproc)
pty_process_connect_cb);
}
- if (!proc->out.closed) {
+ if (!proc->out.s.closed) {
out_req = xmalloc(sizeof(uv_connect_t));
uv_pipe_connect(out_req,
- &proc->out.uv.pipe,
+ &proc->out.s.uv.pipe,
out_name,
pty_process_connect_cb);
}
@@ -216,7 +216,7 @@ static void wait_eof_timer_cb(uv_timer_t *wait_eof_timer)
Process *proc = (Process *)ptyproc;
assert(ptyproc->finish_wait != NULL);
- if (proc->out.closed || proc->out.did_eof || !uv_is_readable(proc->out.uvstream)) {
+ if (proc->out.s.closed || proc->out.did_eof || !uv_is_readable(proc->out.s.uvstream)) {
uv_timer_stop(&ptyproc->wait_eof_timer);
pty_process_finish2(ptyproc);
}
@@ -399,7 +399,7 @@ static int build_env_block(dict_T *denv, wchar_t **env_block)
QUEUE_INSERT_TAIL(&env_q, &env_node->node);
}
- // Additional '\0' after the final entry
+ // Additional NUL after the final entry
env_block_len++;
*env_block = xmalloc(sizeof(**env_block) * env_block_len);
diff --git a/src/nvim/os/shell.c b/src/nvim/os/shell.c
index 2a10510b0f..4b34ed1c4e 100644
--- a/src/nvim/os/shell.c
+++ b/src/nvim/os/shell.c
@@ -10,6 +10,7 @@
#include "nvim/ascii_defs.h"
#include "nvim/buffer_defs.h"
#include "nvim/charset.h"
+#include "nvim/errors.h"
#include "nvim/eval.h"
#include "nvim/eval/typval_defs.h"
#include "nvim/event/defs.h"
@@ -39,8 +40,6 @@
#include "nvim/path.h"
#include "nvim/pos_defs.h"
#include "nvim/profile.h"
-#include "nvim/rbuffer.h"
-#include "nvim/rbuffer_defs.h"
#include "nvim/state_defs.h"
#include "nvim/strings.h"
#include "nvim/tag.h"
@@ -48,17 +47,11 @@
#include "nvim/ui.h"
#include "nvim/vim_defs.h"
-#define DYNAMIC_BUFFER_INIT { NULL, 0, 0 }
#define NS_1_SECOND 1000000000U // 1 second, in nanoseconds
#define OUT_DATA_THRESHOLD 1024 * 10U // 10KB, "a few screenfuls" of data.
#define SHELL_SPECIAL "\t \"&'$;<>()\\|"
-typedef struct {
- char *data;
- size_t cap, len;
-} DynamicBuffer;
-
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "os/shell.c.generated.h"
#endif
@@ -255,11 +248,11 @@ int os_expand_wildcards(int num_pat, char **pat, int *num_file, char ***file, in
} else {
STRCPY(command, "(");
}
- STRCAT(command, pat[0] + 1); // exclude first backtick
+ strcat(command, pat[0] + 1); // exclude first backtick
p = command + strlen(command) - 1;
if (is_fish_shell) {
*p-- = ';';
- STRCAT(command, " end");
+ strcat(command, " end");
} else {
*p-- = ')'; // remove last backtick
}
@@ -270,7 +263,7 @@ int os_expand_wildcards(int num_pat, char **pat, int *num_file, char ***file, in
ampersand = true;
*p = ' ';
}
- STRCAT(command, ">");
+ strcat(command, ">");
} else {
STRCPY(command, "");
if (shell_style == STYLE_GLOB) {
@@ -278,26 +271,26 @@ int os_expand_wildcards(int num_pat, char **pat, int *num_file, char ***file, in
// otherwise, this may set the positional parameters for the shell,
// e.g. "$*".
if (flags & EW_NOTFOUND) {
- STRCAT(command, "set nonomatch; ");
+ strcat(command, "set nonomatch; ");
} else {
- STRCAT(command, "unset nonomatch; ");
+ strcat(command, "unset nonomatch; ");
}
}
if (shell_style == STYLE_GLOB) {
- STRCAT(command, "glob >");
+ strcat(command, "glob >");
} else if (shell_style == STYLE_PRINT) {
- STRCAT(command, "print -N >");
+ strcat(command, "print -N >");
} else if (shell_style == STYLE_VIMGLOB) {
- STRCAT(command, sh_vimglob_func);
+ strcat(command, sh_vimglob_func);
} else if (shell_style == STYLE_GLOBSTAR) {
- STRCAT(command, sh_globstar_opt);
- STRCAT(command, sh_vimglob_func);
+ strcat(command, sh_globstar_opt);
+ strcat(command, sh_vimglob_func);
} else {
- STRCAT(command, "echo >");
+ strcat(command, "echo >");
}
}
- STRCAT(command, tempname);
+ strcat(command, tempname);
if (shell_style != STYLE_BT) {
for (i = 0; i < num_pat; i++) {
@@ -341,7 +334,7 @@ int os_expand_wildcards(int num_pat, char **pat, int *num_file, char ***file, in
}
if (ampersand) {
- STRCAT(command, "&"); // put the '&' after the redirection
+ strcat(command, "&"); // put the '&' after the redirection
}
// Using zsh -G: If a pattern has no matches, it is just deleted from
@@ -647,13 +640,13 @@ char *shell_argv_to_str(char **const argv)
p++;
}
if (n < maxsize) {
- rv[n - 1] = '\0';
+ rv[n - 1] = NUL;
} else {
// Command too long, show ellipsis: "/bin/bash 'foo' 'bar'..."
rv[maxsize - 4] = '.';
rv[maxsize - 3] = '.';
rv[maxsize - 2] = '.';
- rv[maxsize - 1] = '\0';
+ rv[maxsize - 1] = NUL;
}
return rv;
}
@@ -668,7 +661,7 @@ char *shell_argv_to_str(char **const argv)
/// @return shell command exit code
int os_call_shell(char *cmd, ShellOpts opts, char *extra_args)
{
- DynamicBuffer input = DYNAMIC_BUFFER_INIT;
+ StringBuilder input = KV_INITIAL_VALUE;
char *output = NULL;
char **output_ptr = NULL;
int current_state = State;
@@ -697,9 +690,9 @@ int os_call_shell(char *cmd, ShellOpts opts, char *extra_args)
size_t nread;
int exitcode = do_os_system(shell_build_argv(cmd, extra_args),
- input.data, input.len, output_ptr, &nread,
+ input.items, input.size, output_ptr, &nread,
emsg_silent, forward_output);
- xfree(input.data);
+ kv_destroy(input);
if (output) {
write_output(output, nread, true);
@@ -860,10 +853,10 @@ static int do_os_system(char **argv, const char *input, size_t len, char **outpu
{
out_data_decide_throttle(0); // Initialize throttle decider.
out_data_ring(NULL, 0); // Initialize output ring-buffer.
- bool has_input = (input != NULL && input[0] != '\0');
+ bool has_input = (input != NULL && input[0] != NUL);
// the output buffer
- DynamicBuffer buf = DYNAMIC_BUFFER_INIT;
+ StringBuilder buf = KV_INITIAL_VALUE;
stream_read_cb data_cb = system_data_cb;
if (nread) {
*nread = 0;
@@ -906,9 +899,9 @@ static int do_os_system(char **argv, const char *input, size_t len, char **outpu
if (has_input) {
wstream_init(&proc->in, 0);
}
- rstream_init(&proc->out, 0);
+ rstream_init(&proc->out);
rstream_start(&proc->out, data_cb, &buf);
- rstream_init(&proc->err, 0);
+ rstream_init(&proc->err);
rstream_start(&proc->err, data_cb, &buf);
// write the input, if any
@@ -951,18 +944,17 @@ static int do_os_system(char **argv, const char *input, size_t len, char **outpu
// prepare the out parameters if requested
if (output) {
- if (buf.len == 0) {
+ assert(nread);
+ if (buf.size == 0) {
// no data received from the process, return NULL
*output = NULL;
- xfree(buf.data);
+ *nread = 0;
+ kv_destroy(buf);
} else {
+ *nread = buf.size;
// NUL-terminate to make the output directly usable as a C string
- buf.data[buf.len] = NUL;
- *output = buf.data;
- }
-
- if (nread) {
- *nread = buf.len;
+ kv_push(buf, NUL);
+ *output = buf.items;
}
}
@@ -972,29 +964,11 @@ static int do_os_system(char **argv, const char *input, size_t len, char **outpu
return exitcode;
}
-/// - ensures at least `desired` bytes in buffer
-///
-/// TODO(aktau): fold with kvec/garray
-static void dynamic_buffer_ensure(DynamicBuffer *buf, size_t desired)
-{
- if (buf->cap >= desired) {
- assert(buf->data);
- return;
- }
-
- buf->cap = desired;
- kv_roundup32(buf->cap);
- buf->data = xrealloc(buf->data, buf->cap);
-}
-
-static void system_data_cb(Stream *stream, RBuffer *buf, size_t count, void *data, bool eof)
+static size_t system_data_cb(RStream *stream, const char *buf, size_t count, void *data, bool eof)
{
- DynamicBuffer *dbuf = data;
-
- size_t nread = buf->size;
- dynamic_buffer_ensure(dbuf, dbuf->len + nread + 1);
- rbuffer_read(buf, dbuf->data + dbuf->len, nread);
- dbuf->len += nread;
+ StringBuilder *dbuf = data;
+ kv_concat_len(*dbuf, buf, count);
+ return count;
}
/// Tracks output received for the current executing shell command, and displays
@@ -1023,7 +997,7 @@ static bool out_data_decide_throttle(size_t size)
static uint64_t started = 0; // Start time of the current throttle.
static size_t received = 0; // Bytes observed since last throttle.
static size_t visit = 0; // "Pulse" count of the current throttle.
- static char pulse_msg[] = { ' ', ' ', ' ', '\0' };
+ static char pulse_msg[] = { ' ', ' ', ' ', NUL };
if (!size) {
bool previous_decision = (visit > 0);
@@ -1077,7 +1051,7 @@ static bool out_data_decide_throttle(size_t size)
///
/// @param output Data to save, or NULL to invoke a special mode.
/// @param size Length of `output`.
-static void out_data_ring(char *output, size_t size)
+static void out_data_ring(const char *output, size_t size)
{
#define MAX_CHUNK_SIZE (OUT_DATA_THRESHOLD / 2)
static char last_skipped[MAX_CHUNK_SIZE]; // Saved output.
@@ -1119,11 +1093,11 @@ static void out_data_ring(char *output, size_t size)
/// @param output Data to append to screen lines.
/// @param count Size of data.
/// @param eof If true, there will be no more data output.
-static void out_data_append_to_screen(char *output, size_t *count, bool eof)
+static void out_data_append_to_screen(const char *output, size_t *count, bool eof)
FUNC_ATTR_NONNULL_ALL
{
- char *p = output;
- char *end = output + *count;
+ const char *p = output;
+ const char *end = output + *count;
while (p < end) {
if (*p == '\n' || *p == '\r' || *p == TAB || *p == BELL) {
msg_putchar_attr((uint8_t)(*p), 0);
@@ -1151,25 +1125,16 @@ end:
ui_flush();
}
-static void out_data_cb(Stream *stream, RBuffer *buf, size_t count, void *data, bool eof)
+static size_t out_data_cb(RStream *stream, const char *ptr, size_t count, void *data, bool eof)
{
- size_t cnt;
- char *ptr = rbuffer_read_ptr(buf, &cnt);
-
- if (ptr != NULL && cnt > 0
- && out_data_decide_throttle(cnt)) { // Skip output above a threshold.
+ if (count > 0 && out_data_decide_throttle(count)) { // Skip output above a threshold.
// Save the skipped output. If it is the final chunk, we display it later.
- out_data_ring(ptr, cnt);
- } else if (ptr != NULL) {
- out_data_append_to_screen(ptr, &cnt, eof);
- }
-
- if (cnt) {
- rbuffer_consumed(buf, cnt);
+ out_data_ring(ptr, count);
+ } else if (count > 0) {
+ out_data_append_to_screen(ptr, &count, eof);
}
- // Move remaining data to start of buffer, so the buffer can never wrap around.
- rbuffer_reset(buf);
+ return count;
}
/// Parses a command string into a sequence of words, taking quotes into
@@ -1233,7 +1198,7 @@ static size_t word_length(const char *str)
/// event loop starts. If we don't (by writing in chunks returned by `ml_get`)
/// the buffer being modified might get modified by reading from the process
/// before we finish writing.
-static void read_input(DynamicBuffer *buf)
+static void read_input(StringBuilder *buf)
{
size_t written = 0;
size_t len = 0;
@@ -1247,14 +1212,11 @@ static void read_input(DynamicBuffer *buf)
} else if (lp[written] == NL) {
// NL -> NUL translation
len = 1;
- dynamic_buffer_ensure(buf, buf->len + len);
- buf->data[buf->len++] = NUL;
+ kv_push(*buf, NUL);
} else {
char *s = vim_strchr(lp + written, NL);
len = s == NULL ? l : (size_t)(s - (lp + written));
- dynamic_buffer_ensure(buf, buf->len + len);
- memcpy(buf->data + buf->len, lp + written, len);
- buf->len += len;
+ kv_concat_len(*buf, lp + written, len);
}
if (len == l) {
@@ -1263,8 +1225,7 @@ static void read_input(DynamicBuffer *buf)
|| (!curbuf->b_p_bin && curbuf->b_p_fixeol)
|| (lnum != curbuf->b_no_eol_lnum
&& (lnum != curbuf->b_ml.ml_line_count || curbuf->b_p_eol))) {
- dynamic_buffer_ensure(buf, buf->len + 1);
- buf->data[buf->len++] = NL;
+ kv_push(*buf, NL);
}
lnum++;
if (lnum > curbuf->b_op_end.lnum) {
@@ -1331,7 +1292,7 @@ static void shell_write_cb(Stream *stream, void *data, int status)
msg_schedule_semsg(_("E5677: Error writing input to shell-command: %s"),
uv_err_name(status));
}
- stream_close(stream, NULL, NULL);
+ stream_close(stream, NULL, NULL, false);
}
/// Applies 'shellxescape' (p_sxe) and 'shellxquote' (p_sxq) to a command.
diff --git a/src/nvim/os/stdpaths.c b/src/nvim/os/stdpaths.c
index e5bdd56fe6..e4435bcaa8 100644
--- a/src/nvim/os/stdpaths.c
+++ b/src/nvim/os/stdpaths.c
@@ -69,7 +69,7 @@ static const char *const xdg_defaults[] = {
const char *get_appname(void)
{
const char *env_val = os_getenv("NVIM_APPNAME");
- if (env_val == NULL || *env_val == '\0') {
+ if (env_val == NULL || *env_val == NUL) {
env_val = "nvim";
}
return env_val;
diff --git a/src/nvim/path.c b/src/nvim/path.c
index d782d1a989..aa630038a8 100644
--- a/src/nvim/path.c
+++ b/src/nvim/path.c
@@ -962,7 +962,7 @@ static void uniquefy_paths(garray_T *gap, char *pattern)
char *file_pattern = xmalloc(len + 2);
file_pattern[0] = '*';
file_pattern[1] = NUL;
- STRCAT(file_pattern, pattern);
+ strcat(file_pattern, pattern);
char *pat = file_pat_to_reg_pat(file_pattern, NULL, NULL, true);
xfree(file_pattern);
if (pat == NULL) {
@@ -1065,7 +1065,7 @@ static void uniquefy_paths(garray_T *gap, char *pattern)
rel_path = xmalloc(strlen(short_name) + strlen(PATHSEPSTR) + 2);
STRCPY(rel_path, ".");
add_pathsep(rel_path);
- STRCAT(rel_path, short_name);
+ strcat(rel_path, short_name);
xfree(fnames[i]);
fnames[i] = rel_path;
diff --git a/src/nvim/plines.c b/src/nvim/plines.c
index 5881d34c48..f273f88dd1 100644
--- a/src/nvim/plines.c
+++ b/src/nvim/plines.c
@@ -5,6 +5,7 @@
#include <stdint.h>
#include <string.h>
+#include "nvim/api/extmark.h"
#include "nvim/ascii_defs.h"
#include "nvim/buffer.h"
#include "nvim/buffer_defs.h"
@@ -158,7 +159,7 @@ CharSize charsize_regular(CharsizeArg *csarg, char *const cur, colnr_T const vco
break;
} else if (mark.pos.col == col) {
if (!mt_end(mark) && (mark.flags & MT_FLAG_DECOR_VIRT_TEXT_INLINE)
- && mt_scoped_in_win(mark, wp)) {
+ && ns_in_win(mark.ns, wp)) {
DecorInline decor = mt_decor(mark);
DecorVirtText *vt = decor.ext ? decor.data.ext.vt : NULL;
while (vt) {
diff --git a/src/nvim/popupmenu.c b/src/nvim/popupmenu.c
index 86f3611ec5..324254a188 100644
--- a/src/nvim/popupmenu.c
+++ b/src/nvim/popupmenu.c
@@ -19,6 +19,7 @@
#include "nvim/charset.h"
#include "nvim/drawscreen.h"
#include "nvim/edit.h"
+#include "nvim/errors.h"
#include "nvim/eval/typval.h"
#include "nvim/ex_cmds.h"
#include "nvim/ex_cmds_defs.h"
@@ -699,7 +700,7 @@ static void pum_preview_set_text(buf_T *buf, char *info, linenr_T *lnum, int *ma
}
// delete the empty last line
ml_delete_buf(buf, buf->b_ml.ml_line_count, false);
- if (strstr(p_cot, "popup") != NULL) {
+ if (get_cot_flags() & COT_POPUP) {
extmark_splice(buf, 1, 0, 1, 0, 0, buf->b_ml.ml_line_count, 0, inserted_bytes, kExtmarkNoUndo);
}
}
@@ -794,7 +795,8 @@ static bool pum_set_selected(int n, int repeat)
int prev_selected = pum_selected;
pum_selected = n;
- bool use_float = strstr(p_cot, "popup") != NULL;
+ unsigned cur_cot_flags = get_cot_flags();
+ bool use_float = (cur_cot_flags & COT_POPUP) != 0;
// when new leader add and info window is shown and no selected we still
// need use the first index item to update the info float window position.
bool force_select = use_float && pum_selected < 0 && win_float_find_preview();
@@ -860,7 +862,7 @@ static bool pum_set_selected(int n, int repeat)
if ((pum_array[pum_selected].pum_info != NULL)
&& (Rows > 10)
&& (repeat <= 1)
- && (vim_strchr(p_cot, 'p') != NULL)) {
+ && (cur_cot_flags & COT_ANY_PREVIEW)) {
win_T *curwin_save = curwin;
tabpage_T *curtab_save = curtab;
diff --git a/src/nvim/popupmenu.h b/src/nvim/popupmenu.h
index 20a342b841..9e3f8f5a7f 100644
--- a/src/nvim/popupmenu.h
+++ b/src/nvim/popupmenu.h
@@ -10,10 +10,11 @@
/// Used for popup menu items.
typedef struct {
- char *pum_text; // main menu text
- char *pum_kind; // extra kind text (may be truncated)
- char *pum_extra; // extra menu text (may be truncated)
- char *pum_info; // extra info
+ char *pum_text; ///< main menu text
+ char *pum_kind; ///< extra kind text (may be truncated)
+ char *pum_extra; ///< extra menu text (may be truncated)
+ char *pum_info; ///< extra info
+ int pum_score; ///< fuzzy match score
} pumitem_T;
EXTERN ScreenGrid pum_grid INIT( = SCREEN_GRID_INIT);
diff --git a/src/nvim/profile.c b/src/nvim/profile.c
index b88b08d3f0..f5e8e013ac 100644
--- a/src/nvim/profile.c
+++ b/src/nvim/profile.c
@@ -10,6 +10,7 @@
#include "nvim/charset.h"
#include "nvim/cmdexpand_defs.h"
#include "nvim/debugger.h"
+#include "nvim/errors.h"
#include "nvim/eval.h"
#include "nvim/eval/typval_defs.h"
#include "nvim/eval/userfunc.h"
@@ -293,7 +294,7 @@ void ex_profile(exarg_T *eap)
int len = (int)(e - eap->arg);
e = skipwhite(e);
- if (len == 5 && strncmp(eap->arg, "start", 5) == 0 && *e != NUL) {
+ if (len == 5 && strncmp(eap->arg, S_LEN("start")) == 0 && *e != NUL) {
xfree(profile_fname);
profile_fname = expand_env_save_opt(e, true);
do_profiling = PROF_YES;
@@ -368,12 +369,12 @@ void set_context_in_profile_cmd(expand_T *xp, const char *arg)
return;
}
- if ((end_subcmd - arg == 5 && strncmp(arg, "start", 5) == 0)
- || (end_subcmd - arg == 4 && strncmp(arg, "file", 4) == 0)) {
+ if ((end_subcmd - arg == 5 && strncmp(arg, S_LEN("start")) == 0)
+ || (end_subcmd - arg == 4 && strncmp(arg, S_LEN("file")) == 0)) {
xp->xp_context = EXPAND_FILES;
xp->xp_pattern = skipwhite(end_subcmd);
return;
- } else if (end_subcmd - arg == 4 && strncmp(arg, "func", 4) == 0) {
+ } else if (end_subcmd - arg == 4 && strncmp(arg, S_LEN("func")) == 0) {
xp->xp_context = EXPAND_USER_FUNC;
xp->xp_pattern = skipwhite(end_subcmd);
return;
diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c
index e022184f2f..ed3fd83fd5 100644
--- a/src/nvim/quickfix.c
+++ b/src/nvim/quickfix.c
@@ -20,6 +20,7 @@
#include "nvim/cursor.h"
#include "nvim/drawscreen.h"
#include "nvim/edit.h"
+#include "nvim/errors.h"
#include "nvim/eval.h"
#include "nvim/eval/typval.h"
#include "nvim/eval/window.h"
@@ -723,7 +724,7 @@ static int qf_get_next_str_line(qfstate_T *state)
state->linelen = len;
}
memcpy(state->linebuf, p_str, state->linelen);
- state->linebuf[state->linelen] = '\0';
+ state->linebuf[state->linelen] = NUL;
// Increment using len in order to discard the rest of the line if it
// exceeds LINE_MAXLEN.
@@ -4530,7 +4531,7 @@ static char *get_mef_name(void)
name = xmalloc(strlen(p_mef) + 30);
STRCPY(name, p_mef);
snprintf(name + (p - p_mef), strlen(name), "%d%d", start, off);
- STRCAT(name, p + 2);
+ strcat(name, p + 2);
// Don't accept a symbolic link, it's a security risk.
FileInfo file_info;
bool file_or_link_found = os_fileinfo_link(name, &file_info);
@@ -7236,7 +7237,7 @@ static void hgr_search_files_in_dir(qf_list_T *qfl, char *dirname, regmatch_T *p
// Find all "*.txt" and "*.??x" files in the "doc" directory.
add_pathsep(dirname);
- STRCAT(dirname, "doc/*.\\(txt\\|??x\\)"); // NOLINT
+ strcat(dirname, "doc/*.\\(txt\\|??x\\)"); // NOLINT
if (gen_expand_wildcards(1, &dirname, &fcount, &fnames, EW_FILE|EW_SILENT) == OK
&& fcount > 0) {
for (int fi = 0; fi < fcount && !got_int; fi++) {
diff --git a/src/nvim/rbuffer.c b/src/nvim/rbuffer.c
deleted file mode 100644
index cf2e10f90d..0000000000
--- a/src/nvim/rbuffer.c
+++ /dev/null
@@ -1,247 +0,0 @@
-#include <assert.h>
-#include <stdbool.h>
-#include <stddef.h>
-#include <string.h>
-
-#include "nvim/macros_defs.h"
-#include "nvim/memory.h"
-#include "nvim/rbuffer.h"
-
-#ifdef INCLUDE_GENERATED_DECLARATIONS
-# include "rbuffer.c.generated.h"
-#endif
-
-/// Creates a new `RBuffer` instance.
-RBuffer *rbuffer_new(size_t capacity)
- FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_RET
-{
- if (!capacity) {
- capacity = 0x10000;
- }
-
- RBuffer *rv = xcalloc(1, sizeof(RBuffer) + capacity);
- rv->full_cb = rv->nonfull_cb = NULL;
- rv->data = NULL;
- rv->size = 0;
- rv->write_ptr = rv->read_ptr = rv->start_ptr;
- rv->end_ptr = rv->start_ptr + capacity;
- rv->temp = NULL;
- return rv;
-}
-
-/// Creates a new `RBuffer` instance for reading from a buffer.
-///
-/// Must not be used with any write function like rbuffer_write_ptr or rbuffer_produced!
-RBuffer *rbuffer_new_wrap_buf(char *data, size_t len)
- FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_RET
-{
- RBuffer *rv = xcalloc(1, sizeof(RBuffer));
- rv->full_cb = rv->nonfull_cb = NULL;
- rv->data = NULL;
- rv->size = len;
- rv->read_ptr = data;
- rv->write_ptr = data + len;
- rv->end_ptr = NULL;
- rv->temp = NULL;
- return rv;
-}
-
-void rbuffer_free(RBuffer *buf) FUNC_ATTR_NONNULL_ALL
-{
- xfree(buf->temp);
- xfree(buf);
-}
-
-/// Return a pointer to a raw buffer containing the first empty slot available
-/// for writing. The second argument is a pointer to the maximum number of
-/// bytes that could be written.
-///
-/// It is necessary to call this function twice to ensure all empty space was
-/// used. See RBUFFER_UNTIL_FULL for a macro that simplifies this task.
-char *rbuffer_write_ptr(RBuffer *buf, size_t *write_count) FUNC_ATTR_NONNULL_ALL
-{
- if (buf->size == rbuffer_capacity(buf)) {
- *write_count = 0;
- return NULL;
- }
-
- if (buf->write_ptr >= buf->read_ptr) {
- *write_count = (size_t)(buf->end_ptr - buf->write_ptr);
- } else {
- *write_count = (size_t)(buf->read_ptr - buf->write_ptr);
- }
-
- return buf->write_ptr;
-}
-
-// Reset an RBuffer so read_ptr is at the beginning of the memory. If
-// necessary, this moves existing data by allocating temporary memory.
-void rbuffer_reset(RBuffer *buf) FUNC_ATTR_NONNULL_ALL
-{
- size_t temp_size;
- if ((temp_size = rbuffer_size(buf))) {
- if (buf->temp == NULL) {
- buf->temp = xcalloc(1, rbuffer_capacity(buf));
- }
- rbuffer_read(buf, buf->temp, buf->size);
- }
- buf->read_ptr = buf->write_ptr = buf->start_ptr;
- if (temp_size) {
- rbuffer_write(buf, buf->temp, temp_size);
- }
-}
-
-/// Adjust `rbuffer` write pointer to reflect produced data. This is called
-/// automatically by `rbuffer_write`, but when using `rbuffer_write_ptr`
-/// directly, this needs to called after the data was copied to the internal
-/// buffer. The write pointer will be wrapped if required.
-void rbuffer_produced(RBuffer *buf, size_t count) FUNC_ATTR_NONNULL_ALL
-{
- assert(count && count <= rbuffer_space(buf));
-
- buf->write_ptr += count;
- if (buf->write_ptr >= buf->end_ptr) {
- // wrap around
- buf->write_ptr -= rbuffer_capacity(buf);
- }
-
- buf->size += count;
- if (buf->full_cb && !rbuffer_space(buf)) {
- buf->full_cb(buf, buf->data);
- }
-}
-
-/// Return a pointer to a raw buffer containing the first byte available
-/// for reading. The second argument is a pointer to the maximum number of
-/// bytes that could be read.
-///
-/// It is necessary to call this function twice to ensure all available bytes
-/// were read. See RBUFFER_UNTIL_EMPTY for a macro that simplifies this task.
-char *rbuffer_read_ptr(RBuffer *buf, size_t *read_count) FUNC_ATTR_NONNULL_ALL
-{
- if (!buf->size) {
- *read_count = 0;
- return buf->read_ptr;
- }
-
- if (buf->read_ptr < buf->write_ptr) {
- *read_count = (size_t)(buf->write_ptr - buf->read_ptr);
- } else {
- *read_count = (size_t)(buf->end_ptr - buf->read_ptr);
- }
-
- return buf->read_ptr;
-}
-
-/// Adjust `rbuffer` read pointer to reflect consumed data. This is called
-/// automatically by `rbuffer_read`, but when using `rbuffer_read_ptr`
-/// directly, this needs to called after the data was copied from the internal
-/// buffer. The read pointer will be wrapped if required.
-void rbuffer_consumed(RBuffer *buf, size_t count)
- FUNC_ATTR_NONNULL_ALL
-{
- if (count == 0) {
- return;
- }
- assert(count <= buf->size);
-
- buf->read_ptr += count;
- if (buf->end_ptr && buf->read_ptr >= buf->end_ptr) {
- buf->read_ptr -= rbuffer_capacity(buf);
- }
-
- bool was_full = buf->size == rbuffer_capacity(buf);
- buf->size -= count;
- if (buf->nonfull_cb && was_full) {
- buf->nonfull_cb(buf, buf->data);
- }
-}
-
-/// Use instead of rbuffer_consumed to use rbuffer in a linear, non-cyclic fashion.
-///
-/// This is generally useful if we can guarantee to parse all input
-/// except some small incomplete token, like when parsing msgpack.
-void rbuffer_consumed_compact(RBuffer *buf, size_t count)
- FUNC_ATTR_NONNULL_ALL
-{
- assert(buf->read_ptr <= buf->write_ptr);
- rbuffer_consumed(buf, count);
- if (buf->read_ptr > buf->start_ptr) {
- assert((size_t)(buf->write_ptr - buf->read_ptr) == buf->size
- || buf->write_ptr == buf->start_ptr);
- memmove(buf->start_ptr, buf->read_ptr, buf->size);
- buf->read_ptr = buf->start_ptr;
- buf->write_ptr = buf->read_ptr + buf->size;
- }
-}
-
-// Higher level functions for copying from/to RBuffer instances and data
-// pointers
-size_t rbuffer_write(RBuffer *buf, const char *src, size_t src_size)
- FUNC_ATTR_NONNULL_ALL
-{
- size_t size = src_size;
-
- RBUFFER_UNTIL_FULL(buf, wptr, wcnt) {
- size_t copy_count = MIN(src_size, wcnt);
- memcpy(wptr, src, copy_count);
- rbuffer_produced(buf, copy_count);
-
- if (!(src_size -= copy_count)) {
- return size;
- }
-
- src += copy_count;
- }
-
- return size - src_size;
-}
-
-size_t rbuffer_read(RBuffer *buf, char *dst, size_t dst_size)
- FUNC_ATTR_NONNULL_ALL
-{
- size_t size = dst_size;
-
- RBUFFER_UNTIL_EMPTY(buf, rptr, rcnt) {
- size_t copy_count = MIN(dst_size, rcnt);
- memcpy(dst, rptr, copy_count);
- rbuffer_consumed(buf, copy_count);
-
- if (!(dst_size -= copy_count)) {
- return size;
- }
-
- dst += copy_count;
- }
-
- return size - dst_size;
-}
-
-char *rbuffer_get(RBuffer *buf, size_t index)
- FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_RET
-{
- assert(index < buf->size);
- char *rptr = buf->read_ptr + index;
- if (rptr >= buf->end_ptr) {
- rptr -= rbuffer_capacity(buf);
- }
- return rptr;
-}
-
-int rbuffer_cmp(RBuffer *buf, const char *str, size_t count)
- FUNC_ATTR_NONNULL_ALL
-{
- assert(count <= buf->size);
- size_t rcnt;
- rbuffer_read_ptr(buf, &rcnt);
- size_t n = MIN(count, rcnt);
- int rv = memcmp(str, buf->read_ptr, n);
- count -= n;
- size_t remaining = buf->size - rcnt;
-
- if (rv || !count || !remaining) {
- return rv;
- }
-
- return memcmp(str + n, buf->start_ptr, count);
-}
diff --git a/src/nvim/rbuffer.h b/src/nvim/rbuffer.h
deleted file mode 100644
index 942e1f2365..0000000000
--- a/src/nvim/rbuffer.h
+++ /dev/null
@@ -1,71 +0,0 @@
-// Specialized ring buffer. This is basically an array that wraps read/write
-// pointers around the memory region. It should be more efficient than the old
-// RBuffer which required memmove() calls to relocate read/write positions.
-//
-// The main purpose of RBuffer is simplify memory management when reading from
-// uv_stream_t instances:
-//
-// - The event loop writes data to a RBuffer, advancing the write pointer
-// - The main loop reads data, advancing the read pointer
-// - If the buffer becomes full(size == capacity) the rstream is temporarily
-// stopped(automatic backpressure handling)
-//
-// Reference: http://en.wikipedia.org/wiki/Circular_buffer
-#pragma once
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include "nvim/rbuffer_defs.h" // IWYU pragma: keep
-
-// Macros that simplify working with the read/write pointers directly by hiding
-// ring buffer wrap logic. Some examples:
-//
-// - Pass the write pointer to a function(write_data) that incrementally
-// produces data, returning the number of bytes actually written to the
-// ring buffer:
-//
-// RBUFFER_UNTIL_FULL(rbuf, ptr, cnt)
-// rbuffer_produced(rbuf, write_data(state, ptr, cnt));
-//
-// - Pass the read pointer to a function(read_data) that incrementally
-// consumes data, returning the number of bytes actually read from the
-// ring buffer:
-//
-// RBUFFER_UNTIL_EMPTY(rbuf, ptr, cnt)
-// rbuffer_consumed(rbuf, read_data(state, ptr, cnt));
-//
-// Note that the rbuffer_{produced,consumed} calls are necessary or these macros
-// create infinite loops
-#define RBUFFER_UNTIL_EMPTY(buf, rptr, rcnt) \
- for (size_t rcnt = 0, _r = 1; _r; _r = 0) \
- for (char *rptr = rbuffer_read_ptr(buf, &rcnt); \
- buf->size; \
- rptr = rbuffer_read_ptr(buf, &rcnt))
-
-#define RBUFFER_UNTIL_FULL(buf, wptr, wcnt) \
- for (size_t wcnt = 0, _r = 1; _r; _r = 0) \
- for (char *wptr = rbuffer_write_ptr(buf, &wcnt); \
- rbuffer_space(buf); \
- wptr = rbuffer_write_ptr(buf, &wcnt))
-
-// Iteration
-#define RBUFFER_EACH(buf, c, i) \
- for (size_t i = 0; \
- i < buf->size; \
- i = buf->size) \
- for (char c = 0; \
- i < buf->size ? ((int)(c = *rbuffer_get(buf, i))) || 1 : 0; \
- i++)
-
-#define RBUFFER_EACH_REVERSE(buf, c, i) \
- for (size_t i = buf->size; \
- i != SIZE_MAX; \
- i = SIZE_MAX) \
- for (char c = 0; \
- i-- > 0 ? ((int)(c = *rbuffer_get(buf, i))) || 1 : 0; \
- )
-
-#ifdef INCLUDE_GENERATED_DECLARATIONS
-# include "rbuffer.h.generated.h"
-#endif
diff --git a/src/nvim/rbuffer_defs.h b/src/nvim/rbuffer_defs.h
deleted file mode 100644
index 51dc349846..0000000000
--- a/src/nvim/rbuffer_defs.h
+++ /dev/null
@@ -1,45 +0,0 @@
-#pragma once
-
-#include <stddef.h>
-
-#include "nvim/func_attr.h"
-
-typedef struct rbuffer RBuffer;
-/// Type of function invoked during certain events:
-/// - When the RBuffer switches to the full state
-/// - When the RBuffer switches to the non-full state
-typedef void (*rbuffer_callback)(RBuffer *buf, void *data);
-
-struct rbuffer {
- rbuffer_callback full_cb, nonfull_cb;
- void *data;
- size_t size;
- // helper memory used to by rbuffer_reset if required
- char *temp;
- char *end_ptr, *read_ptr, *write_ptr;
- char start_ptr[];
-};
-
-static inline size_t rbuffer_size(RBuffer *buf)
- REAL_FATTR_ALWAYS_INLINE REAL_FATTR_NONNULL_ALL;
-
-static inline size_t rbuffer_size(RBuffer *buf)
-{
- return buf->size;
-}
-
-static inline size_t rbuffer_capacity(RBuffer *buf)
- REAL_FATTR_ALWAYS_INLINE REAL_FATTR_NONNULL_ALL;
-
-static inline size_t rbuffer_capacity(RBuffer *buf)
-{
- return (size_t)(buf->end_ptr - buf->start_ptr);
-}
-
-static inline size_t rbuffer_space(RBuffer *buf)
- REAL_FATTR_ALWAYS_INLINE REAL_FATTR_NONNULL_ALL;
-
-static inline size_t rbuffer_space(RBuffer *buf)
-{
- return rbuffer_capacity(buf) - buf->size;
-}
diff --git a/src/nvim/regexp.c b/src/nvim/regexp.c
index 5600d6a2f8..e00dbdfc78 100644
--- a/src/nvim/regexp.c
+++ b/src/nvim/regexp.c
@@ -18,6 +18,7 @@
#include "nvim/ascii_defs.h"
#include "nvim/buffer_defs.h"
#include "nvim/charset.h"
+#include "nvim/errors.h"
#include "nvim/eval.h"
#include "nvim/eval/typval.h"
#include "nvim/eval/userfunc.h"
@@ -11450,7 +11451,7 @@ static void nfa_set_code(int c)
}
if (addnl == true) {
- STRCAT(code, " + NEWLINE ");
+ strcat(code, " + NEWLINE ");
}
}
@@ -11494,7 +11495,7 @@ static void nfa_print_state(FILE *debugf, nfa_state_T *state)
garray_T indent;
ga_init(&indent, 1, 64);
- ga_append(&indent, '\0');
+ ga_append(&indent, NUL);
nfa_print_state2(debugf, state, &indent);
ga_clear(&indent);
}
@@ -11516,7 +11517,7 @@ static void nfa_print_state2(FILE *debugf, nfa_state_T *state, garray_T *indent)
uint8_t save[2];
strncpy(save, &p[last], 2); // NOLINT(runtime/printf)
- memcpy(&p[last], "+-", 2);
+ memcpy(&p[last], S_LEN("+-"));
fprintf(debugf, " %s", p);
strncpy(&p[last], save, 2); // NOLINT(runtime/printf)
} else {
@@ -14800,7 +14801,7 @@ static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start, regsubs_T *subm
}
case NFA_ANY:
- // Any char except '\0', (end of input) does not match.
+ // Any char except NUL, (end of input) does not match.
if (curc > 0) {
add_state = t->state->out;
add_off = clen;
@@ -15931,7 +15932,7 @@ regprog_T *vim_regcomp(const char *expr_arg, int re_flags)
regexp_engine = (int)p_re;
// Check for prefix "\%#=", that sets the regexp engine
- if (strncmp(expr, "\\%#=", 4) == 0) {
+ if (strncmp(expr, S_LEN("\\%#=")) == 0) {
int newengine = expr[4] - '0';
if (newengine == AUTOMATIC_ENGINE
diff --git a/src/nvim/runtime.c b/src/nvim/runtime.c
index d913d311db..6728262432 100644
--- a/src/nvim/runtime.c
+++ b/src/nvim/runtime.c
@@ -22,6 +22,7 @@
#include "nvim/charset.h"
#include "nvim/cmdexpand.h"
#include "nvim/debugger.h"
+#include "nvim/errors.h"
#include "nvim/eval.h"
#include "nvim/eval/typval.h"
#include "nvim/eval/userfunc.h"
@@ -408,7 +409,7 @@ int do_in_path(const char *path, const char *prefix, char *name, int flags,
did_one = true;
} else if (buflen + 2 + strlen(prefix) + strlen(name) < MAXPATHL) {
add_pathsep(buf);
- STRCAT(buf, prefix);
+ strcat(buf, prefix);
tail = buf + strlen(buf);
// Loop over all patterns in "name"
@@ -1320,16 +1321,16 @@ expand:
}
if (flags & DIP_START) {
- memcpy(tail - 15, "pack/*/start/*/", 15); // NOLINT
+ memcpy(tail - 15, S_LEN("pack/*/start/*/")); // NOLINT
globpath(p_pp, tail - 15, gap, glob_flags, expand_dirs);
- memcpy(tail - 8, "start/*/", 8); // NOLINT
+ memcpy(tail - 8, S_LEN("start/*/")); // NOLINT
globpath(p_pp, tail - 8, gap, glob_flags, expand_dirs);
}
if (flags & DIP_OPT) {
- memcpy(tail - 13, "pack/*/opt/*/", 13); // NOLINT
+ memcpy(tail - 13, S_LEN("pack/*/opt/*/")); // NOLINT
globpath(p_pp, tail - 13, gap, glob_flags, expand_dirs);
- memcpy(tail - 6, "opt/*/", 6); // NOLINT
+ memcpy(tail - 6, S_LEN("opt/*/")); // NOLINT
globpath(p_pp, tail - 6, gap, glob_flags, expand_dirs);
}
@@ -1876,7 +1877,7 @@ static bool concat_continued_line(garray_T *const ga, const int init_growsize, c
const char *const line = skipwhite_len(p, len);
len -= (size_t)(line - p);
// Skip lines starting with '\" ', concat lines starting with '\'
- if (len >= 3 && strncmp(line, "\"\\ ", 3) == 0) {
+ if (len >= 3 && strncmp(line, S_LEN("\"\\ ")) == 0) {
return true;
} else if (len == 0 || line[0] != '\\') {
return false;
diff --git a/src/nvim/search.c b/src/nvim/search.c
index 746c253708..5318970d44 100644
--- a/src/nvim/search.c
+++ b/src/nvim/search.c
@@ -18,6 +18,7 @@
#include "nvim/cmdhist.h"
#include "nvim/cursor.h"
#include "nvim/drawscreen.h"
+#include "nvim/errors.h"
#include "nvim/eval.h"
#include "nvim/eval/typval.h"
#include "nvim/ex_cmds.h"
@@ -542,7 +543,7 @@ void last_pat_prog(regmmatch_T *regmatch)
return;
}
emsg_off++; // So it doesn't beep if bad expr
- search_regcomp("", 0, NULL, 0, last_idx, SEARCH_KEEP, regmatch);
+ search_regcomp(S_LEN(""), NULL, 0, last_idx, SEARCH_KEEP, regmatch);
emsg_off--;
}
@@ -1820,9 +1821,9 @@ pos_T *findmatchlimit(oparg_T *oap, int initc, int flags, int64_t maxtravel)
ptr = skipwhite(linep);
if (*ptr == '#' && pos.col <= (colnr_T)(ptr - linep)) {
ptr = skipwhite(ptr + 1);
- if (strncmp(ptr, "if", 2) == 0
- || strncmp(ptr, "endif", 5) == 0
- || strncmp(ptr, "el", 2) == 0) {
+ if (strncmp(ptr, S_LEN("if")) == 0
+ || strncmp(ptr, S_LEN("endif")) == 0
+ || strncmp(ptr, S_LEN("el")) == 0) {
hash_dir = 1;
}
} else if (linep[pos.col] == '/') { // Are we on a comment?
@@ -1893,9 +1894,9 @@ pos_T *findmatchlimit(oparg_T *oap, int initc, int flags, int64_t maxtravel)
}
if (initc != '#') {
ptr = skipwhite(skipwhite(linep) + 1);
- if (strncmp(ptr, "if", 2) == 0 || strncmp(ptr, "el", 2) == 0) {
+ if (strncmp(ptr, S_LEN("if")) == 0 || strncmp(ptr, S_LEN("el")) == 0) {
hash_dir = 1;
- } else if (strncmp(ptr, "endif", 5) == 0) {
+ } else if (strncmp(ptr, S_LEN("endif")) == 0) {
hash_dir = -1;
} else {
return NULL;
@@ -1920,29 +1921,29 @@ pos_T *findmatchlimit(oparg_T *oap, int initc, int flags, int64_t maxtravel)
pos.col = (colnr_T)(ptr - linep);
ptr = skipwhite(ptr + 1);
if (hash_dir > 0) {
- if (strncmp(ptr, "if", 2) == 0) {
+ if (strncmp(ptr, S_LEN("if")) == 0) {
count++;
- } else if (strncmp(ptr, "el", 2) == 0) {
+ } else if (strncmp(ptr, S_LEN("el")) == 0) {
if (count == 0) {
return &pos;
}
- } else if (strncmp(ptr, "endif", 5) == 0) {
+ } else if (strncmp(ptr, S_LEN("endif")) == 0) {
if (count == 0) {
return &pos;
}
count--;
}
} else {
- if (strncmp(ptr, "if", 2) == 0) {
+ if (strncmp(ptr, S_LEN("if")) == 0) {
if (count == 0) {
return &pos;
}
count--;
- } else if (initc == '#' && strncmp(ptr, "el", 2) == 0) {
+ } else if (initc == '#' && strncmp(ptr, S_LEN("el")) == 0) {
if (count == 0) {
return &pos;
}
- } else if (strncmp(ptr, "endif", 5) == 0) {
+ } else if (strncmp(ptr, S_LEN("endif")) == 0) {
count++;
}
}
@@ -3890,7 +3891,7 @@ search_line:
// is not considered to be a comment line.
if (skip_comments) {
if ((*line != '#'
- || strncmp(skipwhite(line + 1), "define", 6) != 0)
+ || strncmp(skipwhite(line + 1), S_LEN("define")) != 0)
&& get_leader_len(line, NULL, false, true)) {
matched = false;
}
diff --git a/src/nvim/sha256.c b/src/nvim/sha256.c
index d49224a987..5e0aac3f69 100644
--- a/src/nvim/sha256.c
+++ b/src/nvim/sha256.c
@@ -15,6 +15,7 @@
#include <stdio.h>
#include <string.h>
+#include "nvim/ascii_defs.h"
#include "nvim/memory.h"
#include "nvim/sha256.h"
@@ -279,7 +280,7 @@ const char *sha256_bytes(const uint8_t *restrict buf, size_t buf_len, const uin
for (size_t j = 0; j < SHA256_SUM_SIZE; j++) {
snprintf(hexit + j * SHA_STEP, SHA_STEP + 1, "%02x", sha256sum[j]);
}
- hexit[sizeof(hexit) - 1] = '\0';
+ hexit[sizeof(hexit) - 1] = NUL;
return hexit;
}
@@ -340,7 +341,7 @@ bool sha256_self_test(void)
if (memcmp(output, sha_self_test_vector[i], SHA256_BUFFER_SIZE) != 0) {
failures = true;
- output[sizeof(output) - 1] = '\0';
+ output[sizeof(output) - 1] = NUL;
// printf("sha256_self_test %d failed %s\n", i, output);
}
diff --git a/src/nvim/shada.c b/src/nvim/shada.c
index 597c7551fd..d5655b1754 100644
--- a/src/nvim/shada.c
+++ b/src/nvim/shada.c
@@ -19,6 +19,7 @@
#include "nvim/buffer.h"
#include "nvim/buffer_defs.h"
#include "nvim/cmdhist.h"
+#include "nvim/errors.h"
#include "nvim/eval.h"
#include "nvim/eval/decode.h"
#include "nvim/eval/encode.h"
diff --git a/src/nvim/sign.c b/src/nvim/sign.c
index 4e6672c5dd..f1ded4d594 100644
--- a/src/nvim/sign.c
+++ b/src/nvim/sign.c
@@ -21,6 +21,7 @@
#include "nvim/decoration_defs.h"
#include "nvim/drawscreen.h"
#include "nvim/edit.h"
+#include "nvim/errors.h"
#include "nvim/eval/funcs.h"
#include "nvim/eval/typval.h"
#include "nvim/eval/typval_defs.h"
@@ -125,8 +126,8 @@ static void buf_set_sign(buf_T *buf, uint32_t *id, char *group, int prio, linenr
| (has_hl ? MT_FLAG_DECOR_SIGNHL : 0);
DecorInline decor = { .ext = true, .data.ext = { .vt = NULL, .sh_idx = decor_put_sh(sign) } };
- extmark_set(buf, ns, id, lnum - 1, 0, -1, -1, decor, decor_flags, true,
- false, true, true, false, NULL);
+ extmark_set(buf, ns, id, MIN(buf->b_ml.ml_line_count, lnum) - 1, 0, -1, -1,
+ decor, decor_flags, true, false, true, true, NULL);
}
/// For an existing, placed sign with "id", modify the sign, group or priority.
@@ -246,12 +247,6 @@ static int buf_delete_signs(buf_T *buf, char *group, int id, linenr_T atlnum)
return FAIL;
}
- // When deleting the last sign need to redraw the windows to remove the
- // sign column. Not when curwin is NULL (this means we're exiting).
- if (!buf_meta_total(buf, kMTMetaSignText) && curwin != NULL) {
- changed_line_abv_curs();
- }
-
return OK;
}
@@ -297,8 +292,8 @@ static void sign_list_placed(buf_T *rbuf, char *group)
qsort((void *)&kv_A(signs, 0), kv_size(signs), sizeof(MTKey), sign_row_cmp);
for (size_t i = 0; i < kv_size(signs); i++) {
- namebuf[0] = '\0';
- groupbuf[0] = '\0';
+ namebuf[0] = NUL;
+ groupbuf[0] = NUL;
MTKey mark = kv_A(signs, i);
DecorSignHighlight *sh = decor_find_sign(mt_decor(mark));
@@ -499,22 +494,11 @@ static void sign_list_by_name(char *name)
}
}
-static void may_force_numberwidth_recompute(buf_T *buf, int unplace)
-{
- FOR_ALL_TAB_WINDOWS(tp, wp)
- if (wp->w_buffer == buf
- && (wp->w_p_nu || wp->w_p_rnu)
- && (unplace || wp->w_nrwidth_width < 2)
- && (*wp->w_p_scl == 'n' && *(wp->w_p_scl + 1) == 'u')) {
- wp->w_nrwidth_line_count = 0;
- }
-}
-
/// Place a sign at the specified file location or update a sign.
static int sign_place(uint32_t *id, char *group, char *name, buf_T *buf, linenr_T lnum, int prio)
{
// Check for reserved character '*' in group name
- if (group != NULL && (*group == '*' || *group == '\0')) {
+ if (group != NULL && (*group == '*' || *group == NUL)) {
return FAIL;
}
@@ -531,11 +515,7 @@ static int sign_place(uint32_t *id, char *group, char *name, buf_T *buf, linenr_
// ":sign place {id} file={fname}": change sign type and/or priority
lnum = buf_mod_sign(buf, id, group, prio, sp);
}
- if (lnum > 0) {
- // When displaying signs in the 'number' column, if the width of the
- // number column is less than 2, then force recomputing the width.
- may_force_numberwidth_recompute(buf, false);
- } else {
+ if (lnum <= 0) {
semsg(_("E885: Not possible to change sign %s"), name);
return FAIL;
}
@@ -562,13 +542,6 @@ static int sign_unplace_inner(buf_T *buf, int id, char *group, linenr_T atlnum)
}
}
- // When all the signs in a buffer are removed, force recomputing the
- // number column width (if enabled) in all the windows displaying the
- // buffer if 'signcolumn' is set to 'number' in that window.
- if (!buf_meta_total(buf, kMTMetaSignText)) {
- may_force_numberwidth_recompute(buf, true);
- }
-
return OK;
}
@@ -637,17 +610,17 @@ static void sign_define_cmd(char *name, char *cmdline)
break;
}
cmdline = skiptowhite_esc(arg);
- if (strncmp(arg, "icon=", 5) == 0) {
+ if (strncmp(arg, S_LEN("icon=")) == 0) {
icon = arg + 5;
- } else if (strncmp(arg, "text=", 5) == 0) {
+ } else if (strncmp(arg, S_LEN("text=")) == 0) {
text = arg + 5;
- } else if (strncmp(arg, "linehl=", 7) == 0) {
+ } else if (strncmp(arg, S_LEN("linehl=")) == 0) {
linehl = arg + 7;
- } else if (strncmp(arg, "texthl=", 7) == 0) {
+ } else if (strncmp(arg, S_LEN("texthl=")) == 0) {
texthl = arg + 7;
- } else if (strncmp(arg, "culhl=", 6) == 0) {
+ } else if (strncmp(arg, S_LEN("culhl=")) == 0) {
culhl = arg + 6;
- } else if (strncmp(arg, "numhl=", 6) == 0) {
+ } else if (strncmp(arg, S_LEN("numhl=")) == 0) {
numhl = arg + 6;
} else {
semsg(_(e_invarg2), arg);
@@ -676,14 +649,14 @@ static void sign_place_cmd(buf_T *buf, linenr_T lnum, char *name, int id, char *
// :sign place
// :sign place group={group}
// :sign place group=*
- if (lnum >= 0 || name != NULL || (group != NULL && *group == '\0')) {
+ if (lnum >= 0 || name != NULL || (group != NULL && *group == NUL)) {
emsg(_(e_invarg));
} else {
sign_list_placed(buf, group);
}
} else {
// Place a new sign
- if (name == NULL || buf == NULL || (group != NULL && *group == '\0')) {
+ if (name == NULL || buf == NULL || (group != NULL && *group == NUL)) {
emsg(_(e_invarg));
return;
}
@@ -695,7 +668,7 @@ static void sign_place_cmd(buf_T *buf, linenr_T lnum, char *name, int id, char *
/// ":sign unplace" command
static void sign_unplace_cmd(buf_T *buf, linenr_T lnum, const char *name, int id, char *group)
{
- if (lnum >= 0 || name != NULL || (group != NULL && *group == '\0')) {
+ if (lnum >= 0 || name != NULL || (group != NULL && *group == NUL)) {
emsg(_(e_invarg));
return;
}
@@ -722,7 +695,7 @@ static void sign_jump_cmd(buf_T *buf, linenr_T lnum, const char *name, int id, c
return;
}
- if (buf == NULL || (group != NULL && *group == '\0') || lnum >= 0 || name != NULL) {
+ if (buf == NULL || (group != NULL && *group == NUL) || lnum >= 0 || name != NULL) {
// File or buffer is not specified or an empty group is used
// or a line number or a sign name is specified.
emsg(_(e_invarg));
@@ -755,19 +728,19 @@ static int parse_sign_cmd_args(int cmd, char *arg, char **name, int *id, char **
}
while (*arg != NUL) {
- if (strncmp(arg, "line=", 5) == 0) {
+ if (strncmp(arg, S_LEN("line=")) == 0) {
arg += 5;
*lnum = atoi(arg);
arg = skiptowhite(arg);
lnum_arg = true;
- } else if (strncmp(arg, "*", 1) == 0 && cmd == SIGNCMD_UNPLACE) {
+ } else if (strncmp(arg, S_LEN("*")) == 0 && cmd == SIGNCMD_UNPLACE) {
if (*id != -1) {
emsg(_(e_invarg));
return FAIL;
}
*id = -2;
arg = skiptowhite(arg + 1);
- } else if (strncmp(arg, "name=", 5) == 0) {
+ } else if (strncmp(arg, S_LEN("name=")) == 0) {
arg += 5;
char *namep = arg;
arg = skiptowhite(arg);
@@ -778,23 +751,23 @@ static int parse_sign_cmd_args(int cmd, char *arg, char **name, int *id, char **
namep++;
}
*name = namep;
- } else if (strncmp(arg, "group=", 6) == 0) {
+ } else if (strncmp(arg, S_LEN("group=")) == 0) {
arg += 6;
*group = arg;
arg = skiptowhite(arg);
if (*arg != NUL) {
*arg++ = NUL;
}
- } else if (strncmp(arg, "priority=", 9) == 0) {
+ } else if (strncmp(arg, S_LEN("priority=")) == 0) {
arg += 9;
*prio = atoi(arg);
arg = skiptowhite(arg);
- } else if (strncmp(arg, "file=", 5) == 0) {
+ } else if (strncmp(arg, S_LEN("file=")) == 0) {
arg += 5;
filename = arg;
*buf = buflist_findname_exp(arg);
break;
- } else if (strncmp(arg, "buffer=", 7) == 0) {
+ } else if (strncmp(arg, S_LEN("buffer=")) == 0) {
arg += 7;
filename = arg;
*buf = buflist_findnr(getdigits_int(&arg, true, 0));
@@ -1172,23 +1145,23 @@ void set_context_in_sign_cmd(expand_T *xp, char *arg)
xp->xp_pattern = p + 1;
switch (cmd_idx) {
case SIGNCMD_DEFINE:
- if (strncmp(last, "texthl", 6) == 0
- || strncmp(last, "linehl", 6) == 0
- || strncmp(last, "culhl", 5) == 0
- || strncmp(last, "numhl", 5) == 0) {
+ if (strncmp(last, S_LEN("texthl")) == 0
+ || strncmp(last, S_LEN("linehl")) == 0
+ || strncmp(last, S_LEN("culhl")) == 0
+ || strncmp(last, S_LEN("numhl")) == 0) {
xp->xp_context = EXPAND_HIGHLIGHT;
- } else if (strncmp(last, "icon", 4) == 0) {
+ } else if (strncmp(last, S_LEN("icon")) == 0) {
xp->xp_context = EXPAND_FILES;
} else {
xp->xp_context = EXPAND_NOTHING;
}
break;
case SIGNCMD_PLACE:
- if (strncmp(last, "name", 4) == 0) {
+ if (strncmp(last, S_LEN("name")) == 0) {
expand_what = EXP_SIGN_NAMES;
- } else if (strncmp(last, "group", 5) == 0) {
+ } else if (strncmp(last, S_LEN("group")) == 0) {
expand_what = EXP_SIGN_GROUPS;
- } else if (strncmp(last, "file", 4) == 0) {
+ } else if (strncmp(last, S_LEN("file")) == 0) {
xp->xp_context = EXPAND_BUFFERS;
} else {
xp->xp_context = EXPAND_NOTHING;
@@ -1196,9 +1169,9 @@ void set_context_in_sign_cmd(expand_T *xp, char *arg)
break;
case SIGNCMD_UNPLACE:
case SIGNCMD_JUMP:
- if (strncmp(last, "group", 5) == 0) {
+ if (strncmp(last, S_LEN("group")) == 0) {
expand_what = EXP_SIGN_GROUPS;
- } else if (strncmp(last, "file", 4) == 0) {
+ } else if (strncmp(last, S_LEN("file")) == 0) {
xp->xp_context = EXPAND_BUFFERS;
} else {
xp->xp_context = EXPAND_NOTHING;
@@ -1343,7 +1316,7 @@ void f_sign_getplaced(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
if (group == NULL) {
return;
}
- if (*group == '\0') { // empty string means global group
+ if (*group == NUL) { // empty string means global group
group = NULL;
}
}
diff --git a/src/nvim/spell.c b/src/nvim/spell.c
index d7a6adef58..8ec28c7f61 100644
--- a/src/nvim/spell.c
+++ b/src/nvim/spell.c
@@ -72,6 +72,7 @@
#include "nvim/decoration.h"
#include "nvim/decoration_provider.h"
#include "nvim/drawscreen.h"
+#include "nvim/errors.h"
#include "nvim/ex_cmds.h"
#include "nvim/ex_cmds_defs.h"
#include "nvim/ex_docmd.h"
@@ -230,14 +231,6 @@ char *repl_to = NULL;
/// caller can skip over the word.
size_t spell_check(win_T *wp, char *ptr, hlf_T *attrp, int *capcol, bool docount)
{
- matchinf_T mi; // Most things are put in "mi" so that it can
- // be passed to functions quickly.
- size_t nrlen = 0; // found a number first
- size_t wrongcaplen = 0;
- bool count_word = docount;
- bool use_camel_case = (wp->w_s->b_p_spo_flags & SPO_CAMEL) != 0;
- bool is_camel_case = false;
-
// A word never starts at a space or a control character. Return quickly
// then, skipping over the character.
if ((uint8_t)(*ptr) <= ' ') {
@@ -249,6 +242,13 @@ size_t spell_check(win_T *wp, char *ptr, hlf_T *attrp, int *capcol, bool docount
return 1;
}
+ size_t nrlen = 0; // found a number first
+ size_t wrongcaplen = 0;
+ bool count_word = docount;
+ bool use_camel_case = (wp->w_s->b_p_spo_flags & SPO_CAMEL) != 0;
+ bool is_camel_case = false;
+
+ matchinf_T mi; // Most things are put in "mi" so that it can be passed to functions quickly.
CLEAR_FIELD(mi);
// A number is always OK. Also skip hexadecimal numbers 0xFF99 and
@@ -540,7 +540,6 @@ static void find_word(matchinf_T *mip, int mode)
int endlen[MAXWLEN]; // length at possible word endings
idx_T endidx[MAXWLEN]; // possible word endings
int endidxcnt = 0;
- int c;
// Repeat advancing in the tree until:
// - there is a byte that doesn't match,
@@ -582,7 +581,7 @@ static void find_word(matchinf_T *mip, int mode)
}
// Perform a binary search in the list of accepted bytes.
- c = (uint8_t)ptr[wlen];
+ int c = (uint8_t)ptr[wlen];
if (c == TAB) { // <Tab> is handled like <Space>
c = ' ';
}
@@ -626,9 +625,6 @@ static void find_word(matchinf_T *mip, int mode)
}
}
- char *p;
- bool word_ends;
-
// Verify that one of the possible endings is valid. Try the longest
// first.
while (endidxcnt > 0) {
@@ -639,6 +635,7 @@ static void find_word(matchinf_T *mip, int mode)
if (utf_head_off(ptr, ptr + wlen) > 0) {
continue; // not at first byte of character
}
+ bool word_ends;
if (spell_iswordp(ptr + wlen, mip->mi_win)) {
if (slang->sl_compprog == NULL && !slang->sl_nobreak) {
continue; // next char is a word character
@@ -655,7 +652,7 @@ static void find_word(matchinf_T *mip, int mode)
// Compute byte length in original word, length may change
// when folding case. This can be slow, take a shortcut when the
// case-folded word is equal to the keep-case word.
- p = mip->mi_word;
+ char *p = mip->mi_word;
if (strncmp(ptr, p, (size_t)wlen) != 0) {
for (char *s = ptr; s < ptr + wlen; MB_PTR_ADV(s)) {
MB_PTR_ADV(p);
@@ -691,10 +688,10 @@ static void find_word(matchinf_T *mip, int mode)
// When mode is FIND_PREFIX the word must support the prefix:
// check the prefix ID and the condition. Do that for the list at
// mip->mi_prefarridx that find_prefix() filled.
- c = valid_word_prefix(mip->mi_prefcnt, mip->mi_prefarridx,
- (int)flags,
- mip->mi_word + mip->mi_cprefixlen, slang,
- false);
+ int c = valid_word_prefix(mip->mi_prefcnt, mip->mi_prefarridx,
+ (int)flags,
+ mip->mi_word + mip->mi_cprefixlen, slang,
+ false);
if (c == 0) {
continue;
}
@@ -765,6 +762,7 @@ static void find_word(matchinf_T *mip, int mode)
if (mode == FIND_COMPOUND) {
int capflags;
+ char *p;
// Need to check the caps type of the appended compound
// word.
@@ -851,7 +849,7 @@ static void find_word(matchinf_T *mip, int mode)
// byte length in keep-case word. Length may change when
// folding case. This can be slow, take a shortcut when
// the case-folded word is equal to the keep-case word.
- p = mip->mi_fword;
+ char *p = mip->mi_fword;
if (strncmp(ptr, p, (size_t)wlen) != 0) {
for (char *s = ptr; s < ptr + wlen; MB_PTR_ADV(s)) {
MB_PTR_ADV(p);
@@ -1296,12 +1294,14 @@ static inline bool can_syn_spell(win_T *wp, linenr_T lnum, int col)
/// @return 0 if not found, length of the badly spelled word otherwise.
size_t spell_move_to(win_T *wp, int dir, smt_T behaviour, bool curline, hlf_T *attrp)
{
+ if (no_spell_checking(wp)) {
+ return 0;
+ }
+
pos_T found_pos;
size_t found_len = 0;
hlf_T attr = HLF_COUNT;
- size_t len;
bool has_syntax = syntax_present(wp);
- colnr_T col;
char *buf = NULL;
size_t buflen = 0;
int skip = 0;
@@ -1309,10 +1309,6 @@ size_t spell_move_to(win_T *wp, int dir, smt_T behaviour, bool curline, hlf_T *a
bool found_one = false;
bool wrapped = false;
- if (no_spell_checking(wp)) {
- return 0;
- }
-
size_t ret = 0;
// Start looking for bad word at the start of the line, because we can't
@@ -1342,7 +1338,7 @@ size_t spell_move_to(win_T *wp, int dir, smt_T behaviour, bool curline, hlf_T *a
while (!got_int) {
char *line = ml_get_buf(wp->w_buffer, lnum);
- len = (size_t)ml_get_buf_len(wp->w_buffer, lnum);
+ size_t len = (size_t)ml_get_buf_len(wp->w_buffer, lnum);
if (buflen < len + MAXWLEN + 2) {
xfree(buf);
buflen = len + MAXWLEN + 2;
@@ -1360,7 +1356,7 @@ size_t spell_move_to(win_T *wp, int dir, smt_T behaviour, bool curline, hlf_T *a
capcol = (colnr_T)getwhitecols(line);
} else if (curline && wp == curwin) {
// For spellbadword(): check if first word needs a capital.
- col = (colnr_T)getwhitecols(line);
+ colnr_T col = (colnr_T)getwhitecols(line);
if (check_need_cap(curwin, lnum, col)) {
capcol = col;
}
@@ -1409,7 +1405,7 @@ size_t spell_move_to(win_T *wp, int dir, smt_T behaviour, bool curline, hlf_T *a
|| ((colnr_T)(curline
? p - buf + (ptrdiff_t)len
: p - buf) > wp->w_cursor.col)) {
- col = (colnr_T)(p - buf);
+ colnr_T col = (colnr_T)(p - buf);
bool no_plain_buffer = (wp->w_s->b_p_spo_flags & SPO_NPBUFFER) != 0;
bool can_spell = !no_plain_buffer;
@@ -1816,17 +1812,16 @@ void count_common_word(slang_T *lp, char *word, int len, uint8_t count)
p = buf;
}
- wordcount_T *wc;
hash_T hash = hash_hash(p);
const size_t p_len = strlen(p);
hashitem_T *hi = hash_lookup(&lp->sl_wordcount, p, p_len, hash);
if (HASHITEM_EMPTY(hi)) {
- wc = xmalloc(offsetof(wordcount_T, wc_word) + p_len + 1);
+ wordcount_T *wc = xmalloc(offsetof(wordcount_T, wc_word) + p_len + 1);
memcpy(wc->wc_word, p, p_len + 1);
wc->wc_count = count;
hash_add_item(&lp->sl_wordcount, hi, wc->wc_word, hash);
} else {
- wc = HI2WC(hi);
+ wordcount_T *wc = HI2WC(hi);
wc->wc_count = (uint16_t)(wc->wc_count + count);
if (wc->wc_count < count) { // check for overflow
wc->wc_count = MAXWORDCOUNT;
@@ -1882,14 +1877,14 @@ int init_syl_tab(slang_T *slang)
static int count_syllables(slang_T *slang, const char *word)
FUNC_ATTR_NONNULL_ALL
{
- int cnt = 0;
- bool skip = false;
- int len;
-
if (slang->sl_syllable == NULL) {
return 0;
}
+ int cnt = 0;
+ bool skip = false;
+ int len;
+
for (const char *p = word; *p != NUL; p += len) {
// When running into a space reset counter.
if (*p == ' ') {
@@ -1929,25 +1924,14 @@ static int count_syllables(slang_T *slang, const char *word)
/// @return NULL if it's OK, an untranslated error message otherwise.
char *parse_spelllang(win_T *wp)
{
- garray_T ga;
- char *splp;
- char *region;
char region_cp[3];
- bool filename;
- int region_mask;
- slang_T *slang;
- int c;
char lang[MAXWLEN + 1];
char spf_name[MAXPATHL];
- char *p;
- int round;
- char *spf;
char *use_region = NULL;
bool dont_use_region = false;
bool nobreak = false;
static bool recursive = false;
char *ret_msg = NULL;
- char *spl_copy;
bufref_T bufref;
set_bufref(&bufref, wp->w_buffer);
@@ -1960,20 +1944,21 @@ char *parse_spelllang(win_T *wp)
}
recursive = true;
+ garray_T ga;
ga_init(&ga, sizeof(langp_T), 2);
clear_midword(wp);
// Make a copy of 'spelllang', the SpellFileMissing autocommands may change
// it under our fingers.
- spl_copy = xstrdup(wp->w_s->b_p_spl);
+ char *spl_copy = xstrdup(wp->w_s->b_p_spl);
wp->w_s->b_cjk = 0;
// Loop over comma separated language names.
- for (splp = spl_copy; *splp != NUL;) {
+ for (char *splp = spl_copy; *splp != NUL;) {
// Get one language name.
copy_option_part(&splp, lang, MAXWLEN, ",");
- region = NULL;
+ char *region = NULL;
int len = (int)strlen(lang);
if (!valid_spelllang(lang)) {
@@ -1985,6 +1970,8 @@ char *parse_spelllang(win_T *wp)
continue;
}
+ slang_T *slang;
+ bool filename;
// If the name ends in ".spl" use it as the name of the spell file.
// If there is a region name let "region" point to it and remove it
// from the name.
@@ -1992,7 +1979,7 @@ char *parse_spelllang(win_T *wp)
filename = true;
// Locate a region and remove it from the file name.
- p = vim_strchr(path_tail(lang), '_');
+ char *p = vim_strchr(path_tail(lang), '_');
if (p != NULL && ASCII_ISALPHA(p[1]) && ASCII_ISALPHA(p[2])
&& !ASCII_ISALPHA(p[3])) {
xstrlcpy(region_cp, p + 1, 3);
@@ -2055,10 +2042,10 @@ char *parse_spelllang(win_T *wp)
if (filename
? path_full_compare(lang, slang->sl_fname, false, true) == kEqualFiles
: STRICMP(lang, slang->sl_name) == 0) {
- region_mask = REGION_ALL;
+ int region_mask = REGION_ALL;
if (!filename && region != NULL) {
// find region in sl_regions
- c = find_region(slang->sl_regions, region);
+ int c = find_region(slang->sl_regions, region);
if (c == REGION_ALL) {
if (slang->sl_add) {
if (*slang->sl_regions != NUL) {
@@ -2094,8 +2081,8 @@ char *parse_spelllang(win_T *wp)
// round 1: load first name in 'spellfile'.
// round 2: load second name in 'spellfile.
// etc.
- spf = curwin->w_s->b_p_spf;
- for (round = 0; round == 0 || *spf != NUL; round++) {
+ char *spf = curwin->w_s->b_p_spf;
+ for (int round = 0; round == 0 || *spf != NUL; round++) {
if (round == 0) {
// Internal wordlist, if there is one.
if (int_wordlist == NULL) {
@@ -2105,11 +2092,12 @@ char *parse_spelllang(win_T *wp)
} else {
// One entry in 'spellfile'.
copy_option_part(&spf, spf_name, MAXPATHL - 5, ",");
- STRCAT(spf_name, ".spl");
+ strcat(spf_name, ".spl");
+ int c;
// If it was already found above then skip it.
for (c = 0; c < ga.ga_len; c++) {
- p = LANGP_ENTRY(ga, c)->lp_slang->sl_fname;
+ char *p = LANGP_ENTRY(ga, c)->lp_slang->sl_fname;
if (p != NULL
&& path_full_compare(spf_name, p, false, true) == kEqualFiles) {
break;
@@ -2120,6 +2108,8 @@ char *parse_spelllang(win_T *wp)
}
}
+ slang_T *slang;
+
// Check if it was loaded already.
for (slang = first_lang; slang != NULL; slang = slang->sl_next) {
if (path_full_compare(spf_name, slang->sl_fname, false, true)
@@ -2135,7 +2125,7 @@ char *parse_spelllang(win_T *wp)
STRCPY(lang, "internal wordlist");
} else {
xstrlcpy(lang, path_tail(spf_name), MAXWLEN + 1);
- p = vim_strchr(lang, '.');
+ char *p = vim_strchr(lang, '.');
if (p != NULL) {
*p = NUL; // truncate at ".encoding.add"
}
@@ -2149,10 +2139,10 @@ char *parse_spelllang(win_T *wp)
}
}
if (slang != NULL) {
- region_mask = REGION_ALL;
+ int region_mask = REGION_ALL;
if (use_region != NULL && !dont_use_region) {
// find region in sl_regions
- c = find_region(slang->sl_regions, use_region);
+ int c = find_region(slang->sl_regions, use_region);
if (c != REGION_ALL) {
region_mask = 1 << c;
} else if (*slang->sl_regions != NUL) {
@@ -2687,7 +2677,7 @@ void ex_spellrepall(exarg_T *eap)
char *p = xmalloc((size_t)get_cursor_line_len() + (size_t)addlen + 1);
memmove(p, line, (size_t)curwin->w_cursor.col);
STRCPY(p + curwin->w_cursor.col, repl_to);
- STRCAT(p, line + curwin->w_cursor.col + repl_from_len);
+ strcat(p, line + curwin->w_cursor.col + repl_from_len);
ml_replace(curwin->w_cursor.lnum, p, false);
inserted_bytes(curwin->w_cursor.lnum, curwin->w_cursor.col,
(int)repl_from_len, (int)repl_to_len);
@@ -2902,19 +2892,7 @@ static void spell_soundfold_sofo(slang_T *slang, const char *inword, char *res)
// Multi-byte version of spell_soundfold().
static void spell_soundfold_wsal(slang_T *slang, const char *inword, char *res)
{
- salitem_T *smp = (salitem_T *)slang->sl_sal.ga_data;
int word[MAXWLEN] = { 0 };
- int wres[MAXWLEN] = { 0 };
- int *ws;
- int *pf;
- int j, z;
- int reslen;
- int k = 0;
- int k0;
- int n0;
- int pri;
- int p0 = -333;
- int c0;
bool did_white = false;
// Convert the multi-byte string to a wide-character string.
@@ -2942,17 +2920,24 @@ static void spell_soundfold_wsal(slang_T *slang, const char *inword, char *res)
}
word[wordlen] = NUL;
+ salitem_T *smp = (salitem_T *)slang->sl_sal.ga_data;
+ int wres[MAXWLEN] = { 0 };
+ int k = 0;
+ int p0 = -333;
int c;
// This algorithm comes from Aspell phonet.cpp.
// Converted from C++ to C. Added support for multi-byte chars.
// Changed to keep spaces.
- int i = reslen = z = 0;
+ int i = 0;
+ int reslen = 0;
+ int z = 0;
while ((c = word[i]) != NUL) {
// Start with the first rule that has the character in the word.
int n = slang->sl_sal_first[c & 0xff];
int z0 = 0;
if (n >= 0) {
+ int *ws;
// Check all rules for the same index byte.
// If c is 0x300 need extra check for the end of the array, as
// (c & 0xff) is NUL.
@@ -2969,6 +2954,7 @@ static void spell_soundfold_wsal(slang_T *slang, const char *inword, char *res)
continue;
}
if (k > 2) {
+ int j;
for (j = 2; j < k; j++) {
if (word[i + j] != ws[j]) {
break;
@@ -2980,6 +2966,7 @@ static void spell_soundfold_wsal(slang_T *slang, const char *inword, char *res)
}
}
+ int *pf;
if ((pf = smp[n].sm_oneof_w) != NULL) {
// Check for match with one of the chars in "sm_oneof".
while (*pf != NUL && *pf != word[i + k]) {
@@ -2991,10 +2978,10 @@ static void spell_soundfold_wsal(slang_T *slang, const char *inword, char *res)
k++;
}
char *s = smp[n].sm_rules;
- pri = 5; // default priority
+ int pri = 5; // default priority
p0 = (uint8_t)(*s);
- k0 = k;
+ int k0 = k;
while (*s == '-' && k > 1) {
k--;
s++;
@@ -3022,8 +3009,8 @@ static void spell_soundfold_wsal(slang_T *slang, const char *inword, char *res)
&& (!spell_iswordp_w(word + i + k0, curwin)))) {
// search for followup rules, if:
// followup and k > 1 and NO '-' in searchstring
- c0 = word[i + k - 1];
- n0 = slang->sl_sal_first[c0 & 0xff];
+ int c0 = word[i + k - 1];
+ int n0 = slang->sl_sal_first[c0 & 0xff];
if (slang->sl_followup && k > 1 && n0 >= 0
&& p0 != '-' && word[i + k] != NUL) {
@@ -3042,6 +3029,7 @@ static void spell_soundfold_wsal(slang_T *slang, const char *inword, char *res)
}
if (k0 > 2) {
pf = word + i + k + 1;
+ int j;
for (j = 2; j < k0; j++) {
if (*pf++ != ws[j]) {
break;
@@ -3262,23 +3250,13 @@ void ex_spelldump(exarg_T *eap)
/// @param dumpflags_arg DUMPFLAG_*
void spell_dump_compl(char *pat, int ic, Direction *dir, int dumpflags_arg)
{
- langp_T *lp;
- slang_T *slang;
idx_T arridx[MAXWLEN];
int curi[MAXWLEN];
char word[MAXWLEN];
- int c;
- uint8_t *byts;
- idx_T *idxs;
linenr_T lnum = 0;
- int depth;
- int n;
- int flags;
char *region_names = NULL; // region names being used
bool do_region = true; // dump region names and numbers
- char *p;
int dumpflags = dumpflags_arg;
- int patlen;
// When ignoring case or when the pattern starts with capital pass this on
// to dump_word().
@@ -3286,7 +3264,7 @@ void spell_dump_compl(char *pat, int ic, Direction *dir, int dumpflags_arg)
if (ic) {
dumpflags |= DUMPFLAG_ICASE;
} else {
- n = captype(pat, NULL);
+ int n = captype(pat, NULL);
if (n == WF_ONECAP) {
dumpflags |= DUMPFLAG_ONECAP;
} else if (n == WF_ALLCAP
@@ -3299,8 +3277,8 @@ void spell_dump_compl(char *pat, int ic, Direction *dir, int dumpflags_arg)
// Find out if we can support regions: All languages must support the same
// regions or none at all.
for (int lpi = 0; lpi < curwin->w_s->b_langp.ga_len; lpi++) {
- lp = LANGP_ENTRY(curwin->w_s->b_langp, lpi);
- p = lp->lp_slang->sl_regions;
+ langp_T *lp = LANGP_ENTRY(curwin->w_s->b_langp, lpi);
+ char *p = lp->lp_slang->sl_regions;
if (p[0] != 0) {
if (region_names == NULL) { // first language with regions
region_names = p;
@@ -3320,8 +3298,8 @@ void spell_dump_compl(char *pat, int ic, Direction *dir, int dumpflags_arg)
// Loop over all files loaded for the entries in 'spelllang'.
for (int lpi = 0; lpi < curwin->w_s->b_langp.ga_len; lpi++) {
- lp = LANGP_ENTRY(curwin->w_s->b_langp, lpi);
- slang = lp->lp_slang;
+ langp_T *lp = LANGP_ENTRY(curwin->w_s->b_langp, lpi);
+ slang_T *slang = lp->lp_slang;
if (slang->sl_fbyts == NULL) { // reloading failed
continue;
}
@@ -3331,6 +3309,7 @@ void spell_dump_compl(char *pat, int ic, Direction *dir, int dumpflags_arg)
ml_append(lnum++, IObuff, 0, false);
}
+ int patlen;
// When matching with a pattern and there are no prefixes only use
// parts of the tree that match "pat".
if (pat != NULL && slang->sl_pbyts == NULL) {
@@ -3342,6 +3321,8 @@ void spell_dump_compl(char *pat, int ic, Direction *dir, int dumpflags_arg)
// round 1: case-folded tree
// round 2: keep-case tree
for (int round = 1; round <= 2; round++) {
+ uint8_t *byts;
+ idx_T *idxs;
if (round == 1) {
dumpflags &= ~DUMPFLAG_KEEPCASE;
byts = slang->sl_fbyts;
@@ -3354,7 +3335,7 @@ void spell_dump_compl(char *pat, int ic, Direction *dir, int dumpflags_arg)
if (byts == NULL) {
continue; // array is empty
}
- depth = 0;
+ int depth = 0;
arridx[0] = 0;
curi[0] = 1;
while (depth >= 0 && !got_int
@@ -3366,16 +3347,16 @@ void spell_dump_compl(char *pat, int ic, Direction *dir, int dumpflags_arg)
ins_compl_check_keys(50, false);
} else {
// Do one more byte at this node.
- n = arridx[depth] + curi[depth];
+ int n = arridx[depth] + curi[depth];
curi[depth]++;
- c = byts[n];
+ int c = byts[n];
if (c == 0 || depth >= MAXWLEN - 1) {
// End of word or reached maximum length, deal with the
// word.
// Don't use keep-case words in the fold-case tree,
// they will appear in the keep-case tree.
// Only use the word when the region matches.
- flags = (int)idxs[n];
+ int flags = (int)idxs[n];
if ((round == 2 || (flags & WF_KEEPCAP) == 0)
&& (flags & WF_NEEDCOMP) == 0
&& (do_region
@@ -3463,14 +3444,14 @@ static void dump_word(slang_T *slang, char *word, char *pat, Direction *dir, int
// Add flags and regions after a slash.
if ((flags & (WF_BANNED | WF_RARE | WF_REGION)) || keepcap) {
STRCPY(badword, p);
- STRCAT(badword, "/");
+ strcat(badword, "/");
if (keepcap) {
- STRCAT(badword, "=");
+ strcat(badword, "=");
}
if (flags & WF_BANNED) {
- STRCAT(badword, "!");
+ strcat(badword, "!");
} else if (flags & WF_RARE) {
- STRCAT(badword, "?");
+ strcat(badword, "?");
}
if (flags & WF_REGION) {
for (int i = 0; i < 7; i++) {
diff --git a/src/nvim/spellfile.c b/src/nvim/spellfile.c
index 046a0a56e5..3feae980c5 100644
--- a/src/nvim/spellfile.c
+++ b/src/nvim/spellfile.c
@@ -240,6 +240,7 @@
#include "nvim/buffer_defs.h"
#include "nvim/charset.h"
#include "nvim/drawscreen.h"
+#include "nvim/errors.h"
#include "nvim/ex_cmds_defs.h"
#include "nvim/fileio.h"
#include "nvim/garray.h"
@@ -2139,11 +2140,11 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char *fname)
+ strlen(items[1]) + 3, false);
if (spin->si_info != NULL) {
STRCPY(p, spin->si_info);
- STRCAT(p, "\n");
+ strcat(p, "\n");
}
- STRCAT(p, items[0]);
- STRCAT(p, " ");
- STRCAT(p, items[1]);
+ strcat(p, items[0]);
+ strcat(p, " ");
+ strcat(p, items[1]);
spin->si_info = p;
} else if (is_aff_rule(items, itemcnt, "MIDWORD", 2) && midword == NULL) {
midword = getroom_save(spin, items[1]);
@@ -2199,7 +2200,7 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char *fname)
// "Na" into "Na+", "1234" into "1234+".
p = getroom(spin, strlen(items[1]) + 2, false);
STRCPY(p, items[1]);
- STRCAT(p, "+");
+ strcat(p, "+");
compflags = p;
} else if (is_aff_rule(items, itemcnt, "COMPOUNDRULES", 2)) {
// We don't use the count, but do check that it's a number and
@@ -2220,9 +2221,9 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char *fname)
p = getroom(spin, (size_t)l, false);
if (compflags != NULL) {
STRCPY(p, compflags);
- STRCAT(p, "/");
+ strcat(p, "/");
}
- STRCAT(p, items[1]);
+ strcat(p, items[1]);
compflags = p;
}
} else if (is_aff_rule(items, itemcnt, "COMPOUNDWORDMAX", 2)
@@ -2843,7 +2844,7 @@ static void process_compflags(spellinfo_T *spin, afffile_T *aff, char *compflags
char *p = getroom(spin, (size_t)len, false);
if (spin->si_compflags != NULL) {
STRCPY(p, spin->si_compflags);
- STRCAT(p, "/");
+ strcat(p, "/");
}
spin->si_compflags = p;
uint8_t *tp = (uint8_t *)p + strlen(p);
@@ -3385,7 +3386,7 @@ static int store_aff_word(spellinfo_T *spin, char *word, char *afflist, afffile_
MB_PTR_ADV(p);
}
}
- STRCAT(newword, p);
+ strcat(newword, p);
} else {
// suffix: chop/add at the end of the word
xstrlcpy(newword, word, MAXWLEN);
@@ -3399,7 +3400,7 @@ static int store_aff_word(spellinfo_T *spin, char *word, char *afflist, afffile_
*p = NUL;
}
if (ae->ae_add != NULL) {
- STRCAT(newword, ae->ae_add);
+ strcat(newword, ae->ae_add);
}
}
@@ -3614,7 +3615,7 @@ static int spell_read_wordfile(spellinfo_T *spin, char *fname)
if (*line == '/') {
line++;
- if (strncmp(line, "encoding=", 9) == 0) {
+ if (strncmp(line, S_LEN("encoding=")) == 0) {
if (spin->si_conv.vc_type != CONV_NONE) {
smsg(0, _("Duplicate /encoding= line ignored in %s line %" PRIdLINENR ": %s"),
fname, lnum, line - 1);
@@ -3636,7 +3637,7 @@ static int spell_read_wordfile(spellinfo_T *spin, char *fname)
continue;
}
- if (strncmp(line, "regions=", 8) == 0) {
+ if (strncmp(line, S_LEN("regions=")) == 0) {
if (spin->si_region_count > 1) {
smsg(0, _("Duplicate /regions= line ignored in %s line %" PRIdLINENR ": %s"),
fname, lnum, line);
@@ -4765,7 +4766,7 @@ void ex_mkspell(exarg_T *eap)
char *arg = eap->arg;
bool ascii = false;
- if (strncmp(arg, "-ascii", 6) == 0) {
+ if (strncmp(arg, S_LEN("-ascii")) == 0) {
ascii = true;
arg = skipwhite(arg + 6);
}
diff --git a/src/nvim/spellsuggest.c b/src/nvim/spellsuggest.c
index a7de20d14e..436599bb13 100644
--- a/src/nvim/spellsuggest.c
+++ b/src/nvim/spellsuggest.c
@@ -14,6 +14,7 @@
#include "nvim/change.h"
#include "nvim/charset.h"
#include "nvim/cursor.h"
+#include "nvim/errors.h"
#include "nvim/eval.h"
#include "nvim/eval/typval.h"
#include "nvim/eval/typval_defs.h"
@@ -412,9 +413,9 @@ int spell_check_sps(void)
f = SPS_FAST;
} else if (strcmp(buf, "double") == 0) {
f = SPS_DOUBLE;
- } else if (strncmp(buf, "expr:", 5) != 0
- && strncmp(buf, "file:", 5) != 0
- && (strncmp(buf, "timeout:", 8) != 0
+ } else if (strncmp(buf, S_LEN("expr:")) != 0
+ && strncmp(buf, S_LEN("file:")) != 0
+ && (strncmp(buf, S_LEN("timeout:")) != 0
|| (!ascii_isdigit(buf[8])
&& !(buf[8] == '-' && ascii_isdigit(buf[9]))))) {
f = -1;
@@ -542,7 +543,7 @@ void spell_suggest(int count)
msg_row = Rows - 1; // for when 'cmdheight' > 1
lines_left = Rows; // avoid more prompt
char *fmt = _("Change \"%.*s\" to:");
- if (cmdmsg_rl && strncmp(fmt, "Change", 6) == 0) {
+ if (cmdmsg_rl && strncmp(fmt, S_LEN("Change")) == 0) {
// And now the rabbit from the high hat: Avoid showing the
// untranslated message rightleft.
fmt = ":ot \"%.*s\" egnahC";
@@ -642,7 +643,7 @@ void spell_suggest(int count)
int c = (int)(sug.su_badptr - line);
memmove(p, line, (size_t)c);
STRCPY(p + c, stp->st_word);
- STRCAT(p, sug.su_badptr + stp->st_orglen);
+ strcat(p, sug.su_badptr + stp->st_orglen);
// For redo we use a change-word command.
ResetRedobuff();
@@ -791,7 +792,7 @@ static void spell_find_suggest(char *badptr, int badlen, suginfo_T *su, int maxc
for (char *p = sps_copy; *p != NUL;) {
copy_option_part(&p, buf, MAXPATHL, ",");
- if (strncmp(buf, "expr:", 5) == 0) {
+ if (strncmp(buf, S_LEN("expr:")) == 0) {
// Evaluate an expression. Skip this when called recursively,
// when using spellsuggest() in the expression.
if (!expr_busy) {
@@ -799,10 +800,10 @@ static void spell_find_suggest(char *badptr, int badlen, suginfo_T *su, int maxc
spell_suggest_expr(su, buf + 5);
expr_busy = false;
}
- } else if (strncmp(buf, "file:", 5) == 0) {
+ } else if (strncmp(buf, S_LEN("file:")) == 0) {
// Use list of suggestions in a file.
spell_suggest_file(su, buf + 5);
- } else if (strncmp(buf, "timeout:", 8) == 0) {
+ } else if (strncmp(buf, S_LEN("timeout:")) == 0) {
// Limit the time searching for suggestions.
spell_suggest_timeout = atoi(buf + 8);
} else if (!did_intern) {
@@ -1637,7 +1638,7 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char *fword, bool soun
// Append a space to preword when splitting.
if (!try_compound && !fword_ends) {
- STRCAT(preword, " ");
+ strcat(preword, " ");
}
sp->ts_prewordlen = (uint8_t)strlen(preword);
sp->ts_splitoff = sp->ts_twordlen;
diff --git a/src/nvim/statusline.c b/src/nvim/statusline.c
index ca7083a9e3..bba209b434 100644
--- a/src/nvim/statusline.c
+++ b/src/nvim/statusline.c
@@ -1487,7 +1487,7 @@ int build_stl_str_hl(win_T *wp, char *out, size_t outlen, char *fmt, OptIndex op
new_fmt_p = (char *)memcpy(new_fmt_p, usefmt, parsed_usefmt) + parsed_usefmt;
new_fmt_p = (char *)memcpy(new_fmt_p, str, str_length) + str_length;
- new_fmt_p = (char *)memcpy(new_fmt_p, "%}", 2) + 2;
+ new_fmt_p = (char *)memcpy(new_fmt_p, S_LEN("%}")) + 2;
new_fmt_p = (char *)memcpy(new_fmt_p, fmt_p, fmt_length) + fmt_length;
*new_fmt_p = 0;
new_fmt_p = NULL;
diff --git a/src/nvim/strings.c b/src/nvim/strings.c
index 8fef4ba7fd..bf7af40a38 100644
--- a/src/nvim/strings.c
+++ b/src/nvim/strings.c
@@ -12,6 +12,7 @@
#include "nvim/ascii_defs.h"
#include "nvim/assert_defs.h"
#include "nvim/charset.h"
+#include "nvim/errors.h"
#include "nvim/eval/encode.h"
#include "nvim/eval/typval.h"
#include "nvim/eval/typval_defs.h"
@@ -332,7 +333,7 @@ void vim_strcpy_up(char *restrict dst, const char *restrict src)
while ((c = (uint8_t)(*src++)) != NUL) {
*dst++ = (char)(uint8_t)(c < 'a' || c > 'z' ? c : c - 0x20);
}
- *dst = '\0';
+ *dst = NUL;
}
// strncpy (NUL-terminated) plus vim_strup.
@@ -343,7 +344,7 @@ void vim_strncpy_up(char *restrict dst, const char *restrict src, size_t n)
while (n-- && (c = (uint8_t)(*src++)) != NUL) {
*dst++ = (char)(uint8_t)(c < 'a' || c > 'z' ? c : c - 0x20);
}
- *dst = '\0';
+ *dst = NUL;
}
// memcpy (does not NUL-terminate) plus vim_strup.
@@ -793,10 +794,10 @@ static int format_typeof(const char *type)
FUNC_ATTR_NONNULL_ALL
{
// allowed values: \0, h, l, L
- char length_modifier = '\0';
+ char length_modifier = NUL;
// current conversion specifier character
- char fmt_spec = '\0';
+ char fmt_spec = NUL;
// parse 'h', 'l', 'll' and 'z' length modifiers
if (*type == 'h' || *type == 'l' || *type == 'z') {
@@ -864,7 +865,7 @@ static int format_typeof(const char *type)
} else if (fmt_spec == 'd') {
// signed
switch (length_modifier) {
- case '\0':
+ case NUL:
case 'h':
// char and short arguments are passed as int.
return TYPE_INT;
@@ -878,7 +879,7 @@ static int format_typeof(const char *type)
} else {
// unsigned
switch (length_modifier) {
- case '\0':
+ case NUL:
case 'h':
return TYPE_UNSIGNEDINT;
case 'l':
@@ -1049,7 +1050,7 @@ static int parse_fmt_types(const char ***ap_types, int *num_posarg, const char *
p += n;
} else {
// allowed values: \0, h, l, L
- char length_modifier = '\0';
+ char length_modifier = NUL;
// variable for positional arg
int pos_arg = -1;
@@ -1440,7 +1441,7 @@ int vim_vsnprintf_typval(char *str, size_t str_m, const char *fmt, va_list ap_st
int space_for_positive = 1;
// allowed values: \0, h, l, 2 (for ll), z, L
- char length_modifier = '\0';
+ char length_modifier = NUL;
// temporary buffer for simple numeric->string conversion
#define TMP_LEN 350 // 1e308 seems reasonable as the maximum printable
@@ -1465,7 +1466,7 @@ int vim_vsnprintf_typval(char *str, size_t str_m, const char *fmt, va_list ap_st
size_t zero_padding_insertion_ind = 0;
// current conversion specifier character
- char fmt_spec = '\0';
+ char fmt_spec = NUL;
// buffer for 's' and 'S' specs
char *tofree = NULL;
@@ -1668,7 +1669,7 @@ int vim_vsnprintf_typval(char *str, size_t str_m, const char *fmt, va_list ap_st
case 'o':
case 'x':
case 'X':
- if (tvs && length_modifier == '\0') {
+ if (tvs && length_modifier == NUL) {
length_modifier = 'L';
}
}
@@ -1789,7 +1790,7 @@ int vim_vsnprintf_typval(char *str, size_t str_m, const char *fmt, va_list ap_st
} else if (fmt_spec == 'd') {
// signed
switch (length_modifier) {
- case '\0':
+ case NUL:
arg = (tvs
? (int)tv_nr(tvs, &arg_idx)
: (skip_to_arg(ap_types, ap_start, &ap, &arg_idx,
@@ -1835,7 +1836,7 @@ int vim_vsnprintf_typval(char *str, size_t str_m, const char *fmt, va_list ap_st
} else {
// unsigned
switch (length_modifier) {
- case '\0':
+ case NUL:
uarg = (tvs
? (unsigned)tv_nr(tvs, &arg_idx)
: (skip_to_arg(ap_types, ap_start, &ap, &arg_idx,
@@ -2222,7 +2223,7 @@ int vim_vsnprintf_typval(char *str, size_t str_m, const char *fmt, va_list ap_st
if (str_m > 0) {
// make sure the string is nul-terminated even at the expense of
// overwriting the last character (shouldn't happen, but just in case)
- str[str_l <= str_m - 1 ? str_l : str_m - 1] = '\0';
+ str[str_l <= str_m - 1 ? str_l : str_m - 1] = NUL;
}
if (tvs != NULL
diff --git a/src/nvim/syntax.c b/src/nvim/syntax.c
index b63d2a729d..538863326c 100644
--- a/src/nvim/syntax.c
+++ b/src/nvim/syntax.c
@@ -15,6 +15,7 @@
#include "nvim/charset.h"
#include "nvim/cmdexpand_defs.h"
#include "nvim/drawscreen.h"
+#include "nvim/errors.h"
#include "nvim/eval.h"
#include "nvim/eval/typval_defs.h"
#include "nvim/eval/vars.h"
@@ -3185,7 +3186,7 @@ static void syn_cmd_onoff(exarg_T *eap, char *name)
if (!eap->skip) {
did_syntax_onoff = true;
char buf[100];
- memcpy(buf, "so ", 4);
+ memcpy(buf, S_LEN("so ") + 1);
vim_snprintf(buf + 3, sizeof(buf) - 3, SYNTAX_FNAME, name);
do_cmdline_cmd(buf);
}
@@ -4295,7 +4296,7 @@ static void syn_cmd_region(exarg_T *eap, int syncing)
if (item == ITEM_MATCHGROUP) {
char *p = skiptowhite(rest);
- if ((p - rest == 4 && strncmp(rest, "NONE", 4) == 0) || eap->skip) {
+ if ((p - rest == 4 && strncmp(rest, S_LEN("NONE")) == 0) || eap->skip) {
matchgroup_id = 0;
} else {
matchgroup_id = syn_check_group(rest, (size_t)(p - rest));
@@ -4814,10 +4815,10 @@ static void syn_cmd_sync(exarg_T *eap, int syncing)
} else if (!eap->skip) {
curwin->w_s->b_syn_sync_id = (int16_t)syn_name2id("Comment");
}
- } else if (strncmp(key, "LINES", 5) == 0
- || strncmp(key, "MINLINES", 8) == 0
- || strncmp(key, "MAXLINES", 8) == 0
- || strncmp(key, "LINEBREAKS", 10) == 0) {
+ } else if (strncmp(key, S_LEN("LINES")) == 0
+ || strncmp(key, S_LEN("MINLINES")) == 0
+ || strncmp(key, S_LEN("MAXLINES")) == 0
+ || strncmp(key, S_LEN("LINEBREAKS")) == 0) {
if (key[4] == 'S') {
arg_end = key + 6;
} else if (key[0] == 'L') {
@@ -4991,7 +4992,7 @@ static int get_id_list(char **const arg, const int keylen, int16_t **const list,
} else {
// Handle match of regexp with group names.
*name = '^';
- STRCAT(name, "$");
+ strcat(name, "$");
regmatch.regprog = vim_regcomp(name, RE_MAGIC);
if (regmatch.regprog == NULL) {
failed = true;
diff --git a/src/nvim/tag.c b/src/nvim/tag.c
index e7f483dd3d..1d318fc3c7 100644
--- a/src/nvim/tag.c
+++ b/src/nvim/tag.c
@@ -18,6 +18,7 @@
#include "nvim/cmdexpand_defs.h"
#include "nvim/cursor.h"
#include "nvim/drawscreen.h"
+#include "nvim/errors.h"
#include "nvim/eval.h"
#include "nvim/eval/typval.h"
#include "nvim/ex_cmds.h"
@@ -878,14 +879,14 @@ static void print_tag_list(bool new_tag, bool use_tagstack, int num_matches, cha
}
// skip "file:" without a value (static tag)
- if (strncmp(p, "file:", 5) == 0 && ascii_isspace(p[5])) {
+ if (strncmp(p, S_LEN("file:")) == 0 && ascii_isspace(p[5])) {
p += 5;
continue;
}
// skip "kind:<kind>" and "<kind>"
if (p == tagp.tagkind
|| (p + 5 == tagp.tagkind
- && strncmp(p, "kind:", 5) == 0)) {
+ && strncmp(p, S_LEN("kind:")) == 0)) {
p = tagp.tagkind_end;
continue;
}
@@ -1059,7 +1060,7 @@ static int add_llist_tags(char *tag, int num_matches, char **matches)
// Precede the tag pattern with \V to make it very
// nomagic.
- STRCAT(cmd, "\\V");
+ strcat(cmd, "\\V");
len += 2;
int cmd_len = (int)(cmd_end - cmd_start + 1);
@@ -1613,16 +1614,16 @@ static tags_read_status_T findtags_get_next_line(findtags_state_T *st, tagsearch
static bool findtags_hdr_parse(findtags_state_T *st)
{
// Header lines in a tags file start with "!_TAG_"
- if (strncmp(st->lbuf, "!_TAG_", 6) != 0) {
+ if (strncmp(st->lbuf, S_LEN("!_TAG_")) != 0) {
// Non-header item before the header, e.g. "!" itself.
return true;
}
// Process the header line.
- if (strncmp(st->lbuf, "!_TAG_FILE_SORTED\t", 18) == 0) {
+ if (strncmp(st->lbuf, S_LEN("!_TAG_FILE_SORTED\t")) == 0) {
st->tag_file_sorted = (uint8_t)st->lbuf[18];
}
- if (strncmp(st->lbuf, "!_TAG_FILE_ENCODING\t", 20) == 0) {
+ if (strncmp(st->lbuf, S_LEN("!_TAG_FILE_ENCODING\t")) == 0) {
// Prepare to convert every line from the specified encoding to
// 'encoding'.
char *p;
@@ -1646,7 +1647,7 @@ static bool findtags_start_state_handler(findtags_state_T *st, bool *sortic,
// The header ends when the line sorts below "!_TAG_". When case is
// folded lower case letters sort before "_".
- if (strncmp(st->lbuf, "!_TAG_", 6) <= 0
+ if (strncmp(st->lbuf, S_LEN("!_TAG_")) <= 0
|| (st->lbuf[0] == '!' && ASCII_ISLOWER(st->lbuf[1]))) {
return findtags_hdr_parse(st);
}
@@ -2669,7 +2670,7 @@ static bool test_for_static(tagptrs_T *tagp)
char *p = tagp->command;
while ((p = vim_strchr(p, '\t')) != NULL) {
p++;
- if (strncmp(p, "file:", 5) == 0) {
+ if (strncmp(p, S_LEN("file:")) == 0) {
return true;
}
}
@@ -2727,11 +2728,11 @@ static int parse_match(char *lbuf, tagptrs_T *tagp)
// Accept ASCII alphabetic kind characters and any multi-byte
// character.
while (ASCII_ISALPHA(*p) || utfc_ptr2len(p) > 1) {
- if (strncmp(p, "kind:", 5) == 0) {
+ if (strncmp(p, S_LEN("kind:")) == 0) {
tagp->tagkind = p + 5;
- } else if (strncmp(p, "user_data:", 10) == 0) {
+ } else if (strncmp(p, S_LEN("user_data:")) == 0) {
tagp->user_data = p + 10;
- } else if (strncmp(p, "line:", 5) == 0) {
+ } else if (strncmp(p, S_LEN("line:")) == 0) {
tagp->tagline = atoi(p + 5);
}
if (tagp->tagkind != NULL && tagp->user_data != NULL) {
@@ -3173,7 +3174,7 @@ static int find_extra(char **pp)
first_char = *str;
}
- if (str != NULL && strncmp(str, ";\"", 2) == 0) {
+ if (str != NULL && strncmp(str, S_LEN(";\"")) == 0) {
*pp = str;
return OK;
}
@@ -3302,7 +3303,7 @@ int get_tags(list_T *list, char *pat, char *buf_fname)
bool is_static = test_for_static(&tp);
// Skip pseudo-tag lines.
- if (strncmp(tp.tagname, "!_TAG_", 6) == 0) {
+ if (strncmp(tp.tagname, S_LEN("!_TAG_")) == 0) {
xfree(matches[i]);
continue;
}
@@ -3327,10 +3328,10 @@ int get_tags(list_T *list, char *pat, char *buf_fname)
*p != NUL && *p != '\n' && *p != '\r';
MB_PTR_ADV(p)) {
if (p == tp.tagkind
- || (p + 5 == tp.tagkind && strncmp(p, "kind:", 5) == 0)) {
+ || (p + 5 == tp.tagkind && strncmp(p, S_LEN("kind:")) == 0)) {
// skip "kind:<kind>" and "<kind>"
p = tp.tagkind_end - 1;
- } else if (strncmp(p, "file:", 5) == 0) {
+ } else if (strncmp(p, S_LEN("file:")) == 0) {
// skip "file:" (static tag)
p += 4;
} else if (!ascii_iswhite(*p)) {
diff --git a/src/nvim/terminal.c b/src/nvim/terminal.c
index 2b05a8047e..000f750413 100644
--- a/src/nvim/terminal.c
+++ b/src/nvim/terminal.c
@@ -112,6 +112,9 @@ typedef struct {
// libvterm. Improves performance when receiving large bursts of data.
#define REFRESH_DELAY 10
+#define TEXTBUF_SIZE 0x1fff
+#define SELECTIONBUF_SIZE 0x0400
+
static TimeWatcher refresh_timer;
static bool refresh_pending = false;
@@ -127,7 +130,7 @@ struct terminal {
// buffer used to:
// - convert VTermScreen cell arrays into utf8 strings
// - receive data from libvterm as a result of key presses.
- char textbuf[0x1fff];
+ char textbuf[TEXTBUF_SIZE];
ScrollbackLine **sb_buffer; // Scrollback storage.
size_t sb_current; // Lines stored in sb_buffer.
@@ -166,6 +169,9 @@ struct terminal {
// When there is a pending TermRequest autocommand, block and store input.
StringBuilder *pending_send;
+ char *selection_buffer; /// libvterm selection buffer
+ StringBuilder selection; /// Growable array containing full selection data
+
size_t refcount; // reference count
};
@@ -179,6 +185,12 @@ static VTermScreenCallbacks vterm_screen_callbacks = {
.sb_popline = term_sb_pop,
};
+static VTermSelectionCallbacks vterm_selection_callbacks = {
+ .set = term_selection_set,
+ // For security reasons we don't support querying the system clipboard from the embedded terminal
+ .query = NULL,
+};
+
static Set(ptr_t) invalidated_terminals = SET_INIT;
static void emit_termrequest(void **argv)
@@ -315,6 +327,11 @@ void terminal_open(Terminal **termpp, buf_T *buf, TerminalOptions opts)
vterm_screen_set_damage_merge(term->vts, VTERM_DAMAGE_SCROLL);
vterm_screen_reset(term->vts, 1);
vterm_output_set_callback(term->vt, term_output_callback, term);
+
+ term->selection_buffer = xcalloc(SELECTIONBUF_SIZE, 1);
+ vterm_state_set_selection_callbacks(state, &vterm_selection_callbacks, term,
+ term->selection_buffer, SELECTIONBUF_SIZE);
+
// force a initial refresh of the screen to ensure the buffer will always
// have as many lines as screen rows when refresh_scrollback is called
term->invalid_start = 0;
@@ -326,14 +343,6 @@ void terminal_open(Terminal **termpp, buf_T *buf, TerminalOptions opts)
refresh_screen(term, buf);
set_option_value(kOptBuftype, STATIC_CSTR_AS_OPTVAL("terminal"), OPT_LOCAL);
- // Default settings for terminal buffers
- buf->b_p_ma = false; // 'nomodifiable'
- buf->b_p_ul = -1; // 'undolevels'
- buf->b_p_scbk = // 'scrollback' (initialize local from global)
- (p_scbk < 0) ? 10000 : MAX(1, p_scbk);
- buf->b_p_tw = 0; // 'textwidth'
- set_option_value(kOptWrap, BOOLEAN_OPTVAL(false), OPT_LOCAL);
- set_option_value(kOptList, BOOLEAN_OPTVAL(false), OPT_LOCAL);
if (buf->b_ffname != NULL) {
buf_set_term_title(buf, buf->b_ffname, strlen(buf->b_ffname));
}
@@ -769,6 +778,8 @@ void terminal_destroy(Terminal **termpp)
}
xfree(term->sb_buffer);
xfree(term->title);
+ xfree(term->selection_buffer);
+ kv_destroy(term->selection);
vterm_free(term->vt);
xfree(term);
*termpp = NULL; // coverity[dead-store]
@@ -833,9 +844,9 @@ void terminal_paste(int count, char **y_array, size_t y_size)
if (j) {
// terminate the previous line
#ifdef MSWIN
- terminal_send(curbuf->terminal, "\r\n", 2);
+ terminal_send(curbuf->terminal, S_LEN("\r\n"));
#else
- terminal_send(curbuf->terminal, "\n", 1);
+ terminal_send(curbuf->terminal, S_LEN("\n"));
#endif
}
size_t len = strlen(y_array[j]);
@@ -845,7 +856,7 @@ void terminal_paste(int count, char **y_array, size_t y_size)
}
char *dst = buff;
char *src = y_array[j];
- while (*src != '\0') {
+ while (*src != NUL) {
len = (size_t)utf_ptr2len(src);
int c = utf_ptr2char(src);
if (!is_filter_char(c)) {
@@ -1198,6 +1209,54 @@ static int term_sb_pop(int cols, VTermScreenCell *cells, void *data)
return 1;
}
+static void term_clipboard_set(void **argv)
+{
+ VTermSelectionMask mask = (VTermSelectionMask)(long)argv[0];
+ char *data = argv[1];
+
+ char regname;
+ switch (mask) {
+ case VTERM_SELECTION_CLIPBOARD:
+ regname = '+';
+ break;
+ case VTERM_SELECTION_PRIMARY:
+ regname = '*';
+ break;
+ default:
+ regname = '+';
+ break;
+ }
+
+ list_T *lines = tv_list_alloc(1);
+ tv_list_append_allocated_string(lines, data);
+
+ list_T *args = tv_list_alloc(3);
+ tv_list_append_list(args, lines);
+
+ const char regtype = 'v';
+ tv_list_append_string(args, &regtype, 1);
+
+ tv_list_append_string(args, &regname, 1);
+ eval_call_provider("clipboard", "set", args, true);
+}
+
+static int term_selection_set(VTermSelectionMask mask, VTermStringFragment frag, void *user)
+{
+ Terminal *term = user;
+ if (frag.initial) {
+ kv_size(term->selection) = 0;
+ }
+
+ kv_concat_len(term->selection, frag.str, frag.len);
+
+ if (frag.final) {
+ char *data = xmemdupz(term->selection.items, kv_size(term->selection));
+ multiqueue_put(main_loop.events, term_clipboard_set, (void *)mask, data);
+ }
+
+ return 1;
+}
+
// }}}
// input handling {{{
diff --git a/src/nvim/testing.c b/src/nvim/testing.c
index 343568d71e..8041cc2e33 100644
--- a/src/nvim/testing.c
+++ b/src/nvim/testing.c
@@ -7,6 +7,7 @@
#include <string.h>
#include "nvim/ascii_defs.h"
+#include "nvim/errors.h"
#include "nvim/eval.h"
#include "nvim/eval/encode.h"
#include "nvim/eval/typval.h"
diff --git a/src/nvim/textformat.c b/src/nvim/textformat.c
index 1722bcc968..01567c9e01 100644
--- a/src/nvim/textformat.c
+++ b/src/nvim/textformat.c
@@ -1017,7 +1017,7 @@ void format_lines(linenr_T line_count, bool avoid_fex)
// and this line has a line comment after some text, the
// paragraph doesn't really end.
if (next_leader_flags == NULL
- || strncmp(next_leader_flags, "://", 3) != 0
+ || strncmp(next_leader_flags, S_LEN("://")) != 0
|| check_linecomment(get_cursor_line_ptr()) == MAXCOL) {
is_end_par = true;
}
diff --git a/src/nvim/tui/input.c b/src/nvim/tui/input.c
index f1594dfcb9..a5768cfc06 100644
--- a/src/nvim/tui/input.c
+++ b/src/nvim/tui/input.c
@@ -15,7 +15,6 @@
#include "nvim/option_vars.h"
#include "nvim/os/os.h"
#include "nvim/os/os_defs.h"
-#include "nvim/rbuffer.h"
#include "nvim/strings.h"
#include "nvim/tui/input.h"
#include "nvim/tui/input_defs.h"
@@ -28,7 +27,6 @@
#include "nvim/msgpack_rpc/channel.h"
#define READ_STREAM_SIZE 0xfff
-#define KEY_BUFFER_SIZE 0xfff
/// Size of libtermkey's internal input buffer. The buffer may grow larger than
/// this when processing very long escape sequences, but will shrink back to
@@ -132,7 +130,6 @@ void tinput_init(TermInput *input, Loop *loop)
input->key_encoding = kKeyEncodingLegacy;
input->ttimeout = (bool)p_ttimeout;
input->ttimeoutlen = p_ttm;
- input->key_buffer = rbuffer_new(KEY_BUFFER_SIZE);
for (size_t i = 0; i < ARRAY_SIZE(kitty_key_map_entry); i++) {
pmap_put(int)(&kitty_key_map, kitty_key_map_entry[i].key, (ptr_t)kitty_key_map_entry[i].name);
@@ -155,7 +152,7 @@ void tinput_init(TermInput *input, Loop *loop)
termkey_set_canonflags(input->tk, curflags | TERMKEY_CANON_DELBS);
// setup input handle
- rstream_init_fd(loop, &input->read_stream, input->in_fd, READ_STREAM_SIZE);
+ rstream_init_fd(loop, &input->read_stream, input->in_fd);
// initialize a timer handle for handling ESC with libtermkey
uv_timer_init(&loop->uv, &input->timer_handle);
@@ -165,9 +162,8 @@ void tinput_init(TermInput *input, Loop *loop)
void tinput_destroy(TermInput *input)
{
map_destroy(int, &kitty_key_map);
- rbuffer_free(input->key_buffer);
uv_close((uv_handle_t *)&input->timer_handle, NULL);
- stream_close(&input->read_stream, NULL, NULL);
+ rstream_may_close(&input->read_stream);
termkey_destroy(input->tk);
}
@@ -191,44 +187,38 @@ static void tinput_done_event(void **argv)
/// Send all pending input in key buffer to Nvim server.
static void tinput_flush(TermInput *input)
{
+ String keys = { .data = input->key_buffer, .size = input->key_buffer_len };
if (input->paste) { // produce exactly one paste event
- const size_t len = rbuffer_size(input->key_buffer);
- String keys = { .data = xmallocz(len), .size = len };
- rbuffer_read(input->key_buffer, keys.data, len);
MAXSIZE_TEMP_ARRAY(args, 3);
ADD_C(args, STRING_OBJ(keys)); // 'data'
ADD_C(args, BOOLEAN_OBJ(true)); // 'crlf'
ADD_C(args, INTEGER_OBJ(input->paste)); // 'phase'
rpc_send_event(ui_client_channel_id, "nvim_paste", args);
- api_free_string(keys);
if (input->paste == 1) {
// Paste phase: "continue"
input->paste = 2;
}
- rbuffer_reset(input->key_buffer);
} else { // enqueue input
- RBUFFER_UNTIL_EMPTY(input->key_buffer, buf, len) {
- const String keys = { .data = buf, .size = len };
+ if (input->key_buffer_len > 0) {
MAXSIZE_TEMP_ARRAY(args, 1);
ADD_C(args, STRING_OBJ(keys));
// NOTE: This is non-blocking and won't check partially processed input,
// but should be fine as all big sends are handled with nvim_paste, not nvim_input
rpc_send_event(ui_client_channel_id, "nvim_input", args);
- rbuffer_consumed(input->key_buffer, len);
- rbuffer_reset(input->key_buffer);
}
}
+ input->key_buffer_len = 0;
}
-static void tinput_enqueue(TermInput *input, char *buf, size_t size)
+static void tinput_enqueue(TermInput *input, const char *buf, size_t size)
{
- if (rbuffer_size(input->key_buffer) >
- rbuffer_capacity(input->key_buffer) - 0xff) {
- // don't ever let the buffer get too full or we risk putting incomplete keys
- // into it
+ if (input->key_buffer_len > KEY_BUFFER_SIZE - size) {
+ // don't ever let the buffer get too full or we risk putting incomplete keys into it
tinput_flush(input);
}
- rbuffer_write(input->key_buffer, buf, size);
+ size_t to_copy = MIN(size, KEY_BUFFER_SIZE - input->key_buffer_len);
+ memcpy(input->key_buffer + input->key_buffer_len, buf, to_copy);
+ input->key_buffer_len += to_copy;
}
/// Handle TERMKEY_KEYMOD_* modifiers, i.e. Shift, Alt and Ctrl.
@@ -472,8 +462,10 @@ static void tinput_timer_cb(uv_timer_t *handle)
TermInput *input = handle->data;
// If the raw buffer is not empty, process the raw buffer first because it is
// processing an incomplete bracketed paster sequence.
- if (rbuffer_size(input->read_stream.buffer)) {
- handle_raw_buffer(input, true);
+ size_t size = rstream_available(&input->read_stream);
+ if (size) {
+ size_t consumed = handle_raw_buffer(input, true, input->read_stream.read_pos, size);
+ rstream_consume(&input->read_stream, consumed);
}
tk_getkeys(input, true);
tinput_flush(input);
@@ -487,39 +479,37 @@ static void tinput_timer_cb(uv_timer_t *handle)
///
/// @param input the input stream
/// @return true iff handle_focus_event consumed some input
-static bool handle_focus_event(TermInput *input)
+static size_t handle_focus_event(TermInput *input, const char *ptr, size_t size)
{
- if (rbuffer_size(input->read_stream.buffer) > 2
- && (!rbuffer_cmp(input->read_stream.buffer, "\x1b[I", 3)
- || !rbuffer_cmp(input->read_stream.buffer, "\x1b[O", 3))) {
- bool focus_gained = *rbuffer_get(input->read_stream.buffer, 2) == 'I';
- // Advance past the sequence
- rbuffer_consumed(input->read_stream.buffer, 3);
+ if (size >= 3
+ && (!memcmp(ptr, "\x1b[I", 3)
+ || !memcmp(ptr, "\x1b[O", 3))) {
+ bool focus_gained = ptr[2] == 'I';
MAXSIZE_TEMP_ARRAY(args, 1);
ADD_C(args, BOOLEAN_OBJ(focus_gained));
rpc_send_event(ui_client_channel_id, "nvim_ui_set_focus", args);
- return true;
+ return 3; // Advance past the sequence
}
- return false;
+ return 0;
}
#define START_PASTE "\x1b[200~"
#define END_PASTE "\x1b[201~"
-static HandleState handle_bracketed_paste(TermInput *input)
+static size_t handle_bracketed_paste(TermInput *input, const char *ptr, size_t size,
+ bool *incomplete)
{
- size_t buf_size = rbuffer_size(input->read_stream.buffer);
- if (buf_size > 5
- && (!rbuffer_cmp(input->read_stream.buffer, START_PASTE, 6)
- || !rbuffer_cmp(input->read_stream.buffer, END_PASTE, 6))) {
- bool enable = *rbuffer_get(input->read_stream.buffer, 4) == '0';
+ if (size >= 6
+ && (!memcmp(ptr, START_PASTE, 6)
+ || !memcmp(ptr, END_PASTE, 6))) {
+ bool enable = ptr[4] == '0';
if (input->paste && enable) {
- return kNotApplicable; // Pasting "start paste" code literally.
+ return 0; // Pasting "start paste" code literally.
}
+
// Advance past the sequence
- rbuffer_consumed(input->read_stream.buffer, 6);
if (!!input->paste == enable) {
- return kComplete; // Spurious "disable paste" code.
+ return 6; // Spurious "disable paste" code.
}
if (enable) {
@@ -534,15 +524,15 @@ static HandleState handle_bracketed_paste(TermInput *input)
// Paste phase: "disabled".
input->paste = 0;
}
- return kComplete;
- } else if (buf_size < 6
- && (!rbuffer_cmp(input->read_stream.buffer, START_PASTE, buf_size)
- || !rbuffer_cmp(input->read_stream.buffer,
- END_PASTE, buf_size))) {
+ return 6;
+ } else if (size < 6
+ && (!memcmp(ptr, START_PASTE, size)
+ || !memcmp(ptr, END_PASTE, size))) {
// Wait for further input, as the sequence may be split.
- return kIncomplete;
+ *incomplete = true;
+ return 0;
}
- return kNotApplicable;
+ return 0;
}
/// Handle an OSC or DCS response sequence from the terminal.
@@ -653,20 +643,31 @@ static void handle_unknown_csi(TermInput *input, const TermKeyKey *key)
}
}
-static void handle_raw_buffer(TermInput *input, bool force)
+static size_t handle_raw_buffer(TermInput *input, bool force, const char *data, size_t size)
{
- HandleState is_paste = kNotApplicable;
+ const char *ptr = data;
do {
- if (!force
- && (handle_focus_event(input)
- || (is_paste = handle_bracketed_paste(input)) != kNotApplicable)) {
- if (is_paste == kIncomplete) {
+ if (!force) {
+ size_t consumed = handle_focus_event(input, ptr, size);
+ if (consumed) {
+ ptr += consumed;
+ size -= consumed;
+ continue;
+ }
+
+ bool incomplete = false;
+ consumed = handle_bracketed_paste(input, ptr, size, &incomplete);
+ if (incomplete) {
+ assert(consumed == 0);
// Wait for the next input, leaving it in the raw buffer due to an
// incomplete sequence.
- return;
+ return (size_t)(ptr - data);
+ } else if (consumed) {
+ ptr += consumed;
+ size -= consumed;
+ continue;
}
- continue;
}
//
@@ -675,55 +676,47 @@ static void handle_raw_buffer(TermInput *input, bool force)
// calls (above) depend on this.
//
size_t count = 0;
- RBUFFER_EACH(input->read_stream.buffer, c, i) {
+ for (size_t i = 0; i < size; i++) {
count = i + 1;
- if (c == '\x1b' && count > 1) {
+ if (ptr[i] == '\x1b' && count > 1) {
count--;
break;
}
}
// Push bytes directly (paste).
if (input->paste) {
- RBUFFER_UNTIL_EMPTY(input->read_stream.buffer, ptr, len) {
- size_t consumed = MIN(count, len);
- assert(consumed <= input->read_stream.buffer->size);
- tinput_enqueue(input, ptr, consumed);
- rbuffer_consumed(input->read_stream.buffer, consumed);
- if (!(count -= consumed)) {
- break;
- }
- }
+ tinput_enqueue(input, ptr, count);
+ ptr += count;
+ size -= count;
continue;
}
+
// Push through libtermkey (translates to "<keycode>" strings, etc.).
- RBUFFER_UNTIL_EMPTY(input->read_stream.buffer, ptr, len) {
- const size_t size = MIN(count, len);
- if (size > termkey_get_buffer_remaining(input->tk)) {
+ {
+ const size_t to_use = MIN(count, size);
+ if (to_use > termkey_get_buffer_remaining(input->tk)) {
// We are processing a very long escape sequence. Increase termkey's
// internal buffer size. We don't handle out of memory situations so
// abort if it fails
- const size_t delta = size - termkey_get_buffer_remaining(input->tk);
+ const size_t delta = to_use - termkey_get_buffer_remaining(input->tk);
const size_t bufsize = termkey_get_buffer_size(input->tk);
if (!termkey_set_buffer_size(input->tk, MAX(bufsize + delta, bufsize * 2))) {
abort();
}
}
- size_t consumed = termkey_push_bytes(input->tk, ptr, size);
+ size_t consumed = termkey_push_bytes(input->tk, ptr, to_use);
// We resize termkey's buffer when it runs out of space, so this should
// never happen
- assert(consumed <= rbuffer_size(input->read_stream.buffer));
- rbuffer_consumed(input->read_stream.buffer, consumed);
+ assert(consumed <= to_use);
+ ptr += consumed;
+ size -= consumed;
// Process the input buffer now for any keys
tk_getkeys(input, false);
-
- if (!(count -= consumed)) {
- break;
- }
}
- } while (rbuffer_size(input->read_stream.buffer));
+ } while (size);
const size_t tk_size = termkey_get_buffer_size(input->tk);
const size_t tk_remaining = termkey_get_buffer_remaining(input->tk);
@@ -735,23 +728,25 @@ static void handle_raw_buffer(TermInput *input, bool force)
abort();
}
}
+
+ return (size_t)(ptr - data);
}
-static void tinput_read_cb(Stream *stream, RBuffer *buf, size_t count_, void *data, bool eof)
+static size_t tinput_read_cb(RStream *stream, const char *buf, size_t count_, void *data, bool eof)
{
TermInput *input = data;
+ size_t consumed = handle_raw_buffer(input, false, buf, count_);
+ tinput_flush(input);
+
if (eof) {
loop_schedule_fast(&main_loop, event_create(tinput_done_event, NULL));
- return;
+ return consumed;
}
- handle_raw_buffer(input, false);
- tinput_flush(input);
-
// An incomplete sequence was found. Leave it in the raw buffer and wait for
// the next input.
- if (rbuffer_size(input->read_stream.buffer)) {
+ if (consumed < count_) {
// If 'ttimeout' is not set, start the timer with a timeout of 0 to process
// the next input.
int64_t ms = input->ttimeout
@@ -759,11 +754,7 @@ static void tinput_read_cb(Stream *stream, RBuffer *buf, size_t count_, void *da
// Stop the current timer if already running
uv_timer_stop(&input->timer_handle);
uv_timer_start(&input->timer_handle, tinput_timer_cb, (uint32_t)ms, 0);
- return;
}
- // Make sure the next input escape sequence fits into the ring buffer without
- // wraparound, else it could be misinterpreted (because rbuffer_read_ptr()
- // exposes the underlying buffer to callers unaware of the wraparound).
- rbuffer_reset(input->read_stream.buffer);
+ return consumed;
}
diff --git a/src/nvim/tui/input.h b/src/nvim/tui/input.h
index bf6d0f2978..8d0c0c20e9 100644
--- a/src/nvim/tui/input.h
+++ b/src/nvim/tui/input.h
@@ -5,7 +5,6 @@
#include <uv.h>
#include "nvim/event/defs.h"
-#include "nvim/rbuffer_defs.h"
#include "nvim/tui/input_defs.h" // IWYU pragma: keep
#include "nvim/tui/tui_defs.h"
#include "nvim/types_defs.h"
@@ -17,6 +16,7 @@ typedef enum {
kKeyEncodingXterm, ///< Xterm's modifyOtherKeys encoding (XTMODKEYS)
} KeyEncoding;
+#define KEY_BUFFER_SIZE 0x1000
typedef struct {
int in_fd;
// Phases: -1=all 0=disabled 1=first-chunk 2=continue 3=last-chunk
@@ -33,17 +33,12 @@ typedef struct {
TermKey_Terminfo_Getstr_Hook *tk_ti_hook_fn; ///< libtermkey terminfo hook
uv_timer_t timer_handle;
Loop *loop;
- Stream read_stream;
- RBuffer *key_buffer;
+ RStream read_stream;
TUIData *tui_data;
+ char key_buffer[KEY_BUFFER_SIZE];
+ size_t key_buffer_len;
} TermInput;
-typedef enum {
- kIncomplete = -1,
- kNotApplicable = 0,
- kComplete = 1,
-} HandleState;
-
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "tui/input.h.generated.h"
#endif
diff --git a/src/nvim/tui/terminfo.c b/src/nvim/tui/terminfo.c
index 3cf9650428..657bd6dd10 100644
--- a/src/nvim/tui/terminfo.c
+++ b/src/nvim/tui/terminfo.c
@@ -35,7 +35,7 @@ bool terminfo_is_term_family(const char *term, const char *family)
// The screen terminfo may have a terminal name like screen.xterm. By making
// the dot(.) a valid separator, such terminal names will also be the
// terminal family of the screen.
- && ('\0' == term[flen] || '-' == term[flen] || '.' == term[flen]);
+ && (NUL == term[flen] || '-' == term[flen] || '.' == term[flen]);
}
bool terminfo_is_bsd_console(const char *term)
diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c
index dc8c8def5b..57696b1839 100644
--- a/src/nvim/tui/tui.c
+++ b/src/nvim/tui/tui.c
@@ -1855,20 +1855,12 @@ static int unibi_find_ext_bool(unibi_term *ut, const char *name)
return -1;
}
-/// Determine if the terminal supports truecolor or not:
+/// Determine if the terminal supports truecolor or not.
///
-/// 1. If $COLORTERM is "24bit" or "truecolor", return true
-/// 2. Else, check terminfo for Tc, RGB, setrgbf, or setrgbb capabilities. If
-/// found, return true
-/// 3. Else, return false
+/// If terminfo contains Tc, RGB, or both setrgbf and setrgbb capabilities, return true.
static bool term_has_truecolor(TUIData *tui, const char *colorterm)
{
- // Check $COLORTERM
- if (strequal(colorterm, "truecolor") || strequal(colorterm, "24bit")) {
- return true;
- }
-
- // Check for Tc and RGB
+ // Check for Tc or RGB
for (size_t i = 0; i < unibi_count_ext_bool(tui->ut); i++) {
const char *n = unibi_get_ext_bool_name(tui->ut, i);
if (n && (!strcmp(n, "Tc") || !strcmp(n, "RGB"))) {
@@ -2508,7 +2500,7 @@ static const char *tui_get_stty_erase(int fd)
struct termios t;
if (tcgetattr(fd, &t) != -1) {
stty_erase[0] = (char)t.c_cc[VERASE];
- stty_erase[1] = '\0';
+ stty_erase[1] = NUL;
DLOG("stty/termios:erase=%s", stty_erase);
}
#endif
diff --git a/src/nvim/undo.c b/src/nvim/undo.c
index ba720c9f6a..ed5c9a508c 100644
--- a/src/nvim/undo.c
+++ b/src/nvim/undo.c
@@ -92,6 +92,7 @@
#include "nvim/decoration.h"
#include "nvim/drawscreen.h"
#include "nvim/edit.h"
+#include "nvim/errors.h"
#include "nvim/eval/funcs.h"
#include "nvim/eval/typval.h"
#include "nvim/ex_cmds_defs.h"
diff --git a/src/nvim/usercmd.c b/src/nvim/usercmd.c
index e3d9dc5f54..877624b07e 100644
--- a/src/nvim/usercmd.c
+++ b/src/nvim/usercmd.c
@@ -422,10 +422,10 @@ char *get_user_cmd_complete(expand_T *xp, int idx)
int cmdcomplete_str_to_type(const char *complete_str)
{
- if (strncmp(complete_str, "custom,", 7) == 0) {
+ if (strncmp(complete_str, S_LEN("custom,")) == 0) {
return EXPAND_USER_DEFINED;
}
- if (strncmp(complete_str, "customlist,", 11) == 0) {
+ if (strncmp(complete_str, S_LEN("customlist,")) == 0) {
return EXPAND_USER_LIST;
}
@@ -580,7 +580,7 @@ static void uc_list(char *name, size_t name_len)
IObuff[len++] = ' ';
} while ((int64_t)len < 25 - over);
- IObuff[len] = '\0';
+ IObuff[len] = NUL;
msg_outtrans(IObuff, 0);
if (cmd->uc_luaref != LUA_NOREF) {
@@ -831,7 +831,7 @@ invalid_count:
}
} else {
char ch = attr[len];
- attr[len] = '\0';
+ attr[len] = NUL;
semsg(_("E181: Invalid attribute: %s"), attr);
attr[len] = ch;
return FAIL;
@@ -1056,7 +1056,7 @@ void ex_delcommand(exarg_T *eap)
const char *arg = eap->arg;
bool buffer_only = false;
- if (strncmp(arg, "-buffer", 7) == 0 && ascii_iswhite(arg[7])) {
+ if (strncmp(arg, S_LEN("-buffer")) == 0 && ascii_iswhite(arg[7])) {
buffer_only = true;
arg = skipwhite(arg + 7);
}
@@ -1274,9 +1274,9 @@ static size_t add_cmd_modifier(char *buf, char *mod_str, bool *multi_mods)
if (buf != NULL) {
if (*multi_mods) {
- STRCAT(buf, " ");
+ strcat(buf, " ");
}
- STRCAT(buf, mod_str);
+ strcat(buf, mod_str);
}
*multi_mods = true;
@@ -1364,7 +1364,7 @@ size_t uc_mods(char *buf, const cmdmod_T *cmod, bool quote)
if (quote) {
*buf++ = '"';
}
- *buf = '\0';
+ *buf = NUL;
}
// the modifiers that are simple flags
diff --git a/src/nvim/window.c b/src/nvim/window.c
index 1a6c3f7263..732ba6566b 100644
--- a/src/nvim/window.c
+++ b/src/nvim/window.c
@@ -22,6 +22,7 @@
#include "nvim/diff.h"
#include "nvim/drawscreen.h"
#include "nvim/edit.h"
+#include "nvim/errors.h"
#include "nvim/eval.h"
#include "nvim/eval/typval.h"
#include "nvim/eval/typval_defs.h"
@@ -788,7 +789,7 @@ int win_fdccol_count(win_T *wp)
const char *fdc = wp->w_p_fdc;
// auto:<NUM>
- if (strncmp(fdc, "auto", 4) == 0) {
+ if (strncmp(fdc, S_LEN("auto")) == 0) {
const int fdccol = fdc[4] == ':' ? fdc[5] - '0' : 1;
int needed_fdccols = getDeepestNesting(wp);
return MIN(fdccol, needed_fdccols);
diff --git a/src/nvim/winfloat.c b/src/nvim/winfloat.c
index e3ca0ff139..77bbaed105 100644
--- a/src/nvim/winfloat.c
+++ b/src/nvim/winfloat.c
@@ -11,6 +11,7 @@
#include "nvim/autocmd.h"
#include "nvim/buffer_defs.h"
#include "nvim/drawscreen.h"
+#include "nvim/errors.h"
#include "nvim/globals.h"
#include "nvim/grid.h"
#include "nvim/grid_defs.h"
diff --git a/test/functional/fixtures/fake-lsp-server.lua b/test/functional/fixtures/fake-lsp-server.lua
index 9aafd38d4f..f806869b40 100644
--- a/test/functional/fixtures/fake-lsp-server.lua
+++ b/test/functional/fixtures/fake-lsp-server.lua
@@ -471,7 +471,7 @@ function tests.basic_check_buffer_open()
languageId = '',
text = table.concat({ 'testing', '123' }, '\n') .. '\n',
uri = 'file://',
- version = 2,
+ version = 0,
},
})
expect_notification('finish')
@@ -498,7 +498,7 @@ function tests.basic_check_buffer_open_and_change()
languageId = '',
text = table.concat({ 'testing', '123' }, '\n') .. '\n',
uri = 'file://',
- version = 2,
+ version = 0,
},
})
expect_notification('textDocument/didChange', {
@@ -534,7 +534,7 @@ function tests.basic_check_buffer_open_and_change_noeol()
languageId = '',
text = table.concat({ 'testing', '123' }, '\n'),
uri = 'file://',
- version = 2,
+ version = 0,
},
})
expect_notification('textDocument/didChange', {
@@ -569,7 +569,7 @@ function tests.basic_check_buffer_open_and_change_multi()
languageId = '',
text = table.concat({ 'testing', '123' }, '\n') .. '\n',
uri = 'file://',
- version = 2,
+ version = 0,
},
})
expect_notification('textDocument/didChange', {
@@ -614,7 +614,7 @@ function tests.basic_check_buffer_open_and_change_multi_and_close()
languageId = '',
text = table.concat({ 'testing', '123' }, '\n') .. '\n',
uri = 'file://',
- version = 2,
+ version = 0,
},
})
expect_notification('textDocument/didChange', {
@@ -672,7 +672,7 @@ function tests.basic_check_buffer_open_and_change_incremental()
languageId = '',
text = table.concat({ 'testing', '123' }, '\n') .. '\n',
uri = 'file://',
- version = 2,
+ version = 0,
},
})
expect_notification('textDocument/didChange', {
@@ -715,7 +715,7 @@ function tests.basic_check_buffer_open_and_change_incremental_editing()
languageId = '',
text = table.concat({ 'testing', '123' }, '\n'),
uri = 'file://',
- version = 2,
+ version = 0,
},
})
expect_notification('textDocument/didChange', {
diff --git a/test/functional/lua/buffer_updates_spec.lua b/test/functional/lua/buffer_updates_spec.lua
index d4af7e4732..6b575ad0ef 100644
--- a/test/functional/lua/buffer_updates_spec.lua
+++ b/test/functional/lua/buffer_updates_spec.lua
@@ -379,6 +379,25 @@ describe('lua buffer event callbacks: on_lines', function()
]],
})
end)
+
+ it('line lengths are correct when pressing TAB with folding #29119', function()
+ api.nvim_buf_set_lines(0, 0, -1, true, { 'a', 'b' })
+
+ exec_lua([[
+ _G.res = {}
+ vim.o.foldmethod = 'indent'
+ vim.o.softtabstop = -1
+ vim.api.nvim_buf_attach(0, false, {
+ on_lines = function(_, bufnr, _, row, _, end_row)
+ local lines = vim.api.nvim_buf_get_lines(bufnr, row, end_row, true)
+ table.insert(_G.res, lines)
+ end
+ })
+ ]])
+
+ feed('i<Tab>')
+ eq({ '\ta' }, exec_lua('return _G.res[#_G.res]'))
+ end)
end)
describe('lua: nvim_buf_attach on_bytes', function()
diff --git a/test/functional/lua/diagnostic_spec.lua b/test/functional/lua/diagnostic_spec.lua
index a4f882e363..decb58dc4d 100644
--- a/test/functional/lua/diagnostic_spec.lua
+++ b/test/functional/lua/diagnostic_spec.lua
@@ -2291,6 +2291,38 @@ describe('vim.diagnostic', function()
return lines
]]
)
+
+ -- End position is exclusive
+ eq(
+ vim.NIL,
+ exec_lua [[
+ local diagnostics = {
+ make_error("Syntax error", 1, 1, 2, 0),
+ }
+ vim.api.nvim_win_set_buf(0, diagnostic_bufnr)
+ vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, diagnostics)
+ vim.api.nvim_win_set_cursor(0, {1, 1})
+ local _, winnr = vim.diagnostic.open_float(0, {header=false, pos={2,0}})
+ return winnr
+ ]]
+ )
+
+ -- Works when width == 0
+ eq(
+ { '1. Syntax error' },
+ exec_lua [[
+ local diagnostics = {
+ make_error("Syntax error", 2, 0, 2, 0),
+ }
+ vim.api.nvim_win_set_buf(0, diagnostic_bufnr)
+ vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, diagnostics)
+ vim.api.nvim_win_set_cursor(0, {1, 1})
+ local float_bufnr, winnr = vim.diagnostic.open_float(0, {header=false, pos={2,1}})
+ local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false)
+ vim.api.nvim_win_close(winnr, true)
+ return lines
+ ]]
+ )
end)
it('can show diagnostics from a specific position', function()
@@ -2299,7 +2331,7 @@ describe('vim.diagnostic', function()
{ 'Syntax error' },
exec_lua [[
local diagnostics = {
- make_error("Syntax error", 1, 1, 1, 2),
+ make_error("Syntax error", 1, 1, 1, 3),
make_warning("Some warning", 1, 3, 1, 4),
}
vim.api.nvim_win_set_buf(0, diagnostic_bufnr)
@@ -2317,7 +2349,7 @@ describe('vim.diagnostic', function()
{ 'Some warning' },
exec_lua [[
local diagnostics = {
- make_error("Syntax error", 1, 1, 1, 2),
+ make_error("Syntax error", 1, 1, 1, 3),
make_warning("Some warning", 1, 3, 1, 4),
}
vim.api.nvim_win_set_buf(0, diagnostic_bufnr)
@@ -2347,6 +2379,38 @@ describe('vim.diagnostic', function()
return lines
]]
)
+
+ -- End position is exclusive
+ eq(
+ vim.NIL,
+ exec_lua [[
+ local diagnostics = {
+ make_error("Syntax error", 1, 1, 1, 3),
+ }
+ vim.api.nvim_win_set_buf(0, diagnostic_bufnr)
+ vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, diagnostics)
+ vim.api.nvim_win_set_cursor(0, {1, 1})
+ local _, winnr = vim.diagnostic.open_float(0, {header=false, scope="cursor", pos={1,3}})
+ return winnr
+ ]]
+ )
+
+ -- Works when width == 0
+ eq(
+ { 'Syntax error' },
+ exec_lua [[
+ local diagnostics = {
+ make_error("Syntax error", 2, 0, 2, 0),
+ }
+ vim.api.nvim_win_set_buf(0, diagnostic_bufnr)
+ vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, diagnostics)
+ vim.api.nvim_win_set_cursor(0, {1, 1})
+ local float_bufnr, winnr = vim.diagnostic.open_float({header=false, scope="cursor", pos={2,1}})
+ local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false)
+ vim.api.nvim_win_close(winnr, true)
+ return lines
+ ]]
+ )
end)
it(
@@ -2755,20 +2819,32 @@ describe('vim.diagnostic', function()
end)
it('works for multi-line diagnostics #21949', function()
- -- open float failed non diagnostic lnum
- eq(
- vim.NIL,
- exec_lua [[
+ -- create diagnostic
+ exec_lua [[
local diagnostics = {
make_error("Error in two lines lnum is 1 and end_lnum is 2", 1, 1, 2, 3),
}
- local winids = {}
vim.api.nvim_win_set_buf(0, diagnostic_bufnr)
vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, diagnostics)
+ ]]
+
+ -- open float failed non diagnostic lnum
+ eq(
+ vim.NIL,
+ exec_lua [[
+ vim.api.nvim_win_set_cursor(0, {1, 0})
local _, winnr = vim.diagnostic.open_float(0, { header = false })
return winnr
]]
)
+ eq(
+ vim.NIL,
+ exec_lua [[
+ vim.api.nvim_win_set_cursor(0, {1, 0})
+ local _, winnr = vim.diagnostic.open_float(0, { header = false, scope = "cursor" })
+ return winnr
+ ]]
+ )
-- can open a float window on lnum 1
eq(
@@ -2782,6 +2858,18 @@ describe('vim.diagnostic', function()
]]
)
+ -- can open a cursor-scoped float window on lnum 1
+ eq(
+ { 'Error in two lines lnum is 1 and end_lnum is 2' },
+ exec_lua [[
+ vim.api.nvim_win_set_cursor(0, {2, 1})
+ local float_bufnr, winnr = vim.diagnostic.open_float(0, { header = false, scope = "cursor" })
+ local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false)
+ vim.api.nvim_win_close(winnr, true)
+ return lines
+ ]]
+ )
+
-- can open a float window on end_lnum 2
eq(
{ '1. Error in two lines lnum is 1 and end_lnum is 2' },
@@ -2793,6 +2881,18 @@ describe('vim.diagnostic', function()
return lines
]]
)
+
+ -- can open a cursor-scoped float window on end_lnum 2
+ eq(
+ { 'Error in two lines lnum is 1 and end_lnum is 2' },
+ exec_lua [[
+ vim.api.nvim_win_set_cursor(0, {3, 2})
+ local float_bufnr, winnr = vim.diagnostic.open_float(0, { header = false, scope = "cursor" })
+ local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false)
+ vim.api.nvim_win_close(winnr, true)
+ return lines
+ ]]
+ )
end)
end)
diff --git a/test/functional/lua/glob_spec.lua b/test/functional/lua/glob_spec.lua
index 56cd4c9bb5..b3e1b79ee7 100644
--- a/test/functional/lua/glob_spec.lua
+++ b/test/functional/lua/glob_spec.lua
@@ -161,7 +161,7 @@ describe('glob', function()
eq(false, match('{ab,cd}', 'a'))
eq(true, match('{ab,cd}', 'cd'))
eq(true, match('{a,b,c}', 'c'))
- eq(true, match('{a,{b,c}}', 'c'))
+ eq(false, match('{a,{b,c}}', 'c')) -- {} cannot nest
end)
it('should match [] groups', function()
@@ -223,6 +223,17 @@ describe('glob', function()
eq(true, match('{[0-9],[a-z]}', '0'))
eq(true, match('{[0-9],[a-z]}', 'a'))
eq(false, match('{[0-9],[a-z]}', 'A'))
+
+ -- glob is from willRename filter in typescript-language-server
+ -- https://github.com/typescript-language-server/typescript-language-server/blob/b224b878652438bcdd639137a6b1d1a6630129e4/src/lsp-server.ts#L266
+ eq(true, match('**/*.{ts,js,jsx,tsx,mjs,mts,cjs,cts}', 'test.js'))
+ eq(true, match('**/*.{ts,js,jsx,tsx,mjs,mts,cjs,cts}', 'test.ts'))
+ eq(true, match('**/*.{ts,js,jsx,tsx,mjs,mts,cjs,cts}', 'test.mts'))
+ eq(true, match('**/*.{ts,js,jsx,tsx,mjs,mts,cjs,cts}', 'test.mjs'))
+ eq(true, match('**/*.{ts,js,jsx,tsx,mjs,mts,cjs,cts}', 'test.cjs'))
+ eq(true, match('**/*.{ts,js,jsx,tsx,mjs,mts,cjs,cts}', 'test.cts'))
+ eq(true, match('**/*.{ts,js,jsx,tsx,mjs,mts,cjs,cts}', 'test.jsx'))
+ eq(true, match('**/*.{ts,js,jsx,tsx,mjs,mts,cjs,cts}', 'test.tsx'))
end)
end)
end)
diff --git a/test/functional/lua/highlight_spec.lua b/test/functional/lua/highlight_spec.lua
index 8f099ac233..ad709a06f1 100644
--- a/test/functional/lua/highlight_spec.lua
+++ b/test/functional/lua/highlight_spec.lua
@@ -4,7 +4,6 @@ local Screen = require('test.functional.ui.screen')
local exec_lua = n.exec_lua
local eq = t.eq
-local neq = t.neq
local eval = n.eval
local command = n.command
local clear = n.clear
@@ -90,6 +89,22 @@ describe('vim.highlight.range', function()
|
]])
end)
+
+ it('can use -1 or v:maxcol to indicate end of line', function()
+ exec_lua([[
+ local ns = vim.api.nvim_create_namespace('')
+ vim.highlight.range(0, ns, 'Search', { 0, 4 }, { 1, -1 }, {})
+ vim.highlight.range(0, ns, 'Search', { 2, 6 }, { 3, vim.v.maxcol }, {})
+ ]])
+ screen:expect([[
+ ^asdf{10:ghjkl}{100:$} |
+ {10:«口=口»}{100:$} |
+ qwerty{10:uiop}{100:$} |
+ {10:口口=口口}{1:$} |
+ zxcvbnm{1:$} |
+ |
+ ]])
+ end)
end)
describe('vim.highlight.on_yank', function()
@@ -126,9 +141,11 @@ describe('vim.highlight.on_yank', function()
vim.api.nvim_buf_set_mark(0,"]",1,1,{})
vim.highlight.on_yank({timeout = math.huge, on_macro = true, event = {operator = "y"}})
]])
- neq({}, api.nvim__win_get_ns(0))
+ local ns = api.nvim_create_namespace('hlyank')
+ local win = api.nvim_get_current_win()
+ eq({ win }, api.nvim__ns_get(ns).wins)
command('wincmd w')
- eq({}, api.nvim__win_get_ns(0))
+ eq({ win }, api.nvim__ns_get(ns).wins)
end)
it('removes old highlight if new one is created before old one times out', function()
@@ -138,14 +155,17 @@ describe('vim.highlight.on_yank', function()
vim.api.nvim_buf_set_mark(0,"]",1,1,{})
vim.highlight.on_yank({timeout = math.huge, on_macro = true, event = {operator = "y"}})
]])
- neq({}, api.nvim__win_get_ns(0))
+ local ns = api.nvim_create_namespace('hlyank')
+ eq(api.nvim_get_current_win(), api.nvim__ns_get(ns).wins[1])
command('wincmd w')
exec_lua([[
vim.api.nvim_buf_set_mark(0,"[",1,1,{})
vim.api.nvim_buf_set_mark(0,"]",1,1,{})
vim.highlight.on_yank({timeout = math.huge, on_macro = true, event = {operator = "y"}})
]])
+ local win = api.nvim_get_current_win()
+ eq({ win }, api.nvim__ns_get(ns).wins)
command('wincmd w')
- eq({}, api.nvim__win_get_ns(0))
+ eq({ win }, api.nvim__ns_get(ns).wins)
end)
end)
diff --git a/test/functional/lua/runtime_spec.lua b/test/functional/lua/runtime_spec.lua
index c6b0577ebe..f63363d6d9 100644
--- a/test/functional/lua/runtime_spec.lua
+++ b/test/functional/lua/runtime_spec.lua
@@ -406,7 +406,7 @@ describe('runtime:', function()
eq('', eval('&commentstring'))
eq('', eval('&omnifunc'))
exec('edit file.cpp')
- eq('/*%s*/', eval('&commentstring'))
+ eq('// %s', eval('&commentstring'))
eq('ccomplete#Complete', eval('&omnifunc'))
end)
end)
diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua
index d50b646085..23bb9f0a2e 100644
--- a/test/functional/lua/vim_spec.lua
+++ b/test/functional/lua/vim_spec.lua
@@ -135,14 +135,15 @@ describe('lua stdlib', function()
-- See MAINTAIN.md for the soft/hard deprecation policy
describe(('vim.deprecate prerel=%s,'):format(prerel or 'nil'), function()
- local curver = exec_lua('return vim.version()') --[[@as {major:number, minor:number}]]
- -- "0.10" or "0.10-dev+xxx"
- local curstr = ('%s.%s%s'):format(curver.major, curver.minor, prerel or '')
- -- "0.10" or "0.11"
- local nextver = ('%s.%s'):format(curver.major, curver.minor + (prerel and 0 or 1))
- local was_removed = prerel and 'was removed' or 'will be removed'
+ local curver --- @type {major:number, minor:number}
+
+ before_each(function()
+ curver = exec_lua('return vim.version()')
+ end)
it('plugin=nil, same message skipped', function()
+ -- "0.10" or "0.10-dev+xxx"
+ local curstr = ('%s.%s%s'):format(curver.major, curver.minor, prerel or '')
eq(
dedent(
[[
@@ -162,6 +163,10 @@ describe('lua stdlib', function()
end)
it('plugin=nil, show error if hard-deprecated', function()
+ -- "0.10" or "0.11"
+ local nextver = ('%s.%s'):format(curver.major, curver.minor + (prerel and 0 or 1))
+
+ local was_removed = prerel and 'was removed' or 'will be removed'
eq(
dedent(
[[
@@ -2023,6 +2028,10 @@ describe('lua stdlib', function()
vim.cmd "enew"
]]
eq(100, fn.luaeval 'vim.wo.scrolloff')
+
+ matches('only bufnr=0 is supported', pcall_err(exec_lua, 'vim.wo[0][10].signcolumn = "no"'))
+
+ matches('only bufnr=0 is supported', pcall_err(exec_lua, 'local a = vim.wo[0][10].signcolumn'))
end)
describe('vim.opt', function()
diff --git a/test/functional/lua/with_spec.lua b/test/functional/lua/with_spec.lua
new file mode 100644
index 0000000000..36dee9630a
--- /dev/null
+++ b/test/functional/lua/with_spec.lua
@@ -0,0 +1,292 @@
+local t = require('test.testutil')
+local n = require('test.functional.testnvim')()
+local Screen = require('test.functional.ui.screen')
+
+local fn = n.fn
+local api = n.api
+local command = n.command
+local eq = t.eq
+local exec_lua = n.exec_lua
+local matches = t.matches
+local pcall_err = t.pcall_err
+
+before_each(function()
+ n.clear()
+end)
+
+describe('vim._with {buf = }', function()
+ it('does not trigger autocmd', function()
+ exec_lua [[
+ local new = vim.api.nvim_create_buf(false, true)
+ vim.api.nvim_create_autocmd( { 'BufEnter', 'BufLeave', 'BufWinEnter', 'BufWinLeave' }, {
+ callback = function() _G.n = (_G.n or 0) + 1 end
+ })
+ vim._with({buf = new}, function()
+ end)
+ assert(_G.n == nil)
+ ]]
+ end)
+
+ it('trigger autocmd if changed within context', function()
+ exec_lua [[
+ local new = vim.api.nvim_create_buf(false, true)
+ vim.api.nvim_create_autocmd( { 'BufEnter', 'BufLeave', 'BufWinEnter', 'BufWinLeave' }, {
+ callback = function() _G.n = (_G.n or 0) + 1 end
+ })
+ vim._with({}, function()
+ vim.api.nvim_set_current_buf(new)
+ assert(_G.n ~= nil)
+ end)
+ ]]
+ end)
+
+ it('can access buf options', function()
+ local buf1 = api.nvim_get_current_buf()
+ local buf2 = exec_lua [[
+ buf2 = vim.api.nvim_create_buf(false, true)
+ return buf2
+ ]]
+
+ eq(false, api.nvim_get_option_value('autoindent', { buf = buf1 }))
+ eq(false, api.nvim_get_option_value('autoindent', { buf = buf2 }))
+
+ local val = exec_lua [[
+ return vim._with({buf = buf2}, function()
+ vim.cmd "set autoindent"
+ return vim.api.nvim_get_current_buf()
+ end)
+ ]]
+
+ eq(false, api.nvim_get_option_value('autoindent', { buf = buf1 }))
+ eq(true, api.nvim_get_option_value('autoindent', { buf = buf2 }))
+ eq(buf1, api.nvim_get_current_buf())
+ eq(buf2, val)
+ end)
+
+ it('does not cause ml_get errors with invalid visual selection', function()
+ exec_lua [[
+ local api = vim.api
+ local t = function(s) return api.nvim_replace_termcodes(s, true, true, true) end
+ api.nvim_buf_set_lines(0, 0, -1, true, {"a", "b", "c"})
+ api.nvim_feedkeys(t "G<C-V>", "txn", false)
+ vim._with({buf = api.nvim_create_buf(false, true)}, function() vim.cmd "redraw" end)
+ ]]
+ end)
+
+ it('can be nested crazily with hidden buffers', function()
+ eq(
+ true,
+ exec_lua([[
+ local function scratch_buf_call(fn)
+ local buf = vim.api.nvim_create_buf(false, true)
+ vim.api.nvim_set_option_value('cindent', true, {buf = buf})
+ return vim._with({buf = buf}, function()
+ return vim.api.nvim_get_current_buf() == buf
+ and vim.api.nvim_get_option_value('cindent', {buf = buf})
+ and fn()
+ end) and vim.api.nvim_buf_delete(buf, {}) == nil
+ end
+
+ return scratch_buf_call(function()
+ return scratch_buf_call(function()
+ return scratch_buf_call(function()
+ return scratch_buf_call(function()
+ return scratch_buf_call(function()
+ return scratch_buf_call(function()
+ return scratch_buf_call(function()
+ return scratch_buf_call(function()
+ return scratch_buf_call(function()
+ return scratch_buf_call(function()
+ return scratch_buf_call(function()
+ return scratch_buf_call(function()
+ return true
+ end)
+ end)
+ end)
+ end)
+ end)
+ end)
+ end)
+ end)
+ end)
+ end)
+ end)
+ end)
+ ]])
+ )
+ end)
+
+ it('can return values by reference', function()
+ eq(
+ { 4, 7 },
+ exec_lua [[
+ local val = {4, 10}
+ local ref = vim._with({ buf = 0}, function() return val end)
+ ref[2] = 7
+ return val
+ ]]
+ )
+ end)
+end)
+
+describe('vim._with {win = }', function()
+ it('does not trigger autocmd', function()
+ exec_lua [[
+ local old = vim.api.nvim_get_current_win()
+ vim.cmd("new")
+ local new = vim.api.nvim_get_current_win()
+ vim.api.nvim_create_autocmd( { 'WinEnter', 'WinLeave' }, {
+ callback = function() _G.n = (_G.n or 0) + 1 end
+ })
+ vim._with({win = old}, function()
+ end)
+ assert(_G.n == nil)
+ ]]
+ end)
+
+ it('trigger autocmd if changed within context', function()
+ exec_lua [[
+ local old = vim.api.nvim_get_current_win()
+ vim.cmd("new")
+ local new = vim.api.nvim_get_current_win()
+ vim.api.nvim_create_autocmd( { 'WinEnter', 'WinLeave' }, {
+ callback = function() _G.n = (_G.n or 0) + 1 end
+ })
+ vim._with({}, function()
+ vim.api.nvim_set_current_win(old)
+ assert(_G.n ~= nil)
+ end)
+ ]]
+ end)
+
+ it('can access window options', function()
+ command('vsplit')
+ local win1 = api.nvim_get_current_win()
+ command('wincmd w')
+ local win2 = exec_lua [[
+ win2 = vim.api.nvim_get_current_win()
+ return win2
+ ]]
+ command('wincmd p')
+
+ eq('', api.nvim_get_option_value('winhighlight', { win = win1 }))
+ eq('', api.nvim_get_option_value('winhighlight', { win = win2 }))
+
+ local val = exec_lua [[
+ return vim._with({win = win2}, function()
+ vim.cmd "setlocal winhighlight=Normal:Normal"
+ return vim.api.nvim_get_current_win()
+ end)
+ ]]
+
+ eq('', api.nvim_get_option_value('winhighlight', { win = win1 }))
+ eq('Normal:Normal', api.nvim_get_option_value('winhighlight', { win = win2 }))
+ eq(win1, api.nvim_get_current_win())
+ eq(win2, val)
+ end)
+
+ it('does not cause ml_get errors with invalid visual selection', function()
+ -- Add lines to the current buffer and make another window looking into an empty buffer.
+ exec_lua [[
+ _G.api = vim.api
+ _G.t = function(s) return api.nvim_replace_termcodes(s, true, true, true) end
+ _G.win_lines = api.nvim_get_current_win()
+ vim.cmd "new"
+ _G.win_empty = api.nvim_get_current_win()
+ api.nvim_set_current_win(win_lines)
+ api.nvim_buf_set_lines(0, 0, -1, true, {"a", "b", "c"})
+ ]]
+
+ -- Start Visual in current window, redraw in other window with fewer lines.
+ exec_lua [[
+ api.nvim_feedkeys(t "G<C-V>", "txn", false)
+ vim._with({win = win_empty}, function() vim.cmd "redraw" end)
+ ]]
+
+ -- Start Visual in current window, extend it in other window with more lines.
+ exec_lua [[
+ api.nvim_feedkeys(t "<Esc>gg", "txn", false)
+ api.nvim_set_current_win(win_empty)
+ api.nvim_feedkeys(t "gg<C-V>", "txn", false)
+ vim._with({win = win_lines}, function() api.nvim_feedkeys(t "G<C-V>", "txn", false) end)
+ vim.cmd "redraw"
+ ]]
+ end)
+
+ it('updates ruler if cursor moved', function()
+ local screen = Screen.new(30, 5)
+ screen:set_default_attr_ids {
+ [1] = { reverse = true },
+ [2] = { bold = true, reverse = true },
+ }
+ screen:attach()
+ exec_lua [[
+ _G.api = vim.api
+ vim.opt.ruler = true
+ local lines = {}
+ for i = 0, 499 do lines[#lines + 1] = tostring(i) end
+ api.nvim_buf_set_lines(0, 0, -1, true, lines)
+ api.nvim_win_set_cursor(0, {20, 0})
+ vim.cmd "split"
+ _G.win = api.nvim_get_current_win()
+ vim.cmd "wincmd w | redraw"
+ ]]
+ screen:expect [[
+ 19 |
+ {1:[No Name] [+] 20,1 3%}|
+ ^19 |
+ {2:[No Name] [+] 20,1 3%}|
+ |
+ ]]
+ exec_lua [[
+ vim._with({win = win}, function() api.nvim_win_set_cursor(0, {100, 0}) end)
+ vim.cmd "redraw"
+ ]]
+ screen:expect [[
+ 99 |
+ {1:[No Name] [+] 100,1 19%}|
+ ^19 |
+ {2:[No Name] [+] 20,1 3%}|
+ |
+ ]]
+ end)
+
+ it('can return values by reference', function()
+ eq(
+ { 7, 10 },
+ exec_lua [[
+ local val = {4, 10}
+ local ref = vim._with({win = 0}, function() return val end)
+ ref[1] = 7
+ return val
+ ]]
+ )
+ end)
+
+ it('layout in current tabpage does not affect windows in others', function()
+ command('tab split')
+ local t2_move_win = api.nvim_get_current_win()
+ command('vsplit')
+ local t2_other_win = api.nvim_get_current_win()
+ command('tabprevious')
+ matches('E36: Not enough room$', pcall_err(command, 'execute "split|"->repeat(&lines)'))
+ command('vsplit')
+
+ exec_lua('vim._with({win = ...}, function() vim.cmd.wincmd "J" end)', t2_move_win)
+ eq({ 'col', { { 'leaf', t2_other_win }, { 'leaf', t2_move_win } } }, fn.winlayout(2))
+ end)
+end)
+
+describe('vim._with {lockmarks = true}', function()
+ it('is reset', function()
+ local mark = exec_lua [[
+ vim.api.nvim_buf_set_lines(0, 0, 0, false, {"marky", "snarky", "malarkey"})
+ vim.api.nvim_buf_set_mark(0,"m",1,0, {})
+ vim._with({lockmarks = true}, function()
+ vim.api.nvim_buf_set_lines(0, 0, 2, false, {"mass", "mess", "moss"})
+ end)
+ return vim.api.nvim_buf_get_mark(0,"m")
+ ]]
+ t.eq(mark, { 1, 0 })
+ end)
+end)
diff --git a/test/functional/plugin/editorconfig_spec.lua b/test/functional/plugin/editorconfig_spec.lua
index 839a723405..242ed9b57f 100644
--- a/test/functional/plugin/editorconfig_spec.lua
+++ b/test/functional/plugin/editorconfig_spec.lua
@@ -16,8 +16,16 @@ local testdir = 'Xtest-editorconfig'
local function test_case(name, expected)
local filename = testdir .. pathsep .. name
command('edit ' .. filename)
+
for opt, val in pairs(expected) do
- eq(val, api.nvim_get_option_value(opt, { buf = 0 }), name)
+ local opt_info = api.nvim_get_option_info2(opt, {})
+ if opt_info.scope == 'win' then
+ eq(val, api.nvim_get_option_value(opt, { win = 0 }), name)
+ elseif opt_info.scope == 'buf' then
+ eq(val, api.nvim_get_option_value(opt, { buf = 0 }), name)
+ else
+ eq(val, api.nvim_get_option_value(opt, {}), name)
+ end
end
end
@@ -93,6 +101,12 @@ setup(function()
[max_line_length.txt]
max_line_length = 42
+
+ [short_spelling_language.txt]
+ spelling_language = de
+
+ [long_spelling_language.txt]
+ spelling_language = en-NZ
]]
)
end)
@@ -222,4 +236,9 @@ But not this one
eq(true, ok, err)
end)
+
+ it('sets spelllang', function()
+ test_case('short_spelling_language.txt', { spelllang = 'de' })
+ test_case('long_spelling_language.txt', { spelllang = 'en_nz' })
+ end)
end)
diff --git a/test/functional/plugin/lsp/completion_spec.lua b/test/functional/plugin/lsp/completion_spec.lua
index d7755dd0c4..0e81e4fddb 100644
--- a/test/functional/plugin/lsp/completion_spec.lua
+++ b/test/functional/plugin/lsp/completion_spec.lua
@@ -126,6 +126,41 @@ describe('vim.lsp.completion: item conversion', function()
eq(expected, result)
end)
+ it('trims trailing newline or tab from textEdit', function()
+ local range0 = {
+ start = { line = 0, character = 0 },
+ ['end'] = { line = 0, character = 0 },
+ }
+ local items = {
+ {
+ detail = 'ansible.builtin',
+ filterText = 'lineinfile ansible.builtin.lineinfile builtin ansible',
+ kind = 7,
+ label = 'ansible.builtin.lineinfile',
+ sortText = '2_ansible.builtin.lineinfile',
+ textEdit = {
+ newText = 'ansible.builtin.lineinfile:\n ',
+ range = range0,
+ },
+ },
+ }
+ local result = complete('|', items)
+ result = vim.tbl_map(function(x)
+ return {
+ abbr = x.abbr,
+ word = x.word,
+ }
+ end, result.items)
+
+ local expected = {
+ {
+ abbr = 'ansible.builtin.lineinfile',
+ word = 'ansible.builtin.lineinfile:',
+ },
+ }
+ eq(expected, result)
+ end)
+
it('prefers wordlike components for snippets', function()
-- There are two goals here:
--
@@ -408,7 +443,7 @@ describe('vim.lsp.completion: protocol', function()
end)
end
- --- @param pos { [1]: integer, [2]: integer }
+ --- @param pos [integer, integer]
local function trigger_at_pos(pos)
exec_lua(
[[
diff --git a/test/functional/plugin/lsp/semantic_tokens_spec.lua b/test/functional/plugin/lsp/semantic_tokens_spec.lua
index 9babb080e7..7908c5d2e7 100644
--- a/test/functional/plugin/lsp/semantic_tokens_spec.lua
+++ b/test/functional/plugin/lsp/semantic_tokens_spec.lua
@@ -111,7 +111,6 @@ describe('semantic token highlighting', function()
end)
it('buffer is highlighted when attached', function()
- insert(text)
exec_lua([[
bufnr = vim.api.nvim_get_current_buf()
vim.api.nvim_win_set_buf(0, bufnr)
@@ -119,6 +118,8 @@ describe('semantic token highlighting', function()
client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd })
]])
+ insert(text)
+
screen:expect {
grid = [[
#include <iostream> |
@@ -140,7 +141,6 @@ describe('semantic token highlighting', function()
end)
it('use LspTokenUpdate and highlight_token', function()
- insert(text)
exec_lua([[
vim.api.nvim_create_autocmd("LspTokenUpdate", {
callback = function(args)
@@ -157,6 +157,8 @@ describe('semantic token highlighting', function()
client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd })
]])
+ insert(text)
+
screen:expect {
grid = [[
#include <iostream> |
@@ -178,17 +180,14 @@ describe('semantic token highlighting', function()
end)
it('buffer is unhighlighted when client is detached', function()
- insert(text)
-
exec_lua([[
bufnr = vim.api.nvim_get_current_buf()
vim.api.nvim_win_set_buf(0, bufnr)
client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd })
- vim.wait(1000, function()
- return #server.messages > 1
- end)
]])
+ insert(text)
+
exec_lua([[
vim.notify = function() end
vim.lsp.buf_detach_client(bufnr, client_id)
@@ -332,13 +331,14 @@ describe('semantic token highlighting', function()
end)
it('buffer is re-highlighted when force refreshed', function()
- insert(text)
exec_lua([[
bufnr = vim.api.nvim_get_current_buf()
vim.api.nvim_win_set_buf(0, bufnr)
client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd })
]])
+ insert(text)
+
screen:expect {
grid = [[
#include <iostream> |
@@ -412,14 +412,13 @@ describe('semantic token highlighting', function()
end)
it('updates highlights with delta request on buffer change', function()
- insert(text)
-
exec_lua([[
bufnr = vim.api.nvim_get_current_buf()
vim.api.nvim_win_set_buf(0, bufnr)
client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd })
]])
+ insert(text)
screen:expect {
grid = [[
#include <iostream> |
@@ -598,7 +597,6 @@ describe('semantic token highlighting', function()
end)
it('does not send delta requests if not supported by server', function()
- insert(text)
exec_lua(
[[
local legend, response, edit_response = ...
@@ -627,6 +625,7 @@ describe('semantic token highlighting', function()
edit_response
)
+ insert(text)
screen:expect {
grid = [[
#include <iostream> |
@@ -1450,7 +1449,6 @@ int main()
},
}) do
it(test.it, function()
- insert(test.text1)
exec_lua(create_server_definition)
exec_lua(
[[
@@ -1487,6 +1485,8 @@ int main()
test.response2
)
+ insert(test.text1)
+
test.expected_screen1()
local highlights = exec_lua([[
diff --git a/test/functional/plugin/lsp_spec.lua b/test/functional/plugin/lsp_spec.lua
index 85891e59b5..50e9c0cc0f 100644
--- a/test/functional/plugin/lsp_spec.lua
+++ b/test/functional/plugin/lsp_spec.lua
@@ -255,7 +255,7 @@ describe('LSP', function()
return
end
local expected_handlers = {
- { NIL, {}, { method = 'shutdown', bufnr = 1, client_id = 1, version = 2 } },
+ { NIL, {}, { method = 'shutdown', bufnr = 1, client_id = 1 } },
{ NIL, {}, { method = 'test', client_id = 1 } },
}
test_rpc_server {
@@ -948,11 +948,7 @@ describe('LSP', function()
it('should forward ContentModified to callback', function()
local expected_handlers = {
{ NIL, {}, { method = 'finish', client_id = 1 } },
- {
- { code = -32801 },
- NIL,
- { method = 'error_code_test', bufnr = 1, client_id = 1, version = 2 },
- },
+ { { code = -32801 }, NIL, { method = 'error_code_test', bufnr = 1, client_id = 1 } },
}
local client --- @type vim.lsp.Client
test_rpc_server {
@@ -982,7 +978,7 @@ describe('LSP', function()
it('should track pending requests to the language server', function()
local expected_handlers = {
{ NIL, {}, { method = 'finish', client_id = 1 } },
- { NIL, {}, { method = 'slow_request', bufnr = 1, client_id = 1, version = 2 } },
+ { NIL, {}, { method = 'slow_request', bufnr = 1, client_id = 1 } },
}
local client --- @type vim.lsp.Client
test_rpc_server {
@@ -1049,7 +1045,7 @@ describe('LSP', function()
it('should clear pending and cancel requests on reply', function()
local expected_handlers = {
{ NIL, {}, { method = 'finish', client_id = 1 } },
- { NIL, {}, { method = 'slow_request', bufnr = 1, client_id = 1, version = 2 } },
+ { NIL, {}, { method = 'slow_request', bufnr = 1, client_id = 1 } },
}
local client --- @type vim.lsp.Client
test_rpc_server {
@@ -1088,7 +1084,7 @@ describe('LSP', function()
it('should trigger LspRequest autocmd when requests table changes', function()
local expected_handlers = {
{ NIL, {}, { method = 'finish', client_id = 1 } },
- { NIL, {}, { method = 'slow_request', bufnr = 1, client_id = 1, version = 2 } },
+ { NIL, {}, { method = 'slow_request', bufnr = 1, client_id = 1 } },
}
local client --- @type vim.lsp.Client
test_rpc_server {
@@ -1368,7 +1364,6 @@ describe('LSP', function()
},
bufnr = 2,
client_id = 1,
- version = 2,
},
},
{ NIL, {}, { method = 'start', client_id = 1 } },
@@ -1794,9 +1789,9 @@ describe('LSP', function()
}
exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, 'utf-16')
eq({
- '',
- '123',
- 'fooFbar',
+ '3',
+ 'foo',
+ '12Fbar',
'123irst guy',
'baz line of text',
'The next line of text',
@@ -1818,9 +1813,9 @@ describe('LSP', function()
}
exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, 'utf-16')
eq({
- '',
- '123',
- 'fooFbar',
+ '3',
+ 'foo',
+ '12Fbar',
'123irst guy',
'baz line of text',
'The next line of text',
@@ -2122,6 +2117,7 @@ describe('LSP', function()
local args = {...}
local bufnr = select(1, ...)
local text_edit = select(2, ...)
+ vim.lsp.util.buf_versions[bufnr] = 10
vim.lsp.util.apply_text_document_edit(text_edit, nil, 'utf-16')
]],
target_bufnr,
@@ -2138,6 +2134,7 @@ describe('LSP', function()
[[
local args = {...}
local versionedBuf = args[2]
+ vim.lsp.util.buf_versions[versionedBuf.bufnr] = versionedBuf.currentVersion
vim.lsp.util.apply_text_document_edit(args[1], nil, 'utf-16')
]],
edit,
@@ -2242,6 +2239,18 @@ describe('LSP', function()
}
vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, lines)
+
+ local update_changed_tick = function()
+ vim.lsp.util.buf_versions[bufnr] = vim.api.nvim_buf_get_var(bufnr, 'changedtick')
+ end
+
+ update_changed_tick()
+ vim.api.nvim_buf_attach(bufnr, false, {
+ on_changedtick = function()
+ update_changed_tick()
+ end
+ })
+
return {bufnr, vim.api.nvim_buf_get_var(bufnr, 'changedtick')}
]]
@@ -2681,13 +2690,15 @@ describe('LSP', function()
{
filename = '/fake/uri',
lnum = 1,
+ end_lnum = 2,
col = 3,
+ end_col = 4,
text = 'testing',
user_data = {
uri = 'file:///fake/uri',
range = {
start = { line = 0, character = 2 },
- ['end'] = { line = 0, character = 3 },
+ ['end'] = { line = 1, character = 3 },
},
},
},
@@ -2701,7 +2712,7 @@ describe('LSP', function()
uri = 'file:///fake/uri',
range = {
start = { line = 0, character = 2 },
- ['end'] = { line = 0, character = 3 },
+ ['end'] = { line = 1, character = 3 },
}
},
}
@@ -2714,7 +2725,9 @@ describe('LSP', function()
{
filename = '/fake/uri',
lnum = 1,
+ end_lnum = 1,
col = 3,
+ end_col = 4,
text = 'testing',
user_data = {
targetUri = 'file:///fake/uri',
diff --git a/test/functional/plugin/man_spec.lua b/test/functional/plugin/man_spec.lua
index 978178191c..5e4ec53f8d 100644
--- a/test/functional/plugin/man_spec.lua
+++ b/test/functional/plugin/man_spec.lua
@@ -117,6 +117,29 @@ describe(':Man', function()
]])
end)
+ it('clears OSC 8 hyperlink markup from text', function()
+ feed(
+ [[
+ ithis <C-v><ESC>]8;;http://example.com<C-v><ESC>\Link Title<C-v><ESC>]8;;<C-v><ESC>\<ESC>]]
+ )
+
+ screen:expect {
+ grid = [=[
+ this {c:^[}]8;;http://example.com{c:^[}\Link Title{c:^[}]8;;{c:^[}^\ |
+ {eob:~ }|*3
+ |
+ ]=],
+ }
+
+ exec_lua [[require'man'.init_pager()]]
+
+ screen:expect([[
+ ^this Link Title |
+ {eob:~ }|*3
+ |
+ ]])
+ end)
+
it('highlights multibyte text', function()
feed(
[[
diff --git a/test/functional/script/luacats_grammar_spec.lua b/test/functional/script/luacats_grammar_spec.lua
index 6d444e1888..9c6417f7bf 100644
--- a/test/functional/script/luacats_grammar_spec.lua
+++ b/test/functional/script/luacats_grammar_spec.lua
@@ -159,4 +159,11 @@ describe('luacats grammar', function()
name = 'type',
type = '`T`',
})
+
+ test('@param type [number,string,"good"|"bad"] this is a tuple type', {
+ desc = 'this is a tuple type',
+ kind = 'param',
+ name = 'type',
+ type = '[number,string,"good"|"bad"]',
+ })
end)
diff --git a/test/functional/terminal/buffer_spec.lua b/test/functional/terminal/buffer_spec.lua
index 96abd9f543..4ad0862986 100644
--- a/test/functional/terminal/buffer_spec.lua
+++ b/test/functional/terminal/buffer_spec.lua
@@ -196,10 +196,10 @@ describe(':terminal buffer', function()
screen:expect([[
ab^c |
{4:~ }|
- {5:========== }|
+ {17:========== }|
rows: 2, cols: 50 |
{2: } |
- {1:========== }|
+ {18:========== }|
|
]])
@@ -340,7 +340,7 @@ describe(':terminal buffer', function()
eq(termbuf, eval('g:termbuf'))
end)
- it('TermReqeust synchronization #27572', function()
+ it('TermRequest synchronization #27572', function()
command('autocmd! nvim_terminal TermRequest')
local term = exec_lua([[
_G.input = {}
diff --git a/test/functional/terminal/clipboard_spec.lua b/test/functional/terminal/clipboard_spec.lua
new file mode 100644
index 0000000000..4a1a0e29fd
--- /dev/null
+++ b/test/functional/terminal/clipboard_spec.lua
@@ -0,0 +1,65 @@
+local t = require('test.testutil')
+local n = require('test.functional.testnvim')()
+
+local eq = t.eq
+local retry = t.retry
+
+local clear = n.clear
+local fn = n.fn
+local testprg = n.testprg
+local exec_lua = n.exec_lua
+local eval = n.eval
+
+describe(':terminal', function()
+ before_each(function()
+ clear()
+
+ exec_lua([[
+ local function clipboard(reg, type)
+ if type == 'copy' then
+ return function(lines)
+ local data = table.concat(lines, '\n')
+ vim.g.clipboard_data = data
+ end
+ end
+
+ if type == 'paste' then
+ return function()
+ error()
+ end
+ end
+
+ error('invalid type: ' .. type)
+ end
+
+ vim.g.clipboard = {
+ name = 'Test',
+ copy = {
+ ['+'] = clipboard('+', 'copy'),
+ ['*'] = clipboard('*', 'copy'),
+ },
+ paste = {
+ ['+'] = clipboard('+', 'paste'),
+ ['*'] = clipboard('*', 'paste'),
+ },
+ }
+ ]])
+ end)
+
+ it('can write to the system clipboard', function()
+ eq('Test', eval('g:clipboard.name'))
+
+ local text = 'Hello, world! This is some\nexample text\nthat spans multiple\nlines'
+ local encoded = exec_lua('return vim.base64.encode(...)', text)
+
+ local function osc52(arg)
+ return string.format('\027]52;;%s\027\\', arg)
+ end
+
+ fn.termopen({ testprg('shell-test'), '-t', osc52(encoded) })
+
+ retry(nil, 1000, function()
+ eq(text, exec_lua([[ return vim.g.clipboard_data ]]))
+ end)
+ end)
+end)
diff --git a/test/functional/terminal/mouse_spec.lua b/test/functional/terminal/mouse_spec.lua
index ad98dfc6c3..476e2a5fe5 100644
--- a/test/functional/terminal/mouse_spec.lua
+++ b/test/functional/terminal/mouse_spec.lua
@@ -14,10 +14,12 @@ describe(':terminal mouse', function()
before_each(function()
clear()
api.nvim_set_option_value('statusline', '==========', {})
- command('highlight StatusLine cterm=NONE')
- command('highlight StatusLineNC cterm=NONE')
- command('highlight VertSplit cterm=NONE')
screen = tt.screen_setup()
+ command('highlight StatusLine NONE')
+ command('highlight StatusLineNC NONE')
+ command('highlight StatusLineTerm NONE')
+ command('highlight StatusLineTermNC NONE')
+ command('highlight VertSplit NONE')
local lines = {}
for i = 1, 30 do
table.insert(lines, 'line' .. tostring(i))
diff --git a/test/functional/terminal/testutil.lua b/test/functional/terminal/testutil.lua
index f3fc5d3f93..45c73b1dc6 100644
--- a/test/functional/terminal/testutil.lua
+++ b/test/functional/terminal/testutil.lua
@@ -92,6 +92,8 @@ local function screen_setup(extra_rows, command, cols, env, screen_opts)
api.nvim_command('highlight TermCursor cterm=reverse')
api.nvim_command('highlight TermCursorNC ctermbg=11')
+ api.nvim_command('highlight StatusLineTerm ctermbg=2 ctermfg=0')
+ api.nvim_command('highlight StatusLineTermNC ctermbg=2 ctermfg=8')
local screen = Screen.new(cols, 7 + extra_rows)
screen:set_default_attr_ids({
@@ -111,6 +113,8 @@ local function screen_setup(extra_rows, command, cols, env, screen_opts)
[14] = { underline = true, reverse = true, bold = true },
[15] = { underline = true, foreground = 12 },
[16] = { background = 248, foreground = 0 }, -- Visual in :terminal session
+ [17] = { background = 2, foreground = 0 }, -- StatusLineTerm
+ [18] = { background = 2, foreground = 8 }, -- StatusLineTermNC
})
screen:attach(screen_opts or { rgb = false })
diff --git a/test/functional/terminal/tui_spec.lua b/test/functional/terminal/tui_spec.lua
index efa65b7441..80df336cc4 100644
--- a/test/functional/terminal/tui_spec.lua
+++ b/test/functional/terminal/tui_spec.lua
@@ -2939,6 +2939,61 @@ describe('TUI', function()
end)
end)
+ it('does not query the terminal for truecolor support if $COLORTERM is set', function()
+ clear()
+ exec_lua([[
+ vim.api.nvim_create_autocmd('TermRequest', {
+ callback = function(args)
+ local req = args.data
+ vim.g.termrequest = req
+ local xtgettcap = req:match('^\027P%+q([%x;]+)$')
+ if xtgettcap then
+ local t = {}
+ for cap in vim.gsplit(xtgettcap, ';') do
+ local resp = string.format('\027P1+r%s\027\\', xtgettcap)
+ vim.api.nvim_chan_send(vim.bo[args.buf].channel, resp)
+ t[vim.text.hexdecode(cap)] = true
+ end
+ vim.g.xtgettcap = t
+ return true
+ elseif req:match('^\027P$qm\027\\$') then
+ vim.g.decrqss = true
+ end
+ end,
+ })
+ ]])
+
+ local child_server = new_pipename()
+ screen = tt.setup_child_nvim({
+ '--listen',
+ child_server,
+ '-u',
+ 'NONE',
+ '-i',
+ 'NONE',
+ }, {
+ env = {
+ VIMRUNTIME = os.getenv('VIMRUNTIME'),
+ -- With COLORTERM=256, Nvim should not query the terminal and should not set 'tgc'
+ COLORTERM = '256',
+ TERM = 'xterm-256colors',
+ },
+ })
+
+ screen:expect({ any = '%[No Name%]' })
+
+ local child_session = n.connect(child_server)
+ retry(nil, 1000, function()
+ local xtgettcap = eval("get(g:, 'xtgettcap', {})")
+ eq(nil, xtgettcap['Tc'])
+ eq(nil, xtgettcap['RGB'])
+ eq(nil, xtgettcap['setrgbf'])
+ eq(nil, xtgettcap['setrgbb'])
+ eq(0, eval([[get(g:, 'decrqss')]]))
+ eq({ true, 0 }, { child_session:request('nvim_eval', '&termguicolors') })
+ end)
+ end)
+
it('queries the terminal for OSC 52 support', function()
clear()
exec_lua([[
diff --git a/test/functional/terminal/window_split_tab_spec.lua b/test/functional/terminal/window_split_tab_spec.lua
index 04d2e0bca7..ccd6a5218b 100644
--- a/test/functional/terminal/window_split_tab_spec.lua
+++ b/test/functional/terminal/window_split_tab_spec.lua
@@ -22,10 +22,12 @@ describe(':terminal', function()
-- set the statusline to a constant value because of variables like pid
-- and current directory and to improve visibility of splits
api.nvim_set_option_value('statusline', '==========', {})
- command('highlight StatusLine cterm=NONE')
- command('highlight StatusLineNC cterm=NONE')
- command('highlight VertSplit cterm=NONE')
screen = tt.screen_setup(3)
+ command('highlight StatusLine NONE')
+ command('highlight StatusLineNC NONE')
+ command('highlight StatusLineTerm NONE')
+ command('highlight StatusLineTermNC NONE')
+ command('highlight VertSplit NONE')
end)
after_each(function()
diff --git a/test/functional/testnvim.lua b/test/functional/testnvim.lua
index 5f24ef3fe6..5a9e7f8c29 100644
--- a/test/functional/testnvim.lua
+++ b/test/functional/testnvim.lua
@@ -256,7 +256,7 @@ end
--- @param notification_cb function?
--- @param setup_cb function?
--- @param timeout integer
---- @return {[1]: integer, [2]: string}
+--- @return [integer, string]
function M.run_session(lsession, request_cb, notification_cb, setup_cb, timeout)
local on_request --- @type function?
local on_notification --- @type function?
diff --git a/test/functional/ui/cursor_spec.lua b/test/functional/ui/cursor_spec.lua
index 8bfceb8cce..f7eb8394bd 100644
--- a/test/functional/ui/cursor_spec.lua
+++ b/test/functional/ui/cursor_spec.lua
@@ -250,7 +250,7 @@ describe('ui/cursor', function()
m.attr = { background = Screen.colors.DarkGray }
end
if m.id_lm then
- m.id_lm = 69
+ m.id_lm = 71
end
end
diff --git a/test/functional/ui/decorations_spec.lua b/test/functional/ui/decorations_spec.lua
index 746bfb3262..318dc8c197 100644
--- a/test/functional/ui/decorations_spec.lua
+++ b/test/functional/ui/decorations_spec.lua
@@ -5497,6 +5497,26 @@ l5
api.nvim_buf_clear_namespace(0, ns, 0, -1)
end)
+
+ it([[correct numberwidth with 'signcolumn' set to "number" #28984]], function()
+ command('set number numberwidth=1 signcolumn=number')
+ api.nvim_buf_set_extmark(0, ns, 0, 0, { sign_text = 'S1' })
+ screen:expect({
+ grid = [[
+ S1 ^ |
+ {1:~ }|*8
+ |
+ ]]
+ })
+ api.nvim_buf_del_extmark(0, ns, 1)
+ screen:expect({
+ grid = [[
+ {8:1 }^ |
+ {1:~ }|*8
+ |
+ ]]
+ })
+ end)
end)
describe('decorations: virt_text', function()
@@ -5575,20 +5595,26 @@ describe('decorations: virt_text', function()
end)
describe('decorations: window scoped', function()
- local screen, ns
+ local screen, ns, win_other
local url = 'https://example.com'
before_each(function()
clear()
screen = Screen.new(20, 10)
screen:attach()
screen:add_extra_attr_ids {
- [100] = { special = Screen.colors.Red, undercurl = true },
- [101] = { url = "https://example.com" },
+ [100] = { special = Screen.colors.Red, undercurl = true },
+ [101] = { url = 'https://example.com' },
}
ns = api.nvim_create_namespace 'test'
insert('12345')
+
+ win_other = api.nvim_open_win(0, false, {
+ col=0,row=0,width=20,height=10,
+ relative = 'win',style = 'minimal',
+ hide = true
+ })
end)
local noextmarks = {
@@ -5596,28 +5622,28 @@ describe('decorations: window scoped', function()
1234^5 |
{1:~ }|*8
|
- ]]}
+ ]],
+ }
- local function set_scoped_extmark(line, col, opts)
- return api.nvim_buf_set_extmark(0, ns, line, col, vim.tbl_extend('error', { scoped = true }, opts))
+ local function set_extmark(line, col, opts)
+ return api.nvim_buf_set_extmark(0, ns, line, col, opts)
end
it('hl_group', function()
- set_scoped_extmark(0, 0, {
+ set_extmark(0, 0, {
hl_group = 'Comment',
end_col = 3,
})
- screen:expect(noextmarks)
-
- api.nvim__win_add_ns(0, ns)
+ api.nvim__ns_set(ns, { wins = { 0 } })
screen:expect {
grid = [[
{18:123}4^5 |
{1:~ }|*8
|
- ]]}
+ ]],
+ }
command 'split'
command 'only'
@@ -5626,48 +5652,55 @@ describe('decorations: window scoped', function()
end)
it('virt_text', function()
- set_scoped_extmark(0, 0, {
+ set_extmark(0, 0, {
virt_text = { { 'a', 'Comment' } },
virt_text_pos = 'eol',
})
- set_scoped_extmark(0, 5, {
+ set_extmark(0, 5, {
virt_text = { { 'b', 'Comment' } },
virt_text_pos = 'inline',
})
- set_scoped_extmark(0, 1, {
+ set_extmark(0, 1, {
virt_text = { { 'c', 'Comment' } },
virt_text_pos = 'overlay',
})
- set_scoped_extmark(0, 1, {
+ set_extmark(0, 1, {
virt_text = { { 'd', 'Comment' } },
virt_text_pos = 'right_align',
})
- screen:expect(noextmarks)
-
- api.nvim__win_add_ns(0, ns)
+ api.nvim__ns_set(ns, { wins = { 0 } })
screen:expect {
grid = [[
1{18:c}34^5{18:b} {18:a} {18:d}|
{1:~ }|*8
|
- ]]}
+ ]],
+ }
command 'split'
command 'only'
screen:expect(noextmarks)
+
+ api.nvim__ns_set(ns, { wins = {} })
+
+ screen:expect {
+ grid = [[
+ 1{18:c}34^5{18:b} {18:a} {18:d}|
+ {1:~ }|*8
+ |
+ ]],
+ }
end)
it('virt_lines', function()
- set_scoped_extmark(0, 0, {
+ set_extmark(0, 0, {
virt_lines = { { { 'a', 'Comment' } } },
})
- screen:expect(noextmarks)
-
- api.nvim__win_add_ns(0, ns)
+ api.nvim__ns_set(ns, { wins = { 0 } })
screen:expect {
grid = [[
@@ -5675,7 +5708,8 @@ describe('decorations: window scoped', function()
{18:a} |
{1:~ }|*7
|
- ]]}
+ ]],
+ }
command 'split'
command 'only'
@@ -5684,14 +5718,12 @@ describe('decorations: window scoped', function()
end)
it('redraws correctly with inline virt_text and wrapping', function()
- set_scoped_extmark(0, 2, {
- virt_text = {{ ('b'):rep(18), 'Comment' }},
- virt_text_pos = 'inline'
+ set_extmark(0, 2, {
+ virt_text = { { ('b'):rep(18), 'Comment' } },
+ virt_text_pos = 'inline',
})
- screen:expect(noextmarks)
-
- api.nvim__win_add_ns(0, ns)
+ api.nvim__ns_set(ns, { wins = { 0 } })
screen:expect {
grid = [[
@@ -5699,9 +5731,10 @@ describe('decorations: window scoped', function()
34^5 |
{1:~ }|*7
|
- ]]}
+ ]],
+ }
- api.nvim__win_del_ns(0, ns)
+ api.nvim__ns_set(ns, { wins = { win_other } })
screen:expect(noextmarks)
end)
@@ -5709,21 +5742,20 @@ describe('decorations: window scoped', function()
pending('sign_text', function()
-- TODO(altermo): The window signcolumn width is calculated wrongly (when `signcolumn=auto`)
-- This happens in function `win_redraw_signcols` on line containing `buf_meta_total(buf, kMTMetaSignText) > 0`
- set_scoped_extmark(0, 0, {
+ set_extmark(0, 0, {
sign_text = 'a',
sign_hl_group = 'Comment',
})
- screen:expect(noextmarks)
-
- api.nvim__win_add_ns(0, ns)
+ api.nvim__ns_set(ns, { wins = { 0 } })
screen:expect {
grid = [[
a 1234^5 |
{2:~ }|*8
|
- ]]}
+ ]],
+ }
command 'split'
command 'only'
@@ -5732,30 +5764,34 @@ describe('decorations: window scoped', function()
end)
it('statuscolumn hl group', function()
- set_scoped_extmark(0, 0, {
- number_hl_group='comment',
+ set_extmark(0, 0, {
+ number_hl_group = 'comment',
})
- set_scoped_extmark(0, 0, {
- line_hl_group='comment',
+ set_extmark(0, 0, {
+ line_hl_group = 'comment',
})
command 'set number'
+ api.nvim__ns_set(ns, { wins = { win_other } })
+
screen:expect {
grid = [[
{8: 1 }1234^5 |
{1:~ }|*8
|
- ]]}
+ ]],
+ }
- api.nvim__win_add_ns(0, ns)
+ api.nvim__ns_set(ns, { wins = { 0 } })
screen:expect {
grid = [[
{18: 1 1234^5 }|
{1:~ }|*8
|
- ]]}
+ ]],
+ }
command 'split'
command 'only'
@@ -5765,36 +5801,43 @@ describe('decorations: window scoped', function()
{8: 1 }1234^5 |
{1:~ }|*8
|
- ]]}
+ ]],
+ }
end)
it('spell', function()
- api.nvim_buf_set_lines(0,0,-1,true,{'aa'})
+ api.nvim_buf_set_lines(0, 0, -1, true, { 'aa' })
- set_scoped_extmark(0, 0, {
- spell=true,
- end_col=2,
+ set_extmark(0, 0, {
+ spell = true,
+ end_col = 2,
})
command 'set spelloptions=noplainbuffer'
command 'set spell'
command 'syntax off'
+ screen:expect({ unchanged = true })
+
+ api.nvim__ns_set(ns, { wins = { win_other } })
+
screen:expect {
grid = [[
a^a |
{1:~ }|*8
|
- ]]}
+ ]],
+ }
- api.nvim__win_add_ns(0, ns)
+ api.nvim__ns_set(ns, { wins = { 0 } })
screen:expect {
grid = [[
{100:a^a} |
{1:~ }|*8
|
- ]]}
+ ]],
+ }
command 'split'
command 'only'
@@ -5804,25 +5847,25 @@ describe('decorations: window scoped', function()
a^a |
{1:~ }|*8
|
- ]]}
+ ]],
+ }
end)
it('url', function()
- set_scoped_extmark(0, 0, {
- end_col=3,
- url=url,
+ set_extmark(0, 0, {
+ end_col = 3,
+ url = url,
})
- screen:expect(noextmarks)
-
- api.nvim__win_add_ns(0, ns)
+ api.nvim__ns_set(ns, { wins = { 0 } })
screen:expect {
grid = [[
{101:123}4^5 |
{1:~ }|*8
|
- ]]}
+ ]],
+ }
command 'split'
command 'only'
@@ -5830,85 +5873,72 @@ describe('decorations: window scoped', function()
screen:expect(noextmarks)
end)
- it('change extmarks scoped option', function()
- local id = set_scoped_extmark(0, 0, {
+ it('change namespace scope', function()
+ set_extmark(0, 0, {
hl_group = 'Comment',
end_col = 3,
})
- api.nvim__win_add_ns(0, ns)
+ api.nvim__ns_set(ns, { wins = { 0 } })
+ eq({ wins={ api.nvim_get_current_win() } }, api.nvim__ns_get(ns))
screen:expect {
grid = [[
{18:123}4^5 |
{1:~ }|*8
|
- ]]}
+ ]],
+ }
command 'split'
command 'only'
screen:expect(noextmarks)
- api.nvim_buf_set_extmark(0, ns, 0, 0, {
- id = id,
- hl_group = 'Comment',
- end_col = 3,
- scoped = false,
- })
+ api.nvim__ns_set(ns, { wins = { 0 } })
+ eq({ wins={ api.nvim_get_current_win() } }, api.nvim__ns_get(ns))
screen:expect {
grid = [[
{18:123}4^5 |
{1:~ }|*8
|
- ]]}
+ ]],
+ }
- api.nvim_buf_set_extmark(0, ns, 0, 0, {
- id = id,
- hl_group = 'Comment',
- end_col = 3,
- scoped = true,
+ local win_new = api.nvim_open_win(0, false, {
+ col=0,row=0,width=20,height=10,
+ relative = 'win',style = 'minimal',
+ hide = true
})
+ api.nvim__ns_set(ns, { wins = { win_new } })
+ eq({ wins={ win_new } }, api.nvim__ns_get(ns))
+
screen:expect(noextmarks)
end)
- it('change namespace scope', function()
- set_scoped_extmark(0, 0, {
- hl_group = 'Comment',
- end_col = 3,
- })
+ it('namespace get works', function()
+ eq({ wins = {} }, api.nvim__ns_get(ns))
- eq(true, api.nvim__win_add_ns(0, ns))
- eq({ ns }, api.nvim__win_get_ns(0))
+ api.nvim__ns_set(ns, { wins = { 0 } })
- screen:expect {
- grid = [[
- {18:123}4^5 |
- {1:~ }|*8
- |
- ]]}
+ eq({ wins = { api.nvim_get_current_win() } }, api.nvim__ns_get(ns))
- command 'split'
- command 'only'
- eq({}, api.nvim__win_get_ns(0))
+ api.nvim__ns_set(ns, { wins = {} })
- screen:expect(noextmarks)
+ eq({ wins = {} }, api.nvim__ns_get(ns))
+ end)
- eq(true, api.nvim__win_add_ns(0, ns))
- eq({ ns }, api.nvim__win_get_ns(0))
+ it('remove window from namespace scope when deleted', function ()
+ api.nvim__ns_set(ns, { wins = { 0 } })
- screen:expect {
- grid = [[
- {18:123}4^5 |
- {1:~ }|*8
- |
- ]]}
+ eq({ wins = { api.nvim_get_current_win() } }, api.nvim__ns_get(ns))
- eq(true, api.nvim__win_del_ns(0, ns))
- eq({}, api.nvim__win_get_ns(0))
+ command 'split'
+ command 'only'
- screen:expect(noextmarks)
+ eq({ wins = {} }, api.nvim__ns_get(ns))
end)
end)
+
diff --git a/test/functional/ui/messages_spec.lua b/test/functional/ui/messages_spec.lua
index ca52a265fa..07192800e5 100644
--- a/test/functional/ui/messages_spec.lua
+++ b/test/functional/ui/messages_spec.lua
@@ -1081,6 +1081,22 @@ stack traceback:
},
})
end)
+
+ it('does not do showmode unnecessarily #29086', function()
+ local screen_showmode = screen._handle_msg_showmode
+ local showmode = 0
+ screen._handle_msg_showmode = function(...)
+ screen_showmode(...)
+ showmode = showmode + 1
+ end
+ screen:expect({
+ grid = [[
+ ^ |
+ {1:~ }|*4
+ ]],
+ })
+ eq(showmode, 1)
+ end)
end)
describe('ui/builtin messages', function()
diff --git a/test/functional/ui/screen.lua b/test/functional/ui/screen.lua
index f8e95f7d88..932ddb070a 100644
--- a/test/functional/ui/screen.lua
+++ b/test/functional/ui/screen.lua
@@ -438,7 +438,7 @@ end
--- @field mouse_enabled? boolean
---
--- @field win_viewport? table<integer,table<string,integer>>
---- @field float_pos? {[1]:integer,[2]:integer}
+--- @field float_pos? [integer,integer]
--- @field hl_groups? table<string,integer>
---
--- The following keys should be used to expect the state of various ext_
diff --git a/test/functional/ui/sign_spec.lua b/test/functional/ui/sign_spec.lua
index b353b3738a..6f4bf5695d 100644
--- a/test/functional/ui/sign_spec.lua
+++ b/test/functional/ui/sign_spec.lua
@@ -577,4 +577,34 @@ describe('Signs', function()
]])
eq({}, eval('sign_getdefined()'))
end)
+
+ it('no crash when unplacing signs beyond end of buffer', function()
+ exec([[
+ sign define S1 text=S1
+ sign define S2 text=S2
+ sign place 1 line=8 name=S1
+ sign place 2 line=9 name=S2
+ ]])
+ -- Now placed at end of buffer
+ local s1 = {
+ grid = [[
+ S2^ |
+ {0:~ }|*12
+ |
+ ]],
+ }
+ screen:expect(s1)
+ -- Signcolumn tracking used to not count signs placed beyond end of buffer here
+ exec('set signcolumn=auto:9')
+ screen:expect({
+ grid = [[
+ S2S1^ |
+ {0:~ }|*12
+ |
+ ]],
+ })
+ -- Unplacing the sign does not crash by decrementing tracked signs below zero
+ exec('sign unplace 1')
+ screen:expect(s1)
+ end)
end)
diff --git a/test/old/testdir/runtest.vim b/test/old/testdir/runtest.vim
index 2d8ba60a7e..a1d4011d7e 100644
--- a/test/old/testdir/runtest.vim
+++ b/test/old/testdir/runtest.vim
@@ -131,7 +131,7 @@ if has('win32')
endif
if has('mac')
- " In MacOS, when starting a shell in a terminal, a bash deprecation warning
+ " In macOS, when starting a shell in a terminal, a bash deprecation warning
" message is displayed. This breaks the terminal test. Disable the warning
" message.
let $BASH_SILENCE_DEPRECATION_WARNING = 1
diff --git a/test/old/testdir/setup.vim b/test/old/testdir/setup.vim
index 7313a0a162..8a5eeb3aab 100644
--- a/test/old/testdir/setup.vim
+++ b/test/old/testdir/setup.vim
@@ -1,7 +1,7 @@
if exists('s:did_load')
" Align Nvim defaults to Vim.
set backspace=
- set commentstring=/*%s*/
+ set commentstring=/*\ %s\ */
set complete=.,w,b,u,t,i
set define=^\\s*#\\s*define
set directory^=.
diff --git a/test/old/testdir/test_debugger.vim b/test/old/testdir/test_debugger.vim
index ad03443cb4..3a469e8a17 100644
--- a/test/old/testdir/test_debugger.vim
+++ b/test/old/testdir/test_debugger.vim
@@ -524,7 +524,7 @@ func Test_Backtrace_Through_Source()
call RunDbgCmd( buf, 'down', [ 'frame is zero' ] )
- " step until we have another meaninfgul trace
+ " step until we have another meaningful trace
call RunDbgCmd(buf, 'step', ['line 5: func File2Function()'])
call RunDbgCmd(buf, 'step', ['line 9: call File2Function()'])
call RunDbgCmd(buf, 'backtrace', [
@@ -611,7 +611,7 @@ func Test_Backtrace_Autocmd()
\ ['cmd: doautocmd User TestGlobalFunction'])
call RunDbgCmd(buf, 'step', ['cmd: call GlobalFunction() | echo "Done"'])
- " At this point the ontly thing in the stack is the autocommand
+ " At this point the only thing in the stack is the autocommand
call RunDbgCmd(buf, 'backtrace', [
\ '>backtrace',
\ '->0 User Autocommands for "TestGlobalFunction"',
@@ -741,7 +741,7 @@ func Test_Backtrace_Autocmd()
call RunDbgCmd( buf, 'down', [ 'frame is zero' ] )
- " step until we have another meaninfgul trace
+ " step until we have another meaningful trace
call RunDbgCmd(buf, 'step', ['line 5: func File2Function()'])
call RunDbgCmd(buf, 'step', ['line 9: call File2Function()'])
call RunDbgCmd(buf, 'backtrace', [
@@ -867,7 +867,7 @@ func Test_Backtrace_CmdLine()
call CheckDbgOutput(buf, ['command line',
\ 'cmd: call GlobalFunction()'], #{msec: 5000})
- " At this point the ontly thing in the stack is the cmdline
+ " At this point the only thing in the stack is the cmdline
call RunDbgCmd(buf, 'backtrace', [
\ '>backtrace',
\ '->0 command line',
@@ -1285,7 +1285,7 @@ func Test_debug_backtrace_level()
\ #{ match: 'pattern' } )
" Expression evaluation in the script frame (not the function frame)
- " FIXME: Unexpected in this scope (a: should not be visibnle)
+ " FIXME: Unexpected in this scope (a: should not be visible)
call RunDbgCmd(buf, 'echo a:arg', [ 'arg1' ] )
call RunDbgCmd(buf, 'echo s:file1_var', [ 'file1' ] )
call RunDbgCmd(buf, 'echo g:global_var', [ 'global' ] )
diff --git a/test/old/testdir/test_diffmode.vim b/test/old/testdir/test_diffmode.vim
index 71483b7469..85ee5df961 100644
--- a/test/old/testdir/test_diffmode.vim
+++ b/test/old/testdir/test_diffmode.vim
@@ -276,7 +276,7 @@ func Test_diffget_diffput_empty_buffer()
endfunc
" :diffput and :diffget completes names of buffers which
-" are in diff mode and which are different then current buffer.
+" are in diff mode and which are different than current buffer.
" No completion when the current window is not in diff mode.
func Test_diffget_diffput_completion()
e Xdiff1 | diffthis
@@ -679,7 +679,7 @@ func Test_diffexpr()
call assert_notequal(normattr, screenattr(3, 1))
diffoff!
- " Try using an non-existing function for 'diffexpr'.
+ " Try using a non-existing function for 'diffexpr'.
set diffexpr=NewDiffFunc()
call assert_fails('windo diffthis', ['E117:', 'E97:'])
diffoff!
diff --git a/test/old/testdir/test_excmd.vim b/test/old/testdir/test_excmd.vim
index 4a780078fd..a9d7c27fe5 100644
--- a/test/old/testdir/test_excmd.vim
+++ b/test/old/testdir/test_excmd.vim
@@ -665,7 +665,7 @@ func Sandbox_tests()
if has('clientserver')
call assert_fails('let s=remote_expr("gvim", "2+2")', 'E48:')
if !has('win32')
- " remote_foreground() doesn't thrown an error message on MS-Windows
+ " remote_foreground() doesn't throw an error message on MS-Windows
call assert_fails('call remote_foreground("gvim")', 'E48:')
endif
call assert_fails('let s=remote_peek("gvim")', 'E48:')
diff --git a/test/old/testdir/test_filetype.vim b/test/old/testdir/test_filetype.vim
index 16125559cf..fa62765398 100644
--- a/test/old/testdir/test_filetype.vim
+++ b/test/old/testdir/test_filetype.vim
@@ -365,7 +365,7 @@ func s:GetFilenameChecks() abort
\ 'jq': ['file.jq'],
\ 'jovial': ['file.jov', 'file.j73', 'file.jovial'],
\ 'jproperties': ['file.properties', 'file.properties_xx', 'file.properties_xx_xx', 'some.properties_xx_xx_file', 'org.eclipse.xyz.prefs'],
- \ 'json': ['file.json', 'file.jsonp', 'file.json-patch', 'file.geojson', 'file.webmanifest', 'Pipfile.lock', 'file.ipynb', 'file.jupyterlab-settings', '.prettierrc', '.firebaserc', '.stylelintrc', 'file.slnf', 'file.sublime-project', 'file.sublime-settings', 'file.sublime-workspace', 'file.bd', 'file.bda', 'file.xci', 'flake.lock'],
+ \ 'json': ['file.json', 'file.jsonp', 'file.json-patch', 'file.geojson', 'file.webmanifest', 'Pipfile.lock', 'file.ipynb', 'file.jupyterlab-settings', '.prettierrc', '.firebaserc', '.stylelintrc', '.lintstagedrc', 'file.slnf', 'file.sublime-project', 'file.sublime-settings', 'file.sublime-workspace', 'file.bd', 'file.bda', 'file.xci', 'flake.lock'],
\ 'json5': ['file.json5'],
\ 'jsonc': ['file.jsonc', '.babelrc', '.eslintrc', '.jsfmtrc', '.jshintrc', '.jscsrc', '.vsconfig', '.hintrc', '.swrc', 'jsconfig.json', 'tsconfig.json', 'tsconfig.test.json', 'tsconfig-test.json', '.luaurc'],
\ 'jsonl': ['file.jsonl'],
@@ -593,6 +593,7 @@ func s:GetFilenameChecks() abort
\ 'radiance': ['file.rad', 'file.mat'],
\ 'raku': ['file.pm6', 'file.p6', 'file.t6', 'file.pod6', 'file.raku', 'file.rakumod', 'file.rakudoc', 'file.rakutest'],
\ 'raml': ['file.raml'],
+ \ 'rasi': ['file.rasi'],
\ 'ratpoison': ['.ratpoisonrc', 'ratpoisonrc'],
\ 'rbs': ['file.rbs'],
\ 'rc': ['file.rc', 'file.rch'],
diff --git a/test/old/testdir/test_flatten.vim b/test/old/testdir/test_flatten.vim
index aa91060313..035ca18f73 100644
--- a/test/old/testdir/test_flatten.vim
+++ b/test/old/testdir/test_flatten.vim
@@ -53,7 +53,7 @@ func Test_flatten()
call test_garbagecollect_now()
call assert_equal([1, 2, 3], l:list)
- " Tests for checking circular reference list can be flatten.
+ " Tests for checking circular reference list can be flattened.
let l:x = [1]
let l:y = [x]
let l:z = flatten(l:y)
diff --git a/test/old/testdir/test_fold.vim b/test/old/testdir/test_fold.vim
index eae6952e72..b7a0cee444 100644
--- a/test/old/testdir/test_fold.vim
+++ b/test/old/testdir/test_fold.vim
@@ -8,7 +8,73 @@ func PrepIndent(arg)
return [a:arg] + repeat(["\t".a:arg], 5)
endfu
-func Test_address_fold()
+func Test_address_fold_new_default_commentstring()
+ " Test with the new commentstring defaults, that includes padding after v9.1.464
+ new
+ call setline(1, ['int FuncName() {/* {{{ */', 1, 2, 3, 4, 5, '}/* }}} */',
+ \ 'after fold 1', 'after fold 2', 'after fold 3'])
+ setl fen fdm=marker
+ " The next commands should all copy the same part of the buffer,
+ " regardless of the addressing type, since the part to be copied
+ " is folded away
+ :1y
+ call assert_equal(['int FuncName() {/* {{{ */', '1', '2', '3', '4', '5', '}/* }}} */'], getreg(0,1,1))
+ :.y
+ call assert_equal(['int FuncName() {/* {{{ */', '1', '2', '3', '4', '5', '}/* }}} */'], getreg(0,1,1))
+ :.+y
+ call assert_equal(['int FuncName() {/* {{{ */', '1', '2', '3', '4', '5', '}/* }}} */'], getreg(0,1,1))
+ :.,.y
+ call assert_equal(['int FuncName() {/* {{{ */', '1', '2', '3', '4', '5', '}/* }}} */'], getreg(0,1,1))
+ :sil .1,.y
+ call assert_equal(['int FuncName() {/* {{{ */', '1', '2', '3', '4', '5', '}/* }}} */'], getreg(0,1,1))
+ " use silent to make E493 go away
+ :sil .+,.y
+ call assert_equal(['int FuncName() {/* {{{ */', '1', '2', '3', '4', '5', '}/* }}} */'], getreg(0,1,1))
+ :,y
+ call assert_equal(['int FuncName() {/* {{{ */', '1', '2', '3', '4', '5', '}/* }}} */'], getreg(0,1,1))
+ :,+y
+ call assert_equal(['int FuncName() {/* {{{ */', '1', '2', '3', '4', '5', '}/* }}} */','after fold 1'], getreg(0,1,1))
+ " using .+3 as second address should c opy the whole folded line + the next 3
+ " lines
+ :.,+3y
+ call assert_equal(['int FuncName() {/* {{{ */', '1', '2', '3', '4', '5', '}/* }}} */',
+ \ 'after fold 1', 'after fold 2' , 'after fold 3'], getreg(0,1,1))
+ :sil .,-2y
+ call assert_equal(['int FuncName() {/* {{{ */', '1', '2', '3', '4', '5', '}/* }}} */'], getreg(0,1,1))
+
+ " now test again with folding disabled
+ set nofoldenable
+ :1y
+ call assert_equal(['int FuncName() {/* {{{ */'], getreg(0,1,1))
+ :.y
+ call assert_equal(['int FuncName() {/* {{{ */'], getreg(0,1,1))
+ :.+y
+ call assert_equal(['1'], getreg(0,1,1) )
+ :.,.y
+ call assert_equal(['int FuncName() {/* {{{ */'], getreg(0,1,1))
+ " use silent to make E493 go away
+ :sil .1,.y
+ call assert_equal(['int FuncName() {/* {{{ */', '1'], getreg(0,1,1))
+ " use silent to make E493 go away
+ :sil .+,.y
+ call assert_equal(['int FuncName() {/* {{{ */', '1'], getreg(0,1,1))
+ :,y
+ call assert_equal(['int FuncName() {/* {{{ */'], getreg(0,1,1))
+ :,+y
+ call assert_equal(['int FuncName() {/* {{{ */', '1'], getreg(0,1,1))
+ " using .+3 as second address should c opy the whole folded line + the next 3
+ " lines
+ :.,+3y
+ call assert_equal(['int FuncName() {/* {{{ */', '1', '2', '3'], getreg(0,1,1))
+ :7
+ :sil .,-2y
+ call assert_equal(['4', '5', '}/* }}} */'], getreg(0,1,1))
+
+ quit!
+endfunc
+
+func Test_address_fold_old_default_commentstring()
+ " Test with the old commentstring defaults, before v9.1.464
new
call setline(1, ['int FuncName() {/*{{{*/', 1, 2, 3, 4, 5, '}/*}}}*/',
\ 'after fold 1', 'after fold 2', 'after fold 3'])
@@ -696,7 +762,7 @@ func Test_fold_create_marker_in_C()
call append(0, content)
call cursor(c + 1, 1)
norm! zfG
- call assert_equal(content[c] . (c < 4 ? '{{{' : '/*{{{*/'), getline(c + 1))
+ call assert_equal(content[c] . (c < 4 ? '{{{' : '/* {{{ */'), getline(c + 1))
endfor
set fdm& fdl&
diff --git a/test/old/testdir/test_ins_complete.vim b/test/old/testdir/test_ins_complete.vim
index 45db2a7364..fd77da67f8 100644
--- a/test/old/testdir/test_ins_complete.vim
+++ b/test/old/testdir/test_ins_complete.vim
@@ -884,6 +884,74 @@ func Test_complete_with_longest()
bwipe!
endfunc
+" Test for buffer-local value of 'completeopt'
+func Test_completeopt_buffer_local()
+ set completeopt=menu
+ new
+ call setline(1, ['foofoo', 'foobar', 'foobaz', ''])
+ call assert_equal('', &l:completeopt)
+ call assert_equal('menu', &completeopt)
+ call assert_equal('menu', &g:completeopt)
+
+ setlocal bufhidden=hide
+ enew
+ call setline(1, ['foofoo', 'foobar', 'foobaz', ''])
+ call assert_equal('', &l:completeopt)
+ call assert_equal('menu', &completeopt)
+ call assert_equal('menu', &g:completeopt)
+
+ setlocal completeopt+=fuzzy,noinsert
+ call assert_equal('menu,fuzzy,noinsert', &l:completeopt)
+ call assert_equal('menu,fuzzy,noinsert', &completeopt)
+ call assert_equal('menu', &g:completeopt)
+ call feedkeys("Gccf\<C-X>\<C-N>bz\<C-Y>", 'tnix')
+ call assert_equal('foobaz', getline('.'))
+
+ setlocal completeopt=
+ call assert_equal('', &l:completeopt)
+ call assert_equal('menu', &completeopt)
+ call assert_equal('menu', &g:completeopt)
+ call feedkeys("Gccf\<C-X>\<C-N>\<C-Y>", 'tnix')
+ call assert_equal('foofoo', getline('.'))
+
+ setlocal completeopt+=longest
+ call assert_equal('menu,longest', &l:completeopt)
+ call assert_equal('menu,longest', &completeopt)
+ call assert_equal('menu', &g:completeopt)
+ call feedkeys("Gccf\<C-X>\<C-N>\<C-X>\<C-Z>", 'tnix')
+ call assert_equal('foo', getline('.'))
+
+ setlocal bufhidden=hide
+ buffer #
+ call assert_equal('', &l:completeopt)
+ call assert_equal('menu', &completeopt)
+ call assert_equal('menu', &g:completeopt)
+ call feedkeys("Gccf\<C-X>\<C-N>\<C-Y>", 'tnix')
+ call assert_equal('foofoo', getline('.'))
+
+ setlocal completeopt+=fuzzy,noinsert
+ call assert_equal('menu,fuzzy,noinsert', &l:completeopt)
+ call assert_equal('menu,fuzzy,noinsert', &completeopt)
+ call assert_equal('menu', &g:completeopt)
+ call feedkeys("Gccf\<C-X>\<C-N>bz\<C-Y>", 'tnix')
+ call assert_equal('foobaz', getline('.'))
+
+ buffer #
+ call assert_equal('menu,longest', &l:completeopt)
+ call assert_equal('menu,longest', &completeopt)
+ call assert_equal('menu', &g:completeopt)
+ call feedkeys("Gccf\<C-X>\<C-N>\<C-X>\<C-Z>", 'tnix')
+ call assert_equal('foo', getline('.'))
+
+ setlocal bufhidden=wipe
+ buffer! #
+ bwipe!
+ call assert_equal('', &l:completeopt)
+ call assert_equal('menu', &completeopt)
+ call assert_equal('menu', &g:completeopt)
+
+ set completeopt&
+endfunc
" Test for completing words following a completed word in a line
func Test_complete_wrapscan()
@@ -2512,4 +2580,63 @@ func Test_completefunc_first_call_complete_add()
bwipe!
endfunc
+func Test_complete_fuzzy_match()
+ func OnPumChange()
+ let g:item = get(v:event, 'completed_item', {})
+ let g:word = get(g:item, 'word', v:null)
+ endfunction
+
+ augroup AAAAA_Group
+ au!
+ autocmd CompleteChanged * :call OnPumChange()
+ augroup END
+
+ func Omni_test(findstart, base)
+ if a:findstart
+ return col(".")
+ endif
+ return [#{word: "foo"}, #{word: "foobar"}, #{word: "fooBaz"}, #{word: "foobala"}]
+ endfunc
+
+ new
+ set omnifunc=Omni_test
+ set completeopt+=noinsert,fuzzy
+ call feedkeys("Gi\<C-x>\<C-o>", 'tx')
+ call assert_equal('foo', g:word)
+ call feedkeys("S\<C-x>\<C-o>fb", 'tx')
+ call assert_equal('fooBaz', g:word)
+ call feedkeys("S\<C-x>\<C-o>fa", 'tx')
+ call assert_equal('foobar', g:word)
+ " select next
+ call feedkeys("S\<C-x>\<C-o>fb\<C-n>", 'tx')
+ call assert_equal('foobar', g:word)
+ " can cyclically select next
+ call feedkeys("S\<C-x>\<C-o>fb\<C-n>\<C-n>\<C-n>", 'tx')
+ call assert_equal(v:null, g:word)
+ " select prev
+ call feedkeys("S\<C-x>\<C-o>fb\<C-p>", 'tx')
+ call assert_equal(v:null, g:word)
+ " can cyclically select prev
+ call feedkeys("S\<C-x>\<C-o>fb\<C-p>\<C-p>\<C-p>\<C-p>", 'tx')
+ call assert_equal('fooBaz', g:word)
+
+ " respect noselect
+ set completeopt+=noselect
+ call feedkeys("S\<C-x>\<C-o>fb", 'tx')
+ call assert_equal(v:null, g:word)
+ call feedkeys("S\<C-x>\<C-o>fb\<C-n>", 'tx')
+ call assert_equal('fooBaz', g:word)
+
+ " clean up
+ set omnifunc=
+ bw!
+ set complete& completeopt&
+ autocmd! AAAAA_Group
+ augroup! AAAAA_Group
+ delfunc OnPumChange
+ delfunc Omni_test
+ unlet g:item
+ unlet g:word
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab nofoldenable
diff --git a/test/old/testdir/test_normal.vim b/test/old/testdir/test_normal.vim
index a2ef07193d..170b2cda53 100644
--- a/test/old/testdir/test_normal.vim
+++ b/test/old/testdir/test_normal.vim
@@ -403,17 +403,17 @@ func Test_normal08_fold()
" First fold
norm! V4jzf
" check that folds have been created
- call assert_equal(['50/*{{{*/', '51', '52', '53', '54/*}}}*/'], getline(50,54))
+ call assert_equal(['50/* {{{ */', '51', '52', '53', '54/* }}} */'], getline(50,54))
" Second fold
46
norm! V10jzf
" check that folds have been created
- call assert_equal('46/*{{{*/', getline(46))
- call assert_equal('60/*}}}*/', getline(60))
+ call assert_equal('46/* {{{ */', getline(46))
+ call assert_equal('60/* }}} */', getline(60))
norm! k
call assert_equal('45', getline('.'))
norm! j
- call assert_equal('46/*{{{*/', getline('.'))
+ call assert_equal('46/* {{{ */', getline('.'))
norm! j
call assert_equal('61', getline('.'))
norm! k
@@ -422,12 +422,12 @@ func Test_normal08_fold()
norm! k
call assert_equal('45', getline('.'))
norm! j
- call assert_equal('46/*{{{*/', getline('.'))
+ call assert_equal('46/* {{{ */', getline('.'))
norm! j
call assert_equal('47', getline('.'))
norm! k
norm! zcVzO
- call assert_equal('46/*{{{*/', getline('.'))
+ call assert_equal('46/* {{{ */', getline('.'))
norm! j
call assert_equal('47', getline('.'))
norm! j
@@ -435,7 +435,7 @@ func Test_normal08_fold()
norm! j
call assert_equal('49', getline('.'))
norm! j
- call assert_equal('50/*{{{*/', getline('.'))
+ call assert_equal('50/* {{{ */', getline('.'))
norm! j
call assert_equal('51', getline('.'))
" delete folds
@@ -1387,14 +1387,14 @@ func Test_normal18_z_fold()
" First fold
norm! 4zF
" check that folds have been created
- call assert_equal(['50/*{{{*/', '51', '52', '53/*}}}*/'], getline(50,53))
+ call assert_equal(['50/* {{{ */', '51', '52', '53/* }}} */'], getline(50,53))
" Test for zd
51
norm! 2zF
call assert_equal(2, foldlevel('.'))
norm! kzd
- call assert_equal(['50', '51/*{{{*/', '52/*}}}*/', '53'], getline(50,53))
+ call assert_equal(['50', '51/* {{{ */', '52/* }}} */', '53'], getline(50,53))
norm! j
call assert_equal(1, foldlevel('.'))
@@ -1413,7 +1413,7 @@ func Test_normal18_z_fold()
norm! 2zF
90
norm! 4zF
- call assert_equal(['85/*{{{*/', '86/*{{{*/', '87/*}}}*/', '88/*}}}*/', '89', '90/*{{{*/', '91', '92', '93/*}}}*/'], getline(85,93))
+ call assert_equal(['85/* {{{ */', '86/* {{{ */', '87/* }}} */', '88/* }}} */', '89', '90/* {{{ */', '91', '92', '93/* }}} */'], getline(85,93))
norm! zE
call assert_equal(['85', '86', '87', '88', '89', '90', '91', '92', '93'], getline(85,93))
@@ -1425,9 +1425,9 @@ func Test_normal18_z_fold()
norm! k
call assert_equal('49', getline('.'))
norm! j
- call assert_equal('50/*{{{*/', getline('.'))
+ call assert_equal('50/* {{{ */', getline('.'))
norm! j
- call assert_equal('51/*}}}*/', getline('.'))
+ call assert_equal('51/* }}} */', getline('.'))
norm! j
call assert_equal('52', getline('.'))
call assert_equal(0, &foldenable)
@@ -1437,7 +1437,7 @@ func Test_normal18_z_fold()
norm! zN
call assert_equal('49', getline('.'))
norm! j
- call assert_equal('50/*{{{*/', getline('.'))
+ call assert_equal('50/* {{{ */', getline('.'))
norm! j
call assert_equal('52', getline('.'))
call assert_equal(1, &foldenable)
@@ -1458,9 +1458,9 @@ func Test_normal18_z_fold()
norm! k
call assert_equal('49', getline('.'))
norm! j
- call assert_equal('50/*{{{*/', getline('.'))
+ call assert_equal('50/* {{{ */', getline('.'))
norm! j
- call assert_equal('51/*}}}*/', getline('.'))
+ call assert_equal('51/* }}} */', getline('.'))
norm! j
call assert_equal('52', getline('.'))
50
@@ -1468,7 +1468,7 @@ func Test_normal18_z_fold()
norm! k
call assert_equal('49', getline('.'))
norm! j
- call assert_equal('50/*{{{*/', getline('.'))
+ call assert_equal('50/* {{{ */', getline('.'))
norm! j
call assert_equal('52', getline('.'))
@@ -1477,14 +1477,14 @@ func Test_normal18_z_fold()
norm! k
call assert_equal('48', getline('.'))
norm! j
- call assert_equal('49/*{{{*/', getline('.'))
+ call assert_equal('49/* {{{ */', getline('.'))
norm! j
call assert_equal('55', getline('.'))
49
norm! za
- call assert_equal('49/*{{{*/', getline('.'))
+ call assert_equal('49/* {{{ */', getline('.'))
norm! j
- call assert_equal('50/*{{{*/', getline('.'))
+ call assert_equal('50/* {{{ */', getline('.'))
norm! j
call assert_equal('52', getline('.'))
set nofoldenable
@@ -1498,11 +1498,11 @@ func Test_normal18_z_fold()
norm! 2k
call assert_equal('48', getline('.'))
norm! j
- call assert_equal('49/*{{{*/', getline('.'))
+ call assert_equal('49/* {{{ */', getline('.'))
norm! j
- call assert_equal('50/*{{{*/', getline('.'))
+ call assert_equal('50/* {{{ */', getline('.'))
norm! j
- call assert_equal('51/*}}}*/', getline('.'))
+ call assert_equal('51/* }}} */', getline('.'))
norm! j
call assert_equal('52', getline('.'))
@@ -1514,15 +1514,15 @@ func Test_normal18_z_fold()
norm! 2k
call assert_equal('48', getline('.'))
norm! j
- call assert_equal('49/*{{{*/', getline('.'))
+ call assert_equal('49/* {{{ */', getline('.'))
norm! j
- call assert_equal('50/*{{{*/', getline('.'))
+ call assert_equal('50/* {{{ */', getline('.'))
norm! j
- call assert_equal('51/*}}}*/', getline('.'))
+ call assert_equal('51/* }}} */', getline('.'))
norm! j
call assert_equal('52', getline('.'))
- " zA on a opened fold when foldenable is not set
+ " zA on an opened fold when foldenable is not set
50
set nofoldenable
norm! zA
@@ -1530,7 +1530,7 @@ func Test_normal18_z_fold()
norm! k
call assert_equal('48', getline('.'))
norm! j
- call assert_equal('49/*{{{*/', getline('.'))
+ call assert_equal('49/* {{{ */', getline('.'))
norm! j
call assert_equal('55', getline('.'))
@@ -1550,7 +1550,7 @@ func Test_normal18_z_fold()
norm! k
call assert_equal('48', getline('.'))
norm! j
- call assert_equal('49/*{{{*/', getline('.'))
+ call assert_equal('49/* {{{ */', getline('.'))
norm! j
call assert_equal('55', getline('.'))
set nofoldenable
@@ -1559,7 +1559,7 @@ func Test_normal18_z_fold()
norm! k
call assert_equal('48', getline('.'))
norm! j
- call assert_equal('49/*{{{*/', getline('.'))
+ call assert_equal('49/* {{{ */', getline('.'))
norm! j
call assert_equal('55', getline('.'))
@@ -1569,7 +1569,7 @@ func Test_normal18_z_fold()
norm! zCk
call assert_equal('48', getline('.'))
norm! j
- call assert_equal('49/*{{{*/', getline('.'))
+ call assert_equal('49/* {{{ */', getline('.'))
norm! j
call assert_equal('55', getline('.'))
@@ -1580,7 +1580,7 @@ func Test_normal18_z_fold()
norm! zx
call assert_equal(1, &foldenable)
norm! j
- call assert_equal('49/*{{{*/', getline('.'))
+ call assert_equal('49/* {{{ */', getline('.'))
norm! j
call assert_equal('55', getline('.'))
@@ -1592,17 +1592,17 @@ func Test_normal18_z_fold()
norm! 3k
call assert_equal('48', getline('.'))
norm! j
- call assert_equal('49/*{{{*/', getline('.'))
+ call assert_equal('49/* {{{ */', getline('.'))
norm! j
- call assert_equal('50/*{{{*/', getline('.'))
+ call assert_equal('50/* {{{ */', getline('.'))
norm! j
- call assert_equal('51/*}}}*/', getline('.'))
+ call assert_equal('51/* }}} */', getline('.'))
norm! j
call assert_equal('52', getline('.'))
norm! j
call assert_equal('53', getline('.'))
norm! j
- call assert_equal('54/*}}}*/', getline('.'))
+ call assert_equal('54/* }}} */', getline('.'))
norm! j
call assert_equal('55', getline('.'))
@@ -1614,15 +1614,15 @@ func Test_normal18_z_fold()
call assert_equal(1, &foldenable)
call assert_equal('48', getline('.'))
norm! j
- call assert_equal('49/*{{{*/', getline('.'))
+ call assert_equal('49/* {{{ */', getline('.'))
norm! j
- call assert_equal('50/*{{{*/', getline('.'))
+ call assert_equal('50/* {{{ */', getline('.'))
norm! j
call assert_equal('52', getline('.'))
norm! j
call assert_equal('53', getline('.'))
norm! j
- call assert_equal('54/*}}}*/', getline('.'))
+ call assert_equal('54/* }}} */', getline('.'))
norm! j
call assert_equal('55', getline('.'))
@@ -1635,7 +1635,7 @@ func Test_normal18_z_fold()
norm! k
call assert_equal('48', getline('.'))
norm! j
- call assert_equal('49/*{{{*/', getline('.'))
+ call assert_equal('49/* {{{ */', getline('.'))
norm! j
call assert_equal('55', getline('.'))
@@ -1652,7 +1652,7 @@ func Test_normal18_z_fold()
norm! k
call assert_equal('48', getline('.'))
norm! j
- call assert_equal('49/*{{{*/', getline('.'))
+ call assert_equal('49/* {{{ */', getline('.'))
norm! j
call assert_equal('55', getline('.'))
@@ -1671,7 +1671,7 @@ func Test_normal18_z_fold()
call assert_equal(0, &foldlevel)
call assert_equal('48', getline('.'))
norm! j
- call assert_equal('49/*{{{*/', getline('.'))
+ call assert_equal('49/* {{{ */', getline('.'))
norm! j
call assert_equal('55', getline('.'))
@@ -1689,11 +1689,11 @@ func Test_normal18_z_fold()
call assert_equal(2, &foldlevel)
call assert_equal('48', getline('.'))
norm! j
- call assert_equal('49/*{{{*/', getline('.'))
+ call assert_equal('49/* {{{ */', getline('.'))
norm! j
- call assert_equal('50/*{{{*/', getline('.'))
+ call assert_equal('50/* {{{ */', getline('.'))
norm! j
- call assert_equal('51/*}}}*/', getline('.'))
+ call assert_equal('51/* }}} */', getline('.'))
norm! j
call assert_equal('52', getline('.'))
@@ -1709,24 +1709,24 @@ func Test_normal18_z_fold()
call assert_equal(2, &foldlevel)
call assert_equal('48', getline('.'))
norm! j
- call assert_equal('49/*{{{*/', getline('.'))
+ call assert_equal('49/* {{{ */', getline('.'))
norm! j
- call assert_equal('50/*{{{*/', getline('.'))
+ call assert_equal('50/* {{{ */', getline('.'))
norm! j
- call assert_equal('51/*}}}*/', getline('.'))
+ call assert_equal('51/* }}} */', getline('.'))
norm! j
call assert_equal('52', getline('.'))
- call append(50, ['a /*{{{*/', 'b /*}}}*/'])
+ call append(50, ['a /* {{{ */', 'b /* }}} */'])
48
call assert_equal('48', getline('.'))
norm! j
- call assert_equal('49/*{{{*/', getline('.'))
+ call assert_equal('49/* {{{ */', getline('.'))
norm! j
- call assert_equal('50/*{{{*/', getline('.'))
+ call assert_equal('50/* {{{ */', getline('.'))
norm! j
- call assert_equal('a /*{{{*/', getline('.'))
+ call assert_equal('a /* {{{ */', getline('.'))
norm! j
- call assert_equal('51/*}}}*/', getline('.'))
+ call assert_equal('51/* }}} */', getline('.'))
norm! j
call assert_equal('52', getline('.'))
48
@@ -1735,15 +1735,15 @@ func Test_normal18_z_fold()
call assert_equal(3, &foldlevel)
call assert_equal('48', getline('.'))
norm! j
- call assert_equal('49/*{{{*/', getline('.'))
+ call assert_equal('49/* {{{ */', getline('.'))
norm! j
- call assert_equal('50/*{{{*/', getline('.'))
+ call assert_equal('50/* {{{ */', getline('.'))
norm! j
- call assert_equal('a /*{{{*/', getline('.'))
+ call assert_equal('a /* {{{ */', getline('.'))
norm! j
- call assert_equal('b /*}}}*/', getline('.'))
+ call assert_equal('b /* }}} */', getline('.'))
norm! j
- call assert_equal('51/*}}}*/', getline('.'))
+ call assert_equal('51/* }}} */', getline('.'))
norm! j
call assert_equal('52', getline('.'))
@@ -1878,7 +1878,7 @@ func Test_normal23_K()
let not_gnu_man = has('mac') || has('bsd')
if not_gnu_man
- " In MacOS and BSD, the option for specifying a pager is different
+ " In macOS and BSD, the option for specifying a pager is different
set keywordprg=man\ -P\ cat
else
set keywordprg=man\ --pager=cat
@@ -2727,7 +2727,7 @@ func Test_normal33_g_cmd2()
call assert_equal('foo first line', getline(1))
set virtualedit&
- " Test for aboring a g command using CTRL-\ CTRL-G
+ " Test for aborting a g command using CTRL-\ CTRL-G
exe "normal! g\<C-\>\<C-G>"
call assert_equal('foo first line', getline('.'))
diff --git a/test/old/testdir/test_options.vim b/test/old/testdir/test_options.vim
index 8ffd8f7ef8..f7eace59c2 100644
--- a/test/old/testdir/test_options.vim
+++ b/test/old/testdir/test_options.vim
@@ -1732,7 +1732,7 @@ func Test_cmdheight()
set cmdheight&
endfunc
-" To specify a control character as a option value, '^' can be used
+" To specify a control character as an option value, '^' can be used
func Test_opt_control_char()
set wildchar=^v
call assert_equal("\<C-V>", nr2char(&wildchar))
diff --git a/test/old/testdir/test_quickfix.vim b/test/old/testdir/test_quickfix.vim
index a708cabc26..791186efe8 100644
--- a/test/old/testdir/test_quickfix.vim
+++ b/test/old/testdir/test_quickfix.vim
@@ -4353,11 +4353,9 @@ endfunc
" Test for shortening/simplifying the file name when opening the
" quickfix window or when displaying the quickfix list
func Test_shorten_fname()
- if !has('unix')
- return
- endif
+ CheckUnix
%bwipe
- " Create a quickfix list with a absolute path filename
+ " Create a quickfix list with an absolute path filename
let fname = getcwd() . '/test_quickfix.vim'
call setqflist([], ' ', {'lines':[fname . ":20:Line20"], 'efm':'%f:%l:%m'})
call assert_equal(fname, bufname('test_quickfix.vim'))
@@ -4366,7 +4364,7 @@ func Test_shorten_fname()
call assert_equal('test_quickfix.vim', bufname('test_quickfix.vim'))
cclose
%bwipe
- " Create a quickfix list with a absolute path filename
+ " Create a quickfix list with an absolute path filename
call setqflist([], ' ', {'lines':[fname . ":20:Line20"], 'efm':'%f:%l:%m'})
call assert_equal(fname, bufname('test_quickfix.vim'))
" Displaying the quickfix list should simplify the file path
diff --git a/test/old/testdir/test_signs.vim b/test/old/testdir/test_signs.vim
index d7baa7e870..69fefccb3f 100644
--- a/test/old/testdir/test_signs.vim
+++ b/test/old/testdir/test_signs.vim
@@ -89,8 +89,9 @@ func Test_sign()
" Place a sign without specifying the filename or buffer
sign place 77 line=9 name=Sign2
let a=execute('sign place')
+ " Nvim: sign line clamped to buffer length
call assert_equal("\n--- Signs ---\nSigns for [NULL]:\n" .
- \ " line=9 id=77 name=Sign2 priority=10\n", a)
+ \ " line=4 id=77 name=Sign2 priority=10\n", a)
sign unplace *
" Check :jump with file=...
@@ -799,10 +800,11 @@ func Test_sign_group()
set buftype=nofile
sign place 25 line=76 name=sign1 priority=99 file=foo
let a = execute('sign place')
+ " Nvim: sign line clamped to buffer length
call assert_equal("\n--- Signs ---\nSigns for Xsign:\n" .
\ " line=10 id=5 name=sign1 priority=10\n" .
\ "Signs for foo:\n" .
- \ " line=76 id=25 name=sign1 priority=99\n", a)
+ \ " line=1 id=25 name=sign1 priority=99\n", a)
close
bwipe foo
diff --git a/test/old/testdir/test_spellfile.vim b/test/old/testdir/test_spellfile.vim
index 4d2a6cf35f..509fed11df 100644
--- a/test/old/testdir/test_spellfile.vim
+++ b/test/old/testdir/test_spellfile.vim
@@ -656,7 +656,7 @@ func Test_aff_file_format_error()
let output = execute('mkspell! Xtest.spl Xtest')
call assert_match('Different combining flag in continued affix block in Xtest.aff line 3', output)
- " Try to reuse a affix used for BAD flag
+ " Try to reuse an affix used for BAD flag
call writefile(['BAD x', 'PFX x Y 1', 'PFX x 0 re x'], 'Xtest.aff')
let output = execute('mkspell! Xtest.spl Xtest')
call assert_match('Affix also used for BAD/RARE/KEEPCASE/NEEDAFFIX/NEEDCOMPOUND/NOSUGGEST in Xtest.aff line 2: x', output)
diff --git a/test/old/testdir/test_syntax.vim b/test/old/testdir/test_syntax.vim
index 35523df17d..8a24c4ae27 100644
--- a/test/old/testdir/test_syntax.vim
+++ b/test/old/testdir/test_syntax.vim
@@ -549,8 +549,7 @@ endfunc
func Test_bg_detection()
CheckNotGui
- " auto-detection of &bg, make sure sure it isn't set anywhere before
- " this test
+ " auto-detection of &bg, make sure it isn't set anywhere before this test
hi Normal ctermbg=0
call assert_equal('dark', &bg)
hi Normal ctermbg=4
diff --git a/test/old/testdir/test_textobjects.vim b/test/old/testdir/test_textobjects.vim
index 3b86ae97da..a7840860c9 100644
--- a/test/old/testdir/test_textobjects.vim
+++ b/test/old/testdir/test_textobjects.vim
@@ -232,7 +232,7 @@ func Test_empty_html_tag()
normal 0f<vitsaaa
call assert_equal('aaa', getline(1))
- " selecting a tag block in an non-empty blank line should fail
+ " selecting a tag block in a non-empty blank line should fail
call setline(1, ' ')
call assert_beeps('normal $vaty')
diff --git a/test/old/testdir/test_trycatch.vim b/test/old/testdir/test_trycatch.vim
index d60b793f1b..f2142f4210 100644
--- a/test/old/testdir/test_trycatch.vim
+++ b/test/old/testdir/test_trycatch.vim
@@ -50,7 +50,7 @@ func T25_F()
Xpath 'i'
endfunc
-" Also try using "fina" and "final" and "finall" as abbraviations.
+" Also try using "fina" and "final" and "finall" as abbreviations.
func T25_G()
if 1
try
diff --git a/test/old/testdir/test_vartabs.vim b/test/old/testdir/test_vartabs.vim
index e12c71d521..82c3a513f9 100644
--- a/test/old/testdir/test_vartabs.vim
+++ b/test/old/testdir/test_vartabs.vim
@@ -445,4 +445,77 @@ func Test_shiftwidth_vartabstop()
setlocal shiftwidth& vartabstop& tabstop&
endfunc
+func Test_vartabstop_latin1()
+ throw "Skipped: Nvim does not support 'compatible'"
+ let save_encoding = &encoding
+ new
+ set encoding=iso8859-1
+ set compatible linebreak list revins smarttab
+ set vartabstop=400
+ exe "norm i00\t\<C-D>"
+ bwipe!
+ let &encoding = save_encoding
+ set nocompatible linebreak& list& revins& smarttab& vartabstop&
+endfunc
+
+" Verify that right-shifting and left-shifting adjust lines to the proper
+" tabstops.
+func Test_vartabstop_shift_right_left()
+ new
+ set expandtab
+ set shiftwidth=0
+ set vartabstop=17,11,7
+ exe "norm! aword"
+ let expect = "word"
+ call assert_equal(expect, getline(1))
+
+ " Shift to first tabstop.
+ norm! >>
+ let expect = " word"
+ call assert_equal(expect, getline(1))
+
+ " Shift to second tabstop.
+ norm! >>
+ let expect = " word"
+ call assert_equal(expect, getline(1))
+
+ " Shift to third tabstop.
+ norm! >>
+ let expect = " word"
+ call assert_equal(expect, getline(1))
+
+ " Shift to fourth tabstop, repeating the third shift width.
+ norm! >>
+ let expect = " word"
+ call assert_equal(expect, getline(1))
+
+ " Shift back to the third tabstop.
+ norm! <<
+ let expect = " word"
+ call assert_equal(expect, getline(1))
+
+ " Shift back to the second tabstop.
+ norm! <<
+ let expect = " word"
+ call assert_equal(expect, getline(1))
+
+ " Shift back to the first tabstop.
+ norm! <<
+ let expect = " word"
+ call assert_equal(expect, getline(1))
+
+ " Shift back to the left margin.
+ norm! <<
+ let expect = "word"
+ call assert_equal(expect, getline(1))
+
+ " Shift again back to the left margin.
+ norm! <<
+ let expect = "word"
+ call assert_equal(expect, getline(1))
+
+ bwipeout!
+endfunc
+
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/test/old/testdir/test_visual.vim b/test/old/testdir/test_visual.vim
index 0b840944bf..5307c49012 100644
--- a/test/old/testdir/test_visual.vim
+++ b/test/old/testdir/test_visual.vim
@@ -2709,4 +2709,13 @@ func Test_visual_block_cursor_delete()
bwipe!
endfunc
+func Test_visual_block_cursor_insert_enter()
+ new
+ call setline(1, ['asdf asdf', 'asdf asdf', 'asdf asdf', 'asdf asdf'])
+ call cursor(1, 5)
+ exe ":norm! \<c-v>3jcw\<cr>"
+ call assert_equal(['asdfw', 'asdf', 'asdfasdf', 'asdfasdf', 'asdfasdf'], getline(1, '$'))
+ bwipe!
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/test/unit/fixtures/rbuffer.c b/test/unit/fixtures/rbuffer.c
deleted file mode 100644
index d587d6b054..0000000000
--- a/test/unit/fixtures/rbuffer.c
+++ /dev/null
@@ -1,28 +0,0 @@
-#include "nvim/rbuffer.h"
-#include "rbuffer.h"
-
-
-void ut_rbuffer_each_read_chunk(RBuffer *buf, each_ptr_cb cb)
-{
- RBUFFER_UNTIL_EMPTY(buf, rptr, rcnt) {
- cb(rptr, rcnt);
- rbuffer_consumed(buf, rcnt);
- }
-}
-
-void ut_rbuffer_each_write_chunk(RBuffer *buf, each_ptr_cb cb)
-{
- RBUFFER_UNTIL_FULL(buf, wptr, wcnt) {
- cb(wptr, wcnt);
- rbuffer_produced(buf, wcnt);
- }
-}
-void ut_rbuffer_each(RBuffer *buf, each_cb cb)
-{
- RBUFFER_EACH(buf, c, i) cb(c, i);
-}
-
-void ut_rbuffer_each_reverse(RBuffer *buf, each_cb cb)
-{
- RBUFFER_EACH_REVERSE(buf, c, i) cb(c, i);
-}
diff --git a/test/unit/fixtures/rbuffer.h b/test/unit/fixtures/rbuffer.h
deleted file mode 100644
index 640092c627..0000000000
--- a/test/unit/fixtures/rbuffer.h
+++ /dev/null
@@ -1,9 +0,0 @@
-#include "nvim/rbuffer.h"
-
-typedef void(*each_ptr_cb)(char *ptr, size_t cnt);
-typedef void(*each_cb)(char c, size_t i);
-
-void ut_rbuffer_each_read_chunk(RBuffer *buf, each_ptr_cb cb);
-void ut_rbuffer_each_write_chunk(RBuffer *buf, each_ptr_cb cb);
-void ut_rbuffer_each(RBuffer *buf, each_cb cb);
-void ut_rbuffer_each_reverse(RBuffer *buf, each_cb cb);
diff --git a/test/unit/rbuffer_spec.lua b/test/unit/rbuffer_spec.lua
deleted file mode 100644
index ad18ea2ddc..0000000000
--- a/test/unit/rbuffer_spec.lua
+++ /dev/null
@@ -1,340 +0,0 @@
-local t = require('test.unit.testutil')
-local itp = t.gen_itp(it)
-
-local eq = t.eq
-local ffi = t.ffi
-local cstr = t.cstr
-local to_cstr = t.to_cstr
-local child_call_once = t.child_call_once
-
-local rbuffer = t.cimport('./test/unit/fixtures/rbuffer.h')
-
-describe('rbuffer functions', function()
- local capacity = 16
- local rbuf
-
- local function inspect()
- return ffi.string(rbuf.start_ptr, capacity)
- end
-
- local function write(str)
- local buf = to_cstr(str)
- return rbuffer.rbuffer_write(rbuf, buf, #str)
- end
-
- local function read(len)
- local buf = cstr(len)
- len = rbuffer.rbuffer_read(rbuf, buf, len)
- return ffi.string(buf, len)
- end
-
- local function get(idx)
- return ffi.string(rbuffer.rbuffer_get(rbuf, idx), 1)
- end
-
- before_each(function()
- child_call_once(function()
- rbuf = ffi.gc(rbuffer.rbuffer_new(capacity), rbuffer.rbuffer_free)
- -- fill the internal buffer with the character '0' to simplify inspecting
- ffi.C.memset(rbuf.start_ptr, string.byte('0'), capacity)
- end)
- end)
-
- describe('RBUFFER_UNTIL_FULL', function()
- local chunks
-
- local function collect_write_chunks()
- rbuffer.ut_rbuffer_each_write_chunk(rbuf, function(wptr, wcnt)
- table.insert(chunks, ffi.string(wptr, wcnt))
- end)
- end
-
- before_each(function()
- chunks = {}
- end)
-
- describe('with empty buffer in one contiguous chunk', function()
- itp('is called once with the empty chunk', function()
- collect_write_chunks()
- eq({ '0000000000000000' }, chunks)
- end)
- end)
-
- describe('with partially empty buffer in one contiguous chunk', function()
- itp('is called once with the empty chunk', function()
- write('string')
- collect_write_chunks()
- eq({ '0000000000' }, chunks)
- end)
- end)
-
- describe('with filled buffer in one contiguous chunk', function()
- itp('is not called', function()
- write('abcdefghijklmnopq')
- collect_write_chunks()
- eq({}, chunks)
- end)
- end)
-
- describe('with buffer partially empty in two contiguous chunks', function()
- itp('is called twice with each filled chunk', function()
- write('1234567890')
- read(8)
- collect_write_chunks()
- eq({ '000000', '12345678' }, chunks)
- end)
- end)
-
- describe('with buffer empty in two contiguous chunks', function()
- itp('is called twice with each filled chunk', function()
- write('12345678')
- read(8)
- collect_write_chunks()
- eq({ '00000000', '12345678' }, chunks)
- end)
- end)
-
- describe('with buffer filled in two contiguous chunks', function()
- itp('is not called', function()
- write('12345678')
- read(8)
- write('abcdefghijklmnopq')
- collect_write_chunks()
- eq({}, chunks)
- end)
- end)
- end)
-
- describe('RBUFFER_UNTIL_EMPTY', function()
- local chunks
-
- local function collect_read_chunks()
- rbuffer.ut_rbuffer_each_read_chunk(rbuf, function(rptr, rcnt)
- table.insert(chunks, ffi.string(rptr, rcnt))
- end)
- end
-
- before_each(function()
- chunks = {}
- end)
-
- describe('with empty buffer', function()
- itp('is not called', function()
- collect_read_chunks()
- eq({}, chunks)
- end)
- end)
-
- describe('with partially filled buffer in one contiguous chunk', function()
- itp('is called once with the filled chunk', function()
- write('string')
- collect_read_chunks()
- eq({ 'string' }, chunks)
- end)
- end)
-
- describe('with filled buffer in one contiguous chunk', function()
- itp('is called once with the filled chunk', function()
- write('abcdefghijklmnopq')
- collect_read_chunks()
- eq({ 'abcdefghijklmnop' }, chunks)
- end)
- end)
-
- describe('with buffer partially filled in two contiguous chunks', function()
- itp('is called twice with each filled chunk', function()
- write('1234567890')
- read(10)
- write('long string')
- collect_read_chunks()
- eq({ 'long s', 'tring' }, chunks)
- end)
- end)
-
- describe('with buffer filled in two contiguous chunks', function()
- itp('is called twice with each filled chunk', function()
- write('12345678')
- read(8)
- write('abcdefghijklmnopq')
- collect_read_chunks()
- eq({ 'abcdefgh', 'ijklmnop' }, chunks)
- end)
- end)
- end)
-
- describe('RBUFFER_EACH', function()
- local chars
-
- local function collect_chars()
- rbuffer.ut_rbuffer_each(rbuf, function(c, i)
- table.insert(chars, { string.char(c), tonumber(i) })
- end)
- end
- before_each(function()
- chars = {}
- end)
-
- describe('with empty buffer', function()
- itp('is not called', function()
- collect_chars()
- eq({}, chars)
- end)
- end)
-
- describe('with buffer filled in two contiguous chunks', function()
- itp('collects each character and index', function()
- write('1234567890')
- read(10)
- write('long string')
- collect_chars()
- eq({
- { 'l', 0 },
- { 'o', 1 },
- { 'n', 2 },
- { 'g', 3 },
- { ' ', 4 },
- { 's', 5 },
- { 't', 6 },
- { 'r', 7 },
- { 'i', 8 },
- { 'n', 9 },
- { 'g', 10 },
- }, chars)
- end)
- end)
- end)
-
- describe('RBUFFER_EACH_REVERSE', function()
- local chars
-
- local function collect_chars()
- rbuffer.ut_rbuffer_each_reverse(rbuf, function(c, i)
- table.insert(chars, { string.char(c), tonumber(i) })
- end)
- end
- before_each(function()
- chars = {}
- end)
-
- describe('with empty buffer', function()
- itp('is not called', function()
- collect_chars()
- eq({}, chars)
- end)
- end)
-
- describe('with buffer filled in two contiguous chunks', function()
- itp('collects each character and index', function()
- write('1234567890')
- read(10)
- write('long string')
- collect_chars()
- eq({
- { 'g', 10 },
- { 'n', 9 },
- { 'i', 8 },
- { 'r', 7 },
- { 't', 6 },
- { 's', 5 },
- { ' ', 4 },
- { 'g', 3 },
- { 'n', 2 },
- { 'o', 1 },
- { 'l', 0 },
- }, chars)
- end)
- end)
- end)
-
- describe('rbuffer_cmp', function()
- local function cmp(str)
- local rv = rbuffer.rbuffer_cmp(rbuf, to_cstr(str), #str)
- if rv == 0 then
- return 0
- else
- return rv / math.abs(rv)
- end
- end
-
- describe('with buffer filled in two contiguous chunks', function()
- itp('compares the common longest sequence', function()
- write('1234567890')
- read(10)
- write('long string')
- eq(0, cmp('long string'))
- eq(0, cmp('long strin'))
- eq(-1, cmp('long striM'))
- eq(1, cmp('long strio'))
- eq(0, cmp('long'))
- eq(-1, cmp('lonG'))
- eq(1, cmp('lonh'))
- end)
- end)
-
- describe('with empty buffer', function()
- itp('returns 0 since no characters are compared', function()
- eq(0, cmp(''))
- end)
- end)
- end)
-
- describe('rbuffer_write', function()
- itp('fills the internal buffer and returns the write count', function()
- eq(12, write('short string'))
- eq('short string0000', inspect())
- end)
-
- itp('wont write beyond capacity', function()
- eq(16, write('very very long string'))
- eq('very very long s', inspect())
- end)
- end)
-
- describe('rbuffer_read', function()
- itp('reads what was previously written', function()
- write('to read')
- eq('to read', read(20))
- end)
-
- itp('reads nothing if the buffer is empty', function()
- eq('', read(20))
- write('empty')
- eq('empty', read(20))
- eq('', read(20))
- end)
- end)
-
- describe('rbuffer_get', function()
- itp('fetch the pointer at offset, wrapping if required', function()
- write('1234567890')
- read(10)
- write('long string')
- eq('l', get(0))
- eq('o', get(1))
- eq('n', get(2))
- eq('g', get(3))
- eq(' ', get(4))
- eq('s', get(5))
- eq('t', get(6))
- eq('r', get(7))
- eq('i', get(8))
- eq('n', get(9))
- eq('g', get(10))
- end)
- end)
-
- describe('wrapping behavior', function()
- itp('writing/reading wraps across the end of the internal buffer', function()
- write('1234567890')
- eq('1234', read(4))
- eq('5678', read(4))
- write('987654321')
- eq('3214567890987654', inspect())
- eq('90987654321', read(20))
- eq('', read(4))
- write('abcdefghijklmnopqrs')
- eq('nopabcdefghijklm', inspect())
- eq('abcdefghijklmnop', read(20))
- end)
- end)
-end)