aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.builds/freebsd.yml2
-rw-r--r--.builds/openbsd.yml6
-rw-r--r--.github/workflows/ci.yml4
-rw-r--r--.github/workflows/release.yml4
-rw-r--r--.gitignore1
-rw-r--r--CONTRIBUTING.md2
-rw-r--r--README.md3
-rw-r--r--contrib/flake.nix169
-rw-r--r--man/nvim.12
-rw-r--r--runtime/autoload/dist/ft.vim23
-rw-r--r--runtime/autoload/man.vim2
-rw-r--r--runtime/compiler/zsh.vim23
-rw-r--r--runtime/doc/api.txt23
-rw-r--r--runtime/doc/eval.txt30
-rw-r--r--runtime/doc/index.txt2
-rw-r--r--runtime/doc/lsp.txt115
-rw-r--r--runtime/doc/lua.txt17
-rw-r--r--runtime/doc/options.txt38
-rw-r--r--runtime/doc/repeat.txt4
-rw-r--r--runtime/doc/starting.txt9
-rw-r--r--runtime/doc/tagsrch.txt2
-rw-r--r--runtime/doc/treesitter.txt3
-rw-r--r--runtime/doc/ui.txt4
-rw-r--r--runtime/doc/various.txt18
-rw-r--r--runtime/doc/windows.txt2
-rw-r--r--runtime/filetype.vim41
-rw-r--r--runtime/ftplugin/elm.vim18
-rw-r--r--runtime/ftplugin/man.vim13
-rw-r--r--runtime/ftplugin/zsh.vim23
-rw-r--r--runtime/indent/elm.vim114
-rw-r--r--runtime/lua/vim/lsp.lua61
-rw-r--r--runtime/lua/vim/lsp/diagnostic.lua73
-rw-r--r--runtime/lua/vim/lsp/handlers.lua13
-rw-r--r--runtime/lua/vim/lsp/log.lua4
-rw-r--r--runtime/lua/vim/lsp/protocol.lua26
-rw-r--r--runtime/lua/vim/lsp/util.lua26
-rw-r--r--runtime/lua/vim/treesitter.lua2
-rw-r--r--runtime/lua/vim/treesitter/languagetree.lua18
-rw-r--r--runtime/lua/vim/treesitter/query.lua19
-rw-r--r--runtime/nvim.appdata.xml1
-rw-r--r--runtime/scripts.vim8
-rw-r--r--runtime/syntax/elm.vim105
-rw-r--r--runtime/syntax/zsh.vim89
-rwxr-xr-xscripts/vim-patch.sh16
-rw-r--r--src/nvim/README.md2
-rw-r--r--src/nvim/api/buffer.c45
-rw-r--r--src/nvim/api/private/helpers.c37
-rw-r--r--src/nvim/api/vim.c42
-rw-r--r--src/nvim/autocmd.c14
-rw-r--r--src/nvim/buffer.c2
-rw-r--r--src/nvim/channel.c12
-rw-r--r--src/nvim/charset.c4
-rw-r--r--src/nvim/decoration.c2
-rw-r--r--src/nvim/edit.c10
-rw-r--r--src/nvim/eval.c2
-rw-r--r--src/nvim/eval/decode.c4
-rw-r--r--src/nvim/eval/encode.c4
-rw-r--r--src/nvim/eval/executor.c2
-rw-r--r--src/nvim/eval/funcs.c173
-rw-r--r--src/nvim/eval/typval.c37
-rw-r--r--src/nvim/event/libuv_process.c14
-rw-r--r--src/nvim/event/process.h3
-rw-r--r--src/nvim/ex_cmds.c31
-rw-r--r--src/nvim/ex_cmds.lua2
-rw-r--r--src/nvim/ex_cmds2.c4
-rw-r--r--src/nvim/ex_docmd.c30
-rw-r--r--src/nvim/ex_getln.c17
-rw-r--r--src/nvim/extmark.c9
-rw-r--r--src/nvim/file_search.c2
-rw-r--r--src/nvim/fold.c7
-rw-r--r--src/nvim/globals.h2
-rw-r--r--src/nvim/log.c18
-rw-r--r--src/nvim/lua/converter.c6
-rw-r--r--src/nvim/lua/executor.c89
-rw-r--r--src/nvim/lua/vim.lua171
-rw-r--r--src/nvim/main.c1
-rw-r--r--src/nvim/mark.c1
-rw-r--r--src/nvim/message.c34
-rw-r--r--src/nvim/message.h9
-rw-r--r--src/nvim/normal.c29
-rw-r--r--src/nvim/ops.c4
-rw-r--r--src/nvim/option.c58
-rw-r--r--src/nvim/option_defs.h20
-rw-r--r--src/nvim/options.lua8
-rw-r--r--src/nvim/os/env.c53
-rw-r--r--src/nvim/os/pty_process_unix.c37
-rw-r--r--src/nvim/os/pty_process_win.c78
-rw-r--r--src/nvim/os/stdpaths.c11
-rw-r--r--src/nvim/os/time.c2
-rw-r--r--src/nvim/po/af.po7
-rw-r--r--src/nvim/po/ca.po4
-rw-r--r--src/nvim/po/cs.cp1250.po4
-rw-r--r--src/nvim/po/cs.po4
-rw-r--r--src/nvim/po/da.po3
-rw-r--r--src/nvim/po/de.po4
-rw-r--r--src/nvim/po/en_GB.po4
-rw-r--r--src/nvim/po/eo.po3
-rw-r--r--src/nvim/po/es.po4
-rw-r--r--src/nvim/po/fi.po7
-rw-r--r--src/nvim/po/fr.po3
-rw-r--r--src/nvim/po/ga.po3
-rw-r--r--src/nvim/po/it.po4
-rw-r--r--src/nvim/po/ja.euc-jp.po3
-rw-r--r--src/nvim/po/ja.po3
-rw-r--r--src/nvim/po/ko.UTF-8.po4
-rw-r--r--src/nvim/po/nb.po4
-rw-r--r--src/nvim/po/nl.po4
-rw-r--r--src/nvim/po/no.po4
-rw-r--r--src/nvim/po/pl.UTF-8.po4
-rw-r--r--src/nvim/po/pt_BR.po4
-rw-r--r--src/nvim/po/ru.po4
-rw-r--r--src/nvim/po/sk.cp1250.po4
-rw-r--r--src/nvim/po/sk.po4
-rw-r--r--src/nvim/po/sr.po3
-rw-r--r--src/nvim/po/sv.po4
-rw-r--r--src/nvim/po/uk.po253
-rw-r--r--src/nvim/po/vi.po4
-rw-r--r--src/nvim/po/zh_CN.UTF-8.po4
-rw-r--r--src/nvim/po/zh_TW.UTF-8.po4
-rw-r--r--src/nvim/quickfix.c4
-rw-r--r--src/nvim/screen.c32
-rw-r--r--src/nvim/search.c87
-rw-r--r--src/nvim/shada.c16
-rw-r--r--src/nvim/spell.c11
-rw-r--r--src/nvim/spellfile.c3
-rw-r--r--src/nvim/tag.c2
-rw-r--r--src/nvim/terminal.c57
-rw-r--r--src/nvim/testdir/test_autocmd.vim40
-rw-r--r--src/nvim/testdir/test_backspace_opt.vim151
-rw-r--r--src/nvim/testdir/test_compiler.vim18
-rw-r--r--src/nvim/testdir/test_eval_stuff.vim11
-rw-r--r--src/nvim/testdir/test_filetype.vim56
-rw-r--r--src/nvim/testdir/test_fold.vim35
-rw-r--r--src/nvim/testdir/test_highlight.vim14
-rw-r--r--src/nvim/testdir/test_marks.vim5
-rw-r--r--src/nvim/testdir/test_mksession.vim26
-rw-r--r--src/nvim/testdir/test_options.vim25
-rw-r--r--src/nvim/testdir/test_quickfix.vim19
-rw-r--r--src/nvim/testdir/test_sleep.vim26
-rw-r--r--src/nvim/testdir/test_startup.vim78
-rw-r--r--src/nvim/testdir/test_window_cmd.vim4
-rw-r--r--src/nvim/tui/input.c2
-rw-r--r--src/nvim/ui_compositor.c2
-rw-r--r--src/nvim/version.c6
-rw-r--r--src/nvim/vim.h1
-rw-r--r--src/nvim/viml/parser/expressions.c6
-rw-r--r--test/functional/api/extmark_spec.lua34
-rw-r--r--test/functional/api/vim_spec.lua73
-rw-r--r--test/functional/core/job_spec.lua21
-rw-r--r--test/functional/eval/environ_spec.lua61
-rw-r--r--test/functional/legacy/backspace_opt_spec.lua67
-rw-r--r--test/functional/lua/buffer_updates_spec.lua130
-rw-r--r--test/functional/lua/command_line_completion_spec.lua171
-rw-r--r--test/functional/options/defaults_spec.lua26
-rw-r--r--test/functional/plugin/lsp/diagnostic_spec.lua100
-rw-r--r--test/functional/plugin/lsp_spec.lua124
-rw-r--r--test/functional/treesitter/parser_spec.lua35
-rw-r--r--test/functional/ui/sign_spec.lua105
-rw-r--r--test/functional/viml/completion_spec.lua43
-rw-r--r--test/symbolic/klee/nvim/charset.c4
-rw-r--r--test/symbolic/klee/nvim/memory.c4
-rw-r--r--third-party/CMakeLists.txt8
162 files changed, 3435 insertions, 996 deletions
diff --git a/.builds/freebsd.yml b/.builds/freebsd.yml
index bb7fbeb78b..d5809c42cf 100644
--- a/.builds/freebsd.yml
+++ b/.builds/freebsd.yml
@@ -28,7 +28,7 @@ tasks:
gmake deps
- build: |
cd neovim
- gmake CMAKE_BUILD_TYPE=Release CMAKE_EXTRA_FLAGS="${CMAKE_EXTRA_FLAGS}" nvim
+ gmake CMAKE_BUILD_TYPE=RelWithDebInfo CMAKE_EXTRA_FLAGS="${CMAKE_EXTRA_FLAGS}" nvim
- functionaltest: |
cd neovim
gmake functionaltest
diff --git a/.builds/openbsd.yml b/.builds/openbsd.yml
index 2f0f970dcb..0ffc8aa786 100644
--- a/.builds/openbsd.yml
+++ b/.builds/openbsd.yml
@@ -28,16 +28,16 @@ tasks:
mkdir neovim/.deps
cd neovim/.deps
cmake -G Ninja ../third-party/
- cmake --build . --config Debug
+ cmake --build . --config RelWithDebInfo
- build: |
mkdir neovim/build
cd neovim/build
cmake -G Ninja $CMAKE_EXTRA_FLAGS ..
- cmake --build . --config Debug
+ cmake --build . --config RelWithDebInfo
./bin/nvim --version
- functionaltest: |
cd neovim/build
- cmake --build . --config Debug --target functionaltest
+ cmake --build . --config RelWithDebInfo --target functionaltest
- oldtest: |
cd neovim
gmake oldtest
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 3653f04d5d..44a911b21b 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -56,10 +56,12 @@ jobs:
- name: Install brew packages
if: matrix.os == 'osx'
run: |
+ # Workaround brew issues
rm -f /usr/local/bin/2to3
+ brew unlink gcc@8 gcc@9
brew update >/dev/null
- brew install automake ccache cpanminus ninja
brew upgrade
+ brew install automake ccache perl cpanminus ninja
- name: Setup interpreter packages
run: |
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 506174971a..753142e555 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -76,7 +76,9 @@ jobs:
- name: Install brew packages
run: |
rm -f /usr/local/bin/2to3
+ brew unlink gcc@8 gcc@9
brew update >/dev/null
+ brew upgrade
brew install automake ninja
- name: Build release
run: |
@@ -154,7 +156,7 @@ jobs:
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
- delete_release: false
+ delete_release: ''
tag_name: nightly
- uses: meeDamian/github-release@2.0
with:
diff --git a/.gitignore b/.gitignore
index ab301bd336..6004101cce 100644
--- a/.gitignore
+++ b/.gitignore
@@ -12,6 +12,7 @@ compile_commands.json
/.deps/
/tmp/
/.clangd/
+/.cache/clangd/
.DS_Store
*.mo
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index c179db0c46..64433e67e7 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -36,6 +36,7 @@ Developer guidelines
make distclean
make # Nvim build system uses ninja automatically, if available.
```
+- [Improve documentation][wiki-contribute-help]
Pull requests (PRs)
---------------------
@@ -235,3 +236,4 @@ as context, use the `-W` argument as well.
[Clang report]: https://neovim.io/doc/reports/clang/
[complexity:low]: https://github.com/neovim/neovim/issues?q=is%3Aopen+is%3Aissue+label%3Acomplexity%3Alow
[master error list]: https://raw.githubusercontent.com/neovim/doc/gh-pages/reports/clint/errors.json
+[wiki-contribute-help]: https://github.com/neovim/neovim/wiki/contribute-%3Ahelp
diff --git a/README.md b/README.md
index 180fc1df14..f4d92b77a1 100644
--- a/README.md
+++ b/README.md
@@ -46,7 +46,7 @@ Install from package
Pre-built packages for Windows, macOS, and Linux are found on the
[Releases](https://github.com/neovim/neovim/releases/) page.
-[Managed packages] are in Homebrew, [Debian], [Ubuntu], [Fedora], [Arch Linux],
+[Managed packages] are in [Homebrew], [Debian], [Ubuntu], [Fedora], [Arch Linux],
[Gentoo], and more!
Install from source
@@ -137,5 +137,6 @@ Apache 2.0 license, except for contributions copied from Vim (identified by the
[Fedora]: https://apps.fedoraproject.org/packages/neovim
[Arch Linux]: https://www.archlinux.org/packages/?q=neovim
[Gentoo]: https://packages.gentoo.org/packages/app-editors/neovim
+[Homebrew]: https://formulae.brew.sh/formula/neovim
<!-- vim: set tw=80: -->
diff --git a/contrib/flake.nix b/contrib/flake.nix
index 86e4b37cfa..d18534215c 100644
--- a/contrib/flake.nix
+++ b/contrib/flake.nix
@@ -3,93 +3,100 @@
inputs = {
nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
+ flake-utils.url = "github:numtide/flake-utils";
};
- outputs = { self, nixpkgs }: let
- system = "x86_64-linux";
- legacyPkgs = nixpkgs.legacyPackages."${system}".pkgs;
- pkgs = legacyPkgs;
- in {
-
- packages."${system}" = rec {
-
- neovim = legacyPkgs.neovim-unwrapped.overrideAttrs(oa: {
- version = "master";
- src = ../.;
-
- buildInputs = oa.buildInputs ++ ([
- pkgs.tree-sitter
- ]);
-
- cmakeFlags = oa.cmakeFlags ++ [
- "-DUSE_BUNDLED=OFF"
- ];
- });
-
- # a development binary to help debug issues
- neovim-debug = (neovim.override {
- stdenv = pkgs.llvmPackages_latest.stdenv;
- lua = pkgs.enableDebugging legacyPkgs.luajit;
- }).overrideAttrs(oa:{
- cmakeBuildType="Debug";
- cmakeFlags = oa.cmakeFlags ++ [
- "-DMIN_LOG_LEVEL=0"
- ];
- });
-
- # for neovim developers, very slow
- # brings development tools as well
- neovim-developer = let
- lib = nixpkgs.lib;
- pythonEnv = legacyPkgs.python3;
- luacheck = legacyPkgs.luaPackages.luacheck;
+ outputs = { self, nixpkgs, flake-utils }:
+ {
+ overlay = final: prev:
+ let
+ pkgs = nixpkgs.legacyPackages.${prev.system};
+ in
+ rec {
+ neovim = pkgs.neovim-unwrapped.overrideAttrs (oa: {
+ version = "master";
+ src = ../.;
+
+ buildInputs = oa.buildInputs ++ ([
+ pkgs.tree-sitter
+ ]);
+
+ cmakeFlags = oa.cmakeFlags ++ [
+ "-DUSE_BUNDLED=OFF"
+ ];
+ });
+
+ # a development binary to help debug issues
+ neovim-debug = (neovim.override {
+ stdenv = if pkgs.stdenv.isLinux then pkgs.llvmPackages_latest.stdenv else pkgs.stdenv;
+ lua = pkgs.enableDebugging pkgs.luajit;
+ }).overrideAttrs (oa: {
+ cmakeBuildType = "Debug";
+ cmakeFlags = oa.cmakeFlags ++ [
+ "-DMIN_LOG_LEVEL=0"
+ ];
+ });
+
+ # for neovim developers, very slow
+ # brings development tools as well
+ neovim-developer =
+ let
+ lib = nixpkgs.lib;
+ pythonEnv = pkgs.python3;
+ luacheck = pkgs.luaPackages.luacheck;
+ in
+ (neovim-debug.override ({ doCheck = pkgs.stdenv.isLinux; })).overrideAttrs (oa: {
+ cmakeFlags = oa.cmakeFlags ++ [
+ "-DLUACHECK_PRG=${luacheck}/bin/luacheck"
+ "-DMIN_LOG_LEVEL=0"
+ "-DENABLE_LTO=OFF"
+ "-DUSE_BUNDLED=OFF"
+ ] ++ pkgs.stdenv.lib.optionals pkgs.stdenv.isLinux [
+ # https://github.com/google/sanitizers/wiki/AddressSanitizerFlags
+ # https://clang.llvm.org/docs/AddressSanitizer.html#symbolizing-the-reports
+ "-DCLANG_ASAN_UBSAN=ON"
+ ];
+
+ nativeBuildInputs = oa.nativeBuildInputs ++ (with pkgs; [
+ pythonEnv
+ include-what-you-use # for scripts/check-includes.py
+ jq # jq for scripts/vim-patch.sh -r
+ doxygen
+ ]);
+
+ shellHook = oa.shellHook + ''
+ export NVIM_PYTHON_LOG_LEVEL=DEBUG
+ export NVIM_LOG_FILE=/tmp/nvim.log
+
+ export ASAN_OPTIONS="log_path=./test.log:abort_on_error=1"
+ export UBSAN_OPTIONS=print_stacktrace=1
+ '';
+ });
+ };
+ } //
+ flake-utils.lib.eachDefaultSystem (system:
+ let
+ pkgs = import nixpkgs {
+ overlays = [ self.overlay ];
+ inherit system;
+ };
in
- (neovim-debug.override({doCheck = true;})).overrideAttrs(oa: {
- cmakeFlags = oa.cmakeFlags ++ [
- "-DLUACHECK_PRG=${luacheck}/bin/luacheck"
- "-DMIN_LOG_LEVEL=0"
- "-DENABLE_LTO=OFF"
- "-DUSE_BUNDLED=OFF"
- # https://github.com/google/sanitizers/wiki/AddressSanitizerFlags
- # https://clang.llvm.org/docs/AddressSanitizer.html#symbolizing-the-reports
- "-DCLANG_ASAN_UBSAN=ON"
- ];
-
- nativeBuildInputs = oa.nativeBuildInputs ++ (with pkgs; [
- pythonEnv
- include-what-you-use # for scripts/check-includes.py
- jq # jq for scripts/vim-patch.sh -r
- doxygen
- ]);
-
- shellHook = oa.shellHook + ''
- export NVIM_PYTHON_LOG_LEVEL=DEBUG
- export NVIM_LOG_FILE=/tmp/nvim.log
+ rec {
- export ASAN_OPTIONS="log_path=./test.log:abort_on_error=1"
- export UBSAN_OPTIONS=print_stacktrace=1
- '';
- });
- };
+ packages = with pkgs; {
+ inherit neovim neovim-debug neovim-developer;
+ };
- defaultPackage."${system}" = self.packages."${system}".neovim;
+ defaultPackage = pkgs.neovim;
- overlay = final: prev: {
- inherit (self.packages."${system}") neovim neovim-debug;
- };
+ apps = {
+ nvim = flake-utils.lib.mkApp { drv = pkgs.neovim; name = "nvim"; };
+ nvim-debug = flake-utils.lib.mkApp { drv = pkgs.neovim-debug; name = "nvim"; };
+ };
- apps."${system}" = let
- mkApp = pkg: {
- type = "app";
- program = pkg + "/bin/nvim";
- };
- in {
- nvim = mkApp self.packages."${system}".neovim;
- nvim-debug = mkApp self.packages."${system}".neovim-debug;
- };
+ defaultApp = apps.nvim;
- defaultApp."${system}" = self.apps."${system}".nvim;
-
- devShell."${system}" = self.packages."${system}".neovim-developer;
- };
+ devShell = pkgs.neovim-developer;
+ }
+ );
}
diff --git a/man/nvim.1 b/man/nvim.1
index 305551c7d4..ca0f41d489 100644
--- a/man/nvim.1
+++ b/man/nvim.1
@@ -327,7 +327,7 @@ Print version information and exit.
.Sh ENVIRONMENT
.Bl -tag -width Fl
.It Ev NVIM_LOG_FILE
-Low-level log file, usually found at ~/.local/share/nvim/log.
+Low-level log file, usually found at ~/.cache/nvim/log.
:help $NVIM_LOG_FILE
.It Ev VIM
Used to locate user files, such as init.vim.
diff --git a/runtime/autoload/dist/ft.vim b/runtime/autoload/dist/ft.vim
index b6297472c3..cf26bc3172 100644
--- a/runtime/autoload/dist/ft.vim
+++ b/runtime/autoload/dist/ft.vim
@@ -362,6 +362,10 @@ func dist#ft#FTinc()
setf aspvbs
elseif lines =~ "<?"
setf php
+ " Pascal supports // comments but they're vary rarely used for file
+ " headers so assume POV-Ray
+ elseif lines =~ '^\s*\%({\|(\*\)' || lines =~? s:ft_pascal_keywords
+ setf pascal
else
call dist#ft#FTasmsyntax()
if exists("b:asmsyntax")
@@ -408,6 +412,9 @@ func dist#ft#FTprogress_asm()
setf progress
endfunc
+let s:ft_pascal_comments = '^\s*\%({\|(\*\|//\)'
+let s:ft_pascal_keywords = '^\s*\%(program\|unit\|library\|uses\|begin\|procedure\|function\|const\|type\|var\)\>'
+
func dist#ft#FTprogress_pascal()
if exists("g:filetype_p")
exe "setf " . g:filetype_p
@@ -419,8 +426,7 @@ func dist#ft#FTprogress_pascal()
let lnum = 1
while lnum <= 10 && lnum < line('$')
let line = getline(lnum)
- if line =~ '^\s*\(program\|unit\|procedure\|function\|const\|type\|var\)\>'
- \ || line =~ '^\s*{' || line =~ '^\s*(\*'
+ if line =~ s:ft_pascal_comments || line =~? s:ft_pascal_keywords
setf pascal
return
elseif line !~ '^\s*$' || line =~ '^/\*'
@@ -433,6 +439,19 @@ func dist#ft#FTprogress_pascal()
setf progress
endfunc
+func dist#ft#FTpp()
+ if exists("g:filetype_pp")
+ exe "setf " . g:filetype_pp
+ else
+ let line = getline(nextnonblank(1))
+ if line =~ s:ft_pascal_comments || line =~? s:ft_pascal_keywords
+ setf pascal
+ else
+ setf puppet
+ endif
+ endif
+endfunc
+
func dist#ft#FTr()
let max = line("$") > 50 ? 50 : line("$")
diff --git a/runtime/autoload/man.vim b/runtime/autoload/man.vim
index 99d8c41dba..78a86315a3 100644
--- a/runtime/autoload/man.vim
+++ b/runtime/autoload/man.vim
@@ -137,8 +137,6 @@ function! s:put_page(page) abort
setlocal modifiable
setlocal noreadonly
setlocal noswapfile
- " git-ls-files(1) is all one keyword/tag-target
- setlocal iskeyword+=(,)
silent keepjumps %delete _
silent put =a:page
while getline(1) =~# '^\s*$'
diff --git a/runtime/compiler/zsh.vim b/runtime/compiler/zsh.vim
new file mode 100644
index 0000000000..5703c1fc44
--- /dev/null
+++ b/runtime/compiler/zsh.vim
@@ -0,0 +1,23 @@
+" Vim compiler file
+" Compiler: Zsh
+" Maintainer: Doug Kearns <dougkearns@gmail.com>
+" Last Change: 2020 Sep 6
+
+if exists("current_compiler")
+ finish
+endif
+let current_compiler = "zsh"
+
+if exists(":CompilerSet") != 2 " older Vim always used :setlocal
+ command -nargs=* CompilerSet setlocal <args>
+endif
+
+let s:cpo_save = &cpo
+set cpo&vim
+
+CompilerSet makeprg=zsh\ -n\ --\ %:S
+CompilerSet errorformat=%f:\ line\ %l:\ %m,
+ \%-G%.%#
+
+let &cpo = s:cpo_save
+unlet s:cpo_save
diff --git a/runtime/doc/api.txt b/runtime/doc/api.txt
index 485c93b0dd..dd3469372e 100644
--- a/runtime/doc/api.txt
+++ b/runtime/doc/api.txt
@@ -663,6 +663,17 @@ nvim_del_var({name}) *nvim_del_var()*
Parameters: ~
{name} Variable name
+nvim_echo({chunks}, {history}, {opts}) *nvim_echo()*
+ Echo a message.
+
+ Parameters: ~
+ {chunks} A list of [text, hl_group] arrays, each
+ representing a text chunk with specified
+ highlight. `hl_group` element can be omitted
+ for no highlight.
+ {history} if true, add to |message-history|.
+ {opts} Optional parameters. Reserved for future use.
+
nvim_err_write({str}) *nvim_err_write()*
Writes a message to the Vim error buffer. Does not append
"\n", the message is buffered (won't display) until a linefeed
@@ -1937,8 +1948,7 @@ nvim_buf_get_extmark_by_id({buffer}, {ns_id}, {id}, {opts})
{ns_id} Namespace id from |nvim_create_namespace()|
{id} Extmark id
{opts} Optional parameters. Keys:
- • limit: Maximum number of marks to return
- • details Whether to include the details dict
+ • details: Whether to include the details dict
Return: ~
(row, col) tuple or empty list () if extmark id was absent
@@ -2153,6 +2163,15 @@ nvim_buf_set_extmark({buffer}, {ns_id}, {line}, {col}, {opts})
mark will only be used for the current redraw
cycle, and not be permantently stored in the
buffer.
+ • right_gravity : boolean that indicates the
+ direction the extmark will be shifted in when
+ new text is inserted (true for right, false
+ for left). defaults to true.
+ • end_right_gravity : boolean that indicates the
+ direction the extmark end position (if it
+ exists) will be shifted in when new text is
+ inserted (true for right, false for left).
+ Defaults to false.
Return: ~
Id of the created/updated extmark
diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt
index 2d433a6d7a..384bdd63a4 100644
--- a/runtime/doc/eval.txt
+++ b/runtime/doc/eval.txt
@@ -1600,7 +1600,7 @@ v:event Dictionary of event data for the current |autocommand|. Valid
regtype Type of register as returned by
|getregtype()|.
visual Selection is visual (as opposed to,
- e.g., via motion).
+ e.g., via motion).
completed_item Current selected complete item on
|CompleteChanged|, Is `{}` when no complete
item selected.
@@ -1783,7 +1783,7 @@ v:msgpack_types Dictionary containing msgpack types used by |msgpackparse()|
of msgpack types, use |is| operator.
*v:null* *null-variable*
-v:null Special value used to put "null" in JSON and NIL in msgpack.
+v:null Special value used to put "null" in JSON and NIL in msgpack.
See |json_encode()|. This value is converted to "v:null" when
used as a String (e.g. in |expr5| with string concatenation
operator) and to zero when used as a Number (e.g. in |expr5|
@@ -4150,7 +4150,7 @@ function({name} [, {arglist}] [, {dict}])
garbagecollect([{atexit}]) *garbagecollect()*
Cleanup unused |Lists| and |Dictionaries| that have circular
references.
-
+
There is hardly ever a need to invoke this function, as it is
automatically done when Vim runs out of memory or is waiting
for the user to press a key after 'updatetime'. Items without
@@ -4934,7 +4934,7 @@ getwininfo([{winid}]) *getwininfo()*
quickfix 1 if quickfix or location list window
terminal 1 if a terminal window
tabnr tab page number
- topline first displayed buffer line
+ topline first displayed buffer line
variables a reference to the dictionary with
window-local variables
width window width
@@ -5074,7 +5074,7 @@ has({feature}) Returns 1 if {feature} is supported, 0 otherwise. The
Vim's compile-time feature-names (prefixed with "+") are not
recognized because Nvim is always compiled with all possible
- features. |feature-compile|
+ features. |feature-compile|
Feature names can be:
1. Nvim version. For example the "nvim-0.2.1" feature means
@@ -5099,7 +5099,7 @@ has({feature}) Returns 1 if {feature} is supported, 0 otherwise. The
ttyin input is a terminal (tty)
ttyout output is a terminal (tty)
unix Unix system.
- *vim_starting* True during |startup|.
+ *vim_starting* True during |startup|.
win32 Windows system (32 or 64 bit).
win64 Windows system (64 bit).
wsl WSL (Windows Subsystem for Linux) system
@@ -5684,7 +5684,7 @@ json_encode({expr}) *json_encode()*
|msgpack-special-dict|), values with self-referencing
containers, strings which contain non-UTF-8 characters,
pseudo-UTF-8 strings which contain codepoints reserved for
- surrogate pairs (such strings are not valid UTF-8 strings).
+ surrogate pairs (such strings are not valid UTF-8 strings).
Non-printable characters are converted into "\u1234" escapes
or special escapes like "\t", other are dumped as-is.
@@ -5847,7 +5847,7 @@ map({expr1}, {expr2}) *map()*
{expr1} must be a |List| or a |Dictionary|.
Replace each item in {expr1} with the result of evaluating
{expr2}. {expr2} must be a |string| or |Funcref|.
-
+
If {expr2} is a |string|, inside {expr2} |v:val| has the value
of the current item. For a |Dictionary| |v:key| has the key
of the current item and for a |List| |v:key| has the index of
@@ -6114,8 +6114,8 @@ matchaddpos({group}, {pos} [, {priority} [, {id} [, {dict}]]])
- A list with three numbers, e.g., [23, 11, 3]. As above, but
the third number gives the length of the highlight in bytes.
- Entries with zero and negative line numbers are silently
- ignored, as well as entries with negative column numbers and
+ Entries with zero and negative line numbers are silently
+ ignored, as well as entries with negative column numbers and
lengths.
The maximum number of positions is 8.
@@ -7608,7 +7608,7 @@ setpos({expr}, {list})
setqflist({list} [, {action}[, {what}]]) *setqflist()*
Create or replace or add to the quickfix list.
-
+
When {what} is not present, use the items in {list}. Each
item must be a dictionary. Non-dictionary items in {list} are
ignored. Each dictionary item can contain the following
@@ -7649,12 +7649,12 @@ setqflist({list} [, {action}[, {what}]]) *setqflist()*
'a' The items from {list} are added to the existing
quickfix list. If there is no existing list, then a
new list is created.
-
+
'r' The items from the current quickfix list are replaced
with the items from {list}. This can also be used to
clear the list: >
:call setqflist([], 'r')
-<
+<
'f' All the quickfix lists in the quickfix stack are
freed.
@@ -8023,7 +8023,7 @@ sign_place({id}, {group}, {name}, {expr} [, {dict}])
empty string. {group} functions as a namespace for {id}, thus
two groups can use the same IDs. Refer to |sign-identifier|
for more information.
-
+
{name} refers to a defined sign.
{expr} refers to a buffer name or number. For the accepted
values, see |bufname()|.
@@ -8803,7 +8803,7 @@ system({cmd} [, {input}]) *system()* *E677*
Note: Use |shellescape()| or |::S| with |expand()| or
|fnamemodify()| to escape special characters in a command
- argument. Newlines in {cmd} may cause the command to fail.
+ argument. Newlines in {cmd} may cause the command to fail.
The characters in 'shellquote' and 'shellxquote' may also
cause trouble.
diff --git a/runtime/doc/index.txt b/runtime/doc/index.txt
index 17de1d8533..172821ac28 100644
--- a/runtime/doc/index.txt
+++ b/runtime/doc/index.txt
@@ -1543,6 +1543,8 @@ tag command action ~
|:sign| :sig[n] manipulate signs
|:silent| :sil[ent] run a command silently
|:sleep| :sl[eep] do nothing for a few seconds
+|:sleep!| :sl[eep]! do nothing for a few seconds, without the
+ cursor visible
|:slast| :sla[st] split window and go to last file in the
argument list
|:smagic| :sm[agic] :substitute with 'magic'
diff --git a/runtime/doc/lsp.txt b/runtime/doc/lsp.txt
index 6ca7b52fff..06666c3a27 100644
--- a/runtime/doc/lsp.txt
+++ b/runtime/doc/lsp.txt
@@ -27,9 +27,9 @@ Follow these steps to get LSP features:
1. Install the nvim-lspconfig plugin. It provides common configuration for
various servers so you can get started quickly.
https://github.com/neovim/nvim-lspconfig
- 2. Install a language server. Try ":LspInstall <tab>" or use your system
- package manager to install the relevant language server:
+ 2. Install a language server. A list of language servers can be found here:
https://microsoft.github.io/language-server-protocol/implementors/servers/
+ See individual server documentation for installation instructions.
3. Add `lua require('lspconfig').xx.setup{…}` to your init.vim, where "xx" is
the name of the relevant config. See the nvim-lspconfig README for details.
NOTE: Make sure to restart nvim after installing and configuring.
@@ -62,20 +62,39 @@ Example config (in init.vim): >
vim.api.nvim_buf_set_option(0, 'omnifunc', 'v:lua.vim.lsp.omnifunc')
-- For plugins with an `on_attach` callback, call them here. For example:
- -- require('completion').on_attach(client)
+ -- require('completion').on_attach()
end
-- An example of configuring for `sumneko_lua`,
-- a language server for Lua.
- -- First, you must run `:LspInstall sumneko_lua` for this to work.
+
+ -- set the path to the sumneko installation
+ local system_name = "Linux" -- (Linux, macOS, or Windows)
+ local sumneko_root_path = '/path/to/lua-language-server'
+ local sumneko_binary = sumneko_root_path.."/bin/"..system_name.."/lua-language-server"
+
require('lspconfig').sumneko_lua.setup({
+ cmd = {sumneko_binary, "-E", sumneko_root_path .. "/main.lua"};
-- An example of settings for an LSP server.
-- For more options, see nvim-lspconfig
settings = {
Lua = {
+ runtime = {
+ -- Tell the language server which version of Lua you're using (most likely LuaJIT in the case of Neovim)
+ version = 'LuaJIT',
+ -- Setup your lua path
+ path = vim.split(package.path, ';'),
+ },
diagnostics = {
- enable = true,
- globals = { "vim" },
+ -- Get the language server to recognize the `vim` global
+ globals = {'vim'},
+ },
+ workspace = {
+ -- Make the server aware of Neovim runtime files
+ library = {
+ [vim.fn.expand('$VIMRUNTIME/lua')] = true,
+ [vim.fn.expand('$VIMRUNTIME/lua/vim/lsp')] = true,
+ },
},
}
},
@@ -620,8 +639,9 @@ client() *vim.lsp.client*
automatically escalate and force shutdown.
• is_stopped() Checks whether a client is stopped. Returns:
true if the client is fully stopped.
- • on_attach(bufnr) Runs the on_attach function from the
- client's config if it was defined.
+ • on_attach(client, bufnr) Runs the on_attach function from
+ the client's config if it was defined. Useful for
+ buffer-local setup.
• Members
• {id} (number): The id allocated to the client.
@@ -659,6 +679,14 @@ get_active_clients() *vim.lsp.get_active_clients()*
Return: ~
Table of |vim.lsp.client| objects
+ *vim.lsp.get_buffers_by_client_id()*
+get_buffers_by_client_id({client_id})
+ Parameters: ~
+ {client_id} client id
+
+ Return: ~
+ list of buffer ids
+
get_client_by_id({client_id}) *vim.lsp.get_client_by_id()*
Gets a client by id, or nil if the id is invalid. The returned
client may not yet be fully initialized.
@@ -757,8 +785,9 @@ start_client({config}) *vim.lsp.start_client()*
{handlers} Map of language server method names to
|lsp-handler|
{settings} Map with language server specific
- settings. These are returned to the language server if
- requested via `workspace/configuration`. Keys are
+ settings. These are returned to the
+ language server if requested via
+ `workspace/configuration` . Keys are
case-sensitive.
{init_options} Values to pass in the initialization
request as `initializationOptions` .
@@ -796,7 +825,14 @@ start_client({config}) *vim.lsp.start_client()*
`capabilities.offsetEncoding` was sent
to it. You can only modify the
`client.offset_encoding` here before
- any notifications are sent.
+ any notifications are sent. Most
+ language servers expect to be sent
+ client specified settings after
+ initialization. Neovim does not make
+ this assumption. A
+ `workspace/didChangeConfiguration`
+ notification should be sent to the
+ server during on_init.
{on_exit} Callback (code, signal, client_id)
invoked on client exit.
• code: exit code of the process
@@ -1323,6 +1359,10 @@ set_signs({diagnostics}, {bufnr}, {client_id}, {sign_ns}, {opts})
{sign_ns} number|nil
{opts} table Configuration for signs. Keys:
• priority: Set the priority of the signs.
+ • severity_limit (DiagnosticSeverity):
+ • Limit severity of diagnostics found.
+ E.g. "Warning" means { "Error",
+ "Warning" } will be valid.
*vim.lsp.diagnostic.set_underline()*
set_underline({diagnostics}, {bufnr}, {client_id}, {diagnostic_ns}, {opts})
@@ -1340,10 +1380,14 @@ set_underline({diagnostics}, {bufnr}, {client_id}, {diagnostic_ns}, {opts})
Parameters: ~
{diagnostics} Diagnostic []
- {bufnr} number The buffer number
- {client_id} number the client id
- {diagnostic_ns} number|nil
- {opts} table Currently unused.
+ {bufnr} number: The buffer number
+ {client_id} number: The client id
+ {diagnostic_ns} number|nil: The namespace
+ {opts} table: Configuration table:
+ • severity_limit (DiagnosticSeverity):
+ • Limit severity of diagnostics found.
+ E.g. "Warning" means { "Error",
+ "Warning" } will be valid.
*vim.lsp.diagnostic.set_virtual_text()*
set_virtual_text({diagnostics}, {bufnr}, {client_id}, {diagnostic_ns}, {opts})
@@ -1370,6 +1414,10 @@ set_virtual_text({diagnostics}, {bufnr}, {client_id}, {diagnostic_ns}, {opts})
before virtual text on line
• spacing (number): Number of spaces to
insert before virtual text
+ • severity_limit (DiagnosticSeverity):
+ • Limit severity of diagnostics found.
+ E.g. "Warning" means { "Error",
+ "Warning" } will be valid.
*vim.lsp.diagnostic.show_line_diagnostics()*
show_line_diagnostics({opts}, {bufnr}, {line_nr}, {client_id})
@@ -1393,16 +1441,31 @@ show_line_diagnostics({opts}, {bufnr}, {line_nr}, {client_id})
{client_id} number|nil the client id
Return: ~
- {popup_bufnr, win_id}
+ table {popup_bufnr, win_id}
+
+
+==============================================================================
+Lua module: vim.lsp.handlers *lsp-handlers*
+
+ *vim.lsp.handlers.progress_callback()*
+progress_callback({_}, {_}, {params}, {client_id})
+ See also: ~
+ https://microsoft.github.io/language-server-protocol/specifications/specification-current/#workspace_executeCommand
==============================================================================
Lua module: vim.lsp.util *lsp-util*
*vim.lsp.util.apply_text_document_edit()*
-apply_text_document_edit({text_document_edit})
+apply_text_document_edit({text_document_edit}, {index})
+ Applies a `TextDocumentEdit` , which is a list of changes to a
+ single document.
+
Parameters: ~
- {text_document_edit} (table) a `TextDocumentEdit` object
+ {text_document_edit} table: a `TextDocumentEdit` object
+ {index} number: Optional index of the edit,
+ if from a list of edits (or nil, if
+ not from a list)
See also: ~
https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocumentEdit
@@ -1582,6 +1645,9 @@ get_effective_tabstop({bufnr}) *vim.lsp.util.get_effective_tabstop()*
See also: ~
|softtabstop|
+get_progress_messages() *vim.lsp.util.get_progress_messages()*
+ TODO: Documentation
+
jump_to_location({location}) *vim.lsp.util.jump_to_location()*
Jumps to a location.
@@ -1603,6 +1669,19 @@ locations_to_items({locations}) *vim.lsp.util.locations_to_items()*
Return: ~
(table) list of items
+lookup_section({settings}, {section}) *vim.lsp.util.lookup_section()*
+ Helper function to return nested values in language server
+ settings
+
+ Parameters: ~
+ {settings} a table of language server settings
+ {section} a string indicating the field of the settings
+ table
+
+ Return: ~
+ (table or string) The value of settings accessed via
+ section
+
*vim.lsp.util.make_floating_popup_options()*
make_floating_popup_options({width}, {height}, {opts})
Creates a table with sensible default options for a floating
diff --git a/runtime/doc/lua.txt b/runtime/doc/lua.txt
index a03de10a17..0bbed56662 100644
--- a/runtime/doc/lua.txt
+++ b/runtime/doc/lua.txt
@@ -622,6 +622,9 @@ vim.api.{func}({...}) *vim.api*
Example: call the "nvim_get_current_line()" API function: >
print(tostring(vim.api.nvim_get_current_line()))
+vim.version() *vim.version*
+ Returns the version of the current neovim build.
+
vim.in_fast_event() *vim.in_fast_event()*
Returns true if the code is executing as part of a "fast" event
handler, where most of the API is disabled. These are low-level events
@@ -1262,14 +1265,12 @@ validate({opt}) *vim.validate()*
vim.validate{arg1={{'foo'}, 'table'}, arg2={'foo', 'string'}}
=> NOP (success)
-<
->
- vim.validate{arg1={1, 'table'}}
- => error('arg1: expected table, got number')
-<
->
- vim.validate{arg1={3, function(a) return (a % 2) == 0 end, 'even number'}}
- => error('arg1: expected even number, got 3')
+
+ vim.validate{arg1={1, 'table'}}
+ => error('arg1: expected table, got number')
+
+ vim.validate{arg1={3, function(a) return (a % 2) == 0 end, 'even number'}}
+ => error('arg1: expected even number, got 3')
<
Parameters: ~
diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt
index e740a45bec..98e2d50f1d 100644
--- a/runtime/doc/options.txt
+++ b/runtime/doc/options.txt
@@ -734,6 +734,8 @@ A jump table for the options with a short description can be found at |Q_op|.
eol allow backspacing over line breaks (join lines)
start allow backspacing over the start of insert; CTRL-W and CTRL-U
stop once at the start of insert.
+ nostop like start, except CTRL-W and CTRL-U do not stop at the start of
+ insert.
When the value is empty, Vi compatible backspacing is used.
@@ -742,6 +744,7 @@ A jump table for the options with a short description can be found at |Q_op|.
0 same as ":set backspace=" (Vi compatible)
1 same as ":set backspace=indent,eol"
2 same as ":set backspace=indent,eol,start"
+ 3 same as ":set backspace=indent,eol,nostop"
*'backup'* *'bk'* *'nobackup'* *'nobk'*
'backup' 'bk' boolean (default off)
@@ -2609,7 +2612,7 @@ A jump table for the options with a short description can be found at |Q_op|.
when internal formatting is used. Make sure the cursor is kept in the
same spot relative to the text then! The |mode()| function will
return "i" or "R" in this situation.
-
+
When the expression evaluates to non-zero Vim will fall back to using
the internal format mechanism.
@@ -3184,7 +3187,7 @@ A jump table for the options with a short description can be found at |Q_op|.
*'inccommand'* *'icm'*
'inccommand' 'icm' string (default "")
global
-
+
"nosplit": Shows the effects of a command incrementally, as you type.
"split" : Also shows partial off-screen results in a preview window.
@@ -5533,6 +5536,12 @@ A jump table for the options with a short description can be found at |Q_op|.
"auto" only when there is a sign to display
"auto:[1-9]" resize to accommodate multiple signs up to the
given number (maximum 9), e.g. "auto:4"
+ "auto:[1-8]-[2-9]"
+ resize to accommodate multiple signs up to the
+ given maximum number (maximum 9) while keeping
+ at least the given minimum (maximum 8) fixed
+ space. The minimum number should always be less
+ than the maximum number, e.g. "auto:2-5"
"no" never
"yes" always
"yes:[1-9]" always, with fixed space for signs up to the given
@@ -6280,6 +6289,29 @@ A jump table for the options with a short description can be found at |Q_op|.
attributes instead of "cterm" attributes. |highlight-guifg|
Requires an ISO-8613-3 compatible terminal.
+ *'termpastefilter'* *'tpf'*
+'termpastefilter' 'tpf' string (default: "BS,HT,ESC,DEL")
+ global
+ A comma separated list of options for specifying control characters
+ to be removed from the text pasted into the terminal window. The
+ supported values are:
+
+ BS Backspace
+
+ HT TAB
+
+ FF Form feed
+
+ ESC Escape
+
+ DEL DEL
+
+ C0 Other control characters, excluding Line feed and
+ Carriage return < ' '
+
+ C1 Control characters 0x80...0x9F
+
+
*'terse'* *'noterse'*
'terse' boolean (default off)
global
@@ -6838,7 +6870,7 @@ A jump table for the options with a short description can be found at |Q_op|.
a built-in |highlight-groups| item to be overridden by {hl} group in
the window. Only built-in |highlight-groups| are supported, not
syntax highlighting (use |:ownsyntax| for that).
-
+
Highlights of vertical separators are determined by the window to the
left of the separator. The 'tabline' highlight of a tabpage is
decided by the last-focused window of the tabpage. Highlights of
diff --git a/runtime/doc/repeat.txt b/runtime/doc/repeat.txt
index d4b6324bc3..604c969c64 100644
--- a/runtime/doc/repeat.txt
+++ b/runtime/doc/repeat.txt
@@ -180,7 +180,7 @@ For writing a Vim script, see chapter 41 of the user manual |usr_41.txt|.
Read Ex commands from {file} in each directory given
by 'runtimepath' and/or 'packpath'. There is no error
for non-existing files.
-
+
Example: >
:runtime syntax/c.vim
@@ -254,7 +254,7 @@ For writing a Vim script, see chapter 41 of the user manual |usr_41.txt|.
*:packl* *:packloadall*
:packl[oadall][!] Load all packages in the "start" directory under each
entry in 'packpath'.
-
+
First all the directories found are added to
'runtimepath', then the plugins found in the
directories are sourced. This allows for a plugin to
diff --git a/runtime/doc/starting.txt b/runtime/doc/starting.txt
index 160995b440..4a99aa47bf 100644
--- a/runtime/doc/starting.txt
+++ b/runtime/doc/starting.txt
@@ -1316,8 +1316,9 @@ file when reading and include:
==============================================================================
Standard Paths *standard-path*
-Nvim stores configuration and data in standard locations. Plugins are strongly
-encouraged to follow this pattern also. Use |stdpath()| to get the paths.
+Nvim stores configuration, data, and logs in standard locations. Plugins are
+strongly encouraged to follow this pattern also. Use |stdpath()| to get the
+paths.
*base-directories* *xdg*
The "base" (root) directories conform to the XDG Base Directory Specification.
@@ -1342,8 +1343,8 @@ LOG FILE *$NVIM_LOG_FILE*
Besides 'debug' and 'verbose', Nvim keeps a general log file for internal
debugging, plugins and RPC clients. >
:echo $NVIM_LOG_FILE
-Usually the file is ~/.local/share/nvim/log unless that path is inaccessible
-or if $NVIM_LOG_FILE was set before |startup|.
+By default, the file is located at stdpath('cache')/log unless that path
+is inaccessible or if $NVIM_LOG_FILE was set before |startup|.
vim:noet:tw=78:ts=8:ft=help:norl:
diff --git a/runtime/doc/tagsrch.txt b/runtime/doc/tagsrch.txt
index b011db3dd3..23db809543 100644
--- a/runtime/doc/tagsrch.txt
+++ b/runtime/doc/tagsrch.txt
@@ -544,7 +544,7 @@ only supported by new versions of ctags (such as Exuberant ctags).
the bar) and ;" is used to have Vi ignore the rest of the
line. Example:
APP file.c call cursor(3, 4)|;" v
-
+
{field} .. A list of optional fields. Each field has the form:
<Tab>{fieldname}:{value}
diff --git a/runtime/doc/treesitter.txt b/runtime/doc/treesitter.txt
index 911e7b8b47..1696d3b9ba 100644
--- a/runtime/doc/treesitter.txt
+++ b/runtime/doc/treesitter.txt
@@ -195,7 +195,8 @@ query:iter_captures({node}, {bufnr}, {start_row}, {end_row})
text of the buffer. {start_row} and {end_row} can be used to limit
matches inside a row range (this is typically used with root node
as the node, i e to get syntax highlight matches in the current
- viewport)
+ viewport). When omitted the start and end row values are used from
+ the given node.
The iterator returns three values, a numeric id identifying the capture,
the captured node, and metadata from any directives processing the match.
diff --git a/runtime/doc/ui.txt b/runtime/doc/ui.txt
index 0a8584927e..82406898c8 100644
--- a/runtime/doc/ui.txt
+++ b/runtime/doc/ui.txt
@@ -170,7 +170,7 @@ the editor.
`mouse_shape`: (To be implemented.)
Some keys are missing in some modes.
-
+
The following keys are deprecated:
`hl_id`: Use `attr_id` instead.
@@ -460,7 +460,7 @@ is not active. New UIs should implement |ui-linegrid| instead.
["set_scroll_region", top, bot, left, right]
Define the scroll region used by `scroll` below.
-
+
Note: ranges are end-inclusive, which is inconsistent with API
conventions.
diff --git a/runtime/doc/various.txt b/runtime/doc/various.txt
index 32551815b0..5fb7c4ce50 100644
--- a/runtime/doc/various.txt
+++ b/runtime/doc/various.txt
@@ -46,26 +46,26 @@ CTRL-L Clears and redraws the screen. The redraw may happen
ga Print the ascii value of the character under the
cursor in decimal, hexadecimal and octal.
Mnemonic: Get Ascii value.
-
+
For example, when the cursor is on a 'R':
<R> 82, Hex 52, Octal 122 ~
When the character is a non-standard ASCII character,
but printable according to the 'isprint' option, the
non-printable version is also given.
-
+
When the character is larger than 127, the <M-x> form
is also printed. For example:
<~A> <M-^A> 129, Hex 81, Octal 201 ~
<p> <|~> <M-~> 254, Hex fe, Octal 376 ~
(where <p> is a special character)
-
+
The <Nul> character in a file is stored internally as
<NL>, but it will be shown as:
<^@> 0, Hex 00, Octal 000 ~
-
+
If the character has composing characters these are
also shown. The value of 'maxcombine' doesn't matter.
-
+
If the character can be inserted as a digraph, also
output the two characters that can be used to create
the character:
@@ -317,11 +317,11 @@ g8 Print the hex values of the bytes used in the
optional.
:redi[r] @{a-z}>> Append messages to register {a-z}.
-:redi[r] @*>
+:redi[r] @*>
:redi[r] @+> Redirect messages to the selection or clipboard. For
backward compatibility, the ">" after the register
name can be omitted. See |quotestar| and |quoteplus|.
-:redi[r] @*>>
+:redi[r] @*>>
:redi[r] @+>> Append messages to the selection or clipboard.
:redi[r] @"> Redirect messages to the unnamed register. For
@@ -489,12 +489,12 @@ gO Show a filetype-specific, navigable "outline" of the
Currently works in |help| and |:Man| buffers.
[N]gs *gs* *:sl* *:sleep*
-:[N]sl[eep] [N] [m] Do nothing for [N] seconds, or [N] milliseconds if [m]
+:[N]sl[eep] [N][m] Do nothing for [N] seconds, or [N] milliseconds if [m]
was given. "gs" always uses seconds.
Default is one second. >
:sleep "sleep for one second
:5sleep "sleep for five seconds
- :sleep 100m "sleep for a hundred milliseconds
+ :sleep 100m "sleep for 100 milliseconds
10gs "sleep for ten seconds
< Can be interrupted with CTRL-C.
"gs" stands for "goto sleep".
diff --git a/runtime/doc/windows.txt b/runtime/doc/windows.txt
index b5623f4ea4..2c3ffcbe9a 100644
--- a/runtime/doc/windows.txt
+++ b/runtime/doc/windows.txt
@@ -124,7 +124,7 @@ CTRL-W CTRL-S *CTRL-W_CTRL-S*
:[N]sp[lit] [++opt] [+cmd] [file] *:sp* *:split*
Split current window in two. The result is two viewports on
the same file.
-
+
Make the new window N high (default is to use half the height
of the current window). Reduces the current window height to
create room (and others, if the 'equalalways' option is set,
diff --git a/runtime/filetype.vim b/runtime/filetype.vim
index 959fe35662..53fd66c4df 100644
--- a/runtime/filetype.vim
+++ b/runtime/filetype.vim
@@ -585,6 +585,9 @@ au BufNewFile,BufRead *.fan,*.fwt setf fan
" Factor
au BufNewFile,BufRead *.factor setf factor
+" Fennel
+autocmd BufRead,BufNewFile *.fnl setf fennel
+
" Fetchmail RC file
au BufNewFile,BufRead .fetchmailrc setf fetchmail
@@ -1169,8 +1172,11 @@ au BufNewFile,BufRead *.papp,*.pxml,*.pxsl setf papp
" Password file
au BufNewFile,BufRead */etc/passwd,*/etc/passwd-,*/etc/passwd.edit,*/etc/shadow,*/etc/shadow-,*/etc/shadow.edit,*/var/backups/passwd.bak,*/var/backups/shadow.bak setf passwd
-" Pascal (also *.p)
-au BufNewFile,BufRead *.pas,*.pp setf pascal
+" Pascal (also *.p, *.pp, *.inc)
+au BufNewFile,BufRead *.pas setf pascal
+
+" Pascal or Puppet manifest
+au BufNewFile,BufRead *.pp call dist#ft#FTpp()
" Delphi or Lazarus program file
au BufNewFile,BufRead *.dpr,*.lpr setf pascal
@@ -1260,7 +1266,7 @@ au BufNewFile,BufRead *.pov setf pov
" Povray configuration
au BufNewFile,BufRead .povrayrc setf povini
-" Povray, PHP or assembly
+" Povray, Pascal, PHP or assembly
au BufNewFile,BufRead *.inc call dist#ft#FTinc()
" Printcap and Termcap
@@ -1269,13 +1275,19 @@ au BufNewFile,BufRead *printcap
au BufNewFile,BufRead *termcap
\ let b:ptcap_type = "term" | setf ptcap
-" PCCTS / ANTRL
-"au BufNewFile,BufRead *.g setf antrl
+" PCCTS / ANTLR
+"au BufNewFile,BufRead *.g setf antlr
au BufNewFile,BufRead *.g setf pccts
" PPWizard
au BufNewFile,BufRead *.it,*.ih setf ppwiz
+" Puppet
+au BufNewFile,BufRead Puppetfile setf ruby
+
+" Embedded Puppet
+au BufNewFile,BufRead *.epp setf epuppet
+
" Obj 3D file format
" TODO: is there a way to avoid MS-Windows Object files?
au BufNewFile,BufRead *.obj setf obj
@@ -1425,8 +1437,8 @@ au BufNewFile,BufRead *.rb,*.rbw setf ruby
" RubyGems
au BufNewFile,BufRead *.gemspec setf ruby
-" Rust
-au BufNewFile,BufRead *.rs setf rust
+" RBS (Ruby Signature)
+au BufNewFile,BufRead *.rbs setf rbs
" Rackup
au BufNewFile,BufRead *.ru setf ruby
@@ -1440,6 +1452,9 @@ au BufNewFile,BufRead *.builder,*.rxml,*.rjs setf ruby
" Rantfile and Rakefile is like Ruby
au BufNewFile,BufRead [rR]antfile,*.rant,[rR]akefile,*.rake setf ruby
+" Rust
+au BufNewFile,BufRead *.rs setf rust
+
" S-lang (or shader language, or SmallLisp)
au BufNewFile,BufRead *.sl setf slang
@@ -1618,6 +1633,9 @@ au BufNewFile,BufRead *.mib,*.my setf mib
au BufNewFile,BufRead *.hog,snort.conf,vision.conf setf hog
au BufNewFile,BufRead *.rules call dist#ft#FTRules()
+" SPARQL queries
+au BufNewFile,BufRead *.rq,*.sparql setf sparql
+
" Spec (Linux RPM)
au BufNewFile,BufRead *.spec setf spec
@@ -1728,8 +1746,13 @@ au BufNewFile,BufRead *.tli setf tli
" Telix Salt
au BufNewFile,BufRead *.slt setf tsalt
-" Tera Term Language
-au BufRead,BufNewFile *.ttl setf teraterm
+" Tera Term Language or Turtle
+au BufRead,BufNewFile *.ttl
+ \ if getline(1) =~ '^@\?\(prefix\|base\)' |
+ \ setf turtle |
+ \ else |
+ \ setf teraterm |
+ \ endif
" Terminfo
au BufNewFile,BufRead *.ti setf terminfo
diff --git a/runtime/ftplugin/elm.vim b/runtime/ftplugin/elm.vim
new file mode 100644
index 0000000000..1e10346186
--- /dev/null
+++ b/runtime/ftplugin/elm.vim
@@ -0,0 +1,18 @@
+" Elm filetype plugin file
+" Language: Elm
+" Maintainer: Andreas Scharf <as@99n.de>
+" Latest Revision: 2020-05-29
+
+if exists("b:did_ftplugin")
+ finish
+endif
+let b:did_ftplugin = 1
+
+let s:cpo_save = &cpo
+set cpo&vim
+
+setlocal comments=s1fl:{-,mb:\ ,ex:-},:--
+setlocal commentstring=--\ %s
+
+let &cpo = s:cpo_save
+unlet s:cpo_save
diff --git a/runtime/ftplugin/man.vim b/runtime/ftplugin/man.vim
index 74225a558c..5d3e00d033 100644
--- a/runtime/ftplugin/man.vim
+++ b/runtime/ftplugin/man.vim
@@ -16,7 +16,11 @@ setlocal noswapfile buftype=nofile bufhidden=hide
setlocal nomodified readonly nomodifiable
setlocal noexpandtab tabstop=8 softtabstop=8 shiftwidth=8
setlocal wrap breakindent linebreak
-setlocal iskeyword+=-
+
+" Parentheses and '-' for references like `git-ls-files(1)`; '@' for systemd
+" pages; ':' for Perl and C++ pages. Here, I intentionally omit the locale
+" specific characters matched by `@`.
+setlocal iskeyword=@-@,:,a-z,A-Z,48-57,_,.,-,(,)
setlocal nonumber norelativenumber
setlocal foldcolumn=0 colorcolumn=0 nolist nofoldenable
@@ -24,9 +28,10 @@ setlocal foldcolumn=0 colorcolumn=0 nolist nofoldenable
setlocal tagfunc=man#goto_tag
if !exists('g:no_plugin_maps') && !exists('g:no_man_maps')
- nnoremap <silent> <buffer> j gj
- nnoremap <silent> <buffer> k gk
- nnoremap <silent> <buffer> gO :call man#show_toc()<CR>
+ nnoremap <silent> <buffer> j gj
+ nnoremap <silent> <buffer> k gk
+ nnoremap <silent> <buffer> gO :call man#show_toc()<CR>
+ nnoremap <silent> <buffer> <2-LeftMouse> :Man<CR>
if s:pager
nnoremap <silent> <buffer> <nowait> q :lclose<CR>:q<CR>
else
diff --git a/runtime/ftplugin/zsh.vim b/runtime/ftplugin/zsh.vim
index fe8efc59ab..53ce1417dd 100644
--- a/runtime/ftplugin/zsh.vim
+++ b/runtime/ftplugin/zsh.vim
@@ -2,7 +2,7 @@
" Language: Zsh shell script
" Maintainer: Christian Brabandt <cb@256bit.org>
" Previous Maintainer: Nikolai Weibull <now@bitwi.se>
-" Latest Revision: 2017-11-22
+" Latest Revision: 2020-09-01
" License: Vim (see :h license)
" Repository: https://github.com/chrisbra/vim-zsh
@@ -14,11 +14,26 @@ let b:did_ftplugin = 1
let s:cpo_save = &cpo
set cpo&vim
-let b:undo_ftplugin = "setl com< cms< fo<"
-
setlocal comments=:# commentstring=#\ %s formatoptions-=t formatoptions+=croql
-let b:match_words = ',\<if\>:\<elif\>:\<else\>:\<fi\>'
+let b:undo_ftplugin = "setl com< cms< fo< "
+
+if executable('zsh')
+ if !has('gui_running') && executable('less')
+ command! -buffer -nargs=1 RunHelp silent exe '!MANPAGER= zsh -ic "autoload -Uz run-help; run-help <args> 2>/dev/null | LESS= less"' | redraw!
+ elseif has('terminal')
+ command! -buffer -nargs=1 RunHelp silent exe ':term zsh -ic "autoload -Uz run-help; run-help <args>"'
+ else
+ command! -buffer -nargs=1 RunHelp echo system('zsh -ic "autoload -Uz run-help; run-help <args> 2>/dev/null"')
+ endif
+ if !exists('current_compiler')
+ compiler zsh
+ endif
+ setlocal keywordprg=:RunHelp
+ let b:undo_ftplugin .= 'keywordprg<'
+endif
+
+let b:match_words = '\<if\>:\<elif\>:\<else\>:\<fi\>'
\ . ',\<case\>:^\s*([^)]*):\<esac\>'
\ . ',\<\%(select\|while\|until\|repeat\|for\%(each\)\=\)\>:\<done\>'
let b:match_skip = 's:comment\|string\|heredoc\|subst'
diff --git a/runtime/indent/elm.vim b/runtime/indent/elm.vim
new file mode 100644
index 0000000000..232c347c66
--- /dev/null
+++ b/runtime/indent/elm.vim
@@ -0,0 +1,114 @@
+" Elm indent plugin file
+" Language: Elm
+" Maintainer: Andreas Scharf <as@99n.de>
+" Original Author: Joseph Hager <ajhager@gmail.com>
+" Copyright: Joseph Hager <ajhager@gmail.com>
+" License: BSD3
+" Latest Revision: 2020-05-29
+
+" Only load this indent file when no other was loaded.
+if exists('b:did_indent')
+ finish
+endif
+let b:did_indent = 1
+
+" Local defaults
+setlocal expandtab
+setlocal indentexpr=GetElmIndent()
+setlocal indentkeys+=0=else,0=if,0=of,0=import,0=then,0=type,0\|,0},0\],0),=-},0=in
+setlocal nolisp
+setlocal nosmartindent
+
+" Only define the function once.
+if exists('*GetElmIndent')
+ finish
+endif
+
+" Indent pairs
+function! s:FindPair(pstart, pmid, pend)
+ "call search(a:pend, 'bW')
+ return indent(searchpair(a:pstart, a:pmid, a:pend, 'bWn', 'synIDattr(synID(line("."), col("."), 0), "name") =~? "string\\|comment"'))
+endfunction
+
+function! GetElmIndent()
+ let l:lnum = v:lnum - 1
+
+ " Ident 0 if the first line of the file:
+ if l:lnum == 0
+ return 0
+ endif
+
+ let l:ind = indent(l:lnum)
+ let l:lline = getline(l:lnum)
+ let l:line = getline(v:lnum)
+
+ " Indent if current line begins with '}':
+ if l:line =~? '^\s*}'
+ return s:FindPair('{', '', '}')
+
+ " Indent if current line begins with 'else':
+ elseif l:line =~# '^\s*else\>'
+ if l:lline !~# '^\s*\(if\|then\)\>'
+ return s:FindPair('\<if\>', '', '\<else\>')
+ endif
+
+ " Indent if current line begins with 'then':
+ elseif l:line =~# '^\s*then\>'
+ if l:lline !~# '^\s*\(if\|else\)\>'
+ return s:FindPair('\<if\>', '', '\<then\>')
+ endif
+
+ " HACK: Indent lines in case with nearest case clause:
+ elseif l:line =~# '->' && l:line !~# ':' && l:line !~# '\\'
+ return indent(search('^\s*case', 'bWn')) + &shiftwidth
+
+ " HACK: Don't change the indentation if the last line is a comment.
+ elseif l:lline =~# '^\s*--'
+ return l:ind
+
+ " Align the end of block comments with the start
+ elseif l:line =~# '^\s*-}'
+ return indent(search('{-', 'bWn'))
+
+ " Indent double shift after let with an empty rhs
+ elseif l:lline =~# '\<let\>.*\s=$'
+ return l:ind + 4 + &shiftwidth
+
+ " Align 'in' with the parent let.
+ elseif l:line =~# '^\s*in\>'
+ return indent(search('^\s*let', 'bWn'))
+
+ " Align bindings with the parent let.
+ elseif l:lline =~# '\<let\>'
+ return l:ind + 4
+
+ " Align bindings with the parent in.
+ elseif l:lline =~# '^\s*in\>'
+ return l:ind
+
+ endif
+
+ " Add a 'shiftwidth' after lines ending with:
+ if l:lline =~# '\(|\|=\|->\|<-\|(\|\[\|{\|\<\(of\|else\|if\|then\)\)\s*$'
+ let l:ind = l:ind + &shiftwidth
+
+ " Add a 'shiftwidth' after lines starting with type ending with '=':
+ elseif l:lline =~# '^\s*type' && l:line =~# '^\s*='
+ let l:ind = l:ind + &shiftwidth
+
+ " Back to normal indent after comments:
+ elseif l:lline =~# '-}\s*$'
+ call search('-}', 'bW')
+ let l:ind = indent(searchpair('{-', '', '-}', 'bWn', 'synIDattr(synID(line("."), col("."), 0), "name") =~? "string"'))
+
+ " Ident some operators if there aren't any starting the last line.
+ elseif l:line =~# '^\s*\(!\|&\|(\|`\|+\||\|{\|[\|,\)=' && l:lline !~# '^\s*\(!\|&\|(\|`\|+\||\|{\|[\|,\)=' && l:lline !~# '^\s*$'
+ let l:ind = l:ind + &shiftwidth
+
+ elseif l:lline ==# '' && getline(l:lnum - 1) !=# ''
+ let l:ind = indent(search('^\s*\S+', 'bWn'))
+
+ endif
+
+ return l:ind
+endfunc
diff --git a/runtime/lua/vim/lsp.lua b/runtime/lua/vim/lsp.lua
index 0326550245..a6f118abde 100644
--- a/runtime/lua/vim/lsp.lua
+++ b/runtime/lua/vim/lsp.lua
@@ -121,6 +121,9 @@ local active_clients = {}
local all_buffer_active_clients = {}
local uninitialized_clients = {}
+-- Tracks all buffers attached to a client.
+local all_client_active_buffers = {}
+
--@private
--- Invokes a function for each LSP client attached to the buffer {bufnr}.
---
@@ -226,6 +229,7 @@ local function validate_client_config(config)
on_error = { config.on_error, "f", true };
on_exit = { config.on_exit, "f", true };
on_init = { config.on_init, "f", true };
+ settings = { config.settings, "t", true };
before_init = { config.before_init, "f", true };
offset_encoding = { config.offset_encoding, "s", true };
flags = { config.flags, "t", true };
@@ -327,8 +331,9 @@ end
--- Checks whether a client is stopped.
--- Returns: true if the client is fully stopped.
---
---- - on_attach(bufnr)
+--- - on_attach(client, bufnr)
--- Runs the on_attach function from the client's config if it was defined.
+--- Useful for buffer-local setup.
---
--- - Members
--- - {id} (number): The id allocated to the client.
@@ -398,6 +403,10 @@ end
---
--@param handlers Map of language server method names to |lsp-handler|
---
+--@param settings Map with language server specific settings. These are
+--- returned to the language server if requested via `workspace/configuration`.
+--- Keys are case-sensitive.
+---
--@param init_options Values to pass in the initialization request
--- as `initializationOptions`. See `initialize` in the LSP spec.
---
@@ -424,7 +433,10 @@ end
--- the server may send. For example, clangd sends
--- `initialize_result.offsetEncoding` if `capabilities.offsetEncoding` was
--- sent to it. You can only modify the `client.offset_encoding` here before
---- any notifications are sent.
+--- any notifications are sent. Most language servers expect to be sent client specified settings after
+--- initialization. Neovim does not make this assumption. A
+--- `workspace/didChangeConfiguration` notification should be sent
+--- to the server during on_init.
---
--@param on_exit Callback (code, signal, client_id) invoked on client
--- exit.
@@ -457,6 +469,7 @@ function lsp.start_client(config)
local cmd, cmd_args, offset_encoding = cleaned_config.cmd, cleaned_config.cmd_args, cleaned_config.offset_encoding
config.flags = config.flags or {}
+ config.settings = config.settings or {}
local client_id = next_client_id()
@@ -581,12 +594,19 @@ function lsp.start_client(config)
local valid_traces = {
off = 'off'; messages = 'messages'; verbose = 'verbose';
}
+ local version = vim.version()
local initialize_params = {
-- The process Id of the parent process that started the server. Is null if
-- the process has not been started by another process. If the parent
-- process is not alive then the server should exit (see exit notification)
-- its process.
processId = uv.getpid();
+ -- Information about the client
+ -- since 3.15.0
+ clientInfo = {
+ name = "Neovim",
+ version = string.format("%s.%s.%s", version.major, version.minor, version.patch)
+ };
-- The rootPath of the workspace. Is null if no folder is open.
--
-- @deprecated in favour of rootUri.
@@ -871,9 +891,7 @@ end
function lsp._text_document_did_save_handler(bufnr)
bufnr = resolve_bufnr(bufnr)
local uri = vim.uri_from_bufnr(bufnr)
- local text = once(function()
- return table.concat(nvim_buf_get_lines(bufnr, 0, -1, false), '\n')
- end)
+ local text = once(buf_get_full_text)
for_each_buffer_client(bufnr, function(client, _client_id)
if client.resolved_capabilities.text_document_save then
local included_text
@@ -916,7 +934,7 @@ function lsp.buf_attach_client(bufnr, client_id)
on_lines = text_document_did_change_handler;
on_detach = function()
local params = { textDocument = { uri = uri; } }
- for_each_buffer_client(bufnr, function(client, _client_id)
+ for_each_buffer_client(bufnr, function(client, _)
if client.resolved_capabilities.text_document_open_close then
client.notify('textDocument/didClose', params)
end
@@ -930,6 +948,13 @@ function lsp.buf_attach_client(bufnr, client_id)
utf_sizes = true;
})
end
+
+ if not all_client_active_buffers[client_id] then
+ all_client_active_buffers[client_id] = {}
+ end
+
+ table.insert(all_client_active_buffers[client_id], bufnr)
+
if buffer_client_ids[client_id] then return end
-- This is our first time attaching this client to this buffer.
buffer_client_ids[client_id] = true
@@ -961,6 +986,19 @@ function lsp.get_client_by_id(client_id)
return active_clients[client_id] or uninitialized_clients[client_id]
end
+--- Returns list of buffers attached to client_id.
+--
+--@param client_id client id
+--@returns list of buffer ids
+function lsp.get_buffers_by_client_id(client_id)
+ local active_client_buffers = all_client_active_buffers[client_id]
+ if active_client_buffers then
+ return active_client_buffers
+ else
+ return {}
+ end
+end
+
--- Stops a client(s).
---
--- You can also use the `stop()` function on a |vim.lsp.client| object.
@@ -978,12 +1016,23 @@ end
function lsp.stop_client(client_id, force)
local ids = type(client_id) == 'table' and client_id or {client_id}
for _, id in ipairs(ids) do
+ local resolved_client_id
if type(id) == 'table' and id.stop ~= nil then
id.stop(force)
+ resolved_client_id = id.id
elseif active_clients[id] then
active_clients[id].stop(force)
+ resolved_client_id = id
elseif uninitialized_clients[id] then
uninitialized_clients[id].stop(true)
+ resolved_client_id = id
+ end
+ if resolved_client_id then
+ local client_buffers = lsp.get_buffers_by_client_id(resolved_client_id)
+ for idx = 1, #client_buffers do
+ lsp.diagnostic.clear(client_buffers[idx], resolved_client_id)
+ end
+ all_client_active_buffers[resolved_client_id] = nil
end
end
end
diff --git a/runtime/lua/vim/lsp/diagnostic.lua b/runtime/lua/vim/lsp/diagnostic.lua
index 072349b226..a625098bab 100644
--- a/runtime/lua/vim/lsp/diagnostic.lua
+++ b/runtime/lua/vim/lsp/diagnostic.lua
@@ -16,6 +16,24 @@ local to_severity = function(severity)
return type(severity) == 'string' and DiagnosticSeverity[severity] or severity
end
+local filter_to_severity_limit = function(severity, diagnostics)
+ local filter_level = to_severity(severity)
+ if not filter_level then
+ return diagnostics
+ end
+
+ return vim.tbl_filter(function(t) return t.severity == filter_level end, diagnostics)
+end
+
+local filter_by_severity_limit = function(severity_limit, diagnostics)
+ local filter_level = to_severity(severity_limit)
+ if not filter_level then
+ return diagnostics
+ end
+
+ return vim.tbl_filter(function(t) return t.severity <= filter_level end, diagnostics)
+end
+
local to_position = function(position, bufnr)
vim.validate { position = {position, 't'} }
@@ -377,11 +395,9 @@ function M.get_line_diagnostics(bufnr, line_nr, opts, client_id)
end
if opts.severity then
- local filter_level = to_severity(opts.severity)
- line_diagnostics = vim.tbl_filter(function(t) return t.severity == filter_level end, line_diagnostics)
+ line_diagnostics = filter_to_severity_limit(opts.severity, line_diagnostics)
elseif opts.severity_limit then
- local filter_level = to_severity(opts.severity_limit)
- line_diagnostics = vim.tbl_filter(function(t) return t.severity <= filter_level end, line_diagnostics)
+ line_diagnostics = filter_by_severity_limit(opts.severity_limit, line_diagnostics)
end
if opts.severity_sort then
@@ -542,7 +558,7 @@ function M.goto_prev(opts)
)
end
---- Get the previous diagnostic closest to the cursor_position
+--- Get the next diagnostic closest to the cursor_position
---@param opts table See |vim.lsp.diagnostic.goto_next()|
---@return table Next diagnostic
function M.get_next(opts)
@@ -609,6 +625,8 @@ end
---@param sign_ns number|nil
---@param opts table Configuration for signs. Keys:
--- - priority: Set the priority of the signs.
+--- - severity_limit (DiagnosticSeverity):
+--- - Limit severity of diagnostics found. E.g. "Warning" means { "Error", "Warning" } will be valid.
function M.set_signs(diagnostics, bufnr, client_id, sign_ns, opts)
opts = opts or {}
sign_ns = sign_ns or M._get_sign_namespace(client_id)
@@ -622,9 +640,11 @@ function M.set_signs(diagnostics, bufnr, client_id, sign_ns, opts)
end
bufnr = get_bufnr(bufnr)
+ diagnostics = filter_by_severity_limit(opts.severity_limit, diagnostics)
local ok = true
for _, diagnostic in ipairs(diagnostics) do
+
ok = ok and pcall(vim.fn.sign_place,
0,
sign_ns,
@@ -654,15 +674,17 @@ end
--- </pre>
---
---@param diagnostics Diagnostic[]
----@param bufnr number The buffer number
----@param client_id number the client id
----@param diagnostic_ns number|nil
----@param opts table Currently unused.
+---@param bufnr number: The buffer number
+---@param client_id number: The client id
+---@param diagnostic_ns number|nil: The namespace
+---@param opts table: Configuration table:
+--- - severity_limit (DiagnosticSeverity):
+--- - Limit severity of diagnostics found. E.g. "Warning" means { "Error", "Warning" } will be valid.
function M.set_underline(diagnostics, bufnr, client_id, diagnostic_ns, opts)
opts = opts or {}
- assert(opts) -- lint
diagnostic_ns = diagnostic_ns or M._get_diagnostic_namespace(client_id)
+ diagnostics = filter_by_severity_limit(opts.severity_limit, diagnostics)
for _, diagnostic in ipairs(diagnostics) do
local start = diagnostic.range["start"]
@@ -703,6 +725,8 @@ end
---@param opts table Options on how to display virtual text. Keys:
--- - prefix (string): Prefix to display before virtual text on line
--- - spacing (number): Number of spaces to insert before virtual text
+--- - severity_limit (DiagnosticSeverity):
+--- - Limit severity of diagnostics found. E.g. "Warning" means { "Error", "Warning" } will be valid.
function M.set_virtual_text(diagnostics, bufnr, client_id, diagnostic_ns, opts)
opts = opts or {}
@@ -721,6 +745,7 @@ function M.set_virtual_text(diagnostics, bufnr, client_id, diagnostic_ns, opts)
end
for line, line_diagnostics in pairs(buffer_line_diagnostics) do
+ line_diagnostics = filter_by_severity_limit(opts.severity_limit, line_diagnostics)
local virt_texts = M.get_virtual_text_chunks_for_line(bufnr, line, line_diagnostics, opts)
if virt_texts then
@@ -1082,7 +1107,7 @@ end
---@param bufnr number The buffer number
---@param line_nr number The line number
---@param client_id number|nil the client id
----@return {popup_bufnr, win_id}
+---@return table {popup_bufnr, win_id}
function M.show_line_diagnostics(opts, bufnr, line_nr, client_id)
opts = opts or {}
opts.severity_sort = if_nil(opts.severity_sort, true)
@@ -1151,30 +1176,14 @@ function M.set_loclist(opts)
local bufnr = vim.api.nvim_get_current_buf()
local buffer_diags = M.get(bufnr, opts.client_id)
- local severity = to_severity(opts.severity)
- local severity_limit = to_severity(opts.severity_limit)
+ if opts.severity then
+ buffer_diags = filter_to_severity_limit(opts.severity, buffer_diags)
+ elseif opts.severity_limit then
+ buffer_diags = filter_by_severity_limit(opts.severity_limit, buffer_diags)
+ end
local items = {}
local insert_diag = function(diag)
- if severity then
- -- Handle missing severities
- if not diag.severity then
- return
- end
-
- if severity ~= diag.severity then
- return
- end
- elseif severity_limit then
- if not diag.severity then
- return
- end
-
- if severity_limit < diag.severity then
- return
- end
- end
-
local pos = diag.range.start
local row = pos.line
local col = util.character_offset(bufnr, row, pos.character)
diff --git a/runtime/lua/vim/lsp/handlers.lua b/runtime/lua/vim/lsp/handlers.lua
index 87f35363b1..7eac3febd9 100644
--- a/runtime/lua/vim/lsp/handlers.lua
+++ b/runtime/lua/vim/lsp/handlers.lua
@@ -97,6 +97,18 @@ M['window/showMessageRequest'] = function(_, _, params)
end
end
+--@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#client_registerCapability
+M['client/registerCapability'] = function(_, _, _, client_id)
+ local warning_tpl = "The language server %s triggers a registerCapability "..
+ "handler despite dynamicRegistration set to false. "..
+ "Report upstream, this warning is harmless"
+ local client = vim.lsp.get_client_by_id(client_id)
+ local client_name = client and client.name or string.format("id=%d", client_id)
+ local warning = string.format(warning_tpl, client_name)
+ log.warn(warning)
+ return vim.NIL
+end
+
--@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_codeAction
M['textDocument/codeAction'] = function(_, _, actions)
if actions == nil or vim.tbl_isempty(actions) then
@@ -150,6 +162,7 @@ M['workspace/configuration'] = function(err, _, params, client_id)
local client = vim.lsp.get_client_by_id(client_id)
if not client then
err_message("LSP[id=", client_id, "] client has shut down after sending the message")
+ return
end
if err then error(vim.inspect(err)) end
if not params.items then
diff --git a/runtime/lua/vim/lsp/log.lua b/runtime/lua/vim/lsp/log.lua
index 587a65cd96..b6e91e37b9 100644
--- a/runtime/lua/vim/lsp/log.lua
+++ b/runtime/lua/vim/lsp/log.lua
@@ -28,7 +28,7 @@ do
local function path_join(...)
return table.concat(vim.tbl_flatten{...}, path_sep)
end
- local logfilename = path_join(vim.fn.stdpath('data'), 'lsp.log')
+ local logfilename = path_join(vim.fn.stdpath('cache'), 'lsp.log')
--- Returns the log filename.
--@returns (string) log filename
@@ -36,7 +36,7 @@ do
return logfilename
end
- vim.fn.mkdir(vim.fn.stdpath('data'), "p")
+ vim.fn.mkdir(vim.fn.stdpath('cache'), "p")
local logfile = assert(io.open(logfilename, "a+"))
for level, levelnr in pairs(log.levels) do
-- Also export the log level on the root object.
diff --git a/runtime/lua/vim/lsp/protocol.lua b/runtime/lua/vim/lsp/protocol.lua
index b2d3d0641c..3e111c154a 100644
--- a/runtime/lua/vim/lsp/protocol.lua
+++ b/runtime/lua/vim/lsp/protocol.lua
@@ -34,6 +34,13 @@ local constants = {
Hint = 4;
};
+ DiagnosticTag = {
+ -- Unused or unnecessary code
+ Unnecessary = 1;
+ -- Deprecated or obsolete code
+ Deprecated = 2;
+ };
+
MessageType = {
-- An error message.
Error = 1;
@@ -521,6 +528,13 @@ export interface TextDocumentClientCapabilities {
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.
--
@@ -706,6 +720,18 @@ function protocol.make_client_capabilities()
dynamicRegistration = false;
prepareSupport = true;
};
+ publishDiagnostics = {
+ relatedInformation = true;
+ tagSupport = {
+ valueSet = (function()
+ local res = {}
+ for k in ipairs(protocol.DiagnosticTag) do
+ if type(k) == 'number' then table.insert(res, k) end
+ end
+ return res
+ end)();
+ };
+ };
};
workspace = {
symbol = {
diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua
index ecff95f61e..00bdeecef3 100644
--- a/runtime/lua/vim/lsp/util.lua
+++ b/runtime/lua/vim/lsp/util.lua
@@ -254,19 +254,27 @@ function M.extract_completion_items(result)
end
--- Applies a `TextDocumentEdit`, which is a list of changes to a single
--- document.
+--- document.
---
---@param text_document_edit (table) a `TextDocumentEdit` object
---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocumentEdit
-function M.apply_text_document_edit(text_document_edit)
+---@param text_document_edit table: a `TextDocumentEdit` object
+---@param index number: Optional index of the edit, if from a list of edits (or nil, if not from a list)
+---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocumentEdit
+function M.apply_text_document_edit(text_document_edit, index)
local text_document = text_document_edit.textDocument
local bufnr = vim.uri_to_bufnr(text_document.uri)
+ -- For lists of text document edits,
+ -- do not check the version after the first edit.
+ local should_check_version = true
+ if index and index > 1 then
+ should_check_version = false
+ end
+
-- `VersionedTextDocumentIdentifier`s version may be null
-- https://microsoft.github.io/language-server-protocol/specification#versionedTextDocumentIdentifier
- if text_document.version
+ if should_check_version and (text_document.version
and M.buf_versions[bufnr]
- and M.buf_versions[bufnr] > text_document.version then
+ and M.buf_versions[bufnr] > text_document.version) then
print("Buffer ", text_document.uri, " newer than edits.")
return
end
@@ -459,12 +467,12 @@ end
-- @see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#workspace_applyEdit
function M.apply_workspace_edit(workspace_edit)
if workspace_edit.documentChanges then
- for _, change in ipairs(workspace_edit.documentChanges) do
+ for idx, change in ipairs(workspace_edit.documentChanges) do
if change.kind then
-- TODO(ashkan) handle CreateFile/RenameFile/DeleteFile
error(string.format("Unsupported change: %q", vim.inspect(change)))
else
- M.apply_text_document_edit(change)
+ M.apply_text_document_edit(change, idx)
end
end
return
@@ -718,7 +726,7 @@ function M.focusable_float(unique_name, fn)
local bufnr = api.nvim_get_current_buf()
do
local win = find_window_by_var(unique_name, bufnr)
- if win and api.nvim_win_is_valid(win) and not vim.fn.pumvisible() then
+ if win and api.nvim_win_is_valid(win) and vim.fn.pumvisible() == 0 then
api.nvim_set_current_win(win)
api.nvim_command("stopinsert")
return
diff --git a/runtime/lua/vim/treesitter.lua b/runtime/lua/vim/treesitter.lua
index 79dcf77f9e..38ac182e32 100644
--- a/runtime/lua/vim/treesitter.lua
+++ b/runtime/lua/vim/treesitter.lua
@@ -50,7 +50,7 @@ function M._create_parser(bufnr, lang, opts)
end
end
- a.nvim_buf_attach(self.bufnr, false, {on_bytes=bytes_cb, on_detach=detach_cb, preview=true})
+ a.nvim_buf_attach(self:source(), false, {on_bytes=bytes_cb, on_detach=detach_cb, preview=true})
self:parse()
diff --git a/runtime/lua/vim/treesitter/languagetree.lua b/runtime/lua/vim/treesitter/languagetree.lua
index 9c620c422c..c864fe5878 100644
--- a/runtime/lua/vim/treesitter/languagetree.lua
+++ b/runtime/lua/vim/treesitter/languagetree.lua
@@ -425,23 +425,21 @@ function LanguageTree:register_cbs(cbs)
end
end
-local function region_contains(region, range)
- for _, node in ipairs(region) do
- local start_row, start_col, end_row, end_col = node:range()
- local start_fits = start_row < range[1] or (start_row == range[1] and start_col <= range[2])
- local end_fits = end_row > range[3] or (end_row == range[3] and end_col >= range[4])
+local function tree_contains(tree, range)
+ local start_row, start_col, end_row, end_col = tree:root():range()
+ local start_fits = start_row < range[1] or (start_row == range[1] and start_col <= range[2])
+ local end_fits = end_row > range[3] or (end_row == range[3] and end_col >= range[4])
- if start_fits and end_fits then
- return true
- end
+ if start_fits and end_fits then
+ return true
end
return false
end
function LanguageTree:contains(range)
- for _, region in pairs(self._regions) do
- if region_contains(region, range) then
+ for _, tree in pairs(self._trees) do
+ if tree_contains(tree, range) then
return true
end
end
diff --git a/runtime/lua/vim/treesitter/query.lua b/runtime/lua/vim/treesitter/query.lua
index 5a27d740a2..e49f54681d 100644
--- a/runtime/lua/vim/treesitter/query.lua
+++ b/runtime/lua/vim/treesitter/query.lua
@@ -340,6 +340,19 @@ function Query:apply_directives(match, pattern, source, metadata)
end
end
+
+--- Returns the start and stop value if set else the node's range.
+-- When the node's range is used, the stop is incremented by 1
+-- to make the search inclusive.
+local function value_or_node_range(start, stop, node)
+ if start == nil and stop == nil then
+ local node_start, _, node_stop, _ = node:range()
+ return node_start, node_stop + 1 -- Make stop inclusive
+ end
+
+ return start, stop
+end
+
--- Iterates of the captures of self on a given range.
--
-- @param node The node under witch the search will occur
@@ -353,6 +366,9 @@ function Query:iter_captures(node, source, start, stop)
if type(source) == "number" and source == 0 then
source = vim.api.nvim_get_current_buf()
end
+
+ start, stop = value_or_node_range(start, stop, node)
+
local raw_iter = node:_rawquery(self.query, true, start, stop)
local function iter()
local capture, captured_node, match = raw_iter()
@@ -385,6 +401,9 @@ function Query:iter_matches(node, source, start, stop)
if type(source) == "number" and source == 0 then
source = vim.api.nvim_get_current_buf()
end
+
+ start, stop = value_or_node_range(start, stop, node)
+
local raw_iter = node:_rawquery(self.query, false, start, stop)
local function iter()
local pattern, match = raw_iter()
diff --git a/runtime/nvim.appdata.xml b/runtime/nvim.appdata.xml
index 025de1b5a9..e99c76a930 100644
--- a/runtime/nvim.appdata.xml
+++ b/runtime/nvim.appdata.xml
@@ -26,6 +26,7 @@
</screenshots>
<releases>
+ <release date="2020-08-04" version="0.4.4"/>
<release date="2019-11-06" version="0.4.3"/>
<release date="2019-09-15" version="0.4.2"/>
<release date="2019-09-15" version="0.4.1"/>
diff --git a/runtime/scripts.vim b/runtime/scripts.vim
index 6aae2b1ec3..3b3409bf4b 100644
--- a/runtime/scripts.vim
+++ b/runtime/scripts.vim
@@ -182,6 +182,14 @@ if s:line1 =~# "^#!"
elseif s:name =~# 'clojure'
set ft=clojure
+ " Free Pascal
+ elseif s:name =~# 'instantfpc\>'
+ set ft=pascal
+
+ " Fennel
+ elseif s:name =~# 'fennel\>'
+ set ft=fennel
+
endif
unlet s:name
diff --git a/runtime/syntax/elm.vim b/runtime/syntax/elm.vim
new file mode 100644
index 0000000000..1277827f57
--- /dev/null
+++ b/runtime/syntax/elm.vim
@@ -0,0 +1,105 @@
+" Vim syntax file
+" Language: Elm
+" Maintainer: Andreas Scharf <as@99n.de>
+" Original Author: Joseph Hager <ajhager@gmail.com>
+" Copyright: Joseph Hager <ajhager@gmail.com>
+" License: BSD3
+" Latest Revision: 2020-05-29
+
+if exists('b:current_syntax')
+ finish
+endif
+
+" Keywords
+syn keyword elmConditional else if of then case
+syn keyword elmAlias alias
+syn keyword elmTypedef contained type port
+syn keyword elmImport exposing as import module where
+
+" Operators
+" elm/core
+syn match elmOperator contained "\(<|\||>\|||\|&&\|==\|/=\|<=\|>=\|++\|::\|+\|-\|*\|/\|//\|^\|<>\|>>\|<<\|<\|>\|%\)"
+" elm/parser
+syn match elmOperator contained "\(|.\||=\)"
+" elm/url
+syn match elmOperator contained "\(</>\|<?>\)"
+
+" Types
+syn match elmType "\<[A-Z][0-9A-Za-z_-]*"
+syn keyword elmNumberType number
+
+" Modules
+syn match elmModule "\<\([A-Z][0-9A-Za-z_'-\.]*\)\+\.[A-Za-z]"me=e-2
+syn match elmModule "^\(module\|import\)\s\+[A-Z][0-9A-Za-z_'-\.]*\(\s\+as\s\+[A-Z][0-9A-Za-z_'-\.]*\)\?\(\s\+exposing\)\?" contains=elmImport
+
+" Delimiters
+syn match elmDelimiter "[,;]"
+syn match elmBraces "[()[\]{}]"
+
+" Functions
+syn match elmTupleFunction "\((,\+)\)"
+
+" Comments
+syn keyword elmTodo TODO FIXME XXX contained
+syn match elmLineComment "--.*" contains=elmTodo,@spell
+syn region elmComment matchgroup=elmComment start="{-|\=" end="-}" contains=elmTodo,elmComment,@spell fold
+
+" Strings
+syn match elmStringEscape "\\u[0-9a-fA-F]\{4}" contained
+syn match elmStringEscape "\\[nrfvbt\\\"]" contained
+syn region elmString start="\"" skip="\\\"" end="\"" contains=elmStringEscape,@spell
+syn region elmTripleString start="\"\"\"" skip="\\\"" end="\"\"\"" contains=elmStringEscape,@spell
+syn match elmChar "'[^'\\]'\|'\\.'\|'\\u[0-9a-fA-F]\{4}'"
+
+" Lambda
+syn region elmLambdaFunc start="\\"hs=s+1 end="->"he=e-2
+
+" Debug
+syn match elmDebug "Debug.\(log\|todo\|toString\)"
+
+" Numbers
+syn match elmInt "-\?\<\d\+\>"
+syn match elmFloat "-\?\(\<\d\+\.\d\+\>\)"
+
+" Identifiers
+syn match elmTopLevelDecl "^\s*[a-zA-Z][a-zA-z0-9_]*\('\)*\s\+:\(\r\n\|\r\|\n\|\s\)\+" contains=elmOperator
+syn match elmFuncName /^\l\w*/
+
+" Folding
+syn region elmTopLevelTypedef start="type" end="\n\(\n\n\)\@=" contains=ALL fold
+syn region elmTopLevelFunction start="^[a-zA-Z].\+\n[a-zA-Z].\+=" end="^\(\n\+\)\@=" contains=ALL fold
+syn region elmCaseBlock matchgroup=elmCaseBlockDefinition start="^\z\(\s\+\)\<case\>" end="^\z1\@!\W\@=" end="\(\n\n\z1\@!\)\@=" end="\n\z1\@!\(\n\n\)\@=" contains=ALL fold
+syn region elmCaseItemBlock start="^\z\(\s\+\).\+->$" end="^\z1\@!\W\@=" end="\(\n\n\z1\@!\)\@=" end="\(\n\z1\S\)\@=" contains=ALL fold
+syn region elmLetBlock matchgroup=elmLetBlockDefinition start="\<let\>" end="\<in\>" contains=ALL fold
+
+hi def link elmFuncName Function
+hi def link elmCaseBlockDefinition Conditional
+hi def link elmCaseBlockItemDefinition Conditional
+hi def link elmLetBlockDefinition TypeDef
+hi def link elmTopLevelDecl Function
+hi def link elmTupleFunction Normal
+hi def link elmTodo Todo
+hi def link elmComment Comment
+hi def link elmLineComment Comment
+hi def link elmString String
+hi def link elmTripleString String
+hi def link elmChar String
+hi def link elmStringEscape Special
+hi def link elmInt Number
+hi def link elmFloat Float
+hi def link elmDelimiter Delimiter
+hi def link elmBraces Delimiter
+hi def link elmTypedef TypeDef
+hi def link elmImport Include
+hi def link elmConditional Conditional
+hi def link elmAlias Delimiter
+hi def link elmOperator Operator
+hi def link elmType Type
+hi def link elmNumberType Identifier
+hi def link elmLambdaFunc Function
+hi def link elmDebug Debug
+hi def link elmModule Type
+
+syn sync minlines=500
+
+let b:current_syntax = 'elm'
diff --git a/runtime/syntax/zsh.vim b/runtime/syntax/zsh.vim
index 3eba438aa7..819c419228 100644
--- a/runtime/syntax/zsh.vim
+++ b/runtime/syntax/zsh.vim
@@ -2,7 +2,7 @@
" Language: Zsh shell script
" Maintainer: Christian Brabandt <cb@256bit.org>
" Previous Maintainer: Nikolai Weibull <now@bitwi.se>
-" Latest Revision: 2018-05-12
+" Latest Revision: 2020-11-21
" License: Vim (see :h license)
" Repository: https://github.com/chrisbra/vim-zsh
@@ -13,32 +13,44 @@ endif
let s:cpo_save = &cpo
set cpo&vim
-if v:version > 704 || (v:version == 704 && has("patch1142"))
- syn iskeyword @,48-57,_,192-255,#,-
-else
- setlocal iskeyword+=-
-endif
+function! s:ContainedGroup()
+ " needs 7.4.2008 for execute() function
+ let result='TOP'
+ " vim-pandoc syntax defines the @langname cluster for embedded syntax languages
+ " However, if no syntax is defined yet, `syn list @zsh` will return
+ " "No syntax items defined", so make sure the result is actually a valid syn cluster
+ for cluster in ['markdownHighlightzsh', 'zsh']
+ try
+ " markdown syntax defines embedded clusters as @markdownhighlight<lang>,
+ " pandoc just uses @<lang>, so check both for both clusters
+ let a=split(execute('syn list @'. cluster), "\n")
+ if len(a) == 2 && a[0] =~# '^---' && a[1] =~? cluster
+ return '@'. cluster
+ endif
+ catch /E392/
+ " ignore
+ endtry
+ endfor
+ return result
+endfunction
+
+let s:contained=s:ContainedGroup()
+
+syn iskeyword @,48-57,_,192-255,#,-
if get(g:, 'zsh_fold_enable', 0)
setlocal foldmethod=syntax
endif
-syn keyword zshTodo contained TODO FIXME XXX NOTE
-
-syn region zshComment oneline start='\%(^\|\s\+\)#' end='$'
- \ contains=zshTodo,@Spell fold
-
-syn region zshComment start='^\s*#' end='^\%(\s*#\)\@!'
- \ contains=zshTodo,@Spell fold
-
-syn match zshPreProc '^\%1l#\%(!\|compdef\|autoload\).*$'
-
+syn match zshPOSIXQuoted '\\[xX][0-9a-fA-F]\{1,2}'
+syn match zshPOSIXQuoted '\\[0-7]\{1,3}'
+syn match zshPOSIXQuoted '\\u[0-9a-fA-F]\{1,4}'
+syn match zshPOSIXQuoted '\\U[1-9a-fA-F]\{1,8}'
syn match zshQuoted '\\.'
syn region zshString matchgroup=zshStringDelimiter start=+"+ end=+"+
\ contains=zshQuoted,@zshDerefs,@zshSubst fold
syn region zshString matchgroup=zshStringDelimiter start=+'+ end=+'+ fold
-" XXX: This should probably be more precise, but Zsh seems a bit confused about it itself
syn region zshPOSIXString matchgroup=zshStringDelimiter start=+\$'+
- \ end=+'+ contains=zshQuoted
+ \ skip=+\\[\\']+ end=+'+ contains=zshPOSIXQuoted,zshQuoted
syn match zshJobSpec '%\(\d\+\|?\=\w\+\|[%+-]\)'
syn keyword zshPrecommand noglob nocorrect exec command builtin - time
@@ -112,7 +124,7 @@ syn keyword zshCommands alias autoload bg bindkey break bye cap cd
\ enable eval exec exit export false fc fg
\ functions getcap getln getopts hash history
\ jobs kill let limit log logout popd print
- \ printf pushd pushln pwd r read readonly
+ \ printf pushd pushln pwd r read
\ rehash return sched set setcap shift
\ source stat suspend test times trap true
\ ttyctl type ulimit umask unalias unfunction
@@ -125,7 +137,7 @@ syn keyword zshCommands alias autoload bg bindkey break bye cap cd
" Create a list of option names from zsh source dir:
" #!/bin/zsh
" topdir=/path/to/zsh-xxx
-" grep '^pindex([A-Za-z_]*)$' $topdir/Src/Doc/Zsh/optionsyo |
+" grep '^pindex([A-Za-z_]*)$' $topdir/Doc/Zsh/options.yo |
" while read opt
" do
" echo ${${(L)opt#pindex\(}%\)}
@@ -136,6 +148,7 @@ syn case ignore
syn match zshOptStart /^\s*\%(\%(\%(un\)\?setopt\)\|set\s+[-+]o\)/ nextgroup=zshOption skipwhite
syn match zshOption /
\ \%(\%(\<no_\?\)\?aliases\>\)\|
+ \ \%(\%(\<no_\?\)\?aliasfuncdef\>\)\|\%(\%(no_\?\)\?alias_func_def\>\)\|
\ \%(\%(\<no_\?\)\?allexport\>\)\|\%(\%(no_\?\)\?all_export\>\)\|
\ \%(\%(\<no_\?\)\?alwayslastprompt\>\)\|\%(\%(no_\?\)\?always_last_prompt\>\)\|\%(\%(no_\?\)\?always_lastprompt\>\)\|
\ \%(\%(\<no_\?\)\?alwaystoend\>\)\|\%(\%(no_\?\)\?always_to_end\>\)\|
@@ -165,10 +178,13 @@ syn match zshOption /
\ \%(\%(\<no_\?\)\?casematch\>\)\|\%(\%(no_\?\)\?case_match\>\)\|
\ \%(\%(\<no_\?\)\?cbases\>\)\|\%(\%(no_\?\)\?c_bases\>\)\|
\ \%(\%(\<no_\?\)\?cdablevars\>\)\|\%(\%(no_\?\)\?cdable_vars\>\)\|\%(\%(no_\?\)\?cd_able_vars\>\)\|
+ \ \%(\%(\<no_\?\)\?cdsilent\>\)\|\%(\%(no_\?\)\?cd_silent\>\)\|\%(\%(no_\?\)\?cd_silent\>\)\|
\ \%(\%(\<no_\?\)\?chasedots\>\)\|\%(\%(no_\?\)\?chase_dots\>\)\|
\ \%(\%(\<no_\?\)\?chaselinks\>\)\|\%(\%(no_\?\)\?chase_links\>\)\|
\ \%(\%(\<no_\?\)\?checkjobs\>\)\|\%(\%(no_\?\)\?check_jobs\>\)\|
+ \ \%(\%(\<no_\?\)\?checkrunningjobs\>\)\|\%(\%(no_\?\)\?check_running_jobs\>\)\|
\ \%(\%(\<no_\?\)\?clobber\>\)\|
+ \ \%(\%(\<no_\?\)\?clobberempty\>\)\|\%(\%(no_\?\)\?clobber_empty\>\)\|
\ \%(\%(\<no_\?\)\?combiningchars\>\)\|\%(\%(no_\?\)\?combining_chars\>\)\|
\ \%(\%(\<no_\?\)\?completealiases\>\)\|\%(\%(no_\?\)\?complete_aliases\>\)\|
\ \%(\%(\<no_\?\)\?completeinword\>\)\|\%(\%(no_\?\)\?complete_in_word\>\)\|
@@ -188,7 +204,7 @@ syn match zshOption /
\ \%(\%(\<no_\?\)\?equals\>\)\|
\ \%(\%(\<no_\?\)\?errexit\>\)\|\%(\%(no_\?\)\?err_exit\>\)\|
\ \%(\%(\<no_\?\)\?errreturn\>\)\|\%(\%(no_\?\)\?err_return\>\)\|
- \ \%(\%(\<no_\?\)\?evallineno_\?\)\|\%(\%(no_\?\)\?eval_lineno_\?\)\|
+ \ \%(\%(\<no_\?\)\?evallineno\>\)\|\%(\%(no_\?\)\?eval_lineno\>\)\|
\ \%(\%(\<no_\?\)\?exec\>\)\|
\ \%(\%(\<no_\?\)\?extendedglob\>\)\|\%(\%(no_\?\)\?extended_glob\>\)\|
\ \%(\%(\<no_\?\)\?extendedhistory\>\)\|\%(\%(no_\?\)\?extended_history\>\)\|
@@ -309,6 +325,7 @@ syn match zshOption /
\ \%(\%(\<no_\?\)\?shnullcmd\>\)\|\%(\%(no_\?\)\?sh_nullcmd\>\)\|
\ \%(\%(\<no_\?\)\?shoptionletters\>\)\|\%(\%(no_\?\)\?sh_option_letters\>\)\|
\ \%(\%(\<no_\?\)\?shortloops\>\)\|\%(\%(no_\?\)\?short_loops\>\)\|
+ \ \%(\%(\<no_\?\)\?shortrepeat\>\)\|\%(\%(no_\?\)\?short_repeat\>\)\|
\ \%(\%(\<no_\?\)\?shwordsplit\>\)\|\%(\%(no_\?\)\?sh_word_split\>\)\|
\ \%(\%(\<no_\?\)\?singlecommand\>\)\|\%(\%(no_\?\)\?single_command\>\)\|
\ \%(\%(\<no_\?\)\?singlelinezle\>\)\|\%(\%(no_\?\)\?single_line_zle\>\)\|
@@ -322,10 +339,13 @@ syn match zshOption /
\ \%(\%(\<no_\?\)\?unset\>\)\|
\ \%(\%(\<no_\?\)\?verbose\>\)\|
\ \%(\%(\<no_\?\)\?vi\>\)\|
+ \ \%(\%(\<no_\?\)\?warnnestedvar\>\)\|\%(\%(no_\?\)\?warn_nested_var\>\)\|
\ \%(\%(\<no_\?\)\?warncreateglobal\>\)\|\%(\%(no_\?\)\?warn_create_global\>\)\|
\ \%(\%(\<no_\?\)\?xtrace\>\)\|
\ \%(\%(\<no_\?\)\?zle\>\)/ nextgroup=zshOption,zshComment skipwhite contained
+syn case match
+
syn keyword zshTypes float integer local typeset declare private readonly
" XXX: this may be too much
@@ -339,31 +359,42 @@ syn match zshNumber '[+-]\=\d\+\.\d\+\>'
" TODO: $[...] is the same as $((...)), so add that as well.
syn cluster zshSubst contains=zshSubst,zshOldSubst,zshMathSubst
-syn region zshSubst matchgroup=zshSubstDelim transparent
- \ start='\$(' skip='\\)' end=')' contains=TOP fold
+exe 'syn region zshSubst matchgroup=zshSubstDelim transparent start=/\$(/ skip=/\\)/ end=/)/ contains='.s:contained. ' fold'
syn region zshParentheses transparent start='(' skip='\\)' end=')' fold
syn region zshGlob start='(#' end=')'
syn region zshMathSubst matchgroup=zshSubstDelim transparent
- \ start='\$((' skip='\\)' end='))'
+ \ start='\%(\$\?\)[<=>]\@<!((' skip='\\)' end='))'
\ contains=zshParentheses,@zshSubst,zshNumber,
\ @zshDerefs,zshString keepend fold
-syn region zshBrackets contained transparent start='{' skip='\\}'
+" The ms=s+1 prevents matching zshBrackets several times on opening brackets
+" (see https://github.com/chrisbra/vim-zsh/issues/21#issuecomment-576330348)
+syn region zshBrackets contained transparent start='{'ms=s+1 skip='\\}'
\ end='}' fold
-syn region zshBrackets transparent start='{' skip='\\}'
- \ end='}' contains=TOP fold
+exe 'syn region zshBrackets transparent start=/{/ms=s+1 skip=/\\}/ end=/}/ contains='.s:contained. ' fold'
+
syn region zshSubst matchgroup=zshSubstDelim start='\${' skip='\\}'
\ end='}' contains=@zshSubst,zshBrackets,zshQuoted,zshString fold
-syn region zshOldSubst matchgroup=zshSubstDelim start=+`+ skip=+\\`+
- \ end=+`+ contains=TOP,zshOldSubst fold
+exe 'syn region zshOldSubst matchgroup=zshSubstDelim start=/`/ skip=/\\[\\`]/ end=/`/ contains='.s:contained. ',zshOldSubst fold'
syn sync minlines=50 maxlines=90
syn sync match zshHereDocSync grouphere NONE '<<-\=\s*\%(\\\=\S\+\|\(["']\)\S\+\1\)'
syn sync match zshHereDocEndSync groupthere NONE '^\s*EO\a\+\>'
+syn keyword zshTodo contained TODO FIXME XXX NOTE
+
+syn region zshComment oneline start='\%(^\|\s\+\)#' end='$'
+ \ contains=zshTodo,@Spell fold
+
+syn region zshComment start='^\s*#' end='^\%(\s*#\)\@!'
+ \ contains=zshTodo,@Spell fold
+
+syn match zshPreProc '^\%1l#\%(!\|compdef\|autoload\).*$'
+
hi def link zshTodo Todo
hi def link zshComment Comment
hi def link zshPreProc PreProc
hi def link zshQuoted SpecialChar
+hi def link zshPOSIXQuoted SpecialChar
hi def link zshString String
hi def link zshStringDelimiter zshString
hi def link zshPOSIXString zshString
diff --git a/scripts/vim-patch.sh b/scripts/vim-patch.sh
index 551b8fb691..f583b2fdea 100755
--- a/scripts/vim-patch.sh
+++ b/scripts/vim-patch.sh
@@ -180,8 +180,12 @@ preprocess_patch() {
local file="$1"
local nvim="nvim -u NORC -i NONE --headless"
- # Remove *.proto, Make*, gui_*, some if_*
- local na_src='proto\|Make*\|gui_*\|if_lua\|if_mzsch\|if_olepp\|if_ole\|if_perl\|if_py\|if_ruby\|if_tcl\|if_xcmdsrv'
+ # Remove Filelist, README
+ local na_files='Filelist\|README.*'
+ 2>/dev/null $nvim --cmd 'set dir=/tmp' +'g@^diff --git a/\<\%('"${na_files}"'\)\>@norm! d/\v(^diff)|%$ ' +w +q "$file"
+
+ # Remove *.proto, Make*, INSTALL*, gui_*, beval.*, some if_*, gvim, libvterm, tee, VisVim, xpm, xxd
+ local na_src='auto\|configure.*\|GvimExt\|libvterm\|proto\|tee\|VisVim\|xpm\|xxd\|Make*\|INSTALL*\|beval.*\|gui_*\|if_lua\|if_mzsch\|if_olepp\|if_ole\|if_perl\|if_py\|if_ruby\|if_tcl\|if_xcmdsrv'
2>/dev/null $nvim --cmd 'set dir=/tmp' +'g@^diff --git a/src/\S*\<\%(testdir/\)\@<!\%('"${na_src}"'\)@norm! d/\v(^diff)|%$ ' +w +q "$file"
# Remove unwanted Vim doc files.
@@ -191,10 +195,14 @@ preprocess_patch() {
# Remove "Last change ..." changes in doc files.
2>/dev/null $nvim --cmd 'set dir=/tmp' +'%s/^@@.*\n.*For Vim version.*Last change.*\n.*For Vim version.*Last change.*//' +w +q "$file"
- # Remove screen dumps, testdir/Make_*.mak files
- local na_src_testdir='Make_amiga.mak\|Make_dos.mak\|Make_ming.mak\|Make_vms.mms\|dumps/.*.dump'
+ # Remove gui, option, setup, screen dumps, testdir/Make_*.mak files
+ local na_src_testdir='gen_opt_test.vim\|gui_.*\|Make_amiga.mak\|Make_dos.mak\|Make_ming.mak\|Make_vms.mms\|dumps/.*.dump\|setup_gui.vim'
2>/dev/null $nvim --cmd 'set dir=/tmp' +'g@^diff --git a/src/testdir/\<\%('"${na_src_testdir}"'\)\>@norm! d/\v(^diff)|%$ ' +w +q "$file"
+ # Remove testdir/test_*.vim files
+ local na_src_testdir='balloon.*\|channel.*\|crypt.vim\|gui.*\|job_fails.vim\|json.vim\|mzscheme.vim\|netbeans.*\|paste.vim\|popupwin.*\|restricted.vim\|shortpathname.vim\|tcl.vim\|terminal.*\|xxd.vim'
+ 2>/dev/null $nvim --cmd 'set dir=/tmp' +'g@^diff --git a/src/testdir/\<test_\%('"${na_src_testdir}"'\)\>@norm! d/\v(^diff)|%$ ' +w +q "$file"
+
# Remove version.c #7555
local na_po='version.c'
2>/dev/null $nvim --cmd 'set dir=/tmp' +'g@^diff --git a/src/\<\%('${na_po}'\)\>@norm! d/\v(^diff)|%$ ' +w +q "$file"
diff --git a/src/nvim/README.md b/src/nvim/README.md
index d14ba85546..affc5c79cc 100644
--- a/src/nvim/README.md
+++ b/src/nvim/README.md
@@ -38,7 +38,7 @@ alternate file (e.g. stderr) use `LOG_CALLSTACK_TO_FILE(FILE*)`. Requires
Many log messages have a shared prefix, such as "UI" or "RPC". Use the shell to
filter the log, e.g. at DEBUG level you might want to exclude UI messages:
- tail -F ~/.local/share/nvim/log | cat -v | stdbuf -o0 grep -v UI | stdbuf -o0 tee -a log
+ tail -F ~/.cache/nvim/log | cat -v | stdbuf -o0 grep -v UI | stdbuf -o0 tee -a log
Build with ASAN
---------------
diff --git a/src/nvim/api/buffer.c b/src/nvim/api/buffer.c
index 8d82d22040..67f4f92bf6 100644
--- a/src/nvim/api/buffer.c
+++ b/src/nvim/api/buffer.c
@@ -1200,8 +1200,7 @@ static Array extmark_to_array(ExtmarkInfo extmark, bool id, bool add_dict)
/// @param ns_id Namespace id from |nvim_create_namespace()|
/// @param id Extmark id
/// @param opts Optional parameters. Keys:
-/// - limit: Maximum number of marks to return
-/// - details Whether to include the details dict
+/// - details: Whether to include the details dict
/// @param[out] err Error details, if any
/// @return (row, col) tuple or empty list () if extmark id was absent
ArrayOf(Integer) nvim_buf_get_extmark_by_id(Buffer buffer, Integer ns_id,
@@ -1400,6 +1399,13 @@ Array nvim_buf_get_extmarks(Buffer buffer, Integer ns_id,
/// callbacks. The mark will only be used for the current
/// redraw cycle, and not be permantently stored in the
/// buffer.
+/// - right_gravity : boolean that indicates the direction
+/// the extmark will be shifted in when new text is inserted
+/// (true for right, false for left). defaults to true.
+/// - end_right_gravity : boolean that indicates the direction
+/// the extmark end position (if it exists) will be shifted
+/// in when new text is inserted (true for right, false
+/// for left). Defaults to false.
/// @param[out] err Error details, if any
/// @return Id of the created/updated extmark
Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id,
@@ -1440,6 +1446,10 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id,
DecorPriority priority = DECOR_PRIORITY_BASE;
colnr_T col2 = 0;
VirtText virt_text = KV_INITIAL_VALUE;
+ bool right_gravity = true;
+ bool end_right_gravity = false;
+ bool end_gravity_set = false;
+
for (size_t i = 0; i < opts.size; i++) {
String k = opts.items[i].key;
Object *v = &opts.items[i].value;
@@ -1522,12 +1532,35 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id,
goto error;
}
priority = (DecorPriority)v->data.integer;
+ } else if (strequal("right_gravity", k.data)) {
+ if (v->type != kObjectTypeBoolean) {
+ api_set_error(err, kErrorTypeValidation,
+ "right_gravity must be a boolean");
+ goto error;
+ }
+ right_gravity = v->data.boolean;
+ } else if (strequal("end_right_gravity", k.data)) {
+ if (v->type != kObjectTypeBoolean) {
+ api_set_error(err, kErrorTypeValidation,
+ "end_right_gravity must be a boolean");
+ goto error;
+ }
+ end_right_gravity = v->data.boolean;
+ end_gravity_set = true;
} else {
api_set_error(err, kErrorTypeValidation, "unexpected key: %s", k.data);
goto error;
}
}
+ // Only error out if they try to set end_right_gravity without
+ // setting end_col or end_line
+ if (line2 == -1 && col2 == 0 && end_gravity_set) {
+ api_set_error(err, kErrorTypeValidation,
+ "cannot set end_right_gravity "
+ "without setting end_line or end_col");
+ }
+
if (col2 >= 0) {
if (line2 >= 0 && line2 < buf->b_ml.ml_line_count) {
len = STRLEN(ml_get_buf(buf, (linenr_T)line2 + 1, false));
@@ -1572,7 +1605,8 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id,
}
id = extmark_set(buf, (uint64_t)ns_id, id, (int)line, (colnr_T)col,
- line2, col2, decor, kExtmarkNoUndo);
+ line2, col2, decor, right_gravity,
+ end_right_gravity, kExtmarkNoUndo);
}
return (Integer)id;
@@ -1687,7 +1721,7 @@ Integer nvim_buf_add_highlight(Buffer buffer,
extmark_set(buf, ns_id, 0,
(int)line, (colnr_T)col_start,
end_line, (colnr_T)col_end,
- decor_hl(hl_id), kExtmarkNoUndo);
+ decor_hl(hl_id), true, false, kExtmarkNoUndo);
return src_id;
}
@@ -1796,7 +1830,8 @@ Integer nvim_buf_set_virtual_text(Buffer buffer,
Decoration *decor = xcalloc(1, sizeof(*decor));
decor->virt_text = virt_text;
- extmark_set(buf, ns_id, 0, (int)line, 0, -1, -1, decor, kExtmarkNoUndo);
+ extmark_set(buf, ns_id, 0, (int)line, 0, -1, -1, decor, true,
+ false, kExtmarkNoUndo);
return src_id;
}
diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c
index 8f224e8c78..7cee569989 100644
--- a/src/nvim/api/private/helpers.c
+++ b/src/nvim/api/private/helpers.c
@@ -1645,6 +1645,43 @@ bool api_object_to_bool(Object obj, const char *what,
}
}
+HlMessage parse_hl_msg(Array chunks, Error *err)
+{
+ HlMessage hl_msg = KV_INITIAL_VALUE;
+ for (size_t i = 0; i < chunks.size; i++) {
+ if (chunks.items[i].type != kObjectTypeArray) {
+ api_set_error(err, kErrorTypeValidation, "Chunk is not an array");
+ goto free_exit;
+ }
+ Array chunk = chunks.items[i].data.array;
+ if (chunk.size == 0 || chunk.size > 2
+ || chunk.items[0].type != kObjectTypeString
+ || (chunk.size == 2 && chunk.items[1].type != kObjectTypeString)) {
+ api_set_error(err, kErrorTypeValidation,
+ "Chunk is not an array with one or two strings");
+ goto free_exit;
+ }
+
+ String str = copy_string(chunk.items[0].data.string);
+
+ int attr = 0;
+ if (chunk.size == 2) {
+ String hl = chunk.items[1].data.string;
+ if (hl.size > 0) {
+ int hl_id = syn_check_group((char_u *)hl.data, (int)hl.size);
+ attr = hl_id > 0 ? syn_id2attr(hl_id) : 0;
+ }
+ }
+ kv_push(hl_msg, ((HlMessageChunk){ .text = str, .attr = attr }));
+ }
+
+ return hl_msg;
+
+free_exit:
+ clear_hl_msg(&hl_msg);
+ return hl_msg;
+}
+
const char *describe_ns(NS ns_id)
{
String name;
diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c
index 1e972e01be..09895a2119 100644
--- a/src/nvim/api/vim.c
+++ b/src/nvim/api/vim.c
@@ -990,6 +990,48 @@ void nvim_set_option(uint64_t channel_id, String name, Object value, Error *err)
set_option_to(channel_id, NULL, SREQ_GLOBAL, name, value, err);
}
+/// Echo a message.
+///
+/// @param chunks A list of [text, hl_group] arrays, each representing a
+/// text chunk with specified highlight. `hl_group` element
+/// can be omitted for no highlight.
+/// @param history if true, add to |message-history|.
+/// @param opts Optional parameters. Reserved for future use.
+void nvim_echo(Array chunks, Boolean history, Dictionary opts, Error *err)
+ FUNC_API_SINCE(7)
+{
+ HlMessage hl_msg = parse_hl_msg(chunks, err);
+ if (ERROR_SET(err)) {
+ goto error;
+ }
+
+ if (opts.size > 0) {
+ api_set_error(err, kErrorTypeValidation, "opts dict isn't empty");
+ goto error;
+ }
+
+ no_wait_return++;
+ msg_start();
+ msg_clr_eos();
+ bool need_clear = false;
+ for (uint32_t i = 0; i < kv_size(hl_msg); i++) {
+ HlMessageChunk chunk = kv_A(hl_msg, i);
+ msg_multiline_attr((const char *)chunk.text.data, chunk.attr,
+ false, &need_clear);
+ }
+ if (history) {
+ msg_ext_set_kind("echomsg");
+ add_hl_msg_hist(hl_msg);
+ } else {
+ msg_ext_set_kind("echo");
+ }
+ no_wait_return--;
+ msg_end();
+
+error:
+ clear_hl_msg(&hl_msg);
+}
+
/// Writes a message to the Vim output buffer. Does not append "\n", the
/// message is buffered (won't display) until a linefeed is written.
///
diff --git a/src/nvim/autocmd.c b/src/nvim/autocmd.c
index 42224d0a4f..140a9c6bcb 100644
--- a/src/nvim/autocmd.c
+++ b/src/nvim/autocmd.c
@@ -700,11 +700,15 @@ void do_autocmd(char_u *arg_in, int forceit)
last_event = (event_T)-1; // for listing the event name
last_group = AUGROUP_ERROR; // for listing the group name
if (*arg == '*' || *arg == NUL || *arg == '|') {
- for (event_T event = (event_T)0; event < (int)NUM_EVENTS;
- event = (event_T)(event + 1)) {
- if (do_autocmd_event(event, pat, once, nested, cmd, forceit, group)
- == FAIL) {
- break;
+ if (!forceit && *cmd != NUL) {
+ EMSG(_(e_cannot_define_autocommands_for_all_events));
+ } else {
+ for (event_T event = (event_T)0; event < (int)NUM_EVENTS;
+ event = (event_T)(event + 1)) {
+ if (do_autocmd_event(event, pat, once, nested, cmd, forceit, group)
+ == FAIL) {
+ break;
+ }
}
}
} else {
diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c
index 76205c70ae..7116b25b29 100644
--- a/src/nvim/buffer.c
+++ b/src/nvim/buffer.c
@@ -3270,7 +3270,7 @@ void maketitle(void)
case 6: buf_p = strappend(buf_p, " -"); break;
case 5:
case 7: buf_p = strappend(buf_p, " -+"); break;
- default: assert(false);
+ default: abort();
}
if (curbuf->b_fname != NULL) {
diff --git a/src/nvim/channel.c b/src/nvim/channel.c
index 37cbfb968b..5628ede2e6 100644
--- a/src/nvim/channel.c
+++ b/src/nvim/channel.c
@@ -304,7 +304,8 @@ Channel *channel_job_start(char **argv, CallbackReader on_stdout,
bool pty, bool rpc, bool overlapped, bool detach,
const char *cwd,
uint16_t pty_width, uint16_t pty_height,
- char *term_name, char **env, varnumber_T *status_out)
+ char *term_name, dict_T *env,
+ varnumber_T *status_out)
{
assert(cwd == NULL || os_isdir_executable(cwd));
@@ -358,7 +359,9 @@ Channel *channel_job_start(char **argv, CallbackReader on_stdout,
if (status) {
EMSG3(_(e_jobspawn), os_strerror(status), cmd);
xfree(cmd);
- os_free_fullenv(proc->env);
+ if (proc->env) {
+ tv_dict_free(proc->env);
+ }
if (proc->type == kProcessTypePty) {
xfree(chan->stream.pty.term_name);
}
@@ -367,8 +370,9 @@ Channel *channel_job_start(char **argv, CallbackReader on_stdout,
return NULL;
}
xfree(cmd);
- os_free_fullenv(proc->env);
-
+ if (proc->env) {
+ tv_dict_free(proc->env);
+ }
wstream_init(&proc->in, 0);
if (has_out) {
diff --git a/src/nvim/charset.c b/src/nvim/charset.c
index 3e52b3e3ce..be265e3f27 100644
--- a/src/nvim/charset.c
+++ b/src/nvim/charset.c
@@ -1747,7 +1747,7 @@ void vim_str2nr(const char_u *const start, int *const prep, int *const len,
goto vim_str2nr_dec;
}
default: {
- assert(false);
+ abort();
}
}
} else if ((what & (STR2NR_HEX|STR2NR_OCT|STR2NR_BIN))
@@ -1788,7 +1788,7 @@ void vim_str2nr(const char_u *const start, int *const prep, int *const len,
}
// Do the string-to-numeric conversion "manually" to avoid sscanf quirks.
- assert(false); // Should’ve used goto earlier.
+ abort(); // Should’ve used goto earlier.
#define PARSE_NUMBER(base, cond, conv) \
do { \
while (!STRING_ENDED(ptr) && (cond)) { \
diff --git a/src/nvim/decoration.c b/src/nvim/decoration.c
index e6a616c927..f3ee42fab1 100644
--- a/src/nvim/decoration.c
+++ b/src/nvim/decoration.c
@@ -69,7 +69,7 @@ void bufhl_add_hl_pos_offset(buf_T *buf,
}
(void)extmark_set(buf, (uint64_t)src_id, 0,
(int)lnum-1, hl_start, (int)lnum-1+end_off, hl_end,
- decor, kExtmarkNoUndo);
+ decor, true, false, kExtmarkNoUndo);
}
}
diff --git a/src/nvim/edit.c b/src/nvim/edit.c
index 876e53e3cd..100e88e261 100644
--- a/src/nvim/edit.c
+++ b/src/nvim/edit.c
@@ -313,6 +313,11 @@ static void insert_enter(InsertState *s)
set_vim_var_string(VV_CHAR, NULL, -1);
ins_apply_autocmds(EVENT_INSERTENTER);
+ // Check for changed highlighting, e.g. for ModeMsg.
+ if (need_highlight_changed) {
+ highlight_changed();
+ }
+
// Make sure the cursor didn't move. Do call check_cursor_col() in
// case the text was modified. Since Insert mode was not started yet
// a call to check_cursor_col() may move the cursor, especially with
@@ -8282,8 +8287,9 @@ static bool ins_bs(int c, int mode, int *inserted_space_p)
}
} while (revins_on
|| (curwin->w_cursor.col > mincol
- && (curwin->w_cursor.lnum != Insstart_orig.lnum
- || curwin->w_cursor.col != Insstart_orig.col)));
+ && (can_bs(BS_NOSTOP)
+ || (curwin->w_cursor.lnum != Insstart_orig.lnum
+ || curwin->w_cursor.col != Insstart_orig.col))));
}
did_backspace = true;
}
diff --git a/src/nvim/eval.c b/src/nvim/eval.c
index 8a1556320c..a25b140b2f 100644
--- a/src/nvim/eval.c
+++ b/src/nvim/eval.c
@@ -365,7 +365,7 @@ void eval_init(void)
eval_msgpack_type_lists[i] = type_list;
if (tv_dict_add(msgpack_types_dict, di) == FAIL) {
// There must not be duplicate items in this dictionary by definition.
- assert(false);
+ abort();
}
}
msgpack_types_dict->dv_lock = VAR_FIXED;
diff --git a/src/nvim/eval/decode.c b/src/nvim/eval/decode.c
index 638fef331a..bd4dc87d31 100644
--- a/src/nvim/eval/decode.c
+++ b/src/nvim/eval/decode.c
@@ -147,7 +147,7 @@ static inline int json_decoder_pop(ValuesStackItem obj,
tv_clear(&key.val);
if (tv_dict_add(last_container.container.vval.v_dict, obj_di)
== FAIL) {
- assert(false);
+ abort();
}
obj_di->di_tv = obj.val;
} else {
@@ -480,7 +480,7 @@ static inline int parse_json_string(const char *const buf, const size_t buf_len,
break;
}
default: {
- assert(false);
+ abort();
}
}
} else {
diff --git a/src/nvim/eval/encode.c b/src/nvim/eval/encode.c
index 9a9f2e4287..a4d7af7971 100644
--- a/src/nvim/eval/encode.c
+++ b/src/nvim/eval/encode.c
@@ -174,7 +174,7 @@ static int conv_error(const char *const msg, const MPConvStack *const mpstack,
case kMPConvPartial: {
switch (v.data.p.stage) {
case kMPConvPartialArgs: {
- assert(false);
+ abort();
break;
}
case kMPConvPartialSelf: {
@@ -237,7 +237,7 @@ bool encode_vim_list_to_buf(const list_T *const list, size_t *const ret_len,
char *const buf = xmalloc(len);
size_t read_bytes;
if (encode_read_from_list(&lrstate, buf, len, &read_bytes) != OK) {
- assert(false);
+ abort();
}
assert(len == read_bytes);
*ret_buf = buf;
diff --git a/src/nvim/eval/executor.c b/src/nvim/eval/executor.c
index da05ecda43..bbba9d12f2 100644
--- a/src/nvim/eval/executor.c
+++ b/src/nvim/eval/executor.c
@@ -118,7 +118,7 @@ int eexe_mod_op(typval_T *const tv1, const typval_T *const tv2,
return OK;
}
case VAR_UNKNOWN: {
- assert(false);
+ abort();
}
}
}
diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c
index 8235d74cbb..1a7bbf2d0e 100644
--- a/src/nvim/eval/funcs.c
+++ b/src/nvim/eval/funcs.c
@@ -1798,7 +1798,7 @@ static void f_environ(typval_T *argvars, typval_T *rettv, FunPtr fptr)
os_copy_fullenv(env, env_size);
- for (size_t i = 0; i < env_size; i++) {
+ for (ssize_t i = env_size - 1; i >= 0; i--) {
const char * str = env[i];
const char * const end = strchr(str + (str[0] == '=' ? 1 : 0),
'=');
@@ -1806,6 +1806,12 @@ static void f_environ(typval_T *argvars, typval_T *rettv, FunPtr fptr)
ptrdiff_t len = end - str;
assert(len > 0);
const char * value = str + len + 1;
+ if (tv_dict_find(rettv->vval.v_dict, str, len) != NULL) {
+ // Since we're traversing from the end of the env block to the front, any
+ // duplicate names encountered should be ignored. This preserves the
+ // semantics of env vars defined later in the env block taking precedence.
+ continue;
+ }
tv_dict_add_str(rettv->vval.v_dict,
str, len,
value);
@@ -3301,7 +3307,7 @@ static void f_getcwd(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
break;
case kCdScopeInvalid: // We should never get here
- assert(false);
+ abort();
}
if (from) {
@@ -4354,7 +4360,7 @@ static void f_haslocaldir(typval_T *argvars, typval_T *rettv, FunPtr fptr)
break;
case kCdScopeInvalid:
// We should never get here
- assert(false);
+ abort();
}
}
@@ -4875,6 +4881,95 @@ static void f_jobresize(typval_T *argvars, typval_T *rettv, FunPtr fptr)
rettv->vval.v_number = 1;
}
+static const char *ignored_env_vars[] = {
+#ifndef WIN32
+ "COLUMNS",
+ "LINES",
+ "TERMCAP",
+ "COLORFGBG",
+#endif
+ NULL
+};
+
+/// According to comments in src/win/process.c of libuv, Windows has a few
+/// "essential" environment variables.
+static const char *required_env_vars[] = {
+#ifdef WIN32
+ "HOMEDRIVE",
+ "HOMEPATH",
+ "LOGONSERVER",
+ "PATH",
+ "SYSTEMDRIVE",
+ "SYSTEMROOT",
+ "TEMP",
+ "USERDOMAIN",
+ "USERNAME",
+ "USERPROFILE",
+ "WINDIR",
+#endif
+ NULL
+};
+
+static dict_T *create_environment(const dictitem_T *job_env,
+ const bool clear_env,
+ const bool pty)
+{
+ dict_T * env = tv_dict_alloc();
+
+ if (!clear_env) {
+ typval_T temp_env = TV_INITIAL_VALUE;
+ f_environ(NULL, &temp_env, NULL);
+ tv_dict_extend(env, temp_env.vval.v_dict, "force");
+ tv_dict_free(temp_env.vval.v_dict);
+
+ if (pty) {
+ // These environment variables generally shouldn't be propagated to the
+ // child process. We're removing them here so the user can still decide
+ // they want to explicitly set them.
+ for (size_t i = 0;
+ i < ARRAY_SIZE(ignored_env_vars) && ignored_env_vars[i];
+ i++) {
+ dictitem_T *dv = tv_dict_find(env, ignored_env_vars[i], -1);
+ if (dv) {
+ tv_dict_item_remove(env, dv);
+ }
+ }
+#ifndef WIN32
+ // Set COLORTERM to "truecolor" if termguicolors is set and 256
+ // otherwise, but only if it was set in the parent terminal at all
+ dictitem_T *dv = tv_dict_find(env, S_LEN("COLORTERM"));
+ if (dv) {
+ tv_dict_item_remove(env, dv);
+ tv_dict_add_str(env, S_LEN("COLORTERM"), p_tgc ? "truecolor" : "256");
+ }
+#endif
+ }
+ }
+
+ if (job_env) {
+ tv_dict_extend(env, job_env->di_tv.vval.v_dict, "force");
+ }
+
+ if (pty) {
+ // Now that the custom environment is configured, we need to ensure certain
+ // environment variables are present.
+ for (size_t i = 0;
+ i < ARRAY_SIZE(required_env_vars) && required_env_vars[i];
+ i++) {
+ size_t len = strlen(required_env_vars[i]);
+ dictitem_T *dv = tv_dict_find(env, required_env_vars[i], len);
+ if (!dv) {
+ const char *env_var = os_getenv(required_env_vars[i]);
+ if (env_var) {
+ tv_dict_add_str(env, required_env_vars[i], len, env_var);
+ }
+ }
+ }
+ }
+
+ return env;
+}
+
// "jobstart()" function
static void f_jobstart(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
@@ -4887,7 +4982,7 @@ static void f_jobstart(typval_T *argvars, typval_T *rettv, FunPtr fptr)
bool executable = true;
char **argv = tv_to_argv(&argvars[0], NULL, &executable);
- char **env = NULL;
+ dict_T *env = NULL;
if (!argv) {
rettv->vval.v_number = executable ? 0 : -1;
return; // Did error message in tv_to_argv.
@@ -4911,6 +5006,7 @@ static void f_jobstart(typval_T *argvars, typval_T *rettv, FunPtr fptr)
on_stderr = CALLBACK_READER_INIT;
Callback on_exit = CALLBACK_NONE;
char *cwd = NULL;
+ dictitem_T *job_env = NULL;
if (argvars[1].v_type == VAR_DICT) {
job_opts = argvars[1].vval.v_dict;
@@ -4936,7 +5032,7 @@ static void f_jobstart(typval_T *argvars, typval_T *rettv, FunPtr fptr)
#endif
char *new_cwd = tv_dict_get_string(job_opts, "cwd", false);
- if (new_cwd && strlen(new_cwd) > 0) {
+ if (new_cwd && *new_cwd != NUL) {
cwd = new_cwd;
// The new cwd must be a directory.
if (!os_isdir_executable((const char *)cwd)) {
@@ -4945,52 +5041,22 @@ static void f_jobstart(typval_T *argvars, typval_T *rettv, FunPtr fptr)
return;
}
}
- dictitem_T *job_env = tv_dict_find(job_opts, S_LEN("env"));
- if (job_env) {
- if (job_env->di_tv.v_type != VAR_DICT) {
- EMSG2(_(e_invarg2), "env");
- shell_free_argv(argv);
- return;
- }
-
- size_t custom_env_size = (size_t)tv_dict_len(job_env->di_tv.vval.v_dict);
- size_t i = 0;
- size_t env_size = 0;
-
- if (clear_env) {
- // + 1 for last null entry
- env = xmalloc((custom_env_size + 1) * sizeof(*env));
- env_size = 0;
- } else {
- env_size = os_get_fullenv_size();
- env = xmalloc((custom_env_size + env_size + 1) * sizeof(*env));
-
- os_copy_fullenv(env, env_size);
- i = env_size;
- }
- assert(env); // env must be allocated at this point
-
- TV_DICT_ITER(job_env->di_tv.vval.v_dict, var, {
- const char *str = tv_get_string(&var->di_tv);
- assert(str);
- size_t len = STRLEN(var->di_key) + strlen(str) + strlen("=") + 1;
- env[i] = xmalloc(len);
- snprintf(env[i], len, "%s=%s", (char *)var->di_key, str);
- i++;
- });
-
- // must be null terminated
- env[env_size + custom_env_size] = NULL;
+ job_env = tv_dict_find(job_opts, S_LEN("env"));
+ if (job_env && job_env->di_tv.v_type != VAR_DICT) {
+ EMSG2(_(e_invarg2), "env");
+ shell_free_argv(argv);
+ return;
}
-
if (!common_job_callbacks(job_opts, &on_stdout, &on_stderr, &on_exit)) {
shell_free_argv(argv);
return;
}
}
+ env = create_environment(job_env, clear_env, pty);
+
uint16_t width = 0, height = 0;
char *term_name = NULL;
@@ -10518,6 +10584,11 @@ static void f_termopen(typval_T *argvars, typval_T *rettv, FunPtr fptr)
Callback on_exit = CALLBACK_NONE;
dict_T *job_opts = NULL;
const char *cwd = ".";
+ dict_T *env = NULL;
+ const bool pty = true;
+ bool clear_env = false;
+ dictitem_T *job_env = NULL;
+
if (argvars[1].v_type == VAR_DICT) {
job_opts = argvars[1].vval.v_dict;
@@ -10532,17 +10603,31 @@ static void f_termopen(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
}
+ job_env = tv_dict_find(job_opts, S_LEN("env"));
+ if (job_env && job_env->di_tv.v_type != VAR_DICT) {
+ EMSG2(_(e_invarg2), "env");
+ shell_free_argv(argv);
+ return;
+ }
+
+ clear_env = tv_dict_get_number(job_opts, "clear_env") != 0;
+
if (!common_job_callbacks(job_opts, &on_stdout, &on_stderr, &on_exit)) {
shell_free_argv(argv);
return;
}
}
+ env = create_environment(job_env, clear_env, pty);
+
+ const bool rpc = false;
+ const bool overlapped = false;
+ const bool detach = false;
uint16_t term_width = MAX(0, curwin->w_width_inner - win_col_off(curwin));
Channel *chan = channel_job_start(argv, on_stdout, on_stderr, on_exit,
- true, false, false, false, cwd,
+ pty, rpc, overlapped, detach, cwd,
term_width, curwin->w_height_inner,
- xstrdup("xterm-256color"), NULL,
+ xstrdup("xterm-256color"), env,
&rettv->vval.v_number);
if (rettv->vval.v_number <= 0) {
return;
diff --git a/src/nvim/eval/typval.c b/src/nvim/eval/typval.c
index 02d32a4f86..9be487f4fd 100644
--- a/src/nvim/eval/typval.c
+++ b/src/nvim/eval/typval.c
@@ -1523,6 +1523,33 @@ varnumber_T tv_dict_get_number(const dict_T *const d, const char *const key)
return tv_get_number(&di->di_tv);
}
+/// Converts a dict to an environment
+///
+///
+char **tv_dict_to_env(dict_T *denv)
+{
+ size_t env_size = (size_t)tv_dict_len(denv);
+
+ size_t i = 0;
+ char **env = NULL;
+
+ // + 1 for NULL
+ env = xmalloc((env_size + 1) * sizeof(*env));
+
+ TV_DICT_ITER(denv, var, {
+ const char *str = tv_get_string(&var->di_tv);
+ assert(str);
+ size_t len = STRLEN(var->di_key) + strlen(str) + strlen("=") + 1;
+ env[i] = xmalloc(len);
+ snprintf(env[i], len, "%s=%s", (char *)var->di_key, str);
+ i++;
+ });
+
+ // must be null terminated
+ env[env_size] = NULL;
+ return env;
+}
+
/// Get a string item from a dictionary
///
/// @param[in] d Dictionary to get item from.
@@ -2494,7 +2521,7 @@ void tv_item_lock(typval_T *const tv, const int deep, const bool lock)
break;
}
case VAR_UNKNOWN: {
- assert(false);
+ abort();
}
}
#undef CHANGE_LOCK
@@ -2666,7 +2693,7 @@ bool tv_equal(typval_T *const tv1, typval_T *const tv2, const bool ic,
}
}
- assert(false);
+ abort();
return false;
}
@@ -2719,7 +2746,7 @@ bool tv_check_str_or_nr(const typval_T *const tv)
return false;
}
}
- assert(false);
+ abort();
return false;
}
@@ -2764,7 +2791,7 @@ bool tv_check_num(const typval_T *const tv)
return false;
}
}
- assert(false);
+ abort();
return false;
}
@@ -2809,7 +2836,7 @@ bool tv_check_str(const typval_T *const tv)
return false;
}
}
- assert(false);
+ abort();
return false;
}
diff --git a/src/nvim/event/libuv_process.c b/src/nvim/event/libuv_process.c
index 13517d3df1..0b1ecb12e2 100644
--- a/src/nvim/event/libuv_process.c
+++ b/src/nvim/event/libuv_process.c
@@ -41,7 +41,6 @@ int libuv_process_spawn(LibuvProcess *uvproc)
#endif
uvproc->uvopts.exit_cb = exit_cb;
uvproc->uvopts.cwd = proc->cwd;
- uvproc->uvopts.env = proc->env;
uvproc->uvopts.stdio = uvproc->uvstdio;
uvproc->uvopts.stdio_count = 3;
uvproc->uvstdio[0].flags = UV_IGNORE;
@@ -49,6 +48,12 @@ int libuv_process_spawn(LibuvProcess *uvproc)
uvproc->uvstdio[2].flags = UV_IGNORE;
uvproc->uv.data = proc;
+ if (proc->env) {
+ uvproc->uvopts.env = tv_dict_to_env(proc->env);
+ } else {
+ uvproc->uvopts.env = NULL;
+ }
+
if (!proc->in.closed) {
uvproc->uvstdio[0].flags = UV_CREATE_PIPE | UV_READABLE_PIPE;
#ifdef WIN32
@@ -78,6 +83,9 @@ int libuv_process_spawn(LibuvProcess *uvproc)
int status;
if ((status = uv_spawn(&proc->loop->uv, &uvproc->uv, &uvproc->uvopts))) {
ELOG("uv_spawn failed: %s", uv_strerror(status));
+ if (uvproc->uvopts.env) {
+ os_free_fullenv(uvproc->uvopts.env);
+ }
return status;
}
@@ -97,6 +105,10 @@ static void close_cb(uv_handle_t *handle)
if (proc->internal_close_cb) {
proc->internal_close_cb(proc);
}
+ LibuvProcess *uvproc = (LibuvProcess *)proc;
+ if (uvproc->uvopts.env) {
+ os_free_fullenv(uvproc->uvopts.env);
+ }
}
static void exit_cb(uv_process_t *handle, int64_t status, int term_signal)
diff --git a/src/nvim/event/process.h b/src/nvim/event/process.h
index 84e81238e9..24debdb276 100644
--- a/src/nvim/event/process.h
+++ b/src/nvim/event/process.h
@@ -4,6 +4,7 @@
#include "nvim/event/loop.h"
#include "nvim/event/rstream.h"
#include "nvim/event/wstream.h"
+#include "nvim/eval/typval.h"
typedef enum {
kProcessTypeUv,
@@ -23,7 +24,7 @@ struct process {
uint64_t stopped_time; // process_stop() timestamp
const char *cwd;
char **argv;
- char **env;
+ dict_T *env;
Stream in, out, err;
process_exit_cb cb;
internal_process_cb internal_exit_cb, internal_close_cb;
diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c
index 61e4d634c6..6d26c5f69c 100644
--- a/src/nvim/ex_cmds.c
+++ b/src/nvim/ex_cmds.c
@@ -790,7 +790,10 @@ void ex_retab(exarg_T *eap)
for (col = 0; col < len; col++) {
ptr[col] = (col < num_tabs) ? '\t' : ' ';
}
- ml_replace(lnum, new_line, false);
+ if (ml_replace(lnum, new_line, false) == OK) {
+ // "new_line" may have been copied
+ new_line = curbuf->b_ml.ml_line_ptr;
+ }
if (first_line == 0) {
first_line = lnum;
}
@@ -2413,7 +2416,10 @@ int do_ecmd(
(flags & ECMD_HIDE) || curbuf->terminal ? 0 : DOBUF_UNLOAD,
false);
- the_curwin->w_closing = false;
+ // Autocommands may have closed the window.
+ if (win_valid(the_curwin)) {
+ the_curwin->w_closing = false;
+ }
buf->b_locked--;
// autocmds may abort script processing
@@ -3126,6 +3132,9 @@ static bool sub_joining_lines(exarg_T *eap, char_u *pat, char_u *sub,
|| *cmd == 'l'
|| *cmd == 'p'
|| *cmd == '#')))) {
+ if (eap->skip) {
+ return true;
+ }
curwin->w_cursor.lnum = eap->line1;
if (*cmd == 'l') {
eap->flags = EXFLAG_LIST;
@@ -3307,11 +3316,7 @@ static buf_T *do_sub(exarg_T *eap, proftime_T timeout,
int save_b_changed = curbuf->b_changed;
bool preview = (State & CMDPREVIEW);
- // inccommand tests fail without this check
- if (!preview) {
- // Required for Undo to work for extmarks.
- u_save_cursor();
- }
+ bool did_save = false;
if (!global_busy) {
sub_nsubs = 0;
@@ -3693,6 +3698,7 @@ static buf_T *do_sub(exarg_T *eap, proftime_T timeout,
} else {
char_u *orig_line = NULL;
int len_change = 0;
+ const bool save_p_lz = p_lz;
int save_p_fen = curwin->w_p_fen;
curwin->w_p_fen = FALSE;
@@ -3701,6 +3707,9 @@ static buf_T *do_sub(exarg_T *eap, proftime_T timeout,
int temp = RedrawingDisabled;
RedrawingDisabled = 0;
+ // avoid calling update_screen() in vgetorpeek()
+ p_lz = false;
+
if (new_start != NULL) {
/* There already was a substitution, we would
* like to show this to the user. We cannot
@@ -3754,7 +3763,8 @@ static buf_T *do_sub(exarg_T *eap, proftime_T timeout,
/* clear the question */
msg_didout = FALSE; /* don't scroll up */
msg_col = 0;
- gotocmdline(TRUE);
+ gotocmdline(true);
+ p_lz = save_p_lz;
// restore the line
if (orig_line != NULL) {
@@ -3983,6 +3993,11 @@ static buf_T *do_sub(exarg_T *eap, proftime_T timeout,
int matchcols = end.col - ((end.lnum == start.lnum)
? start.col : 0);
int subcols = new_endcol - ((lnum == lnum_start) ? start_col : 0);
+ if (!did_save) {
+ // Required for Undo to work for extmarks.
+ u_save_cursor();
+ did_save = true;
+ }
extmark_splice(curbuf, lnum_start-1, start_col,
end.lnum-start.lnum, matchcols, replaced_bytes,
lnum-lnum_start, subcols, sublen-1, kExtmarkUndo);
diff --git a/src/nvim/ex_cmds.lua b/src/nvim/ex_cmds.lua
index 069d5d461b..e9046da800 100644
--- a/src/nvim/ex_cmds.lua
+++ b/src/nvim/ex_cmds.lua
@@ -2455,7 +2455,7 @@ module.cmds = {
},
{
command='sleep',
- flags=bit.bor(RANGE, COUNT, EXTRA, TRLBAR, CMDWIN),
+ flags=bit.bor(BANG, RANGE, COUNT, EXTRA, TRLBAR, CMDWIN),
addr_type='ADDR_OTHER',
func='ex_sleep',
},
diff --git a/src/nvim/ex_cmds2.c b/src/nvim/ex_cmds2.c
index c400975108..e49bb99aa0 100644
--- a/src/nvim/ex_cmds2.c
+++ b/src/nvim/ex_cmds2.c
@@ -1639,10 +1639,10 @@ int get_arglist_exp(char_u *str, int *fcountp, char_u ***fnamesp, bool wig)
if (wig) {
i = expand_wildcards(ga.ga_len, (char_u **)ga.ga_data,
- fcountp, fnamesp, EW_FILE|EW_NOTFOUND);
+ fcountp, fnamesp, EW_FILE|EW_NOTFOUND|EW_NOTWILD);
} else {
i = gen_expand_wildcards(ga.ga_len, (char_u **)ga.ga_data,
- fcountp, fnamesp, EW_FILE|EW_NOTFOUND);
+ fcountp, fnamesp, EW_FILE|EW_NOTFOUND|EW_NOTWILD);
}
ga_clear(&ga);
diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c
index ccf7dd0f68..52da7fe4f6 100644
--- a/src/nvim/ex_docmd.c
+++ b/src/nvim/ex_docmd.c
@@ -317,7 +317,9 @@ int do_cmdline(char_u *cmdline, LineGetter fgetline,
int count = 0; /* line number count */
int did_inc = FALSE; /* incremented RedrawingDisabled */
int retval = OK;
- cstack_T cstack; // conditional stack
+ cstack_T cstack = { // conditional stack
+ .cs_idx = -1,
+ };
garray_T lines_ga; // keep lines for ":while"/":for"
int current_line = 0; // active line in lines_ga
char_u *fname = NULL; // function or script name
@@ -360,11 +362,6 @@ int do_cmdline(char_u *cmdline, LineGetter fgetline,
call_depth++;
start_batch_changes();
- cstack.cs_idx = -1;
- cstack.cs_looplevel = 0;
- cstack.cs_trylevel = 0;
- cstack.cs_emsg_silent_list = NULL;
- cstack.cs_lflags = 0;
ga_init(&lines_ga, (int)sizeof(wcmd_T), 10);
real_cookie = getline_cookie(fgetline, cookie);
@@ -3041,9 +3038,10 @@ const char * set_one_cmd_context(
p = arg + 1;
arg = (const char *)skip_cmd_arg((char_u *)arg, false);
- /* Still touching the command after '+'? */
- if (*arg == NUL)
+ // Still touching the command after '+'?
+ if (*arg == NUL) {
return p;
+ }
// Skip space(s) after +command to get to the real argument.
arg = (const char *)skipwhite((const char_u *)arg);
@@ -3680,6 +3678,10 @@ const char * set_one_cmd_context(
xp->xp_pattern = (char_u *)arg;
break;
+ case CMD_lua:
+ xp->xp_context = EXPAND_LUA;
+ break;
+
default:
break;
}
@@ -3968,7 +3970,7 @@ static linenr_T get_address(exarg_T *eap,
break;
default:
- if (ascii_isdigit(*cmd)) { // absolute line number
+ if (ascii_isdigit(*cmd)) { // absolute line number
lnum = getdigits_long(&cmd, false, 0);
}
}
@@ -5187,6 +5189,7 @@ static const char *command_complete[] =
#ifdef HAVE_WORKING_LIBINTL
[EXPAND_LOCALES] = "locale",
#endif
+ [EXPAND_LUA] = "lua",
[EXPAND_MAPCLEAR] = "mapclear",
[EXPAND_MAPPINGS] = "mapping",
[EXPAND_MENUS] = "menu",
@@ -5400,8 +5403,8 @@ static int uc_scan_attr(char_u *attr, size_t len, uint32_t *argt, long *def,
size_t vallen = 0;
size_t attrlen = len;
- /* Look for the attribute name - which is the part before any '=' */
- for (i = 0; i < (int)len; ++i) {
+ // Look for the attribute name - which is the part before any '='
+ for (i = 0; i < (int)len; i++) {
if (attr[i] == '=') {
val = &attr[i + 1];
vallen = len - i - 1;
@@ -7503,8 +7506,9 @@ static void ex_read(exarg_T *eap)
}
if (*eap->arg == NUL) {
- if (check_fname() == FAIL) /* check for no file name */
+ if (check_fname() == FAIL) { // check for no file name
return;
+ }
i = readfile(curbuf->b_ffname, curbuf->b_fname,
eap->line2, (linenr_T)0, (linenr_T)MAXLNUM, eap, 0);
} else {
@@ -7587,7 +7591,7 @@ void post_chdir(CdScope scope, bool trigger_dirchanged)
curwin->w_localdir = (char_u *)xstrdup(cwd);
break;
case kCdScopeInvalid:
- assert(false);
+ abort();
}
shorten_fnames(true);
diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c
index 626b840798..cf6bb6d492 100644
--- a/src/nvim/ex_getln.c
+++ b/src/nvim/ex_getln.c
@@ -69,6 +69,7 @@
#include "nvim/lib/kvec.h"
#include "nvim/api/private/helpers.h"
#include "nvim/highlight_defs.h"
+#include "nvim/lua/executor.h"
#include "nvim/viml/parser/parser.h"
#include "nvim/viml/parser/expressions.h"
@@ -3828,7 +3829,7 @@ static void cmd_cursor_goto(int row, int col)
ui_grid_cursor_goto(grid->handle, row, col);
}
-void gotocmdline(int clr)
+void gotocmdline(bool clr)
{
if (ui_has(kUICmdline)) {
return;
@@ -3945,6 +3946,12 @@ nextwild (
p2 = ExpandOne(xp, p1, vim_strnsave(&ccline.cmdbuff[i], xp->xp_pattern_len),
use_options, type);
xfree(p1);
+
+ // xp->xp_pattern might have been modified by ExpandOne (for example,
+ // in lua completion), so recompute the pattern index and length
+ i = (int)(xp->xp_pattern - ccline.cmdbuff);
+ xp->xp_pattern_len = (size_t)ccline.cmdpos - (size_t)i;
+
// Longest match: make sure it is not shorter, happens with :help.
if (p2 != NULL && type == WILD_LONGEST) {
for (j = 0; (size_t)j < xp->xp_pattern_len; j++) {
@@ -3960,7 +3967,7 @@ nextwild (
}
if (p2 != NULL && !got_int) {
- difflen = (int)STRLEN(p2) - (int)xp->xp_pattern_len;
+ difflen = (int)STRLEN(p2) - (int)(xp->xp_pattern_len);
if (ccline.cmdlen + difflen + 4 > ccline.cmdbufflen) {
realloc_cmdbuff(ccline.cmdlen + difflen + 4);
xp->xp_pattern = ccline.cmdbuff + i;
@@ -5106,6 +5113,10 @@ ExpandFromContext (
if (xp->xp_context == EXPAND_PACKADD) {
return ExpandPackAddDir(pat, num_file, file);
}
+ if (xp->xp_context == EXPAND_LUA) {
+ ILOG("PAT %s", pat);
+ return nlua_expand_pat(xp, pat, num_file, file);
+ }
regmatch.regprog = vim_regcomp(pat, p_magic ? RE_MAGIC : 0);
if (regmatch.regprog == NULL)
@@ -6372,7 +6383,7 @@ int hist_type2char(int type)
return '>';
}
default: {
- assert(false);
+ abort();
}
}
return NUL;
diff --git a/src/nvim/extmark.c b/src/nvim/extmark.c
index b2d8532cd7..cacbeddb32 100644
--- a/src/nvim/extmark.c
+++ b/src/nvim/extmark.c
@@ -71,7 +71,8 @@ static ExtmarkNs *buf_ns_ref(buf_T *buf, uint64_t ns_id, bool put) {
/// @returns the mark id
uint64_t extmark_set(buf_T *buf, uint64_t ns_id, uint64_t id,
int row, colnr_T col, int end_row, colnr_T end_col,
- Decoration *decor, ExtmarkOp op)
+ Decoration *decor, bool right_gravity,
+ bool end_right_gravity, ExtmarkOp op)
{
ExtmarkNs *ns = buf_ns_ref(buf, ns_id, true);
assert(ns != NULL);
@@ -109,10 +110,10 @@ uint64_t extmark_set(buf_T *buf, uint64_t ns_id, uint64_t id,
if (end_row > -1) {
mark = marktree_put_pair(buf->b_marktree,
- row, col, true,
- end_row, end_col, false);
+ row, col, right_gravity,
+ end_row, end_col, end_right_gravity);
} else {
- mark = marktree_put(buf->b_marktree, row, col, true);
+ mark = marktree_put(buf->b_marktree, row, col, right_gravity);
}
revised:
diff --git a/src/nvim/file_search.c b/src/nvim/file_search.c
index b1fa0b6779..8beba38509 100644
--- a/src/nvim/file_search.c
+++ b/src/nvim/file_search.c
@@ -1595,7 +1595,7 @@ void do_autocmd_dirchanged(char *new_dir, CdScope scope, bool changed_window)
}
case kCdScopeInvalid: {
// Should never happen.
- assert(false);
+ abort();
}
}
diff --git a/src/nvim/fold.c b/src/nvim/fold.c
index 0593c16999..5032646d7e 100644
--- a/src/nvim/fold.c
+++ b/src/nvim/fold.c
@@ -2999,7 +2999,6 @@ static void foldlevelDiff(fline_T *flp)
static void foldlevelExpr(fline_T *flp)
{
win_T *win;
- int n;
int c;
linenr_T lnum = flp->lnum + flp->off;
@@ -3017,7 +3016,7 @@ static void foldlevelExpr(fline_T *flp)
/* KeyTyped may be reset to 0 when calling a function which invokes
* do_cmdline(). To make 'foldopen' work correctly restore KeyTyped. */
const bool save_keytyped = KeyTyped;
- n = (int)eval_foldexpr(flp->wp->w_p_fde, &c);
+ const int n = eval_foldexpr(flp->wp->w_p_fde, &c);
KeyTyped = save_keytyped;
switch (c) {
@@ -3202,8 +3201,10 @@ int put_folds(FILE *fd, win_T *wp)
{
if (foldmethodIsManual(wp)) {
if (put_line(fd, "silent! normal! zE") == FAIL
- || put_folds_recurse(fd, &wp->w_folds, (linenr_T)0) == FAIL)
+ || put_folds_recurse(fd, &wp->w_folds, (linenr_T)0) == FAIL
+ || put_line(fd, "let &fdl = &fdl") == FAIL) {
return FAIL;
+ }
}
/* If some folds are manually opened/closed, need to restore that. */
diff --git a/src/nvim/globals.h b/src/nvim/globals.h
index 3b8f4116b7..22f06941aa 100644
--- a/src/nvim/globals.h
+++ b/src/nvim/globals.h
@@ -1009,6 +1009,8 @@ EXTERN char_u e_floatonly[] INIT(=N_(
EXTERN char_u e_floatexchange[] INIT(=N_(
"E5602: Cannot exchange or rotate float"));
+EXTERN char e_cannot_define_autocommands_for_all_events[] INIT(= N_(
+ "E1155: Cannot define autocommands for ALL events"));
EXTERN char top_bot_msg[] INIT(= N_("search hit TOP, continuing at BOTTOM"));
EXTERN char bot_top_msg[] INIT(= N_("search hit BOTTOM, continuing at TOP"));
diff --git a/src/nvim/log.c b/src/nvim/log.c
index 19203a3c2a..324382a0f7 100644
--- a/src/nvim/log.c
+++ b/src/nvim/log.c
@@ -51,7 +51,7 @@ static bool log_try_create(char *fname)
/// Initializes path to log file. Sets $NVIM_LOG_FILE if empty.
///
-/// Tries $NVIM_LOG_FILE, or falls back to $XDG_DATA_HOME/nvim/log. Path to log
+/// Tries $NVIM_LOG_FILE, or falls back to $XDG_CACHE_HOME/nvim/log. Path to log
/// file is cached, so only the first call has effect, unless first call was not
/// successful. Failed initialization indicates either a bug in expand_env()
/// or both $NVIM_LOG_FILE and $HOME environment variables are undefined.
@@ -69,8 +69,16 @@ static bool log_path_init(void)
|| log_file_path[0] == '\0'
|| os_isdir((char_u *)log_file_path)
|| !log_try_create(log_file_path)) {
+ // Make kXDGCacheHome if it does not exist.
+ char *cachehome = get_xdg_home(kXDGCacheHome);
+ char *failed_dir = NULL;
+ bool log_dir_failure = false;
+ if (!os_isdir((char_u *)cachehome)) {
+ log_dir_failure = (os_mkdir_recurse(cachehome, 0700, &failed_dir) != 0);
+ }
+ XFREE_CLEAR(cachehome);
// Invalid $NVIM_LOG_FILE or failed to expand; fall back to default.
- char *defaultpath = stdpaths_user_data_subpath("log", 0, true);
+ char *defaultpath = stdpaths_user_cache_subpath("log");
size_t len = xstrlcpy(log_file_path, defaultpath, size);
xfree(defaultpath);
// Fall back to .nvimlog
@@ -83,6 +91,11 @@ static bool log_path_init(void)
return false;
}
os_setenv(LOG_FILE_ENV, log_file_path, true);
+ if (log_dir_failure) {
+ WLOG("Failed to create directory %s for writing logs: %s",
+ failed_dir, os_strerror(log_dir_failure));
+ }
+ XFREE_CLEAR(failed_dir);
}
return true;
}
@@ -323,4 +336,3 @@ static bool v_do_log_to_file(FILE *log_file, int log_level,
return true;
}
-
diff --git a/src/nvim/lua/converter.c b/src/nvim/lua/converter.c
index 030df69caa..83b3729ad3 100644
--- a/src/nvim/lua/converter.c
+++ b/src/nvim/lua/converter.c
@@ -245,7 +245,7 @@ bool nlua_pop_typval(lua_State *lstate, typval_T *ret_tv)
} else {
dictitem_T *const di = tv_dict_item_alloc_len(s, len);
if (tv_dict_add(cur.tv->vval.v_dict, di) == FAIL) {
- assert(false);
+ abort();
}
kv_push(stack, cur);
cur = (TVPopStackItem) { &di->di_tv, false, false, 0 };
@@ -391,7 +391,7 @@ bool nlua_pop_typval(lua_State *lstate, typval_T *ret_tv)
break;
}
default: {
- assert(false);
+ abort();
}
}
nlua_pop_typval_table_processing_end:
@@ -1200,7 +1200,7 @@ Object nlua_pop_Object(lua_State *const lstate, bool ref, Error *const err)
break;
}
default: {
- assert(false);
+ abort();
}
}
break;
diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c
index 344a2387d6..310b194c8c 100644
--- a/src/nvim/lua/executor.c
+++ b/src/nvim/lua/executor.c
@@ -5,6 +5,7 @@
#include <lualib.h>
#include <lauxlib.h>
+#include "nvim/version.h"
#include "nvim/misc1.h"
#include "nvim/getchar.h"
#include "nvim/garray.h"
@@ -78,6 +79,17 @@ static void nlua_error(lua_State *const lstate, const char *const msg)
lua_pop(lstate, 1);
}
+/// Return version of current neovim build
+///
+/// @param lstate Lua interpreter state.
+static int nlua_nvim_version(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL
+{
+ Dictionary version = version_dict();
+ nlua_push_Dictionary(lstate, version, true);
+ api_free_dictionary(version);
+ return 1;
+}
+
/// Compare two strings, ignoring case
///
/// Expects two values on the stack: compared strings. Returns one of the
@@ -420,6 +432,9 @@ static int nlua_state_init(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL
// str_byteindex
lua_pushcfunction(lstate, &nlua_str_byteindex);
lua_setfield(lstate, -2, "str_byteindex");
+ // neovim version
+ lua_pushcfunction(lstate, &nlua_nvim_version);
+ lua_setfield(lstate, -2, "version");
// schedule
lua_pushcfunction(lstate, &nlua_schedule);
lua_setfield(lstate, -2, "schedule");
@@ -1277,6 +1292,80 @@ static void nlua_add_treesitter(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL
lua_setfield(lstate, -2, "_ts_parse_query");
}
+int nlua_expand_pat(expand_T *xp,
+ char_u *pat,
+ int *num_results,
+ char_u ***results)
+{
+ lua_State *const lstate = nlua_enter();
+ int ret = OK;
+
+ // [ vim ]
+ lua_getglobal(lstate, "vim");
+
+ // [ vim, vim._expand_pat ]
+ lua_getfield(lstate, -1, "_expand_pat");
+ luaL_checktype(lstate, -1, LUA_TFUNCTION);
+
+ // [ vim, vim._log_keystroke, buf ]
+ lua_pushlstring(lstate, (const char *)pat, STRLEN(pat));
+
+ if (lua_pcall(lstate, 1, 2, 0) != 0) {
+ nlua_error(
+ lstate,
+ _("Error executing vim._expand_pat: %.*s"));
+ return FAIL;
+ }
+
+ Error err = ERROR_INIT;
+
+ *num_results = 0;
+ *results = NULL;
+
+ int prefix_len = (int)nlua_pop_Integer(lstate, &err);
+ if (ERROR_SET(&err)) {
+ ret = FAIL;
+ goto cleanup;
+ }
+
+ Array completions = nlua_pop_Array(lstate, &err);
+ if (ERROR_SET(&err)) {
+ ret = FAIL;
+ goto cleanup_array;
+ }
+
+ garray_T result_array;
+ ga_init(&result_array, (int)sizeof(char *), 80);
+ for (size_t i = 0; i < completions.size; i++) {
+ Object v = completions.items[i];
+
+ if (v.type != kObjectTypeString) {
+ ret = FAIL;
+ goto cleanup_array;
+ }
+
+ GA_APPEND(
+ char_u *,
+ &result_array,
+ vim_strsave((char_u *)v.data.string.data));
+ }
+
+ xp->xp_pattern += prefix_len;
+ *results = result_array.ga_data;
+ *num_results = result_array.ga_len;
+
+cleanup_array:
+ api_free_array(completions);
+
+cleanup:
+
+ if (ret == FAIL) {
+ ga_clear(&result_array);
+ }
+
+ return ret;
+}
+
static int nlua_regex(lua_State *lstate)
{
Error err = ERROR_INIT;
diff --git a/src/nvim/lua/vim.lua b/src/nvim/lua/vim.lua
index b20fbbf038..dbf4f6014c 100644
--- a/src/nvim/lua/vim.lua
+++ b/src/nvim/lua/vim.lua
@@ -121,10 +121,17 @@ function vim._load_package(name)
end
for _,trail in ipairs(vim._so_trails) do
- local path = "lua/"..trail:gsub('?',basename)
+ local path = "lua"..trail:gsub('?', basename) -- so_trails contains a leading slash
local found = vim.api.nvim_get_runtime_file(path, false)
if #found > 0 then
- local f, err = package.loadlib(found[1])
+ -- Making function name in Lua 5.1 (see src/loadlib.c:mkfuncname) is
+ -- a) strip prefix up to and including the first dash, if any
+ -- b) replace all dots by underscores
+ -- c) prepend "luaopen_"
+ -- So "foo-bar.baz" should result in "luaopen_bar_baz"
+ local dash = name:find("-", 1, true)
+ local modname = dash and name:sub(dash + 1) or name
+ local f, err = package.loadlib(found[1], "luaopen_"..modname:gsub("%.", "_"))
return f or error(err)
end
end
@@ -527,4 +534,164 @@ function vim._log_keystroke(char)
end
end
+--- Generate a list of possible completions for the string.
+--- String starts with ^ and then has the pattern.
+---
+--- 1. Can we get it to just return things in the global namespace with that name prefix
+--- 2. Can we get it to return things from global namespace even with `print(` in front.
+function vim._expand_pat(pat, env)
+ env = env or _G
+
+ pat = string.sub(pat, 2, #pat)
+
+ if pat == '' then
+ local result = vim.tbl_keys(env)
+ table.sort(result)
+ return result, 0
+ end
+
+ -- TODO: We can handle spaces in [] ONLY.
+ -- We should probably do that at some point, just for cooler completion.
+ -- TODO: We can suggest the variable names to go in []
+ -- This would be difficult as well.
+ -- Probably just need to do a smarter match than just `:match`
+
+ -- Get the last part of the pattern
+ local last_part = pat:match("[%w.:_%[%]'\"]+$")
+ if not last_part then return {}, 0 end
+
+ local parts, search_index = vim._expand_pat_get_parts(last_part)
+
+ local match_part = string.sub(last_part, search_index, #last_part)
+ local prefix_match_pat = string.sub(pat, 1, #pat - #match_part) or ''
+
+ local final_env = env
+
+ for _, part in ipairs(parts) do
+ if type(final_env) ~= 'table' then
+ return {}, 0
+ end
+ local key
+
+ -- Normally, we just have a string
+ -- Just attempt to get the string directly from the environment
+ if type(part) == "string" then
+ key = part
+ else
+ -- However, sometimes you want to use a variable, and complete on it
+ -- With this, you have the power.
+
+ -- MY_VAR = "api"
+ -- vim[MY_VAR]
+ -- -> _G[MY_VAR] -> "api"
+ local result_key = part[1]
+ if not result_key then
+ return {}, 0
+ end
+
+ local result = rawget(env, result_key)
+
+ if result == nil then
+ return {}, 0
+ end
+
+ key = result
+ end
+ local field = rawget(final_env, key)
+ if field == nil then
+ local mt = getmetatable(final_env)
+ if mt and type(mt.__index) == "table" then
+ field = rawget(mt.__index, key)
+ end
+ end
+ final_env = field
+
+ if not final_env then
+ return {}, 0
+ end
+ end
+
+ local keys = {}
+ local function insert_keys(obj)
+ for k,_ in pairs(obj) do
+ if type(k) == "string" and string.sub(k,1,string.len(match_part)) == match_part then
+ table.insert(keys,k)
+ end
+ end
+ end
+
+ if type(final_env) == "table" then
+ insert_keys(final_env)
+ end
+ local mt = getmetatable(final_env)
+ if mt and type(mt.__index) == "table" then
+ insert_keys(mt.__index)
+ end
+
+ table.sort(keys)
+
+ return keys, #prefix_match_pat
+end
+
+vim._expand_pat_get_parts = function(lua_string)
+ local parts = {}
+
+ local accumulator, search_index = '', 1
+ local in_brackets, bracket_end = false, -1
+ local string_char = nil
+ for idx = 1, #lua_string do
+ local s = lua_string:sub(idx, idx)
+
+ if not in_brackets and (s == "." or s == ":") then
+ table.insert(parts, accumulator)
+ accumulator = ''
+
+ search_index = idx + 1
+ elseif s == "[" then
+ in_brackets = true
+
+ table.insert(parts, accumulator)
+ accumulator = ''
+
+ search_index = idx + 1
+ elseif in_brackets then
+ if idx == bracket_end then
+ in_brackets = false
+ search_index = idx + 1
+
+ if string_char == "VAR" then
+ table.insert(parts, { accumulator })
+ accumulator = ''
+
+ string_char = nil
+ end
+ elseif not string_char then
+ bracket_end = string.find(lua_string, ']', idx, true)
+
+ if s == '"' or s == "'" then
+ string_char = s
+ elseif s ~= ' ' then
+ string_char = "VAR"
+ accumulator = s
+ end
+ elseif string_char then
+ if string_char ~= s then
+ accumulator = accumulator .. s
+ else
+ table.insert(parts, accumulator)
+ accumulator = ''
+
+ string_char = nil
+ end
+ end
+ else
+ accumulator = accumulator .. s
+ end
+ end
+
+ parts = vim.tbl_filter(function(val) return #val > 0 end, parts)
+
+ return parts, search_index
+end
+
return module
diff --git a/src/nvim/main.c b/src/nvim/main.c
index 8bf745966e..9f71df3a46 100644
--- a/src/nvim/main.c
+++ b/src/nvim/main.c
@@ -2044,7 +2044,6 @@ static void usage(void)
mch_msg(_(" -u <config> Use this config file\n"));
mch_msg(_(" -v, --version Print version information\n"));
mch_msg(_(" -V[N][file] Verbose [level][file]\n"));
- mch_msg(_(" -Z Restricted mode\n"));
mch_msg("\n");
mch_msg(_(" --api-info Write msgpack-encoded API metadata to stdout\n"));
mch_msg(_(" --embed Use stdin/stdout as a msgpack-rpc channel\n"));
diff --git a/src/nvim/mark.c b/src/nvim/mark.c
index 45ca097033..73a9c1d1d7 100644
--- a/src/nvim/mark.c
+++ b/src/nvim/mark.c
@@ -777,6 +777,7 @@ void ex_delmarks(exarg_T *eap)
n = i - 'A';
}
namedfm[n].fmark.mark.lnum = 0;
+ namedfm[n].fmark.fnum = 0;
XFREE_CLEAR(namedfm[n].fname);
}
}
diff --git a/src/nvim/message.c b/src/nvim/message.c
index f94529c687..ba7a667a60 100644
--- a/src/nvim/message.c
+++ b/src/nvim/message.c
@@ -890,6 +890,40 @@ char_u *msg_may_trunc(int force, char_u *s)
return s;
}
+void clear_hl_msg(HlMessage *hl_msg)
+{
+ for (size_t i = 0; i < kv_size(*hl_msg); i++) {
+ xfree(kv_A(*hl_msg, i).text.data);
+ }
+ kv_destroy(*hl_msg);
+ *hl_msg = (HlMessage)KV_INITIAL_VALUE;
+}
+
+#define LINE_BUFFER_SIZE 4096
+
+void add_hl_msg_hist(HlMessage hl_msg)
+{
+ // TODO(notomo): support multi highlighted message history
+ size_t pos = 0;
+ char buf[LINE_BUFFER_SIZE];
+ for (uint32_t i = 0; i < kv_size(hl_msg); i++) {
+ HlMessageChunk chunk = kv_A(hl_msg, i);
+ for (uint32_t j = 0; j < chunk.text.size; j++) {
+ if (pos == LINE_BUFFER_SIZE - 1) {
+ buf[pos] = NUL;
+ add_msg_hist((const char *)buf, -1, MSG_HIST, true);
+ pos = 0;
+ continue;
+ }
+ buf[pos++] = chunk.text.data[j];
+ }
+ }
+ if (pos != 0) {
+ buf[pos] = NUL;
+ add_msg_hist((const char *)buf, -1, MSG_HIST, true);
+ }
+}
+
/// @param[in] len Length of s or -1.
static void add_msg_hist(const char *s, int len, int attr, bool multiline)
{
diff --git a/src/nvim/message.h b/src/nvim/message.h
index fdb9bc96ca..377c725fa1 100644
--- a/src/nvim/message.h
+++ b/src/nvim/message.h
@@ -8,6 +8,8 @@
#include "nvim/macros.h"
#include "nvim/types.h"
#include "nvim/grid_defs.h"
+#include "nvim/api/private/defs.h"
+#include "nvim/lib/kvec.h"
/*
* Types of dialogs passed to do_dialog().
@@ -75,6 +77,13 @@
/// Like #MSG_PUTS_ATTR, but if middle part of long messages will be replaced
#define MSG_PUTS_LONG_ATTR(s, a) msg_puts_long_attr((char_u *)(s), (a))
+typedef struct {
+ String text;
+ int attr;
+} HlMessageChunk;
+
+typedef kvec_t(HlMessageChunk) HlMessage;
+
/// Message history for `:messages`
typedef struct msg_hist {
struct msg_hist *next; ///< Next message.
diff --git a/src/nvim/normal.c b/src/nvim/normal.c
index 4e955667dc..8f22243348 100644
--- a/src/nvim/normal.c
+++ b/src/nvim/normal.c
@@ -3978,16 +3978,19 @@ static bool nv_screengo(oparg_T *oap, int dir, long dist)
curwin->w_curswant -= width2;
} else {
// to previous line
+
+ // Move to the start of a closed fold. Don't do that when
+ // 'foldopen' contains "all": it will open in a moment.
+ if (!(fdo_flags & FDO_ALL)) {
+ (void)hasFolding(curwin->w_cursor.lnum,
+ &curwin->w_cursor.lnum, NULL);
+ }
if (curwin->w_cursor.lnum == 1) {
retval = false;
break;
}
- --curwin->w_cursor.lnum;
- /* Move to the start of a closed fold. Don't do that when
- * 'foldopen' contains "all": it will open in a moment. */
- if (!(fdo_flags & FDO_ALL))
- (void)hasFolding(curwin->w_cursor.lnum,
- &curwin->w_cursor.lnum, NULL);
+ curwin->w_cursor.lnum--;
+
linelen = linetabsize(get_cursor_line_ptr());
if (linelen > width1) {
int w = (((linelen - width1 - 1) / width2) + 1) * width2;
@@ -6708,11 +6711,8 @@ static void nv_g_cmd(cmdarg_T *cap)
*/
case 'j':
case K_DOWN:
- /* with 'nowrap' it works just like the normal "j" command; also when
- * in a closed fold */
- if (!curwin->w_p_wrap
- || hasFolding(curwin->w_cursor.lnum, NULL, NULL)
- ) {
+ // with 'nowrap' it works just like the normal "j" command.
+ if (!curwin->w_p_wrap) {
oap->motion_type = kMTLineWise;
i = cursor_down(cap->count1, oap->op_type == OP_NOP);
} else
@@ -6723,11 +6723,8 @@ static void nv_g_cmd(cmdarg_T *cap)
case 'k':
case K_UP:
- /* with 'nowrap' it works just like the normal "k" command; also when
- * in a closed fold */
- if (!curwin->w_p_wrap
- || hasFolding(curwin->w_cursor.lnum, NULL, NULL)
- ) {
+ // with 'nowrap' it works just like the normal "k" command.
+ if (!curwin->w_p_wrap) {
oap->motion_type = kMTLineWise;
i = cursor_up(cap->count1, oap->op_type == OP_NOP);
} else
diff --git a/src/nvim/ops.c b/src/nvim/ops.c
index 052b07ed44..87d092281a 100644
--- a/src/nvim/ops.c
+++ b/src/nvim/ops.c
@@ -2623,7 +2623,7 @@ static void op_yank_reg(oparg_T *oap, bool message, yankreg_T *reg, bool append)
}
// NOTREACHED
case kMTUnknown:
- assert(false);
+ abort();
}
}
@@ -6092,7 +6092,7 @@ static void set_clipboard(int name, yankreg_T *reg)
break;
}
case kMTUnknown: {
- assert(false);
+ abort();
}
}
diff --git a/src/nvim/option.c b/src/nvim/option.c
index d43dd9ba15..7cc83399e5 100644
--- a/src/nvim/option.c
+++ b/src/nvim/option.c
@@ -306,7 +306,7 @@ static char *(p_buftype_values[]) = { "nofile", "nowrite", "quickfix",
static char *(p_bufhidden_values[]) = { "hide", "unload", "delete",
"wipe", NULL };
-static char *(p_bs_values[]) = { "indent", "eol", "start", NULL };
+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 };
@@ -1366,6 +1366,10 @@ int do_set(
*(char_u **)varp = vim_strsave(
(char_u *)"indent,eol,start");
break;
+ case 3:
+ *(char_u **)varp = vim_strsave(
+ (char_u *)"indent,eol,nostop");
+ break;
}
xfree(oldval);
if (origval == oldval) {
@@ -1938,6 +1942,7 @@ static void didset_options(void)
(void)opt_strings_flags(p_dy, p_dy_values, &dy_flags, true);
(void)opt_strings_flags(p_rdb, p_rdb_values, &rdb_flags, true);
(void)opt_strings_flags(p_tc, p_tc_values, &tc_flags, false);
+ (void)opt_strings_flags(p_tpf, p_tpf_values, &tpf_flags, true);
(void)opt_strings_flags(p_ve, p_ve_values, &ve_flags, true);
(void)opt_strings_flags(p_wop, p_wop_values, &wop_flags, true);
(void)opt_strings_flags(p_jop, p_jop_values, &jop_flags, true);
@@ -2909,7 +2914,7 @@ ambw_end:
#endif
} else if (varp == &curwin->w_p_scl) {
// 'signcolumn'
- if (check_opt_strings(*varp, p_scl_values, false) != OK) {
+ if (check_signcolumn(*varp) != OK) {
errmsg = e_invarg;
}
// When changing the 'signcolumn' to or from 'number', recompute the
@@ -2939,7 +2944,7 @@ ambw_end:
}
} else if (varp == &p_bs) { // 'backspace'
if (ascii_isdigit(*p_bs)) {
- if (*p_bs >'2' || p_bs[1] != NUL) {
+ if (*p_bs > '3' || p_bs[1] != NUL) {
errmsg = e_invarg;
}
} else if (check_opt_strings(p_bs, p_bs_values, true) != OK) {
@@ -3073,6 +3078,10 @@ ambw_end:
if (!parse_winhl_opt(curwin)) {
errmsg = e_invarg;
}
+ } else if (varp == &p_tpf) {
+ if (opt_strings_flags(p_tpf, p_tpf_values, &tpf_flags, true) != OK) {
+ errmsg = e_invarg;
+ }
} else {
// Options that are a list of flags.
p = NULL;
@@ -3228,6 +3237,34 @@ static int int_cmp(const void *a, const void *b)
return *(const int *)a - *(const int *)b;
}
+/// Handle setting 'signcolumn' for value 'val'
+///
+/// @return OK when the value is valid, FAIL otherwise
+int check_signcolumn(char_u *val)
+{
+ // check for basic match
+ if (check_opt_strings(val, p_scl_values, false) == OK) {
+ return OK;
+ }
+
+ // check for 'auto:<NUMBER>-<NUMBER>'
+ if (STRLEN(val) == 8
+ && !STRNCMP(val, "auto:", 5)
+ && ascii_isdigit(val[5])
+ && val[6] == '-'
+ && ascii_isdigit(val[7])
+ ) {
+ int min = val[5] - '0';
+ int max = val[7] - '0';
+ if (min < 1 || max < 2 || min > 8 || max > 9 || min >= max) {
+ return FAIL;
+ }
+ return OK;
+ }
+
+ return FAIL;
+}
+
/// Handle setting 'colorcolumn' or 'textwidth' in window "wp".
///
/// @return error message, NULL if it's OK.
@@ -6801,15 +6838,15 @@ static int check_opt_wim(void)
}
/// Check if backspacing over something is allowed.
-/// The parameter what is one of the following: whatBS_INDENT, BS_EOL
-/// or BS_START
+/// @param what BS_INDENT, BS_EOL, BS_START, or BS_NOSTOP
bool can_bs(int what)
{
if (what == BS_START && bt_prompt(curbuf)) {
return false;
}
switch (*p_bs) {
- case '2': return true;
+ case '3': return true;
+ case '2': return what != BS_NOSTOP;
case '1': return what != BS_START;
case '0': return false;
}
@@ -7091,7 +7128,7 @@ int csh_like_shell(void)
/// buffer signs and on user configuration.
int win_signcol_count(win_T *wp)
{
- int maximum = 1, needed_signcols;
+ int minimum = 0, maximum = 1, needed_signcols;
const char *scl = (const char *)wp->w_p_scl;
// Note: It checks "no" or "number" in 'signcolumn' option
@@ -7115,9 +7152,14 @@ int win_signcol_count(win_T *wp)
if (!strncmp(scl, "auto:", 5)) {
// Variable depending on a configuration
maximum = scl[5] - '0';
+ // auto:<NUM>-<NUM>
+ if (strlen(scl) == 8 && *(scl + 6) == '-') {
+ minimum = maximum;
+ maximum = scl[7] - '0';
+ }
}
- return MIN(maximum, needed_signcols);
+ return MAX(minimum, MIN(maximum, needed_signcols));
}
/// Get window or buffer local options
diff --git a/src/nvim/option_defs.h b/src/nvim/option_defs.h
index ec2160d365..43b0107800 100644
--- a/src/nvim/option_defs.h
+++ b/src/nvim/option_defs.h
@@ -282,9 +282,14 @@ enum {
#define WIM_BUFLASTUSED 8
// arguments for can_bs()
+// each defined char should be unique over all values
+// except for BS_START, that intentionally also matches BS_NOSTOP
+// because BS_NOSTOP behaves exactly the same except it
+// does not stop at the start of the insert point
#define BS_INDENT 'i' // "Indent"
-#define BS_EOL 'o' // "eOl"
+#define BS_EOL 'l' // "eoL"
#define BS_START 's' // "Start"
+#define BS_NOSTOP 'p' // "nostoP
#define LISPWORD_VALUE \
"defun,define,defmacro,set!,lambda,if,case,let,flet,let*,letrec,do,do*,define-syntax,let-syntax,letrec-syntax,destructuring-bind,defpackage,defparameter,defstruct,deftype,defvar,do-all-symbols,do-external-symbols,do-symbols,dolist,dotimes,ecase,etypecase,eval-when,labels,macrolet,multiple-value-bind,multiple-value-call,multiple-value-prog1,multiple-value-setq,prog1,progv,typecase,unless,unwind-protect,when,with-input-from-string,with-open-file,with-open-stream,with-output-to-string,with-package-iterator,define-condition,handler-bind,handler-case,restart-bind,restart-case,with-simple-restart,store-value,use-value,muffle-warning,abort,continue,with-slots,with-slots*,with-accessors,with-accessors*,defclass,defmethod,print-unreadable-object"
@@ -616,6 +621,19 @@ EXTERN int p_sta; // 'smarttab'
EXTERN int p_sb; // 'splitbelow'
EXTERN long p_tpm; // 'tabpagemax'
EXTERN char_u *p_tal; // 'tabline'
+EXTERN char_u *p_tpf; // 'termpastefilter'
+EXTERN unsigned int tpf_flags; ///< flags from 'termpastefilter'
+#ifdef IN_OPTION_C
+static char *(p_tpf_values[]) =
+ { "BS", "HT", "FF", "ESC", "DEL", "C0", "C1", NULL };
+#endif
+# define TPF_BS 0x001
+# define TPF_HT 0x002
+# define TPF_FF 0x004
+# define TPF_ESC 0x008
+# define TPF_DEL 0x010
+# define TPF_C0 0x020
+# define TPF_C1 0x040
EXTERN char_u *p_sps; // 'spellsuggest'
EXTERN int p_spr; // 'splitright'
EXTERN int p_sol; // 'startofline'
diff --git a/src/nvim/options.lua b/src/nvim/options.lua
index df2bfbce34..fe108ef1cc 100644
--- a/src/nvim/options.lua
+++ b/src/nvim/options.lua
@@ -2821,6 +2821,14 @@ return {
defaults={if_true={vi=false}}
},
{
+ full_name='termpastefilter', abbreviation='tpf',
+ type='string', list='onecomma', scope={'global'},
+ deny_duplicates=true,
+ vim=true,
+ varname='p_tpf',
+ defaults={if_true={vi="", vim="BS,HT,ESC,DEL"}}
+ },
+ {
full_name='terse',
short_desc=N_("hides notification of search wrap"),
type='bool', scope={'global'},
diff --git a/src/nvim/os/env.c b/src/nvim/os/env.c
index 879266e3d4..008f5ef63b 100644
--- a/src/nvim/os/env.c
+++ b/src/nvim/os/env.c
@@ -394,13 +394,21 @@ void os_get_hostname(char *hostname, size_t size)
}
/// To get the "real" home directory:
-/// - get value of $HOME
+/// 1. get value of $HOME
+/// 2. if $HOME is not set, try the following
+/// For Windows:
+/// 1. assemble homedir using HOMEDRIVE and HOMEPATH
+/// 2. try os_homedir()
+/// 3. resolve a direct reference to another system variable
+/// 4. guess C drive
/// For Unix:
-/// - go to that directory
-/// - do os_dirname() to get the real name of that directory.
-/// This also works with mounts and links.
-/// Don't do this for Windows, it will change the "current dir" for a drive.
+/// 1. try os_homedir()
+/// 2. go to that directory
+/// This also works with mounts and links.
+/// Don't do this for Windows, it will change the "current dir" for a drive.
+/// 3. fall back to current working directory as a last resort
static char *homedir = NULL;
+static char *os_homedir(void);
void init_homedir(void)
{
@@ -430,7 +438,7 @@ void init_homedir(void)
}
}
if (var == NULL) {
- var = os_getenv("USERPROFILE");
+ var = os_homedir();
}
// Weird but true: $HOME may contain an indirect reference to another
@@ -440,6 +448,7 @@ void init_homedir(void)
const char *p = strchr(var + 1, '%');
if (p != NULL) {
vim_snprintf(os_buf, (size_t)(p - var), "%s", var + 1);
+ var = NULL;
const char *exp = os_getenv(os_buf);
if (exp != NULL && *exp != NUL
&& STRLEN(exp) + STRLEN(p) < MAXPATHL) {
@@ -458,8 +467,12 @@ void init_homedir(void)
}
#endif
- if (var != NULL) {
#ifdef UNIX
+ if (var == NULL) {
+ var = os_homedir();
+ }
+
+ if (var != NULL) {
// Change to the directory and get the actual path. This resolves
// links. Don't do it when we can't return.
if (os_dirname((char_u *)os_buf, MAXPATHL) == OK && os_chdir(os_buf) == 0) {
@@ -470,11 +483,37 @@ void init_homedir(void)
EMSG(_(e_prev_dir));
}
}
+ }
+
+ // Fall back to current working directory if home is not found
+ if ((var == NULL || *var == NUL)
+ && os_dirname((char_u *)os_buf, sizeof(os_buf)) == OK) {
+ var = os_buf;
+ }
#endif
+ if (var != NULL) {
homedir = xstrdup(var);
}
}
+static char homedir_buf[MAXPATHL];
+
+static char *os_homedir(void)
+{
+ homedir_buf[0] = NUL;
+ size_t homedir_size = MAXPATHL;
+ uv_mutex_lock(&mutex);
+ // http://docs.libuv.org/en/v1.x/misc.html#c.uv_os_homedir
+ int ret_value = uv_os_homedir(homedir_buf, &homedir_size);
+ uv_mutex_unlock(&mutex);
+ if (ret_value == 0 && homedir_size < MAXPATHL) {
+ return homedir_buf;
+ }
+ ELOG("uv_os_homedir() failed %d: %s", ret_value, os_strerror(ret_value));
+ homedir_buf[0] = NUL;
+ return NULL;
+}
+
#if defined(EXITFREE)
void free_homedir(void)
diff --git a/src/nvim/os/pty_process_unix.c b/src/nvim/os/pty_process_unix.c
index 4d7d9a45df..348a139e79 100644
--- a/src/nvim/os/pty_process_unix.c
+++ b/src/nvim/os/pty_process_unix.c
@@ -20,6 +20,10 @@
# include <pty.h>
#endif
+#ifdef __APPLE__
+# include <crt_externs.h>
+#endif
+
#include <uv.h>
#include "nvim/lib/klist.h"
@@ -154,28 +158,14 @@ void pty_process_teardown(Loop *loop)
static void init_child(PtyProcess *ptyproc)
FUNC_ATTR_NONNULL_ALL
{
+#if defined(HAVE__NSGETENVIRON)
+#define environ (*_NSGetEnviron())
+#else
+ extern char **environ;
+#endif
// New session/process-group. #6530
setsid();
- os_unsetenv("COLUMNS");
- os_unsetenv("LINES");
- os_unsetenv("TERMCAP");
- os_unsetenv("COLORFGBG");
- // setting COLORTERM to "truecolor" if termguicolors is set and 256
- // otherwise, but only if it was set in the parent terminal at all
- if (os_env_exists("COLORTERM")) {
- const char *colorterm = os_getenv("COLORTERM");
- if (colorterm != NULL) {
- if (p_tgc) {
- os_setenv("COLORTERM", "truecolor", 1);
- } else {
- os_setenv("COLORTERM", "256", 1);
- }
- } else {
- os_unsetenv("COLORTERM");
- }
- }
-
signal(SIGCHLD, SIG_DFL);
signal(SIGHUP, SIG_DFL);
signal(SIGINT, SIG_DFL);
@@ -190,9 +180,14 @@ static void init_child(PtyProcess *ptyproc)
}
char *prog = ptyproc->process.argv[0];
- os_setenv("TERM", ptyproc->term_name ? ptyproc->term_name : "ansi", 1);
- execvp(prog, ptyproc->process.argv);
+
+ assert(proc->env);
+ tv_dict_add_str(proc->env, S_LEN("TERM"),
+ ptyproc->term_name ? ptyproc->term_name : "ansi");
+ environ = tv_dict_to_env(proc->env);
+ execvp(prog, proc->argv);
ELOG("execvp failed: %s: %s", strerror(errno), prog);
+
_exit(122); // 122 is EXEC_FAILED in the Vim source.
}
diff --git a/src/nvim/os/pty_process_win.c b/src/nvim/os/pty_process_win.c
index 6f7100e846..52d2f84ace 100644
--- a/src/nvim/os/pty_process_win.c
+++ b/src/nvim/os/pty_process_win.c
@@ -52,6 +52,7 @@ int pty_process_spawn(PtyProcess *ptyproc)
uv_connect_t *out_req = NULL;
wchar_t *cmd_line = NULL;
wchar_t *cwd = NULL;
+ wchar_t *env = NULL;
const char *emsg = NULL;
assert(proc->err.closed);
@@ -124,13 +125,22 @@ int pty_process_spawn(PtyProcess *ptyproc)
goto cleanup;
}
+ if (proc->env != NULL) {
+ status = build_env_block(proc->env, &env);
+ }
+
+ if (status != 0) {
+ emsg = "build_env_block failed";
+ goto cleanup;
+ }
+
if (ptyproc->type == kConpty) {
if (!os_conpty_spawn(conpty_object,
&process_handle,
NULL,
cmd_line,
cwd,
- NULL)) {
+ env)) {
emsg = "os_conpty_spawn failed";
status = (int)GetLastError();
goto cleanup;
@@ -141,7 +151,7 @@ int pty_process_spawn(PtyProcess *ptyproc)
NULL, // Optional application name
cmd_line,
cwd,
- NULL, // Optional environment variables
+ env,
&err);
if (spawncfg == NULL) {
emsg = "winpty_spawn_config_new failed";
@@ -213,6 +223,7 @@ cleanup:
xfree(in_req);
xfree(out_req);
xfree(cmd_line);
+ xfree(env);
xfree(cwd);
return status;
}
@@ -454,3 +465,66 @@ int translate_winpty_error(int winpty_errno)
default: return UV_UNKNOWN;
}
}
+
+typedef struct EnvNode {
+ wchar_t *str;
+ size_t len;
+ QUEUE node;
+} EnvNode;
+
+/// Build the environment block to pass to CreateProcessW.
+///
+/// @param[in] denv Dict of environment name/value pairs
+/// @param[out] env Allocated environment block
+///
+/// @returns zero on success or error code of MultiByteToWideChar function.
+static int build_env_block(dict_T *denv, wchar_t **env_block)
+{
+ const size_t denv_size = (size_t)tv_dict_len(denv);
+ size_t env_block_len = 0;
+ int rc;
+ char **env = tv_dict_to_env(denv);
+
+ QUEUE *q;
+ QUEUE env_q;
+ QUEUE_INIT(&env_q);
+ // Convert env vars to wchar_t and calculate how big the final env block
+ // needs to be
+ for (size_t i = 0; i < denv_size; i++) {
+ EnvNode *env_node = xmalloc(sizeof(*env_node));
+ rc = utf8_to_utf16(env[i], -1, &env_node->str);
+ if (rc != 0) {
+ goto cleanup;
+ }
+ env_node->len = wcslen(env_node->str) + 1;
+ env_block_len += env_node->len;
+ QUEUE_INSERT_TAIL(&env_q, &env_node->node);
+ }
+
+ // Additional '\0' after the final entry
+ env_block_len++;
+
+ *env_block = xmalloc(sizeof(**env_block) * env_block_len);
+ wchar_t *pos = *env_block;
+
+ QUEUE_FOREACH(q, &env_q) {
+ EnvNode *env_node = QUEUE_DATA(q, EnvNode, node);
+ memcpy(pos, env_node->str, env_node->len * sizeof(*pos));
+ pos += env_node->len;
+ }
+
+ *pos = L'\0';
+
+cleanup:
+ q = QUEUE_HEAD(&env_q);
+ while (q != &env_q) {
+ QUEUE *next = q->next;
+ EnvNode *env_node = QUEUE_DATA(q, EnvNode, node);
+ XFREE_CLEAR(env_node->str);
+ QUEUE_REMOVE(q);
+ xfree(env_node);
+ q = next;
+ }
+
+ return rc;
+}
diff --git a/src/nvim/os/stdpaths.c b/src/nvim/os/stdpaths.c
index 66bc990402..93b8d5ca12 100644
--- a/src/nvim/os/stdpaths.c
+++ b/src/nvim/os/stdpaths.c
@@ -108,6 +108,17 @@ char *get_xdg_home(const XDGVarType idx)
return dir;
}
+/// Return subpath of $XDG_CACHE_HOME
+///
+/// @param[in] fname New component of the path.
+///
+/// @return [allocated] `$XDG_CACHE_HOME/nvim/{fname}`
+char *stdpaths_user_cache_subpath(const char *fname)
+ FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_RET
+{
+ return concat_fnames_realloc(get_xdg_home(kXDGCacheHome), fname, true);
+}
+
/// Return subpath of $XDG_CONFIG_HOME
///
/// @param[in] fname New component of the path.
diff --git a/src/nvim/os/time.c b/src/nvim/os/time.c
index 4b6533cd0c..5cf628935f 100644
--- a/src/nvim/os/time.c
+++ b/src/nvim/os/time.c
@@ -97,7 +97,7 @@ void os_microdelay(uint64_t us, bool ignoreinput)
const int rv = uv_cond_timedwait(&delay_cond, &delay_mutex, ns_delta);
if (0 != rv && UV_ETIMEDOUT != rv) {
- assert(false);
+ abort();
break;
} // Else: Timeout proceeded normally.
diff --git a/src/nvim/po/af.po b/src/nvim/po/af.po
index fa6674469c..db44f50a46 100644
--- a/src/nvim/po/af.po
+++ b/src/nvim/po/af.po
@@ -3290,10 +3290,6 @@ msgstr "-o[N]\t\tMaak N vensters oop (verstek: een vir elke ler)"
#~ msgid " -V[N][file] Verbose [level][file]\n"
#~ msgstr ""
-#, fuzzy
-#~ msgid " -Z Restricted mode\n"
-#~ msgstr " vir twee modusse "
-
#~ msgid " --api-info Write msgpack-encoded API metadata to stdout\n"
#~ msgstr ""
@@ -7473,9 +7469,6 @@ msgstr "E446: Geen lernaam onder loper"
#~ msgid "-b\t\t\tBinary mode"
#~ msgstr "-b\t\t\tBinre modus"
-#~ msgid "-Z\t\t\tRestricted mode (like \"rvim\")"
-#~ msgstr "-Z\t\t\tBeperkte modus (soos \"rvim\")"
-
#~ msgid "-R\t\t\tReadonly mode (like \"view\")"
#~ msgstr "-R\t\t\tLeesalleen modus (soos \"view\")"
diff --git a/src/nvim/po/ca.po b/src/nvim/po/ca.po
index be4206f36e..6c4d6ddd22 100644
--- a/src/nvim/po/ca.po
+++ b/src/nvim/po/ca.po
@@ -3469,10 +3469,6 @@ msgstr "-y\t\t\tMode senzill (com \"evim\", sense modes)"
msgid "-R\t\t\tReadonly mode (like \"view\")"
msgstr "-R\t\t\tMode noms lectura (com \"view\")"
-#: ../main.c:2208
-msgid "-Z\t\t\tRestricted mode (like \"rvim\")"
-msgstr "-Z\t\t\tMode restringit (com \"rvim)"
-
#: ../main.c:2209
msgid "-m\t\t\tModifications (writing files) not allowed"
msgstr "-m\t\t\tNo permet modificar (escriure) fitxers"
diff --git a/src/nvim/po/cs.cp1250.po b/src/nvim/po/cs.cp1250.po
index 5b9f3d3a58..859039eb87 100644
--- a/src/nvim/po/cs.cp1250.po
+++ b/src/nvim/po/cs.cp1250.po
@@ -3547,10 +3547,6 @@ msgstr "-v\t\t\tSnadn reim (stejn jako \"evim\", dn mdy )"
msgid "-R\t\t\tReadonly mode (like \"view\")"
msgstr "-R\t\t\tReim pouze_pro_ten (jako \"view\")"
-#: ../main.c:2208
-msgid "-Z\t\t\tRestricted mode (like \"rvim\")"
-msgstr "-Z\t\t\tOmezen reim (stejn jako \"rvim\")"
-
#: ../main.c:2209
msgid "-m\t\t\tModifications (writing files) not allowed"
msgstr "-m\t\t\tZmny (ukldn soubor) zakzny"
diff --git a/src/nvim/po/cs.po b/src/nvim/po/cs.po
index 31a90dc514..4d9ad58836 100644
--- a/src/nvim/po/cs.po
+++ b/src/nvim/po/cs.po
@@ -3547,10 +3547,6 @@ msgstr "-v\t\t\tSnadn reim (stejn jako \"evim\", dn mdy )"
msgid "-R\t\t\tReadonly mode (like \"view\")"
msgstr "-R\t\t\tReim pouze_pro_ten (jako \"view\")"
-#: ../main.c:2208
-msgid "-Z\t\t\tRestricted mode (like \"rvim\")"
-msgstr "-Z\t\t\tOmezen reim (stejn jako \"rvim\")"
-
#: ../main.c:2209
msgid "-m\t\t\tModifications (writing files) not allowed"
msgstr "-m\t\t\tZmny (ukldn soubor) zakzny"
diff --git a/src/nvim/po/da.po b/src/nvim/po/da.po
index f35272810b..7a75425019 100644
--- a/src/nvim/po/da.po
+++ b/src/nvim/po/da.po
@@ -3015,9 +3015,6 @@ msgstr "-y\t\t\tEasy-tilstand (ligesom \"evim\", tilstandsløs)"
msgid "-R\t\t\tReadonly mode (like \"view\")"
msgstr "-R\t\t\tSkrivebeskyttet tilstand (ligesom \"view\")"
-msgid "-Z\t\t\tRestricted mode (like \"rvim\")"
-msgstr "-Z\t\t\tRestriktiv tilstand (ligesom \"rvim\")"
-
msgid "-m\t\t\tModifications (writing files) not allowed"
msgstr "-m\t\t\tÆndringer (skrivning af filer) ikke tilladt"
diff --git a/src/nvim/po/de.po b/src/nvim/po/de.po
index a2e04965e5..740e9e5f6a 100644
--- a/src/nvim/po/de.po
+++ b/src/nvim/po/de.po
@@ -2895,10 +2895,6 @@ msgstr "-y\t\t\tLeichter Modus (wie \"evim\", ohne Modi)"
msgid "-R\t\t\tReadonly mode (like \"view\")"
msgstr "-R\t\t\tModus ohne Schreibrechte (wie \"view\")"
-#: ../main.c:2186
-msgid "-Z\t\t\tRestricted mode (like \"rvim\")"
-msgstr "-Z\t\t\tEingeschrnkter Modus (wie \"rvim\")"
-
#: ../main.c:2187
msgid "-m\t\t\tModifications (writing files) not allowed"
msgstr "-m\t\t\tnderungen (beim Schreiben von Dateien) sind nicht erlaubt"
diff --git a/src/nvim/po/en_GB.po b/src/nvim/po/en_GB.po
index 7919fc8946..66cdba6f92 100644
--- a/src/nvim/po/en_GB.po
+++ b/src/nvim/po/en_GB.po
@@ -3368,10 +3368,6 @@ msgstr ""
msgid "-R\t\t\tReadonly mode (like \"view\")"
msgstr ""
-#: ../main.c:2208
-msgid "-Z\t\t\tRestricted mode (like \"rvim\")"
-msgstr ""
-
#: ../main.c:2209
msgid "-m\t\t\tModifications (writing files) not allowed"
msgstr ""
diff --git a/src/nvim/po/eo.po b/src/nvim/po/eo.po
index 99c46c7275..5480e6a4d8 100644
--- a/src/nvim/po/eo.po
+++ b/src/nvim/po/eo.po
@@ -2989,9 +2989,6 @@ msgstr "-y\t\t\tFacila reĝimo (kiel \"evim\", senreĝima)"
msgid "-R\t\t\tReadonly mode (like \"view\")"
msgstr "-R\t\t\tNurlegebla reĝimo (kiel \"view\")"
-msgid "-Z\t\t\tRestricted mode (like \"rvim\")"
-msgstr "-Z\t\t\tLimigita reĝimo (kiel \"rvim\")"
-
msgid "-m\t\t\tModifications (writing files) not allowed"
msgstr "-m\t\t\tŜanĝoj (skribo al dosieroj) nepermeseblaj"
diff --git a/src/nvim/po/es.po b/src/nvim/po/es.po
index eeea27610d..064484d1a4 100644
--- a/src/nvim/po/es.po
+++ b/src/nvim/po/es.po
@@ -3524,10 +3524,6 @@ msgstr "-y\t\t\tModo fácil (como \"evim\", sin modo)"
msgid "-R\t\t\tReadonly mode (like \"view\")"
msgstr "-R\t\t\tModo de solo lectura (como \"view\")"
-#: ../main.c:2208
-msgid "-Z\t\t\tRestricted mode (like \"rvim\")"
-msgstr "-Z\t\t\tModo restringido (como \"rvim\")"
-
#: ../main.c:2209
msgid "-m\t\t\tModifications (writing files) not allowed"
msgstr "-m\t\t\tModificación de archivos desactivada"
diff --git a/src/nvim/po/fi.po b/src/nvim/po/fi.po
index 4489139cfb..5986a57488 100644
--- a/src/nvim/po/fi.po
+++ b/src/nvim/po/fi.po
@@ -3249,10 +3249,6 @@ msgstr ""
#~ msgstr " kahta tilaa varten "
#, fuzzy
-#~ msgid " -Z Restricted mode\n"
-#~ msgstr " kahta tilaa varten "
-
-#, fuzzy
#~ msgid " -m Modifications (writing files) not allowed\n"
#~ msgstr "-m\t\t\tMuokkaukset (kirjoittaminen tiedostoon) pois käytöstä"
@@ -6961,9 +6957,6 @@ msgstr "Lista tai luku tarvitaan"
#~ msgid "-b\t\t\tBinary mode"
#~ msgstr "-b\t\t\tBinääritila"
-#~ msgid "-Z\t\t\tRestricted mode (like \"rvim\")"
-#~ msgstr "-Z\t\t\tRajoitettu tila (kuten rvimillä)"
-
#~ msgid "-R\t\t\tReadonly mode (like \"view\")"
#~ msgstr "-R\t\t\tKirjoitussuojattu tila (kuten view'lla)"
diff --git a/src/nvim/po/fr.po b/src/nvim/po/fr.po
index bb60649c91..5f1ca2fec5 100644
--- a/src/nvim/po/fr.po
+++ b/src/nvim/po/fr.po
@@ -3231,9 +3231,6 @@ msgstr "-y\t\tMode facile (comme \"evim\", vim sans modes)"
msgid "-R\t\t\tReadonly mode (like \"view\")"
msgstr "-R\t\tMode lecture seule (comme \"view\")"
-msgid "-Z\t\t\tRestricted mode (like \"rvim\")"
-msgstr "-Z\t\tMode restreint (comme \"rvim\")"
-
msgid "-m\t\t\tModifications (writing files) not allowed"
msgstr "-m\t\tInterdire l'enregistrement des fichiers"
diff --git a/src/nvim/po/ga.po b/src/nvim/po/ga.po
index 1104b31c32..bad01d592a 100644
--- a/src/nvim/po/ga.po
+++ b/src/nvim/po/ga.po
@@ -3022,9 +3022,6 @@ msgstr "-y\t\t\tMd asca (mar \"evim\", gan mhid)"
msgid "-R\t\t\tReadonly mode (like \"view\")"
msgstr "-R\t\t\tMd inlite amhin (mar \"view\")"
-msgid "-Z\t\t\tRestricted mode (like \"rvim\")"
-msgstr "-Z\t\t\tMd srianta (mar \"rvim\")"
-
msgid "-m\t\t\tModifications (writing files) not allowed"
msgstr "-m\t\t\tN cheadatear athruithe (.i. scrobh na gcomhad)"
diff --git a/src/nvim/po/it.po b/src/nvim/po/it.po
index 511f910b71..dfabc4bee0 100644
--- a/src/nvim/po/it.po
+++ b/src/nvim/po/it.po
@@ -3510,10 +3510,6 @@ msgstr "-y\t\t\tModalit Facile (come \"evim\", senza modalit)"
msgid "-R\t\t\tReadonly mode (like \"view\")"
msgstr "-R\t\t\tModalit Sola Lettura (come \"view\")"
-#: ../main.c:2208
-msgid "-Z\t\t\tRestricted mode (like \"rvim\")"
-msgstr "-Z\t\t\tModalit Ristretta (come \"rvim\")"
-
#: ../main.c:2209
msgid "-m\t\t\tModifications (writing files) not allowed"
msgstr "-m\t\t\tRiscritture del file non permesse"
diff --git a/src/nvim/po/ja.euc-jp.po b/src/nvim/po/ja.euc-jp.po
index 523e9ca4e3..e2cf68f016 100644
--- a/src/nvim/po/ja.euc-jp.po
+++ b/src/nvim/po/ja.euc-jp.po
@@ -3024,9 +3024,6 @@ msgstr "-y\t\t\t⡼ (\"evim\" Ʊ⡼̵)"
msgid "-R\t\t\tReadonly mode (like \"view\")"
msgstr "-R\t\t\tɹѥ⡼ (\"view\" Ʊ)"
-msgid "-Z\t\t\tRestricted mode (like \"rvim\")"
-msgstr "-Z\t\t\t¥⡼ (\"rvim\" Ʊ)"
-
msgid "-m\t\t\tModifications (writing files) not allowed"
msgstr "-m\t\t\tѹ (ե¸) Ǥʤ褦ˤ"
diff --git a/src/nvim/po/ja.po b/src/nvim/po/ja.po
index 5a69d0c5bf..85a45cd171 100644
--- a/src/nvim/po/ja.po
+++ b/src/nvim/po/ja.po
@@ -3024,9 +3024,6 @@ msgstr "-y\t\t\tイージーモード (\"evim\" と同じ、モード無)"
msgid "-R\t\t\tReadonly mode (like \"view\")"
msgstr "-R\t\t\t読込専用モード (\"view\" と同じ)"
-msgid "-Z\t\t\tRestricted mode (like \"rvim\")"
-msgstr "-Z\t\t\t制限モード (\"rvim\" と同じ)"
-
msgid "-m\t\t\tModifications (writing files) not allowed"
msgstr "-m\t\t\t変更 (ファイル保存時) をできないようにする"
diff --git a/src/nvim/po/ko.UTF-8.po b/src/nvim/po/ko.UTF-8.po
index 128b238f8b..b99c22caeb 100644
--- a/src/nvim/po/ko.UTF-8.po
+++ b/src/nvim/po/ko.UTF-8.po
@@ -3438,10 +3438,6 @@ msgstr "-y\t\t\t쉬운 상태 (\"evim\"과 같음, modeless)"
msgid "-R\t\t\tReadonly mode (like \"view\")"
msgstr "-R\t\t\t읽기 전용 상태 (\"view\"와 같음)"
-#: ../main.c:2208
-msgid "-Z\t\t\tRestricted mode (like \"rvim\")"
-msgstr "-Z\t\t\t제한된 상태 (\"rvim\"과 같음)"
-
#: ../main.c:2209
msgid "-m\t\t\tModifications (writing files) not allowed"
msgstr "-m\t\t\t수정(파일 쓰기)이 허용되지 않음"
diff --git a/src/nvim/po/nb.po b/src/nvim/po/nb.po
index 34617ccf18..2285d755cf 100644
--- a/src/nvim/po/nb.po
+++ b/src/nvim/po/nb.po
@@ -3452,10 +3452,6 @@ msgstr "-y\t\t\tLett modus (som \"evim\", uten modus)"
msgid "-R\t\t\tReadonly mode (like \"view\")"
msgstr "-R\t\t\tSkrivebeskyttet modus (som \"view\")"
-#: ../main.c:2208
-msgid "-Z\t\t\tRestricted mode (like \"rvim\")"
-msgstr "-Z\t\t\tBegrenset modus (som \"rvim\")"
-
#: ../main.c:2209
msgid "-m\t\t\tModifications (writing files) not allowed"
msgstr "-m\t\t\tModifisering (lagring av filer) ikke tillatt"
diff --git a/src/nvim/po/nl.po b/src/nvim/po/nl.po
index 30f34508f5..00d113c83c 100644
--- a/src/nvim/po/nl.po
+++ b/src/nvim/po/nl.po
@@ -3449,10 +3449,6 @@ msgstr "-y\t\t\tEenvoudige modus (zoals \"evim\", zonder modus)"
msgid "-R\t\t\tReadonly mode (like \"view\")"
msgstr "-R\t\t\tAlleen-lezen modus (zoals \"view\")"
-#: ../main.c:2208
-msgid "-Z\t\t\tRestricted mode (like \"rvim\")"
-msgstr "-Z\t\t\tBeperkte modus (zoals \"rvim\")"
-
#: ../main.c:2209
msgid "-m\t\t\tModifications (writing files) not allowed"
msgstr "-m\t\t\tAanpassingen (bestanden opslaan) niet toegestaan"
diff --git a/src/nvim/po/no.po b/src/nvim/po/no.po
index 34617ccf18..2285d755cf 100644
--- a/src/nvim/po/no.po
+++ b/src/nvim/po/no.po
@@ -3452,10 +3452,6 @@ msgstr "-y\t\t\tLett modus (som \"evim\", uten modus)"
msgid "-R\t\t\tReadonly mode (like \"view\")"
msgstr "-R\t\t\tSkrivebeskyttet modus (som \"view\")"
-#: ../main.c:2208
-msgid "-Z\t\t\tRestricted mode (like \"rvim\")"
-msgstr "-Z\t\t\tBegrenset modus (som \"rvim\")"
-
#: ../main.c:2209
msgid "-m\t\t\tModifications (writing files) not allowed"
msgstr "-m\t\t\tModifisering (lagring av filer) ikke tillatt"
diff --git a/src/nvim/po/pl.UTF-8.po b/src/nvim/po/pl.UTF-8.po
index f5c452e924..5f1779d1bd 100644
--- a/src/nvim/po/pl.UTF-8.po
+++ b/src/nvim/po/pl.UTF-8.po
@@ -3417,10 +3417,6 @@ msgstr "-y\t\t\tTryb łatwy (jak \"evim\", bez trybów)"
msgid "-R\t\t\tReadonly mode (like \"view\")"
msgstr "-R\t\t\tTryb wyłącznie do odczytu (jak \"view\")"
-#: ../main.c:2208
-msgid "-Z\t\t\tRestricted mode (like \"rvim\")"
-msgstr "-Z\t\t\tTryb ograniczenia (jak \"rvim\")"
-
#: ../main.c:2209
msgid "-m\t\t\tModifications (writing files) not allowed"
msgstr "-m\t\t\tModyfikacje (zapisywanie plików) niedozwolone"
diff --git a/src/nvim/po/pt_BR.po b/src/nvim/po/pt_BR.po
index 4f39cb5bdb..533d916de1 100644
--- a/src/nvim/po/pt_BR.po
+++ b/src/nvim/po/pt_BR.po
@@ -6229,10 +6229,6 @@ msgstr "-y\t\t\tModo fácil (como \"evim\", o Vim não modal)"
msgid "-R\t\t\tReadonly mode (like \"view\")"
msgstr "-R\t\t\tmodo somente-leitura (como \"view\")"
-#: ../main.c:2186
-msgid "-Z\t\t\tRestricted mode (like \"rvim\")"
-msgstr "-Z\t\t\tmodo restrito (como \"rvim\")"
-
#: ../main.c:2187
msgid "-m\t\t\tModifications (writing files) not allowed"
msgstr "-m\t\t\tNo permitir alteraes (gravao de arquivos)"
diff --git a/src/nvim/po/ru.po b/src/nvim/po/ru.po
index 62f892d257..3a96ece2fb 100644
--- a/src/nvim/po/ru.po
+++ b/src/nvim/po/ru.po
@@ -3442,10 +3442,6 @@ msgstr "-y\t\t\tПростой режим (как \"evim\", безрежимны
msgid "-R\t\t\tReadonly mode (like \"view\")"
msgstr "-R\t\t\tТолько для чтения (как \"view\")"
-#: ../main.c:2208
-msgid "-Z\t\t\tRestricted mode (like \"rvim\")"
-msgstr "-Z\t\t\tОграниченный режим (как \"rvim\")"
-
#: ../main.c:2209
msgid "-m\t\t\tModifications (writing files) not allowed"
msgstr "-m\t\t\tБез возможности сохранения изменений (записи файлов)"
diff --git a/src/nvim/po/sk.cp1250.po b/src/nvim/po/sk.cp1250.po
index ced343bf6b..ff95c68a12 100644
--- a/src/nvim/po/sk.cp1250.po
+++ b/src/nvim/po/sk.cp1250.po
@@ -3450,10 +3450,6 @@ msgstr "-y\t\t\tJednoduch md (rovnak ako \"evim\", bezmdov)"
msgid "-R\t\t\tReadonly mode (like \"view\")"
msgstr "-R\t\t\tMd iba pre tanie (ako \"view\")"
-#: ../main.c:2208
-msgid "-Z\t\t\tRestricted mode (like \"rvim\")"
-msgstr "-Z\t\t\tObmedzen md (rovnak ako \"rvim\")"
-
#: ../main.c:2209
msgid "-m\t\t\tModifications (writing files) not allowed"
msgstr "-m\t\t\tZmeny (ukladanie sborov) zakzan"
diff --git a/src/nvim/po/sk.po b/src/nvim/po/sk.po
index 66b3d5abb1..d35622726f 100644
--- a/src/nvim/po/sk.po
+++ b/src/nvim/po/sk.po
@@ -3450,10 +3450,6 @@ msgstr "-y\t\t\tJednoduch md (rovnak ako \"evim\", bezmdov)"
msgid "-R\t\t\tReadonly mode (like \"view\")"
msgstr "-R\t\t\tMd iba pre tanie (ako \"view\")"
-#: ../main.c:2208
-msgid "-Z\t\t\tRestricted mode (like \"rvim\")"
-msgstr "-Z\t\t\tObmedzen md (rovnak ako \"rvim\")"
-
#: ../main.c:2209
msgid "-m\t\t\tModifications (writing files) not allowed"
msgstr "-m\t\t\tZmeny (ukladanie sborov) zakzan"
diff --git a/src/nvim/po/sr.po b/src/nvim/po/sr.po
index 4c157658e5..a93a2ec584 100644
--- a/src/nvim/po/sr.po
+++ b/src/nvim/po/sr.po
@@ -3028,9 +3028,6 @@ msgstr "-y\t\t\tEasy режим (као \"evim\", безрежимни)"
msgid "-R\t\t\tReadonly mode (like \"view\")"
msgstr "-R\t\t\tReadonly режим (као \"view\")"
-msgid "-Z\t\t\tRestricted mode (like \"rvim\")"
-msgstr "-Z\t\t\tRestricted режим (као \"rvim\")"
-
msgid "-m\t\t\tModifications (writing files) not allowed"
msgstr "-m\t\t\tИзмене (уписивање датотека) нису дозвољене"
diff --git a/src/nvim/po/sv.po b/src/nvim/po/sv.po
index db7bada888..d50c9d695d 100644
--- a/src/nvim/po/sv.po
+++ b/src/nvim/po/sv.po
@@ -5735,10 +5735,6 @@ msgstr "-y\t\t\tLtt lge (som \"evim\", lgesls)"
msgid "-R\t\t\tReadonly mode (like \"view\")"
msgstr "-R\t\t\tSkrivskyddat lge (som \"view\")"
-#: ../main.c:2186
-msgid "-Z\t\t\tRestricted mode (like \"rvim\")"
-msgstr "-Z\t\t\tBegrnsat lge (som \"rvim\")"
-
#: ../main.c:2187
msgid "-m\t\t\tModifications (writing files) not allowed"
msgstr "-m\t\t\tModifieringar (skriva filer) inte tilltet"
diff --git a/src/nvim/po/uk.po b/src/nvim/po/uk.po
index 604e425bd0..f0ae154648 100644
--- a/src/nvim/po/uk.po
+++ b/src/nvim/po/uk.po
@@ -14,7 +14,7 @@ msgid ""
msgstr ""
"Project-Id-Version: vim 7.4\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2020-08-23 18:45+0300\n"
+"POT-Creation-Date: 2021-01-18 17:46+0200\n"
"PO-Revision-Date: 2020-08-23 20:19+0300\n"
"Last-Translator: Анатолій Сахнік <sakhnik@gmail.com>\n"
"Language-Team: Ukrainian\n"
@@ -23,6 +23,67 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
+msgid "--Deleted--"
+msgstr "--Знищено--"
+
+#, c-format
+msgid "auto-removing autocommand: %s <buffer=%d>"
+msgstr "Автоматичне знищення автокоманди: %s <буфер=%d>"
+
+#, c-format
+msgid "E367: No such group: \"%s\""
+msgstr "E367: Немає такої групи: «%s»"
+
+msgid "E936: Cannot delete the current group"
+msgstr "E936: Не вдалося знищити цю групу"
+
+msgid "W19: Deleting augroup that is still in use"
+msgstr "W19: Знищення автогрупи, яка все ще використовується"
+
+#, c-format
+msgid "E215: Illegal character after *: %s"
+msgstr "E215: Недозволений символ після *: %s"
+
+#, c-format
+msgid "E216: No such event: %s"
+msgstr "E216: Немає такої події: %s"
+
+#, c-format
+msgid "E216: No such group or event: %s"
+msgstr "E216: Немає такої групи чи події: %s"
+
+msgid ""
+"\n"
+"--- Autocommands ---"
+msgstr ""
+"\n"
+"--- Автокоманди ---"
+
+#, c-format
+msgid "E680: <buffer=%d>: invalid buffer number "
+msgstr "E680: <буфер=%d>: некоректний номер буфера "
+
+msgid "E217: Can't execute autocommands for ALL events"
+msgstr "E217: Не можу виконувати автокоманди для УСІХ подій"
+
+msgid "No matching autocommands"
+msgstr "Немає відповідних автокоманд"
+
+msgid "E218: autocommand nesting too deep"
+msgstr "E218: Забагато вкладених автокоманд"
+
+#, c-format
+msgid "%s Autocommands for \"%s\""
+msgstr "%s Автокоманди для «%s»"
+
+#, c-format
+msgid "Executing %s"
+msgstr "Виконується %s"
+
+#, c-format
+msgid "autocommand %s"
+msgstr "автокоманда %s"
+
msgid "[Location List]"
msgstr "[Список місць]"
@@ -95,9 +156,15 @@ msgid ""
"E89: No write since last change for buffer %<PRId64> (add ! to override)"
msgstr "E89: Буфер %<PRId64> має зміни (! щоб не зважати)"
+msgid "E948: Job still running (add ! to end the job)"
+msgstr "E948: Задача все ще виконується (! щоб закінчити)"
+
msgid "E37: No write since last change (add ! to override)"
msgstr "E37: Зміни не було записано (! щоб не зважати)"
+msgid "E948: Job still running"
+msgstr "E948: Задача все ще виконується"
+
msgid "E37: No write since last change"
msgstr "E37: Не записано після останніх змін"
@@ -465,6 +532,10 @@ msgid "E957: Invalid window number"
msgstr "E957: Некоректний номер вікна"
#, c-format
+msgid "E940: Cannot lock or unlock variable %s"
+msgstr "E940: Неможливо заблокувати чи розблокувати змінну %s"
+
+#, c-format
msgid "E734: Wrong variable type for %s="
msgstr "E734: Неправильний тип змінної для %s="
@@ -544,10 +615,6 @@ msgstr "E690: Пропущено «in» після :for"
msgid "E108: No such variable: \"%s\""
msgstr "E108: Змінної немає: «%s»"
-#, c-format
-msgid "E940: Cannot lock or unlock variable %s"
-msgstr "E940: Неможливо заблокувати чи розблокувати змінну %s"
-
msgid "E109: Missing ':' after '?'"
msgstr "E109: Бракує ':' після '?'"
@@ -950,9 +1017,6 @@ msgstr "E684: Індекс списку поза межами: %<PRId64>"
msgid "E686: Argument of %s must be a List"
msgstr "E686: Аргумент у %s має бути списком"
-msgid "E928: String required"
-msgstr "E928: Потрібен String"
-
#, c-format
msgid "Error converting the call result: %s"
msgstr "Не вдалося перетворити результат виклику: %s"
@@ -1591,6 +1655,10 @@ msgid "Close \"%s\"?"
msgstr "Закрити «%s»?"
#, c-format
+msgid "E947: Job still running in buffer \"%s\""
+msgstr "E947: Задача все ще запущена у буфері «%s»"
+
+#, c-format
msgid "E162: No write since last change for buffer \"%s\""
msgstr "E162: Буфер «%s» має незбережені зміни"
@@ -1615,18 +1683,6 @@ msgid "E666: compiler not supported: %s"
msgstr "E666: Компілятор не підтримується: %s"
#, c-format
-msgid "Searching for \"%s\" in \"%s\""
-msgstr "Пошук «%s» в «%s»"
-
-#, c-format
-msgid "Searching for \"%s\""
-msgstr "Пошук «%s»"
-
-#, c-format
-msgid "not found in '%s': \"%s\""
-msgstr "не знайдено в '%s': «%s»"
-
-#, c-format
msgid ":source error parsing command %s"
msgstr ":source помилка розбору команди %s"
@@ -1702,12 +1758,16 @@ msgstr "Режим Ex. Для повернення до нормального
msgid "E501: At end-of-file"
msgstr "E501: Кінець файлу"
-msgid "E169: Command too recursive"
-msgstr "E169: Команда занадто рекурсивна"
+#, c-format
+msgid "Executing: %s"
+msgstr "Виконується: %s"
msgid "line %"
msgstr "рядок %"
+msgid "E169: Command too recursive"
+msgstr "E169: Команда занадто рекурсивна"
+
#, c-format
msgid "E605: Exception not caught: %s"
msgstr "E605: Виняткова ситуація не оброблена: %s"
@@ -1724,9 +1784,6 @@ msgstr "E464: Неоднозначний вжиток команди корис
msgid "E492: Not an editor command"
msgstr "E492: Це не команда редактора"
-msgid "E981: Command not allowed in restricted mode"
-msgstr "E981: Команду не дозволено у обмеженому режимі"
-
msgid "E493: Backwards range given"
msgstr "E493: Інтервал задано навиворіт"
@@ -1736,6 +1793,11 @@ msgstr "Інтервал задано навиворіт, щоб помінят
msgid "E494: Use w or w>>"
msgstr "E494: Спробуйте w або w>>"
+msgid ""
+"INTERNAL: Cannot use EX_DFLALL with ADDR_NONE, ADDR_UNSIGNED or ADDR_QUICKFIX"
+msgstr ""
+"ВНУТРІШНЄ: Не можна вживати EX_DFLALL з ADDR_NONE, ADDR_UNSIGNED чи ADDR_QUICKFIX"
+
msgid "E943: Command table needs to be updated, run 'make'"
msgstr "E943: Потрібно поновити таблицю команд, запустіть 'make'"
@@ -1762,10 +1824,10 @@ msgstr "E174: Команда вже існує, ! щоб замінити її:
msgid ""
"\n"
-" Name Args Address Complete Definition"
+" Name Args Address Complete Definition"
msgstr ""
"\n"
-" Назва Арг. Адреса Доповнення Визначення"
+" Назва Арг. Адреса Доповнення Визначення"
msgid "No user-defined commands found"
msgstr "Не знайдено команд користувача"
@@ -2077,12 +2139,12 @@ msgstr "E347: У шляху пошуку більше немає файлів «
msgid "E812: Autocommands changed buffer or buffer name"
msgstr "E812: Автокоманди змінили буфер чи його назву"
-msgid "Illegal file name"
-msgstr "Недозволена назва файлу"
-
msgid "is a directory"
msgstr "каталог"
+msgid "Illegal file name"
+msgstr "Недозволена назва файлу"
+
msgid "is not a file"
msgstr "не файл"
@@ -2104,9 +2166,6 @@ msgstr "E201: Автокоманди *ReadPre не повинні змінюва
msgid "E202: Conversion made file unreadable!"
msgstr "E202: Конвертація унеможливила читання файлу!"
-msgid "[fifo/socket]"
-msgstr "[канал/сокет]"
-
msgid "[fifo]"
msgstr "[канал]"
@@ -2353,67 +2412,6 @@ msgstr "E462: Не вдалося підготувати «%s», щоб пере
msgid "E321: Could not reload \"%s\""
msgstr "E321: Не вдалося перечитати «%s»"
-msgid "--Deleted--"
-msgstr "--Знищено--"
-
-#, c-format
-msgid "auto-removing autocommand: %s <buffer=%d>"
-msgstr "Автоматичне знищення автокоманди: %s <буфер=%d>"
-
-#, c-format
-msgid "E367: No such group: \"%s\""
-msgstr "E367: Немає такої групи: «%s»"
-
-msgid "E936: Cannot delete the current group"
-msgstr "E936: Не вдалося знищити цю групу"
-
-msgid "W19: Deleting augroup that is still in use"
-msgstr "W19: Знищення автогрупи, яка все ще використовується"
-
-#, c-format
-msgid "E215: Illegal character after *: %s"
-msgstr "E215: Недозволений символ після *: %s"
-
-#, c-format
-msgid "E216: No such event: %s"
-msgstr "E216: Немає такої події: %s"
-
-#, c-format
-msgid "E216: No such group or event: %s"
-msgstr "E216: Немає такої групи чи події: %s"
-
-msgid ""
-"\n"
-"--- Autocommands ---"
-msgstr ""
-"\n"
-"--- Автокоманди ---"
-
-#, c-format
-msgid "E680: <buffer=%d>: invalid buffer number "
-msgstr "E680: <буфер=%d>: некоректний номер буфера "
-
-msgid "E217: Can't execute autocommands for ALL events"
-msgstr "E217: Не можу виконувати автокоманди для УСІХ подій"
-
-msgid "No matching autocommands"
-msgstr "Немає відповідних автокоманд"
-
-msgid "E218: autocommand nesting too deep"
-msgstr "E218: Забагато вкладених автокоманд"
-
-#, c-format
-msgid "%s Autocommands for \"%s\""
-msgstr "%s Автокоманди для «%s»"
-
-#, c-format
-msgid "Executing %s"
-msgstr "Виконується %s"
-
-#, c-format
-msgid "autocommand %s"
-msgstr "автокоманда %s"
-
msgid "E219: Missing {."
msgstr "E219: Бракує {."
@@ -2519,9 +2517,6 @@ msgstr "E685: Внутрішня помилка: %s"
msgid "Interrupted"
msgstr "Перервано"
-msgid "E14: Invalid address"
-msgstr "E14: Неправильна адреса"
-
msgid "E474: Invalid argument"
msgstr "E474: Некоректний аргумент"
@@ -2719,6 +2714,9 @@ msgstr "E45: Встановлено опцію 'readonly' (! щоб не зва
msgid "E46: Cannot change read-only variable \"%.*s\""
msgstr "E46: Змінна тільки для читання: «%.*s»"
+msgid "E928: String required"
+msgstr "E928: Потрібен String"
+
msgid "E715: Dictionary required"
msgstr "E715: Потрібен словник"
@@ -2727,8 +2725,8 @@ msgid "E118: Too many arguments for function: %s"
msgstr "E118: Забагато аргументів для функції: %s"
#, c-format
-msgid "E716: Key not present in Dictionary: %s"
-msgstr "E716: Немає такого ключа у словнику: %s"
+msgid "E716: Key not present in Dictionary: \"%s\""
+msgstr "E716: Немає такого ключа у словнику: «%s»"
msgid "E714: List required"
msgstr "E714: Потрібен список"
@@ -3158,6 +3156,10 @@ msgid "E5106: Error while creating shared module: %.*s"
msgstr "E5106: Помилка створення розділюваного модуля: %.*s"
#, c-format
+msgid "E5106: Error while creating inspect module: %.*s"
+msgstr "E5106: Помилка створення модуля inspect: %.*s"
+
+#, c-format
msgid "E5106: Error while creating vim module: %.*s"
msgstr "E5106: Помилка створення модуля vim: %.*s"
@@ -3165,10 +3167,6 @@ msgid "E970: Failed to initialize lua interpreter"
msgstr "E970: Не вдалося ініціалізувати інтерпретатор lua"
#, c-format
-msgid "E5117: Error while updating package paths: %.*s"
-msgstr "E5117: Помилка оновлення шляхів пакунку: %.*s"
-
-#, c-format
msgid "E5114: Error while converting print argument #%i: %.*s"
msgstr "E5114: Не вдалося перетворити аргумент #%i друку: %.*s"
@@ -3256,6 +3254,10 @@ msgid "pre-vimrc command line"
msgstr "команди перед vimrc"
#, c-format
+msgid "Conflicting configs: \"%s\" \"%s\""
+msgstr "Суперечливі конфігурації: «%s» «%s»"
+
+#, c-format
msgid "E282: Cannot read from \"%s\""
msgstr "E282: Не вдалося прочитати з «%s»"
@@ -3367,9 +3369,6 @@ msgstr " -v, --version Надрукувати інформацію пр
msgid " -V[N][file] Verbose [level][file]\n"
msgstr " -V[N][файл] Більше повідомлень [рівень][файл]\n"
-msgid " -Z Restricted mode\n"
-msgstr " -Z Обмежений режим\n"
-
msgid " --api-info Write msgpack-encoded API metadata to stdout\n"
msgstr ""
" --api-info Записати метадані API, серіалізовані у msgpack, у "
@@ -4005,8 +4004,7 @@ msgstr ""
"Введіть :qa! і натисність <Enter> щоб відкинути всі зміни і вийти Nvim"
msgid "Type :qa and press <Enter> to exit Nvim"
-msgstr ""
-"Введіть :qa і натисність <Enter> щоб вийти з Nvim"
+msgstr "Введіть :qa і натисність <Enter> щоб вийти з Nvim"
#, c-format
msgid "1 line %sed 1 time"
@@ -4071,10 +4069,10 @@ msgstr "E353: У регістрі %s нічого немає"
msgid ""
"\n"
-"--- Registers ---"
+"Type Name Content"
msgstr ""
"\n"
-"--- Регістри ---"
+"Тип Наз. Вміст "
msgid ""
"E883: search pattern and expression register may not contain two or more "
@@ -4187,9 +4185,6 @@ msgstr "E537: 'commentstring' має бути порожньою чи місти
msgid "E540: Unclosed expression sequence"
msgstr "E540: Послідовність виразів не завершено"
-msgid "E541: too many items"
-msgstr "E541: Забагато елементів"
-
msgid "E542: unbalanced groups"
msgstr "E542: Групи не збалансовано"
@@ -4277,6 +4272,9 @@ msgstr ""
msgid "E5677: Error writing input to shell-command: %s"
msgstr "E5677: Не вдалося записати на вхід команди оболонки: %s"
+msgid "%a %b %d %H:%M:%S %Y"
+msgstr "%H:%M:%S %a, %d %B %Y р."
+
#, c-format
msgid "E447: Can't find file \"%s\" in path"
msgstr "E447: Файл «%s» не знайдено у шляху пошуку"
@@ -4284,8 +4282,11 @@ msgstr "E447: Файл «%s» не знайдено у шляху пошуку"
msgid "E553: No more items"
msgstr "E553: Немає більше елементів"
+msgid "E925: Current quickfix list was changed"
+msgstr "E925: Поточний список quickfix змінився"
+
msgid "E926: Current location list was changed"
-msgstr "E926: Цей список місць було змінено"
+msgstr "E926: Поточний список місць змінився"
#, c-format
msgid "E372: Too many %%%c in format string"
@@ -4319,9 +4320,6 @@ msgstr "E379: Пропущена чи порожня назва каталогу
msgid "E924: Current window was closed"
msgstr "E924: Активне вікно було закрито"
-msgid "E925: Current quickfix was changed"
-msgstr "E925: Цей quickfix було змінено"
-
#, c-format
msgid "(%d of %d)%s%s: "
msgstr "(%d з %d)%s%s: "
@@ -4349,6 +4347,9 @@ msgstr "E683: Пропущено назву файлу чи некоректни
msgid "Cannot open file \"%s\""
msgstr "Не вдалося відкрити файл «%s»"
+msgid "cannot have both a list and a \"what\" argument"
+msgstr "не можна задавати одночасно список і аргумент «що»"
+
msgid "E681: Buffer is not loaded"
msgstr "E681: Буфер не завантажено"
@@ -4469,6 +4470,18 @@ msgstr ""
msgid "Switching to backtracking RE engine for pattern: "
msgstr "Перемикання до простого рушія регулярних виразів: "
+#, c-format
+msgid "Searching for \"%s\" in \"%s\""
+msgstr "Пошук «%s» в «%s»"
+
+#, c-format
+msgid "Searching for \"%s\""
+msgstr "Пошук «%s»"
+
+#, c-format
+msgid "not found in '%s': \"%s\""
+msgstr "не знайдено в '%s': «%s»"
+
msgid " TERMINAL"
msgstr " ТЕРМІНАЛ"
@@ -5252,6 +5265,9 @@ msgstr "синхронізується по коментарях стилю С"
msgid "no syncing"
msgstr "без синхронізації"
+msgid "syncing starts at the first line"
+msgstr "синхронізація починається з першого рядка"
+
msgid "syncing starts "
msgstr "починається синхронізація за "
@@ -5283,6 +5299,9 @@ msgstr ""
msgid "E392: No such syntax cluster: %s"
msgstr "E392: Немає такого синтаксичного кластера: %s"
+msgid "from the first line"
+msgstr "з першого рядка"
+
msgid "minimal "
msgstr "мінімальний "
diff --git a/src/nvim/po/vi.po b/src/nvim/po/vi.po
index a954ea6e34..c693f910d8 100644
--- a/src/nvim/po/vi.po
+++ b/src/nvim/po/vi.po
@@ -3479,10 +3479,6 @@ msgstr "-y\t\t\tChế độ đơn giản (giống \"evim\", không có chế đ
msgid "-R\t\t\tReadonly mode (like \"view\")"
msgstr "-R\t\t\tChế độ chỉ đọc (giống \"view\")"
-#: ../main.c:2208
-msgid "-Z\t\t\tRestricted mode (like \"rvim\")"
-msgstr "-Z\t\t\tChế độ hạn chế (giống \"rvim\")"
-
#: ../main.c:2209
msgid "-m\t\t\tModifications (writing files) not allowed"
msgstr "-m\t\t\tKhông có khả năng ghi nhớ thay đổi (ghi nhớ tập tin)"
diff --git a/src/nvim/po/zh_CN.UTF-8.po b/src/nvim/po/zh_CN.UTF-8.po
index 542157002a..1e329443ce 100644
--- a/src/nvim/po/zh_CN.UTF-8.po
+++ b/src/nvim/po/zh_CN.UTF-8.po
@@ -3427,10 +3427,6 @@ msgstr "-y\t\t\t容易模式 (同 \"evim\",无模式)"
msgid "-R\t\t\tReadonly mode (like \"view\")"
msgstr "-R\t\t\t只读模式 (同 \"view\")"
-#: ../main.c:2208
-msgid "-Z\t\t\tRestricted mode (like \"rvim\")"
-msgstr "-Z\t\t\t限制模式 (同 \"rvim\")"
-
#: ../main.c:2209
msgid "-m\t\t\tModifications (writing files) not allowed"
msgstr "-m\t\t\t不可修改(写入文件)"
diff --git a/src/nvim/po/zh_TW.UTF-8.po b/src/nvim/po/zh_TW.UTF-8.po
index 6a11b5e669..c97f31ddcf 100644
--- a/src/nvim/po/zh_TW.UTF-8.po
+++ b/src/nvim/po/zh_TW.UTF-8.po
@@ -3482,10 +3482,6 @@ msgstr "-y\t\t\t簡易模式 (同 \"evim\", modeless)"
msgid "-R\t\t\tReadonly mode (like \"view\")"
msgstr "-R\t\t\t唯讀模式 (同 \"view\")"
-#: ../main.c:2208
-msgid "-Z\t\t\tRestricted mode (like \"rvim\")"
-msgstr "-Z\t\t\t限制模式 (同 \"rvim\")"
-
#: ../main.c:2209
msgid "-m\t\t\tModifications (writing files) not allowed"
msgstr "-m\t\t\t不可修改 (寫入檔案)"
diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c
index a625c09f78..e074f73d04 100644
--- a/src/nvim/quickfix.c
+++ b/src/nvim/quickfix.c
@@ -5264,7 +5264,7 @@ void ex_vimgrep(exarg_T *eap)
qf_new_list(qi, title);
}
- // parse the list of arguments
+ // Parse the list of arguments, wildcards have already been expanded.
if (get_arglist_exp(p, &fcount, &fnames, true) == FAIL) {
goto theend;
}
@@ -5648,7 +5648,7 @@ static int get_qfline_items(qfline_T *qfp, list_T *list)
== FAIL)) {
// tv_dict_add* fail only if key already exist, but this is a newly
// allocated dictionary which is thus guaranteed to have no existing keys.
- assert(false);
+ abort();
}
return OK;
diff --git a/src/nvim/screen.c b/src/nvim/screen.c
index a7fd2bfcc6..a78f905a70 100644
--- a/src/nvim/screen.c
+++ b/src/nvim/screen.c
@@ -2417,8 +2417,8 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow,
}
}
- if (wp->w_p_list) {
- if (curwin->w_p_lcs_chars.space
+ if (wp->w_p_list && !has_fold) {
+ if (wp->w_p_lcs_chars.space
|| wp->w_p_lcs_chars.trail
|| wp->w_p_lcs_chars.nbsp) {
extra_check = true;
@@ -2665,7 +2665,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow,
}
}
- //sign column
+ // sign column, this is hit until sign_idx reaches count
if (draw_state == WL_SIGN - 1 && n_extra == 0) {
draw_state = WL_SIGN;
/* Show the sign column when there are any signs in this
@@ -2883,8 +2883,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow,
}
if (draw_state == WL_LINE
- && foldinfo.fi_level != 0
- && foldinfo.fi_lines > 0
+ && has_fold
&& vcol == 0
&& n_extra == 0
&& row == startrow) {
@@ -2905,8 +2904,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow,
}
if (draw_state == WL_LINE
- && foldinfo.fi_level != 0
- && foldinfo.fi_lines > 0
+ && has_fold
&& col < grid->Columns
&& n_extra == 0
&& row == startrow) {
@@ -2918,8 +2916,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow,
}
if (draw_state == WL_LINE
- && foldinfo.fi_level != 0
- && foldinfo.fi_lines > 0
+ && has_fold
&& col >= grid->Columns
&& n_extra != 0
&& row == startrow) {
@@ -3087,7 +3084,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow,
|| vcol < fromcol || vcol_prev < fromcol_prev
|| vcol >= tocol)) {
char_attr = line_attr;
- } else {
+ } else {
attr_pri = false;
if (has_syntax) {
char_attr = syntax_attr;
@@ -3742,7 +3739,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow,
}
wp->w_wrow = row;
did_wcol = true;
- curwin->w_valid |= VALID_WCOL|VALID_WROW|VALID_VIRTCOL;
+ wp->w_valid |= VALID_WCOL|VALID_WROW|VALID_VIRTCOL;
}
// Don't override visual selection highlighting.
@@ -3835,9 +3832,9 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow,
// Add a blank character to highlight.
schar_from_ascii(linebuf_char[off], ' ');
}
- if (area_attr == 0) {
- /* Use attributes from match with highest priority among
- * 'search_hl' and the match list. */
+ if (area_attr == 0 && !has_fold) {
+ // Use attributes from match with highest priority among
+ // 'search_hl' and the match list.
char_attr = search_hl.attr;
cur = wp->w_match_head;
shl_flag = FALSE;
@@ -4053,6 +4050,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow,
&& !wp->w_p_wrap
&& filler_todo <= 0
&& (wp->w_p_rl ? col == 0 : col == grid->Columns - 1)
+ && !has_fold
&& (*ptr != NUL
|| lcs_eol_one > 0
|| (n_extra && (c_extra != NUL || *p_extra != NUL)))) {
@@ -4347,6 +4345,10 @@ void screen_adjust_grid(ScreenGrid **grid, int *row_off, int *col_off)
// Get information needed to display the sign in line 'lnum' in window 'wp'.
// If 'nrcol' is TRUE, the sign is going to be displayed in the number column.
// Otherwise the sign is going to be displayed in the sign column.
+//
+// @param count max number of signs
+// @param[out] n_extrap number of characters from pp_extra to display
+// @param[in, out] sign_idxp Index of the displayed sign
static void get_sign_display_info(
bool nrcol,
win_T *wp,
@@ -4423,6 +4425,8 @@ static void get_sign_display_info(
(*sign_idxp)++;
if (*sign_idxp < count) {
*draw_statep = WL_SIGN - 1;
+ } else {
+ *sign_idxp = 0;
}
}
diff --git a/src/nvim/search.c b/src/nvim/search.c
index 787a464070..2802da6f7f 100644
--- a/src/nvim/search.c
+++ b/src/nvim/search.c
@@ -4497,9 +4497,9 @@ find_pattern_in_path(
regmatch_T regmatch;
regmatch_T incl_regmatch;
regmatch_T def_regmatch;
- int matched = FALSE;
- int did_show = FALSE;
- int found = FALSE;
+ bool matched = false;
+ bool did_show = false;
+ bool found = false;
int i;
char_u *already = NULL;
char_u *startp = NULL;
@@ -4611,7 +4611,7 @@ find_pattern_in_path(
}
MSG_PUTS_TITLE(_("in path ---\n"));
}
- did_show = TRUE;
+ did_show = true;
while (depth_displayed < depth && !got_int) {
++depth_displayed;
for (i = 0; i < depth_displayed; i++)
@@ -4761,10 +4761,10 @@ search_line:
matched = !STRNCMP(startp, ptr, len);
if (matched && define_matched && whole
&& vim_iswordc(startp[len]))
- matched = FALSE;
+ matched = false;
} else if (regmatch.regprog != NULL
&& vim_regexec(&regmatch, line, (colnr_T)(p - line))) {
- matched = TRUE;
+ matched = true;
startp = regmatch.startp[0];
// Check if the line is not a comment line (unless we are
// looking for a define). A line starting with "# define"
@@ -4789,15 +4789,16 @@ search_line:
if (matched
&& p[0] == '/'
&& (p[1] == '*' || p[1] == '/')) {
- matched = FALSE;
- /* After "//" all text is comment */
- if (p[1] == '/')
+ matched = false;
+ // After "//" all text is comment
+ if (p[1] == '/') {
break;
- ++p;
+ }
+ p++;
} else if (!matched && p[0] == '*' && p[1] == '/') {
- /* Can find match after "* /". */
- matched = TRUE;
- ++p;
+ // Can find match after "* /".
+ matched = true;
+ p++;
}
}
}
@@ -4811,7 +4812,7 @@ search_line:
if (depth == -1 && lnum == curwin->w_cursor.lnum)
break;
- found = TRUE;
+ found = true;
aux = p = startp;
if (compl_cont_status & CONT_ADDING) {
p += compl_length;
@@ -4879,9 +4880,10 @@ search_line:
break;
}
} else if (action == ACTION_SHOW_ALL) {
- found = TRUE;
- if (!did_show)
- gotocmdline(TRUE); /* cursor at status line */
+ found = true;
+ if (!did_show) {
+ gotocmdline(true); // cursor at status line
+ }
if (curr_fname != prev_fname) {
if (did_show)
msg_putchar('\n'); /* cursor below last one */
@@ -4890,28 +4892,28 @@ search_line:
msg_home_replace_hl(curr_fname);
prev_fname = curr_fname;
}
- did_show = TRUE;
- if (!got_int)
- show_pat_in_path(line, type, TRUE, action,
- (depth == -1) ? NULL : files[depth].fp,
- (depth == -1) ? &lnum : &files[depth].lnum,
- match_count++);
+ did_show = true;
+ if (!got_int) {
+ show_pat_in_path(line, type, true, action,
+ (depth == -1) ? NULL : files[depth].fp,
+ (depth == -1) ? &lnum : &files[depth].lnum,
+ match_count++);
+ }
/* Set matched flag for this file and all the ones that
* include it */
for (i = 0; i <= depth; ++i)
files[i].matched = TRUE;
} else if (--count <= 0) {
- found = TRUE;
+ found = true;
if (depth == -1 && lnum == curwin->w_cursor.lnum
- && l_g_do_tagpreview == 0
- )
+ && l_g_do_tagpreview == 0) {
EMSG(_("E387: Match is on current line"));
- else if (action == ACTION_SHOW) {
+ } else if (action == ACTION_SHOW) {
show_pat_in_path(line, type, did_show, action,
- (depth == -1) ? NULL : files[depth].fp,
- (depth == -1) ? &lnum : &files[depth].lnum, 1L);
- did_show = TRUE;
+ (depth == -1) ? NULL : files[depth].fp,
+ (depth == -1) ? &lnum : &files[depth].lnum, 1L);
+ did_show = true;
} else {
/* ":psearch" uses the preview window */
if (l_g_do_tagpreview != 0) {
@@ -4960,15 +4962,16 @@ search_line:
break;
}
exit_matched:
- matched = FALSE;
- /* look for other matches in the rest of the line if we
- * are not at the end of it already */
+ matched = false;
+ // look for other matches in the rest of the line if we
+ // are not at the end of it already
if (def_regmatch.regprog == NULL
&& action == ACTION_EXPAND
&& !(compl_cont_status & CONT_SOL)
&& *startp != NUL
- && *(p = startp + utfc_ptr2len(startp)) != NUL)
+ && *(p = startp + utfc_ptr2len(startp)) != NUL) {
goto search_line;
+ }
}
line_breakcheck();
if (action == ACTION_EXPAND)
@@ -5046,16 +5049,20 @@ fpip_end:
vim_regfree(def_regmatch.regprog);
}
-static void show_pat_in_path(char_u *line, int type, int did_show, int action, FILE *fp, linenr_T *lnum, long count)
+static void show_pat_in_path(char_u *line, int type, bool did_show, int action,
+ FILE *fp, linenr_T *lnum, long count)
+ FUNC_ATTR_NONNULL_ARG(1, 6)
{
char_u *p;
- if (did_show)
- msg_putchar('\n'); /* cursor below last one */
- else if (!msg_silent)
- gotocmdline(TRUE); /* cursor at status line */
- if (got_int) /* 'q' typed at "--more--" message */
+ if (did_show) {
+ msg_putchar('\n'); // cursor below last one
+ } else if (!msg_silent) {
+ gotocmdline(true); // cursor at status line
+ }
+ if (got_int) { // 'q' typed at "--more--" message
return;
+ }
for (;; ) {
p = line + STRLEN(line) - 1;
if (fp != NULL) {
diff --git a/src/nvim/shada.c b/src/nvim/shada.c
index 2444910bb3..c0e787380f 100644
--- a/src/nvim/shada.c
+++ b/src/nvim/shada.c
@@ -765,7 +765,7 @@ static ShaDaReadResult sd_reader_skip(ShaDaReadDef *const sd_reader,
(uint64_t) offset);
return kSDReadStatusNotShaDa;
}
- assert(false);
+ abort();
}
return kSDReadStatusSuccess;
}
@@ -1224,7 +1224,7 @@ static void shada_read(ShaDaReadDef *const sd_reader, const int flags)
}
case kSDReadStatusFinished: {
// Should be handled by the while condition.
- assert(false);
+ abort();
}
case kSDReadStatusNotShaDa:
case kSDReadStatusReadError: {
@@ -1236,7 +1236,7 @@ static void shada_read(ShaDaReadDef *const sd_reader, const int flags)
}
switch (cur_entry.type) {
case kSDItemMissing: {
- assert(false);
+ abort();
}
case kSDItemUnknown: {
break;
@@ -1628,7 +1628,7 @@ static ShaDaWriteResult shada_pack_entry(msgpack_packer *const packer,
((size_t) (!CHECK_DEFAULT(entry, attr)))
switch (entry.type) {
case kSDItemMissing: {
- assert(false);
+ abort();
}
case kSDItemUnknown: {
if (spacker->callback(spacker->data, entry.data.unknown_item.contents,
@@ -1850,7 +1850,7 @@ static ShaDaWriteResult shada_pack_entry(msgpack_packer *const packer,
break;
}
default: {
- assert(false);
+ abort();
}
}
}
@@ -2147,7 +2147,7 @@ static inline ShaDaWriteResult shada_read_when_writing(
}
case kSDReadStatusFinished: {
// Should be handled by the while condition.
- assert(false);
+ abort();
}
case kSDReadStatusNotShaDa: {
ret = kSDWriteReadNotShada;
@@ -2184,7 +2184,7 @@ static inline ShaDaWriteResult shada_read_when_writing(
}
case kSDItemHeader:
case kSDItemBufferList: {
- assert(false);
+ abort();
}
case kSDItemUnknown: {
ret = shada_pack_entry(packer, entry, 0);
@@ -4044,7 +4044,7 @@ shada_read_next_item_start:
}
case kSDItemMissing:
case kSDItemUnknown: {
- assert(false);
+ abort();
}
}
entry->type = (ShadaEntryType) type_u64;
diff --git a/src/nvim/spell.c b/src/nvim/spell.c
index 5714f5e425..6425c9fed5 100644
--- a/src/nvim/spell.c
+++ b/src/nvim/spell.c
@@ -3123,6 +3123,7 @@ spell_find_suggest (
static bool expr_busy = false;
int c;
langp_T *lp;
+ bool did_intern = false;
// Set the info in "*su".
memset(su, 0, sizeof(suginfo_T));
@@ -3206,14 +3207,16 @@ spell_find_suggest (
spell_suggest_expr(su, buf + 5);
expr_busy = false;
}
- } else if (STRNCMP(buf, "file:", 5) == 0)
+ } else if (STRNCMP(buf, "file:", 5) == 0) {
// Use list of suggestions in a file.
spell_suggest_file(su, buf + 5);
- else {
- // Use internal method.
+ } else if (!did_intern) {
+ // Use internal method once.
spell_suggest_intern(su, interactive);
- if (sps_flags & SPS_DOUBLE)
+ if (sps_flags & SPS_DOUBLE) {
do_combine = true;
+ }
+ did_intern = true;
}
}
diff --git a/src/nvim/spellfile.c b/src/nvim/spellfile.c
index 90af010164..3c125959a9 100644
--- a/src/nvim/spellfile.c
+++ b/src/nvim/spellfile.c
@@ -5387,7 +5387,8 @@ spell_add_word (
len, word, NameBuff);
}
}
- if (fseek(fd, fpos_next, SEEK_SET) <= 0) {
+ if (fseek(fd, fpos_next, SEEK_SET) != 0) {
+ PERROR(_("Seek error in spellfile"));
break;
}
}
diff --git a/src/nvim/tag.c b/src/nvim/tag.c
index c6b1a0d04c..84ca240734 100644
--- a/src/nvim/tag.c
+++ b/src/nvim/tag.c
@@ -1461,7 +1461,7 @@ find_tags(
p_ic = ignorecase_opt(pat, true, true);
break;
default:
- assert(false);
+ abort();
}
help_save = curbuf->b_help;
diff --git a/src/nvim/terminal.c b/src/nvim/terminal.c
index 39e2ca6171..642c443318 100644
--- a/src/nvim/terminal.c
+++ b/src/nvim/terminal.c
@@ -535,8 +535,44 @@ void terminal_send(Terminal *term, char *data, size_t size)
term->opts.write_cb(data, size, term->opts.data);
}
+static bool is_filter_char(int c)
+{
+ unsigned int flag = 0;
+ switch (c) {
+ case 0x08:
+ flag = TPF_BS;
+ break;
+ case 0x09:
+ flag = TPF_HT;
+ break;
+ case 0x0A:
+ case 0x0D:
+ break;
+ case 0x0C:
+ flag = TPF_FF;
+ break;
+ case 0x1b:
+ flag = TPF_ESC;
+ break;
+ case 0x7F:
+ flag = TPF_DEL;
+ break;
+ default:
+ if (c < ' ') {
+ flag = TPF_C0;
+ } else if (c >= 0x80 && c <= 0x9F) {
+ flag = TPF_C1;
+ }
+ }
+ return !!(tpf_flags & flag);
+}
+
void terminal_paste(long count, char_u **y_array, size_t y_size)
{
+ vterm_keyboard_start_paste(curbuf->terminal->vt);
+ terminal_flush_output(curbuf->terminal);
+ size_t buff_len = STRLEN(y_array[0]);
+ char_u *buff = xmalloc(buff_len);
for (int i = 0; i < count; i++) { // -V756
// feed the lines to the terminal
for (size_t j = 0; j < y_size; j++) {
@@ -544,9 +580,28 @@ void terminal_paste(long count, char_u **y_array, size_t y_size)
// terminate the previous line
terminal_send(curbuf->terminal, "\n", 1);
}
- terminal_send(curbuf->terminal, (char *)y_array[j], STRLEN(y_array[j]));
+ size_t len = STRLEN(y_array[j]);
+ if (len > buff_len) {
+ buff = xrealloc(buff, len);
+ buff_len = len;
+ }
+ char_u *dst = buff;
+ char_u *src = y_array[j];
+ while (*src != '\0') {
+ len = (size_t)utf_ptr2len(src);
+ int c = utf_ptr2char(src);
+ if (!is_filter_char(c)) {
+ memcpy(dst, src, len);
+ dst += len;
+ }
+ src += len;
+ }
+ terminal_send(curbuf->terminal, (char *)buff, (size_t)(dst - buff));
}
}
+ xfree(buff);
+ vterm_keyboard_end_paste(curbuf->terminal->vt);
+ terminal_flush_output(curbuf->terminal);
}
void terminal_flush_output(Terminal *term)
diff --git a/src/nvim/testdir/test_autocmd.vim b/src/nvim/testdir/test_autocmd.vim
index 641e98ab30..1f3a45a9ab 100644
--- a/src/nvim/testdir/test_autocmd.vim
+++ b/src/nvim/testdir/test_autocmd.vim
@@ -1110,14 +1110,14 @@ func Test_BufReadCmd()
endfunc
func SetChangeMarks(start, end)
- exe a:start. 'mark ['
- exe a:end. 'mark ]'
+ exe a:start .. 'mark ['
+ exe a:end .. 'mark ]'
endfunc
" Verify the effects of autocmds on '[ and ']
func Test_change_mark_in_autocmds()
edit! Xtest
- call feedkeys("ia\<CR>b\<CR>c\<CR>d\<C-g>u", 'xtn')
+ call feedkeys("ia\<CR>b\<CR>c\<CR>d\<C-g>u\<Esc>", 'xtn')
call SetChangeMarks(2, 3)
write
@@ -1279,26 +1279,9 @@ func Test_TextYankPost()
bwipe!
endfunc
-func Test_nocatch_wipe_all_buffers()
- " Real nasty autocommand: wipe all buffers on any event.
- au * * bwipe *
- call assert_fails('next x', 'E93')
- bwipe
- au!
-endfunc
-
-func Test_nocatch_wipe_dummy_buffer()
- " Nasty autocommand: wipe buffer on any event.
- au * x bwipe
- call assert_fails('lv½ /x', 'E480')
- au!
-endfunc
-
-func Test_wipe_cbuffer()
- sv x
- au * * bw
- lb
- au!
+func Test_autocommand_all_events()
+ call assert_fails('au * * bwipe', 'E1155:')
+ call assert_fails('au * x bwipe', 'E1155:')
endfunc
" Test TextChangedI and TextChangedP
@@ -1956,4 +1939,15 @@ func Test_autocmd_window()
%bw!
endfunc
+func Test_autocmd_closes_window()
+ au BufNew,BufWinLeave * e %e
+ file yyy
+ au BufNew,BufWinLeave * ball
+ call assert_fails('n xxx', 'E143:')
+
+ bwipe %
+ au! BufNew
+ au! BufWinLeave
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_backspace_opt.vim b/src/nvim/testdir/test_backspace_opt.vim
new file mode 100644
index 0000000000..d680b442db
--- /dev/null
+++ b/src/nvim/testdir/test_backspace_opt.vim
@@ -0,0 +1,151 @@
+" Tests for 'backspace' settings
+
+func Exec(expr)
+ let str=''
+ try
+ exec a:expr
+ catch /.*/
+ let str=v:exception
+ endtry
+ return str
+endfunc
+
+func Test_backspace_option()
+ set backspace=
+ call assert_equal('', &backspace)
+ set backspace=indent
+ call assert_equal('indent', &backspace)
+ set backspace=eol
+ call assert_equal('eol', &backspace)
+ set backspace=start
+ call assert_equal('start', &backspace)
+ set backspace=nostop
+ call assert_equal('nostop', &backspace)
+ " Add the value
+ set backspace=
+ set backspace=indent
+ call assert_equal('indent', &backspace)
+ set backspace+=eol
+ call assert_equal('indent,eol', &backspace)
+ set backspace+=start
+ call assert_equal('indent,eol,start', &backspace)
+ set backspace+=nostop
+ call assert_equal('indent,eol,start,nostop', &backspace)
+ " Delete the value
+ set backspace-=nostop
+ call assert_equal('indent,eol,start', &backspace)
+ set backspace-=indent
+ call assert_equal('eol,start', &backspace)
+ set backspace-=start
+ call assert_equal('eol', &backspace)
+ set backspace-=eol
+ call assert_equal('', &backspace)
+ " Check the error
+ call assert_equal(0, match(Exec('set backspace=ABC'), '.*E474'))
+ call assert_equal(0, match(Exec('set backspace+=def'), '.*E474'))
+ " NOTE: Vim doesn't check following error...
+ "call assert_equal(0, match(Exec('set backspace-=ghi'), '.*E474'))
+
+ " Check backwards compatibility with version 5.4 and earlier
+ set backspace=0
+ call assert_equal('0', &backspace)
+ set backspace=1
+ call assert_equal('1', &backspace)
+ set backspace=2
+ call assert_equal('2', &backspace)
+ set backspace=3
+ call assert_equal('3', &backspace)
+ call assert_false(match(Exec('set backspace=4'), '.*E474'))
+ call assert_false(match(Exec('set backspace=10'), '.*E474'))
+
+ " Cleared when 'compatible' is set
+ " set compatible
+ " call assert_equal('', &backspace)
+ set nocompatible viminfo+=nviminfo
+endfunc
+
+" Test with backspace set to the non-compatible setting
+func Test_backspace_ctrl_u()
+ new
+ call append(0, [
+ \ "1 this shouldn't be deleted",
+ \ "2 this shouldn't be deleted",
+ \ "3 this shouldn't be deleted",
+ \ "4 this should be deleted",
+ \ "5 this shouldn't be deleted",
+ \ "6 this shouldn't be deleted",
+ \ "7 this shouldn't be deleted",
+ \ "8 this shouldn't be deleted (not touched yet)"])
+ call cursor(2, 1)
+
+ " set compatible
+ set backspace=2
+
+ exe "normal Avim1\<C-U>\<Esc>\<CR>"
+ exe "normal Avim2\<C-G>u\<C-U>\<Esc>\<CR>"
+
+ set cpo-=<
+ inoremap <c-u> <left><c-u>
+ exe "normal Avim3\<C-U>\<Esc>\<CR>"
+ iunmap <c-u>
+ exe "normal Avim4\<C-U>\<C-U>\<Esc>\<CR>"
+
+ " Test with backspace set to the compatible setting
+ set backspace= visualbell
+ exe "normal A vim5\<Esc>A\<C-U>\<C-U>\<Esc>\<CR>"
+ exe "normal A vim6\<Esc>Azwei\<C-G>u\<C-U>\<Esc>\<CR>"
+
+ inoremap <c-u> <left><c-u>
+ exe "normal A vim7\<C-U>\<C-U>\<Esc>\<CR>"
+
+ call assert_equal([
+ \ "1 this shouldn't be deleted",
+ \ "2 this shouldn't be deleted",
+ \ "3 this shouldn't be deleted",
+ \ "4 this should be deleted3",
+ \ "",
+ \ "6 this shouldn't be deleted vim5",
+ \ "7 this shouldn't be deleted vim6",
+ \ "8 this shouldn't be deleted (not touched yet) vim7",
+ \ ""], getline(1, '$'))
+
+ " Reset values
+ set compatible&vim
+ set visualbell&vim
+ set backspace&vim
+
+ " Test new nostop option
+ %d_
+ let expected = "foo bar foobar"
+ call setline(1, expected)
+ call cursor(1, 8)
+ exe ":norm! ianotherone\<c-u>"
+ call assert_equal(expected, getline(1))
+ call cursor(1, 8)
+ exe ":norm! ianothertwo\<c-w>"
+ call assert_equal(expected, getline(1))
+
+ let content = getline(1)
+ for value in ['indent,nostop', 'eol,nostop', 'indent,eol,nostop', 'indent,eol,start,nostop']
+ exe ":set bs=".. value
+ %d _
+ call setline(1, content)
+ let expected = " foobar"
+ call cursor(1, 8)
+ exe ":norm! ianotherone\<c-u>"
+ call assert_equal(expected, getline(1), 'CTRL-U backspace value: '.. &bs)
+ let expected = "foo foobar"
+ call setline(1, content)
+ call cursor(1, 8)
+ exe ":norm! ianothertwo\<c-w>"
+ call assert_equal(expected, getline(1), 'CTRL-W backspace value: '.. &bs)
+ endfor
+
+ " Reset options
+ set compatible&vim
+ set visualbell&vim
+ set backspace&vim
+ close!
+endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_compiler.vim b/src/nvim/testdir/test_compiler.vim
index 9101f8cfa0..d361205baa 100644
--- a/src/nvim/testdir/test_compiler.vim
+++ b/src/nvim/testdir/test_compiler.vim
@@ -37,17 +37,27 @@ func Test_compiler()
bw!
endfunc
+func GetCompilerNames()
+ " return glob('$VIMRUNTIME/compiler/*.vim', 0, 1)
+ " \ ->map({i, v -> substitute(v, '.*[\\/]\([a-zA-Z0-9_\-]*\).vim', '\1', '')})
+ " \ ->sort()
+ return sort(map(glob('$VIMRUNTIME/compiler/*.vim', 0, 1), {i, v -> substitute(v, '.*[\\/]\([a-zA-Z0-9_\-]*\).vim', '\1', '')}))
+endfunc
+
func Test_compiler_without_arg()
let runtime = substitute($VIMRUNTIME, '\\', '/', 'g')
let a = split(execute('compiler'))
- call assert_match(runtime .. '/compiler/ant.vim$', a[0])
- call assert_match(runtime .. '/compiler/bcc.vim$', a[1])
- call assert_match(runtime .. '/compiler/xo.vim$', a[-1])
+ let exp = GetCompilerNames()
+ call assert_match(runtime .. '/compiler/' .. exp[0] .. '.vim$', a[0])
+ call assert_match(runtime .. '/compiler/' .. exp[1] .. '.vim$', a[1])
+ call assert_match(runtime .. '/compiler/' .. exp[-1] .. '.vim$', a[-1])
endfunc
func Test_compiler_completion()
+ " let clist = GetCompilerNames()->join(' ')
+ let clist = join(GetCompilerNames(), ' ')
call feedkeys(":compiler \<C-A>\<C-B>\"\<CR>", 'tx')
- call assert_match('^"compiler ant bcc .* xmlwf xo$', @:)
+ call assert_match('^"compiler ' .. clist .. '$', @:)
call feedkeys(":compiler p\<C-A>\<C-B>\"\<CR>", 'tx')
call assert_equal('"compiler pbx perl php pylint pyunit', @:)
diff --git a/src/nvim/testdir/test_eval_stuff.vim b/src/nvim/testdir/test_eval_stuff.vim
index 061364fb73..ff50d53d86 100644
--- a/src/nvim/testdir/test_eval_stuff.vim
+++ b/src/nvim/testdir/test_eval_stuff.vim
@@ -22,6 +22,17 @@ func Test_E963()
call assert_equal(v_o, v:oldfiles)
endfunc
+func Test_for_invalid()
+ call assert_fails("for x in 99", 'E714:')
+ call assert_fails("for x in 'asdf'", 'E714:')
+ call assert_fails("for x in {'a': 9}", 'E714:')
+
+ if 0
+ /1/5/2/s/\n
+ endif
+ redraw
+endfunc
+
func Test_mkdir_p()
call mkdir('Xmkdir/nested', 'p')
call assert_true(isdirectory('Xmkdir/nested'))
diff --git a/src/nvim/testdir/test_filetype.vim b/src/nvim/testdir/test_filetype.vim
index 1cb68e7fef..f9f0ade1f6 100644
--- a/src/nvim/testdir/test_filetype.vim
+++ b/src/nvim/testdir/test_filetype.vim
@@ -159,6 +159,7 @@ let s:filename_checks = {
\ 'elinks': ['elinks.conf'],
\ 'elm': ['file.elm'],
\ 'elmfilt': ['filter-rules'],
+ \ 'epuppet': ['file.epp'],
\ 'erlang': ['file.erl', 'file.hrl', 'file.yaws'],
\ 'eruby': ['file.erb', 'file.rhtml'],
\ 'esmtprc': ['anyesmtprc'],
@@ -171,6 +172,7 @@ let s:filename_checks = {
\ 'factor': ['file.factor'],
\ 'falcon': ['file.fal'],
\ 'fan': ['file.fan', 'file.fwt'],
+ \ 'fennel': ['file.fnl'],
\ 'fetchmail': ['.fetchmailrc'],
\ 'fgl': ['file.4gl', 'file.4gh', 'file.m4gl'],
\ 'focexec': ['file.fex', 'file.focexec'],
@@ -332,7 +334,7 @@ let s:filename_checks = {
\ 'pamconf': ['/etc/pam.conf'],
\ 'pamenv': ['/etc/security/pam_env.conf', '/home/user/.pam_environment'],
\ 'papp': ['file.papp', 'file.pxml', 'file.pxsl'],
- \ 'pascal': ['file.pas', 'file.pp', 'file.dpr', 'file.lpr'],
+ \ 'pascal': ['file.pas', 'file.dpr', 'file.lpr'],
\ 'passwd': ['any/etc/passwd', 'any/etc/passwd-', 'any/etc/passwd.edit', 'any/etc/shadow', 'any/etc/shadow-', 'any/etc/shadow.edit', 'any/var/backups/passwd.bak', 'any/var/backups/shadow.bak'],
\ 'pbtxt': ['file.pbtxt'],
\ 'pccts': ['file.g'],
@@ -368,11 +370,13 @@ let s:filename_checks = {
\ 'proto': ['file.proto'],
\ 'protocols': ['/etc/protocols'],
\ 'psf': ['file.psf'],
+ \ 'puppet': ['file.pp'],
\ 'pyrex': ['file.pyx', 'file.pxd'],
\ 'python': ['file.py', 'file.pyw', '.pythonstartup', '.pythonrc', 'file.ptl', 'file.pyi', 'SConstruct'],
\ 'quake': ['anybaseq2/file.cfg', 'anyid1/file.cfg', 'quake3/file.cfg'],
\ 'radiance': ['file.rad', 'file.mat'],
\ 'ratpoison': ['.ratpoisonrc', 'ratpoisonrc'],
+ \ 'rbs': ['file.rbs'],
\ 'rc': ['file.rc', 'file.rch'],
\ 'rcs': ['file,v'],
\ 'readline': ['.inputrc', 'inputrc'],
@@ -389,7 +393,7 @@ let s:filename_checks = {
\ 'rpl': ['file.rpl'],
\ 'rst': ['file.rst'],
\ 'rtf': ['file.rtf'],
- \ 'ruby': ['.irbrc', 'irbrc', 'file.rb', 'file.rbw', 'file.gemspec', 'file.ru', 'Gemfile', 'file.builder', 'file.rxml', 'file.rjs', 'file.rant', 'file.rake'],
+ \ 'ruby': ['.irbrc', 'irbrc', 'file.rb', 'file.rbw', 'file.gemspec', 'file.ru', 'Gemfile', 'file.builder', 'file.rxml', 'file.rjs', 'file.rant', 'file.rake', 'rakefile', 'Rakefile', 'rantfile', 'Rantfile', 'rakefile-file', 'Rakefile-file', 'Puppetfile'],
\ 'rust': ['file.rs'],
\ 'samba': ['smb.conf'],
\ 'sas': ['file.sas'],
@@ -428,6 +432,7 @@ let s:filename_checks = {
\ 'smith': ['file.smt', 'file.smith'],
\ 'sml': ['file.sml'],
\ 'snobol4': ['file.sno', 'file.spt'],
+ \ 'sparql': ['file.rq', 'file.sparql'],
\ 'spec': ['file.spec'],
\ 'spice': ['file.sp', 'file.spice'],
\ 'spup': ['file.speedup', 'file.spdata', 'file.spd'],
@@ -619,6 +624,8 @@ let s:script_checks = {
\ 'cpp': [['// Standard iostream objects -*- C++ -*-'],
\ ['// -*- C++ -*-']],
\ 'yaml': [['%YAML 1.2']],
+ \ 'pascal': [['#!/path/instantfpc']],
+ \ 'fennel': [['#!/path/fennel']],
\ }
" Various forms of "env" optional arguments.
@@ -689,5 +696,50 @@ func Test_ts_file()
filetype off
endfunc
+func Test_ttl_file()
+ filetype on
+
+ call writefile(['@base <http://example.org/> .'], 'Xfile.ttl')
+ split Xfile.ttl
+ call assert_equal('turtle', &filetype)
+ bwipe!
+
+ call writefile(['looks like Tera Term Language'], 'Xfile.ttl')
+ split Xfile.ttl
+ call assert_equal('teraterm', &filetype)
+ bwipe!
+
+ call delete('Xfile.ttl')
+ filetype off
+endfunc
+
+func Test_pp_file()
+ filetype on
+
+ call writefile(['looks like puppet'], 'Xfile.pp')
+ split Xfile.pp
+ call assert_equal('puppet', &filetype)
+ bwipe!
+
+ let g:filetype_pp = 'pascal'
+ split Xfile.pp
+ call assert_equal('pascal', &filetype)
+ bwipe!
+
+ " Test dist#ft#FTpp()
+ call writefile(['{ pascal comment'], 'Xfile.pp')
+ split Xfile.pp
+ call assert_equal('pascal', &filetype)
+ bwipe!
+
+ call writefile(['procedure pascal'], 'Xfile.pp')
+ split Xfile.pp
+ call assert_equal('pascal', &filetype)
+ bwipe!
+
+ call delete('Xfile.pp')
+ filetype off
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_fold.vim b/src/nvim/testdir/test_fold.vim
index 88ce64b9eb..2d058e8e32 100644
--- a/src/nvim/testdir/test_fold.vim
+++ b/src/nvim/testdir/test_fold.vim
@@ -822,4 +822,39 @@ func Test_fold_create_delete()
bwipe!
endfunc
+func Test_fold_relative_move()
+ enew!
+ set fdm=indent sw=2 wrap tw=80
+
+ let content = [ ' foo', ' bar', ' baz',
+ \ repeat('x', &columns + 1),
+ \ ' foo', ' bar', ' baz'
+ \ ]
+ call append(0, content)
+
+ normal zM
+
+ call cursor(3, 1)
+ call assert_true(foldclosed(line('.')))
+ normal gj
+ call assert_equal(2, winline())
+
+ call cursor(2, 1)
+ call assert_true(foldclosed(line('.')))
+ normal 2gj
+ call assert_equal(3, winline())
+
+ call cursor(5, 1)
+ call assert_true(foldclosed(line('.')))
+ normal gk
+ call assert_equal(3, winline())
+
+ call cursor(6, 1)
+ call assert_true(foldclosed(line('.')))
+ normal 2gk
+ call assert_equal(2, winline())
+
+ set fdm& sw& wrap& tw&
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_highlight.vim b/src/nvim/testdir/test_highlight.vim
index 8f6834c2ab..4cc4d775d1 100644
--- a/src/nvim/testdir/test_highlight.vim
+++ b/src/nvim/testdir/test_highlight.vim
@@ -2,6 +2,7 @@
source view_util.vim
source screendump.vim
+source check.vim
func Test_highlight()
" basic test if ":highlight" doesn't crash
@@ -610,3 +611,16 @@ func Test_1_highlight_Normalgroup_exists()
call assert_match('hi Normal\s*font=.*', hlNormal)
endif
endfunc
+
+" Test for using RGB color values in a highlight group
+func Test_xxlast_highlight_RGB_color()
+ CheckCanRunGui
+ gui -f
+ hi MySearch guifg=#110000 guibg=#001100 guisp=#000011
+ call assert_equal('#110000', synIDattr(synIDtrans(hlID('MySearch')), 'fg#'))
+ call assert_equal('#001100', synIDattr(synIDtrans(hlID('MySearch')), 'bg#'))
+ call assert_equal('#000011', synIDattr(synIDtrans(hlID('MySearch')), 'sp#'))
+ hi clear
+endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_marks.vim b/src/nvim/testdir/test_marks.vim
index e25fe33bb7..2fd82a4b6d 100644
--- a/src/nvim/testdir/test_marks.vim
+++ b/src/nvim/testdir/test_marks.vim
@@ -171,6 +171,11 @@ func Test_delmarks()
" Deleting an already deleted mark should not fail.
delmarks x
+ " getpos() should return all zeros after deleting a filemark.
+ norm mA
+ delmarks A
+ call assert_equal([0, 0, 0, 0], getpos("'A"))
+
" Test deleting a range of marks.
norm ma
norm mb
diff --git a/src/nvim/testdir/test_mksession.vim b/src/nvim/testdir/test_mksession.vim
index f71da92bf8..88320e0c22 100644
--- a/src/nvim/testdir/test_mksession.vim
+++ b/src/nvim/testdir/test_mksession.vim
@@ -291,6 +291,32 @@ endfunc
endif
+func Test_mkview_open_folds()
+ enew!
+
+ call append(0, ['a', 'b', 'c'])
+ 1,3fold
+ " zR affects 'foldlevel', make sure the option is applied after the folds
+ " have been recreated.
+ normal zR
+ write! Xtestfile
+
+ call assert_equal(-1, foldclosed(1))
+ call assert_equal(-1, foldclosed(2))
+ call assert_equal(-1, foldclosed(3))
+
+ mkview! Xtestview
+ source Xtestview
+
+ call assert_equal(-1, foldclosed(1))
+ call assert_equal(-1, foldclosed(2))
+ call assert_equal(-1, foldclosed(3))
+
+ call delete('Xtestview')
+ call delete('Xtestfile')
+ %bwipe
+endfunc
+
" Test :mkview with a file argument.
func Test_mkview_file()
" Create a view with line number and a fold.
diff --git a/src/nvim/testdir/test_options.vim b/src/nvim/testdir/test_options.vim
index ccc5e6ffc9..5a10c9baa6 100644
--- a/src/nvim/testdir/test_options.vim
+++ b/src/nvim/testdir/test_options.vim
@@ -266,8 +266,14 @@ func Test_set_errors()
call assert_fails('set foldmarker=x', 'E536:')
call assert_fails('set commentstring=x', 'E537:')
call assert_fails('set complete=x', 'E539:')
+ call assert_fails('set rulerformat=%-', 'E539:')
+ call assert_fails('set rulerformat=%(', 'E542:')
+ call assert_fails('set rulerformat=%15(%%', 'E542:')
+ call assert_fails('set statusline=%$', 'E539:')
call assert_fails('set statusline=%{', 'E540:')
call assert_fails('set statusline=%(', 'E542:')
+ call assert_fails('set statusline=%)', 'E542:')
+
if has('cursorshape')
" This invalid value for 'guicursor' used to cause Vim to crash.
call assert_fails('set guicursor=i-ci,r-cr:h', 'E545:')
@@ -281,6 +287,21 @@ func Test_set_errors()
call assert_fails('set winminwidth=10 winwidth=9', 'E592:')
call assert_fails("set showbreak=\x01", 'E595:')
call assert_fails('set t_foo=', 'E846:')
+ if has('python') || has('python3')
+ call assert_fails('set pyxversion=6', 'E474:')
+ endif
+ call assert_fails("let &tabstop='ab'", 'E521:')
+ call assert_fails('set sessionoptions=curdir,sesdir', 'E474:')
+ call assert_fails('set foldmarker={{{,', 'E474:')
+ call assert_fails('set sessionoptions=sesdir,curdir', 'E474:')
+ call assert_fails('set listchars=trail:· ambiwidth=double', 'E834:')
+ set listchars&
+ call assert_fails('set fillchars=stl:· ambiwidth=double', 'E835:')
+ set fillchars&
+ call assert_fails('set fileencoding=latin1,utf-8', 'E474:')
+ set nomodifiable
+ call assert_fails('set fileencoding=latin1', 'E21:')
+ set modifiable&
endfunc
" Must be executed before other tests that set 'term'.
@@ -309,12 +330,10 @@ func Test_set_ttytype()
set ttytype=xterm
call assert_equal('xterm', &ttytype)
call assert_equal(&ttytype, &term)
- " "set ttytype=" gives E522 instead of E529
- " in travis on some builds. Why? Catch both for now
try
set ttytype=
call assert_report('set ttytype= did not fail')
- catch /E529\|E522/
+ catch /E529/
endtry
" Some systems accept any terminal name and return dumb settings,
diff --git a/src/nvim/testdir/test_quickfix.vim b/src/nvim/testdir/test_quickfix.vim
index 48c0a83053..704fdacdcd 100644
--- a/src/nvim/testdir/test_quickfix.vim
+++ b/src/nvim/testdir/test_quickfix.vim
@@ -2650,6 +2650,13 @@ func Test_vimgrep()
call XvimgrepTests('l')
endfunc
+func Test_vimgrep_wildcards_expanded_once()
+ new X[id-01] file.txt
+ call setline(1, 'some text to search for')
+ vimgrep text %
+ bwipe!
+endfunc
+
" Test for incsearch highlighting of the :vimgrep pattern
" This test used to cause "E315: ml_get: invalid lnum" errors.
func Test_vimgrep_incsearch()
@@ -3540,7 +3547,7 @@ func Test_lbuffer_crash()
sv Xtest
augroup QF_Test
au!
- au * * bw
+ au QuickFixCmdPre,QuickFixCmdPost,BufEnter,BufLeave * bw
augroup END
lbuffer
augroup QF_Test
@@ -3552,7 +3559,7 @@ endfunc
func Test_lexpr_crash()
augroup QF_Test
au!
- au * * call setloclist(0, [], 'f')
+ au QuickFixCmdPre,QuickFixCmdPost,BufEnter,BufLeave * call setloclist(0, [], 'f')
augroup END
lexpr ""
augroup QF_Test
@@ -3587,7 +3594,7 @@ func Test_lvimgrep_crash()
sv Xtest
augroup QF_Test
au!
- au * * call setloclist(0, [], 'f')
+ au QuickFixCmdPre,QuickFixCmdPost,BufEnter,BufLeave * call setloclist(0, [], 'f')
augroup END
lvimgrep quickfix test_quickfix.vim
augroup QF_Test
@@ -3889,7 +3896,7 @@ func Test_lbuffer_with_bwipe()
new
new
augroup nasty
- au * * bwipe
+ au QuickFixCmdPre,QuickFixCmdPost,BufEnter,BufLeave * bwipe
augroup END
lbuffer
augroup nasty
@@ -3902,9 +3909,9 @@ endfunc
func Xexpr_acmd_freelist(cchar)
call s:setup_commands(a:cchar)
- " This was using freed memory.
+ " This was using freed memory (but with what events?)
augroup nasty
- au * * call g:Xsetlist([], 'f')
+ au QuickFixCmdPre,QuickFixCmdPost,BufEnter,BufLeave * call g:Xsetlist([], 'f')
augroup END
Xexpr "x"
augroup nasty
diff --git a/src/nvim/testdir/test_sleep.vim b/src/nvim/testdir/test_sleep.vim
new file mode 100644
index 0000000000..f71855fd4b
--- /dev/null
+++ b/src/nvim/testdir/test_sleep.vim
@@ -0,0 +1,26 @@
+" Test for sleep and sleep! commands
+
+func! s:get_time_ms()
+ let timestr = reltimestr(reltime())
+ let dotidx = stridx(timestr, '.')
+ let sec = str2nr(timestr[:dotidx])
+ let msec = str2nr(timestr[dotidx + 1:])
+ return (sec * 1000) + (msec / 1000)
+endfunc
+
+func! s:assert_takes_longer(cmd, time_ms)
+ let start = s:get_time_ms()
+ execute a:cmd
+ let end = s:get_time_ms()
+ call assert_true(end - start >=# a:time_ms)
+endfun
+
+func! Test_sleep_bang()
+ call s:assert_takes_longer('sleep 50m', 50)
+ call s:assert_takes_longer('sleep! 50m', 50)
+ call s:assert_takes_longer('sl 50m', 50)
+ call s:assert_takes_longer('sl! 50m', 50)
+ call s:assert_takes_longer('1sleep', 1000)
+endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_startup.vim b/src/nvim/testdir/test_startup.vim
index e7f332bc4c..e6ad92f483 100644
--- a/src/nvim/testdir/test_startup.vim
+++ b/src/nvim/testdir/test_startup.vim
@@ -735,4 +735,82 @@ func Test_x_arg()
call delete('Xtest_x_arg')
endfunc
+" Test starting vim with various names: vim, ex, view, evim, etc.
+func Test_progname()
+ CheckUnix
+
+ call mkdir('Xprogname', 'p')
+ call writefile(['silent !date',
+ \ 'call writefile([mode(1), '
+ \ .. '&insertmode, &diff, &readonly, &updatecount, '
+ \ .. 'join(split(execute("message"), "\n")[1:])], "Xprogname_out")',
+ \ 'qall'], 'Xprogname_after')
+
+ " +---------------------------------------------- progname
+ " | +--------------------------------- mode(1)
+ " | | +--------------------------- &insertmode
+ " | | | +---------------------- &diff
+ " | | | | +----------------- &readonly
+ " | | | | | +-------- &updatecount
+ " | | | | | | +--- :messages
+ " | | | | | | |
+ " let expectations = {
+ " \ 'vim': ['n', '0', '0', '0', '200', ''],
+ " \ 'gvim': ['n', '0', '0', '0', '200', ''],
+ " \ 'ex': ['ce', '0', '0', '0', '200', ''],
+ " \ 'exim': ['cv', '0', '0', '0', '200', ''],
+ " \ 'view': ['n', '0', '0', '1', '10000', ''],
+ " \ 'gview': ['n', '0', '0', '1', '10000', ''],
+ " \ 'evim': ['n', '1', '0', '0', '200', ''],
+ " \ 'eview': ['n', '1', '0', '1', '10000', ''],
+ " \ 'rvim': ['n', '0', '0', '0', '200', 'line 1: E145: Shell commands and some functionality not allowed in rvim'],
+ " \ 'rgvim': ['n', '0', '0', '0', '200', 'line 1: E145: Shell commands and some functionality not allowed in rvim'],
+ " \ 'rview': ['n', '0', '0', '1', '10000', 'line 1: E145: Shell commands and some functionality not allowed in rvim'],
+ " \ 'rgview': ['n', '0', '0', '1', '10000', 'line 1: E145: Shell commands and some functionality not allowed in rvim'],
+ " \ 'vimdiff': ['n', '0', '1', '0', '200', ''],
+ " \ 'gvimdiff': ['n', '0', '1', '0', '200', '']}
+ let expectations = {'nvim': ['n', '0', '0', '0', '200', '']}
+
+ " let prognames = ['vim', 'gvim', 'ex', 'exim', 'view', 'gview',
+ " \ 'evim', 'eview', 'rvim', 'rgvim', 'rview', 'rgview',
+ " \ 'vimdiff', 'gvimdiff']
+ let prognames = ['nvim']
+
+ for progname in prognames
+ if empty($DISPLAY)
+ if progname =~# 'g'
+ " Can't run gvim, gview (etc.) if $DISPLAY is not setup.
+ continue
+ endif
+ if has('gui') && (progname ==# 'evim' || progname ==# 'eview')
+ " evim or eview will start the GUI if there is gui support.
+ " So don't try to start them either if $DISPLAY is not setup.
+ continue
+ endif
+ endif
+
+ exe 'silent !ln -s -f ' ..exepath(GetVimProg()) .. ' Xprogname/' .. progname
+
+ let stdout_stderr = ''
+ if progname =~# 'g'
+ let stdout_stderr = system('Xprogname/'..progname..' -f --clean --not-a-term -S Xprogname_after')
+ else
+ exe 'sil !Xprogname/'..progname..' -f --clean -S Xprogname_after'
+ endif
+
+ if progname =~# 'g' && !has('gui')
+ call assert_equal("E25: GUI cannot be used: Not enabled at compile time\n", stdout_stderr, progname)
+ else
+ call assert_equal('', stdout_stderr, progname)
+ call assert_equal(expectations[progname], readfile('Xprogname_out'), progname)
+ endif
+
+ call delete('Xprogname/' .. progname)
+ call delete('Xprogname_out')
+ endfor
+
+ call delete('Xprogname_after')
+ call delete('Xprogname', 'd')
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_window_cmd.vim b/src/nvim/testdir/test_window_cmd.vim
index 687b1cb989..969b75d424 100644
--- a/src/nvim/testdir/test_window_cmd.vim
+++ b/src/nvim/testdir/test_window_cmd.vim
@@ -513,8 +513,8 @@ func Test_window_colon_command()
endfunc
func Test_access_freed_mem()
- " This was accessing freed memory
- au * 0 vs xxx
+ " This was accessing freed memory (but with what events?)
+ au BufEnter,BufLeave,WinEnter,WinLeave 0 vs xxx
arg 0
argadd
all
diff --git a/src/nvim/tui/input.c b/src/nvim/tui/input.c
index 124f96e039..3e683a4926 100644
--- a/src/nvim/tui/input.c
+++ b/src/nvim/tui/input.c
@@ -297,7 +297,7 @@ static void forward_mouse_event(TermInput *input, TermKeyKey *key)
len += (size_t)snprintf(buf + len, sizeof(buf) - len, "Release");
break;
case TERMKEY_MOUSE_UNKNOWN:
- assert(false);
+ abort();
}
len += (size_t)snprintf(buf + len, sizeof(buf) - len, "><%d,%d>", col, row);
diff --git a/src/nvim/ui_compositor.c b/src/nvim/ui_compositor.c
index 9d3ec21949..06efc9fa99 100644
--- a/src/nvim/ui_compositor.c
+++ b/src/nvim/ui_compositor.c
@@ -157,7 +157,7 @@ bool ui_comp_put_grid(ScreenGrid *grid, int row, int col, int height, int width,
#ifndef NDEBUG
for (size_t i = 0; i < kv_size(layers); i++) {
if (kv_A(layers, i) == grid) {
- assert(false);
+ abort();
}
}
#endif
diff --git a/src/nvim/version.c b/src/nvim/version.c
index 834d27cc84..deba3f6e49 100644
--- a/src/nvim/version.c
+++ b/src/nvim/version.c
@@ -300,7 +300,7 @@ static const int included_patches[] = {
1620,
1619,
1618,
- // 1617,
+ 1617,
// 1616,
1615,
1614,
@@ -392,7 +392,7 @@ static const int included_patches[] = {
1528,
1527,
1526,
- // 1525,
+ 1525,
1524,
1523,
1522,
@@ -462,7 +462,7 @@ static const int included_patches[] = {
1458,
1457,
1456,
- // 1455,
+ 1455,
1454,
1453,
1452,
diff --git a/src/nvim/vim.h b/src/nvim/vim.h
index 01f20cf29a..e70749795b 100644
--- a/src/nvim/vim.h
+++ b/src/nvim/vim.h
@@ -159,6 +159,7 @@ enum {
EXPAND_MAPCLEAR,
EXPAND_ARGLIST,
EXPAND_CHECKHEALTH,
+ EXPAND_LUA,
};
diff --git a/src/nvim/viml/parser/expressions.c b/src/nvim/viml/parser/expressions.c
index 44b6ab5f5a..e9d82ca87d 100644
--- a/src/nvim/viml/parser/expressions.c
+++ b/src/nvim/viml/parser/expressions.c
@@ -2078,7 +2078,7 @@ viml_pexpr_parse_process_token:
case kExprLexMissing:
case kExprLexSpacing:
case kExprLexEOC: {
- assert(false);
+ abort();
}
case kExprLexInvalid: {
ERROR_FROM_TOKEN(cur_token);
@@ -3028,7 +3028,7 @@ viml_pexpr_parse_end:
// Until trailing "}" it is impossible to distinguish curly braces
// identifier and dictionary, so it must not appear in the stack like
// this.
- assert(false);
+ abort();
}
case kExprNodeInteger:
case kExprNodeFloat:
@@ -3042,7 +3042,7 @@ viml_pexpr_parse_end:
// These are plain values and not containers, for them it should only
// be possible to show up in the topmost stack element, but it was
// unconditionally popped at the start.
- assert(false);
+ abort();
}
case kExprNodeComma:
case kExprNodeColon:
diff --git a/test/functional/api/extmark_spec.lua b/test/functional/api/extmark_spec.lua
index ab913ba4a4..d2b555ee5b 100644
--- a/test/functional/api/extmark_spec.lua
+++ b/test/functional/api/extmark_spec.lua
@@ -1389,6 +1389,40 @@ describe('API/extmarks', function()
undo]],false)
eq(2, meths.eval('1+1')) -- did not crash
end)
+
+ it('works with left and right gravity', function()
+ -- right gravity should move with inserted text, while
+ -- left gravity should stay in place.
+ curbufmeths.set_extmark(ns, 0, 5, {right_gravity = false})
+ curbufmeths.set_extmark(ns, 0, 5, {right_gravity = true})
+ feed([[Aasdfasdf]])
+
+ eq({ {1, 0, 5}, {2, 0, 13} },
+ curbufmeths.get_extmarks(ns, 0, -1, {}))
+
+ -- but both move when text is inserted before
+ feed([[<esc>Iasdf<esc>]])
+ -- eq({}, curbufmeths.get_lines(0, -1, true))
+ eq({ {1, 0, 9}, {2, 0, 17} },
+ curbufmeths.get_extmarks(ns, 0, -1, {}))
+
+ -- clear text
+ curbufmeths.set_text(0, 0, 0, 17, {})
+
+ -- handles set_text correctly as well
+ eq({ {1, 0, 0}, {2, 0, 0} },
+ meths.buf_get_extmarks(0, ns, 0, -1, {}))
+ curbufmeths.set_text(0, 0, 0, 0, {'asdfasdf'})
+ eq({ {1, 0, 0}, {2, 0, 8} },
+ curbufmeths.get_extmarks(ns, 0, -1, {}))
+
+ feed('u')
+ -- handles pasting
+ meths.exec([[let @a='asdfasdf']], false)
+ feed([["ap]])
+ eq({ {1, 0, 0}, {2, 0, 8} },
+ meths.buf_get_extmarks(0, ns, 0, -1, {}))
+ end)
end)
describe('Extmarks buffer api with many marks', function()
diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua
index 30128e9c40..3ff3efb8c9 100644
--- a/test/functional/api/vim_spec.lua
+++ b/test/functional/api/vim_spec.lua
@@ -2002,4 +2002,77 @@ describe('API', function()
}, meths.get_option_info'showcmd')
end)
end)
+
+ describe('nvim_echo', function()
+ local screen
+
+ before_each(function()
+ clear()
+ screen = Screen.new(40, 8)
+ screen:attach()
+ screen:set_default_attr_ids({
+ [0] = {bold=true, foreground=Screen.colors.Blue},
+ [1] = {bold = true, foreground = Screen.colors.SeaGreen},
+ [2] = {bold = true, reverse = true},
+ [3] = {foreground = Screen.colors.Brown, bold = true}, -- Statement
+ [4] = {foreground = Screen.colors.SlateBlue}, -- Special
+ })
+ command('highlight Statement gui=bold guifg=Brown')
+ command('highlight Special guifg=SlateBlue')
+ end)
+
+ it('should clear cmdline message before echo', function()
+ feed(':call nvim_echo([["msg"]], v:false, {})<CR>')
+ screen:expect{grid=[[
+ ^ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ msg |
+ ]]}
+ end)
+
+ it('can show highlighted line', function()
+ nvim_async("echo", {{"msg_a"}, {"msg_b", "Statement"}, {"msg_c", "Special"}}, true, {})
+ screen:expect{grid=[[
+ ^ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ msg_a{3:msg_b}{4:msg_c} |
+ ]]}
+ end)
+
+ it('can show highlighted multiline', function()
+ nvim_async("echo", {{"msg_a\nmsg_a", "Statement"}, {"msg_b", "Special"}}, true, {})
+ screen:expect{grid=[[
+ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {2: }|
+ {3:msg_a} |
+ {3:msg_a}{4:msg_b} |
+ {1:Press ENTER or type command to continue}^ |
+ ]]}
+ end)
+
+ it('can save message history', function()
+ nvim('command', 'set cmdheight=2') -- suppress Press ENTER
+ nvim("echo", {{"msg\nmsg"}, {"msg"}}, true, {})
+ eq("msg\nmsgmsg", meths.exec('messages', true))
+ end)
+
+ it('can disable saving message history', function()
+ nvim('command', 'set cmdheight=2') -- suppress Press ENTER
+ nvim_async("echo", {{"msg\nmsg"}, {"msg"}}, false, {})
+ eq("", meths.exec("messages", true))
+ end)
+ end)
end)
diff --git a/test/functional/core/job_spec.lua b/test/functional/core/job_spec.lua
index 6d1182478a..b59d87eb12 100644
--- a/test/functional/core/job_spec.lua
+++ b/test/functional/core/job_spec.lua
@@ -31,9 +31,9 @@ describe('jobs', function()
nvim('set_var', 'channel', channel)
source([[
function! Normalize(data) abort
- " Windows: remove ^M
+ " Windows: remove ^M and term escape sequences
return type([]) == type(a:data)
- \ ? map(a:data, 'substitute(v:val, "\r", "", "g")')
+ \ ? map(a:data, 'substitute(substitute(v:val, "\r", "", "g"), "\x1b\\%(\\]\\d\\+;.\\{-}\x07\\|\\[.\\{-}[\x40-\x7E]\\)", "", "g")')
\ : a:data
endfunction
function! OnEvent(id, data, event) dict
@@ -63,6 +63,7 @@ describe('jobs', function()
it('append environment #env', function()
nvim('command', "let $VAR = 'abc'")
+ nvim('command', "let $TOTO = 'goodbye world'")
nvim('command', "let g:job_opts.env = {'TOTO': 'hello world'}")
if iswin() then
nvim('command', [[call jobstart('echo %TOTO% %VAR%', g:job_opts)]])
@@ -75,8 +76,24 @@ describe('jobs', function()
})
end)
+ it('append environment with pty #env', function()
+ nvim('command', "let $VAR = 'abc'")
+ nvim('command', "let $TOTO = 'goodbye world'")
+ nvim('command', "let g:job_opts.pty = v:true")
+ nvim('command', "let g:job_opts.env = {'TOTO': 'hello world'}")
+ if iswin() then
+ nvim('command', [[call jobstart('echo %TOTO% %VAR%', g:job_opts)]])
+ else
+ nvim('command', [[call jobstart('echo $TOTO $VAR', g:job_opts)]])
+ end
+ expect_msg_seq({
+ {'notification', 'stdout', {0, {'hello world abc', ''}}},
+ })
+ end)
+
it('replace environment #env', function()
nvim('command', "let $VAR = 'abc'")
+ nvim('command', "let $TOTO = 'goodbye world'")
nvim('command', "let g:job_opts.env = {'TOTO': 'hello world'}")
nvim('command', "let g:job_opts.clear_env = 1")
diff --git a/test/functional/eval/environ_spec.lua b/test/functional/eval/environ_spec.lua
index 54d2dc960b..9e19568249 100644
--- a/test/functional/eval/environ_spec.lua
+++ b/test/functional/eval/environ_spec.lua
@@ -3,6 +3,11 @@ local clear = helpers.clear
local eq = helpers.eq
local environ = helpers.funcs.environ
local exists = helpers.funcs.exists
+local system = helpers.funcs.system
+local nvim_prog = helpers.nvim_prog
+local command = helpers.command
+local eval = helpers.eval
+local setenv = helpers.funcs.setenv
describe('environment variables', function()
it('environ() handles empty env variable', function()
@@ -17,3 +22,59 @@ describe('environment variables', function()
eq(0, exists('$DOES_NOT_EXIST'))
end)
end)
+
+describe('empty $HOME', function()
+ local original_home = os.getenv('HOME')
+
+ -- recover $HOME after each test
+ after_each(function()
+ if original_home ~= nil then
+ setenv('HOME', original_home)
+ end
+ os.remove('test_empty_home')
+ os.remove('./~')
+ end)
+
+ local function tilde_in_cwd()
+ -- get files in cwd
+ command("let test_empty_home_cwd_files = split(globpath('.', '*'), '\n')")
+ -- get the index of the file named '~'
+ command('let test_empty_home_tilde_index = index(test_empty_home_cwd_files, "./~")')
+ return eval('test_empty_home_tilde_index') ~= -1
+ end
+
+ local function write_and_test_tilde()
+ system({nvim_prog, '-u', 'NONE', '-i', 'NONE', '--headless',
+ '-c', 'write test_empty_home', '+q'})
+ eq(false, tilde_in_cwd())
+ end
+
+ it("'~' folder not created in cwd if $HOME and related env not defined", function()
+ command("unlet $HOME")
+ write_and_test_tilde()
+
+ command("let $HOMEDRIVE='C:'")
+ command("let $USERPROFILE='C:\\'")
+ write_and_test_tilde()
+
+ command("unlet $HOMEDRIVE")
+ write_and_test_tilde()
+
+ command("unlet $USERPROFILE")
+ write_and_test_tilde()
+
+ command("let $HOME='%USERPROFILE%'")
+ command("let $USERPROFILE='C:\\'")
+ write_and_test_tilde()
+ end)
+
+ it("'~' folder not created in cwd if writing a file with invalid $HOME", function()
+ setenv('HOME', '/path/does/not/exist')
+ write_and_test_tilde()
+ end)
+
+ it("'~' folder not created in cwd if writing a file with $HOME=''", function()
+ command("let $HOME=''")
+ write_and_test_tilde()
+ end)
+end)
diff --git a/test/functional/legacy/backspace_opt_spec.lua b/test/functional/legacy/backspace_opt_spec.lua
deleted file mode 100644
index 90bc6f74f0..0000000000
--- a/test/functional/legacy/backspace_opt_spec.lua
+++ /dev/null
@@ -1,67 +0,0 @@
-local helpers = require('test.functional.helpers')(after_each)
-local call, clear = helpers.call, helpers.clear
-local source, eq, nvim = helpers.source, helpers.eq, helpers.meths
-
-describe("test 'backspace' settings", function()
- before_each(function()
- clear()
-
- source([[
- func Exec(expr)
- let str=''
- try
- exec a:expr
- catch /.*/
- let str=v:exception
- endtry
- return str
- endfunc
-
- func Test_backspace_option()
- set backspace=
- call assert_equal('', &backspace)
- set backspace=indent
- call assert_equal('indent', &backspace)
- set backspace=eol
- call assert_equal('eol', &backspace)
- set backspace=start
- call assert_equal('start', &backspace)
- " Add the value
- set backspace=
- set backspace=indent
- call assert_equal('indent', &backspace)
- set backspace+=eol
- call assert_equal('indent,eol', &backspace)
- set backspace+=start
- call assert_equal('indent,eol,start', &backspace)
- " Delete the value
- set backspace-=indent
- call assert_equal('eol,start', &backspace)
- set backspace-=start
- call assert_equal('eol', &backspace)
- set backspace-=eol
- call assert_equal('', &backspace)
- " Check the error
- call assert_equal(0, match(Exec('set backspace=ABC'), '.*E474'))
- call assert_equal(0, match(Exec('set backspace+=def'), '.*E474'))
- " NOTE: Vim doesn't check following error...
- "call assert_equal(0, match(Exec('set backspace-=ghi'), '.*E474'))
-
- " Check backwards compatibility with version 5.4 and earlier
- set backspace=0
- call assert_equal('0', &backspace)
- set backspace=1
- call assert_equal('1', &backspace)
- set backspace=2
- call assert_equal('2', &backspace)
- call assert_false(match(Exec('set backspace=3'), '.*E474'))
- call assert_false(match(Exec('set backspace=10'), '.*E474'))
- endfunc
- ]])
- end)
-
- it('works', function()
- call('Test_backspace_option')
- eq({}, nvim.get_vvar('errors'))
- end)
-end)
diff --git a/test/functional/lua/buffer_updates_spec.lua b/test/functional/lua/buffer_updates_spec.lua
index 67dc5f5a16..6087f9e7d6 100644
--- a/test/functional/lua/buffer_updates_spec.lua
+++ b/test/functional/lua/buffer_updates_spec.lua
@@ -20,12 +20,13 @@ local origlines = {"original line 1",
"original line 6",
" indented line"}
-local function attach_buffer(evname)
- exec_lua([[
+before_each(function ()
+ clear()
+ exec_lua [[
local evname = ...
local events = {}
- function test_register(bufnr, id, changedtick, utf_sizes, preview)
+ function test_register(bufnr, evname, id, changedtick, utf_sizes, preview)
local function callback(...)
table.insert(events, {id, ...})
if test_unreg == id then
@@ -44,41 +45,30 @@ local function attach_buffer(evname)
events = {}
return ret_events
end
- ]], evname)
-end
+ ]]
+end)
describe('lua buffer event callbacks: on_lines', function()
- before_each(function()
- clear()
- attach_buffer('on_lines')
- end)
-
-
- -- verifying the sizes with nvim_buf_get_offset is nice (checks we cannot
- -- assert the wrong thing), but masks errors with unflushed lines (as
- -- nvim_buf_get_offset forces a flush of the memline). To be safe run the
- -- test both ways.
- local function check(verify,utf_sizes)
+ local function setup_eventcheck(verify, utf_sizes, lines)
local lastsize
- meths.buf_set_lines(0, 0, -1, true, origlines)
+ meths.buf_set_lines(0, 0, -1, true, lines)
if verify then
lastsize = meths.buf_get_offset(0, meths.buf_line_count(0))
end
- exec_lua("return test_register(...)", 0, "test1",false,utf_sizes)
- local tick = meths.buf_get_changedtick(0)
-
+ exec_lua("return test_register(...)", 0, "on_lines", "test1",false,utf_sizes)
local verify_name = "test1"
+
local function check_events(expected)
local events = exec_lua("return get_events(...)" )
if utf_sizes then
-- this test case uses ASCII only, so sizes should be the same.
-- Unicode is tested below.
for _, event in ipairs(expected) do
- event[9] = event[8]
- event[10] = event[8]
+ event[9] = event[9] or event[8]
+ event[10] = event[10] or event[9]
end
end
- eq(expected, events)
+ expect_events(expected, events, "line updates")
if verify then
for _, event in ipairs(events) do
if event[1] == verify_name and event[2] == "lines" then
@@ -92,25 +82,38 @@ describe('lua buffer event callbacks: on_lines', function()
end
end
end
+ return check_events, function(new) verify_name = new end
+ end
+
+ -- verifying the sizes with nvim_buf_get_offset is nice (checks we cannot
+ -- assert the wrong thing), but masks errors with unflushed lines (as
+ -- nvim_buf_get_offset forces a flush of the memline). To be safe run the
+ -- test both ways.
+ local function check(verify,utf_sizes)
+ local check_events, verify_name = setup_eventcheck(verify, utf_sizes, origlines)
+
+ local tick = meths.buf_get_changedtick(0)
command('set autoindent')
command('normal! GyyggP')
tick = tick + 1
- check_events({{ "test1", "lines", 1, tick, 0, 0, 1, 0}})
+ check_events {{ "test1", "lines", 1, tick, 0, 0, 1, 0}}
meths.buf_set_lines(0, 3, 5, true, {"changed line"})
tick = tick + 1
- check_events({{ "test1", "lines", 1, tick, 3, 5, 4, 32 }})
+ check_events {{ "test1", "lines", 1, tick, 3, 5, 4, 32 }}
- exec_lua("return test_register(...)", 0, "test2", true, utf_sizes)
+ exec_lua("return test_register(...)", 0, "on_lines", "test2", true, utf_sizes)
tick = tick + 1
command('undo')
-- plugins can opt in to receive changedtick events, or choose
-- to only receive actual changes.
- check_events({{ "test1", "lines", 1, tick, 3, 4, 5, 13 },
- { "test2", "lines", 1, tick, 3, 4, 5, 13 },
- { "test2", "changedtick", 1, tick+1 } })
+ check_events {
+ { "test1", "lines", 1, tick, 3, 4, 5, 13 };
+ { "test2", "lines", 1, tick, 3, 4, 5, 13 };
+ { "test2", "changedtick", 1, tick+1 };
+ }
tick = tick + 1
-- simulate next callback returning true
@@ -121,38 +124,40 @@ describe('lua buffer event callbacks: on_lines', function()
-- plugins can opt in to receive changedtick events, or choose
-- to only receive actual changes.
- check_events({{ "test1", "lines", 1, tick, 6, 7, 9, 16 },
- { "test2", "lines", 1, tick, 6, 7, 9, 16 }})
+ check_events {
+ { "test1", "lines", 1, tick, 6, 7, 9, 16 };
+ { "test2", "lines", 1, tick, 6, 7, 9, 16 };
+ }
- verify_name = "test2"
+ verify_name "test2"
meths.buf_set_lines(0, 1, 1, true, {"added"})
tick = tick + 1
- check_events({{ "test2", "lines", 1, tick, 1, 1, 2, 0 }})
+ check_events {{ "test2", "lines", 1, tick, 1, 1, 2, 0 }}
feed('wix')
tick = tick + 1
- check_events({{ "test2", "lines", 1, tick, 4, 5, 5, 16 }})
+ check_events {{ "test2", "lines", 1, tick, 4, 5, 5, 16 }}
-- check hot path for multiple insert
feed('yz')
tick = tick + 1
- check_events({{ "test2", "lines", 1, tick, 4, 5, 5, 17 }})
+ check_events {{ "test2", "lines", 1, tick, 4, 5, 5, 17 }}
feed('<bs>')
tick = tick + 1
- check_events({{ "test2", "lines", 1, tick, 4, 5, 5, 19 }})
+ check_events {{ "test2", "lines", 1, tick, 4, 5, 5, 19 }}
feed('<esc>Go')
tick = tick + 1
- check_events({{ "test2", "lines", 1, tick, 11, 11, 12, 0 }})
+ check_events {{ "test2", "lines", 1, tick, 11, 11, 12, 0 }}
feed('x')
tick = tick + 1
- check_events({{ "test2", "lines", 1, tick, 11, 12, 12, 5 }})
+ check_events {{ "test2", "lines", 1, tick, 11, 12, 12, 5 }}
command('bwipe!')
- check_events({{ "test2", "detach", 1 }})
+ check_events {{ "test2", "detach", 1 }}
end
it('works', function()
@@ -167,51 +172,63 @@ describe('lua buffer event callbacks: on_lines', function()
check(false,true)
end)
- it('works with utf_sizes and unicode text', function()
+ local function check_unicode(verify)
local unicode_text = {"ascii text",
"latin text åäö",
"BMP text ɧ αλφά",
"BMP text 汉语 ↥↧",
"SMP 🤦 🦄🦃",
"combining å بِيَّة"}
- meths.buf_set_lines(0, 0, -1, true, unicode_text)
- feed('gg')
- exec_lua("return test_register(...)", 0, "test1", false, true)
+ local check_events, verify_name = setup_eventcheck(verify, true, unicode_text)
+
local tick = meths.buf_get_changedtick(0)
- feed('dd')
+ feed('ggdd')
tick = tick + 1
- eq({{ "test1", "lines", 1, tick, 0, 1, 0, 11, 11, 11 }}, exec_lua("return get_events(...)" ))
+ check_events {{ "test1", "lines", 1, tick, 0, 1, 0, 11, 11, 11 }}
feed('A<bs>')
tick = tick + 1
- eq({{ "test1", "lines", 1, tick, 0, 1, 1, 18, 15, 15 }}, exec_lua("return get_events(...)" ))
+ check_events {{ "test1", "lines", 1, tick, 0, 1, 1, 18, 15, 15 }}
feed('<esc>jylp')
tick = tick + 1
- eq({{ "test1", "lines", 1, tick, 1, 2, 2, 21, 16, 16 }}, exec_lua("return get_events(...)" ))
+ check_events {{ "test1", "lines", 1, tick, 1, 2, 2, 21, 16, 16 }}
feed('+eea<cr>')
tick = tick + 1
- eq({{ "test1", "lines", 1, tick, 2, 3, 4, 23, 15, 15 }}, exec_lua("return get_events(...)" ))
+ check_events {{ "test1", "lines", 1, tick, 2, 3, 4, 23, 15, 15 }}
feed('<esc>jdw')
tick = tick + 1
-- non-BMP chars count as 2 UTF-2 codeunits
- eq({{ "test1", "lines", 1, tick, 4, 5, 5, 18, 9, 12 }}, exec_lua("return get_events(...)" ))
+ check_events {{ "test1", "lines", 1, tick, 4, 5, 5, 18, 9, 12 }}
feed('+rx')
tick = tick + 1
-- count the individual codepoints of a composed character.
- eq({{ "test1", "lines", 1, tick, 5, 6, 6, 27, 20, 20 }}, exec_lua("return get_events(...)" ))
+ check_events {{ "test1", "lines", 1, tick, 5, 6, 6, 27, 20, 20 }}
feed('kJ')
tick = tick + 1
+ -- verification fails with multiple line updates, sorry about that
+ verify_name ""
-- NB: this is inefficient (but not really wrong).
- eq({{ "test1", "lines", 1, tick, 4, 5, 5, 14, 5, 8 },
- { "test1", "lines", 1, tick+1, 5, 6, 5, 27, 20, 20 }}, exec_lua("return get_events(...)" ))
+ check_events {
+ { "test1", "lines", 1, tick, 4, 5, 5, 14, 5, 8 };
+ { "test1", "lines", 1, tick+1, 5, 6, 5, 27, 20, 20 };
+ }
+ end
+
+ it('works with utf_sizes and unicode text', function()
+ check_unicode(false)
+ end)
+
+ it('works with utf_sizes and unicode text with verify', function()
+ check_unicode(true)
end)
+
it('has valid cursor position while shifting', function()
meths.buf_set_lines(0, 0, -1, true, {'line1'})
exec_lua([[
@@ -272,11 +289,6 @@ describe('lua buffer event callbacks: on_lines', function()
end)
describe('lua: nvim_buf_attach on_bytes', function()
- before_each(function()
- clear()
- attach_buffer('on_bytes')
- end)
-
-- verifying the sizes with nvim_buf_get_offset is nice (checks we cannot
-- assert the wrong thing), but masks errors with unflushed lines (as
-- nvim_buf_get_offset forces a flush of the memline). To be safe run the
@@ -291,7 +303,7 @@ describe('lua: nvim_buf_attach on_bytes', function()
local len = meths.buf_get_offset(0, meths.buf_line_count(0))
eq(len == -1 and 1 or len, string.len(shadowbytes))
end
- exec_lua("return test_register(...)", 0, "test1", false, false, true)
+ exec_lua("return test_register(...)", 0, "on_bytes", "test1", false, false, true)
meths.buf_get_changedtick(0)
local verify_name = "test1"
@@ -504,11 +516,13 @@ describe('lua: nvim_buf_attach on_bytes', function()
feed ':%s/bcd/'
check_events {
{ "test1", "bytes", 1, 3, 0, 1, 1, 0, 3, 3, 0, 0, 0 };
+ { "test1", "bytes", 1, 5, 0, 1, 1, 0, 0, 0, 0, 3, 3 };
}
feed 'a'
check_events {
{ "test1", "bytes", 1, 3, 0, 1, 1, 0, 3, 3, 0, 1, 1 };
+ { "test1", "bytes", 1, 5, 0, 1, 1, 0, 1, 1, 0, 3, 3 };
}
end)
diff --git a/test/functional/lua/command_line_completion_spec.lua b/test/functional/lua/command_line_completion_spec.lua
new file mode 100644
index 0000000000..3ba7e1589f
--- /dev/null
+++ b/test/functional/lua/command_line_completion_spec.lua
@@ -0,0 +1,171 @@
+local helpers = require('test.functional.helpers')(after_each)
+
+local clear = helpers.clear
+local eq = helpers.eq
+local exec_lua = helpers.exec_lua
+
+local get_completions = function(input, env)
+ return exec_lua("return {vim._expand_pat(...)}", '^' .. input, env)
+end
+
+local get_compl_parts = function(parts)
+ return exec_lua("return {vim._expand_pat_get_parts(...)}", parts)
+end
+
+before_each(clear)
+
+describe('nlua_expand_pat', function()
+ it('should complete exact matches', function()
+ eq({{'exact'}, 0}, get_completions('exact', { exact = true }))
+ end)
+
+ it('should return empty table when nothing matches', function()
+ eq({{}, 0}, get_completions('foo', { bar = true }))
+ end)
+
+ it('should return nice completions with function call prefix', function()
+ eq({{'FOO'}, 6}, get_completions('print(F', { FOO = true, bawr = true }))
+ end)
+
+ it('should return keys for nested dictionaries', function()
+ eq(
+ {{
+ 'nvim_buf_set_lines',
+ 'nvim_buf_set_option'
+ }, 8
+ },
+ get_completions('vim.api.nvim_buf_', {
+ vim = {
+ api = {
+ nvim_buf_set_lines = true,
+ nvim_buf_set_option = true,
+ nvim_win_doesnt_match = true,
+ },
+ other_key = true,
+ }
+ })
+ )
+ end)
+
+ it('it should work with colons', function()
+ eq(
+ {{
+ 'bawr',
+ 'baz',
+ }, 8
+ },
+ get_completions('MyClass:b', {
+ MyClass = {
+ baz = true,
+ bawr = true,
+ foo = false,
+ }
+ })
+ )
+ end)
+
+ it('should return keys for string reffed dictionaries', function()
+ eq(
+ {{
+ 'nvim_buf_set_lines',
+ 'nvim_buf_set_option'
+ }, 11
+ },
+ get_completions('vim["api"].nvim_buf_', {
+ vim = {
+ api = {
+ nvim_buf_set_lines = true,
+ nvim_buf_set_option = true,
+ nvim_win_doesnt_match = true,
+ },
+ other_key = true,
+ }
+ })
+ )
+ end)
+
+ it('should return keys for string reffed dictionaries', function()
+ eq(
+ {{
+ 'nvim_buf_set_lines',
+ 'nvim_buf_set_option'
+ }, 21
+ },
+ get_completions('vim["nested"]["api"].nvim_buf_', {
+ vim = {
+ nested = {
+ api = {
+ nvim_buf_set_lines = true,
+ nvim_buf_set_option = true,
+ nvim_win_doesnt_match = true,
+ },
+ },
+ other_key = true,
+ }
+ })
+ )
+ end)
+
+ it('should be able to interpolate globals', function()
+ eq(
+ {{
+ 'nvim_buf_set_lines',
+ 'nvim_buf_set_option'
+ }, 12
+ },
+ get_completions('vim[MY_VAR].nvim_buf_', {
+ MY_VAR = "api",
+ vim = {
+ api = {
+ nvim_buf_set_lines = true,
+ nvim_buf_set_option = true,
+ nvim_win_doesnt_match = true,
+ },
+ other_key = true,
+ }
+ })
+ )
+ end)
+
+ it('should return everything if the input is of length 0', function()
+ eq({{"other", "vim"}, 0}, get_completions('', { vim = true, other = true }))
+ end)
+
+ describe('get_parts', function()
+ it('should return an empty list for no separators', function()
+ eq({{}, 1}, get_compl_parts("vim"))
+ end)
+
+ it('just the first item before a period', function()
+ eq({{"vim"}, 5}, get_compl_parts("vim.ap"))
+ end)
+
+ it('should return multiple parts just for period', function()
+ eq({{"vim", "api"}, 9}, get_compl_parts("vim.api.nvim_buf"))
+ end)
+
+ it('should be OK with colons', function()
+ eq({{"vim", "api"}, 9}, get_compl_parts("vim:api.nvim_buf"))
+ end)
+
+ it('should work for just one string ref', function()
+ eq({{"vim", "api"}, 12}, get_compl_parts("vim['api'].nvim_buf"))
+ end)
+
+ it('should work for just one string ref, with double quote', function()
+ eq({{"vim", "api"}, 12}, get_compl_parts('vim["api"].nvim_buf'))
+ end)
+
+ it('should allows back-to-back string ref', function()
+ eq({{"vim", "nested", "api"}, 22}, get_compl_parts('vim["nested"]["api"].nvim_buf'))
+ end)
+
+ it('should allows back-to-back string ref with spaces before and after', function()
+ eq({{"vim", "nested", "api"}, 25}, get_compl_parts('vim[ "nested" ]["api"].nvim_buf'))
+ end)
+
+ it('should allow VAR style loolup', function()
+ eq({{"vim", {"NESTED"}, "api"}, 20}, get_compl_parts('vim[NESTED]["api"].nvim_buf'))
+ end)
+ end)
+end)
diff --git a/test/functional/options/defaults_spec.lua b/test/functional/options/defaults_spec.lua
index 92d077ed14..eb5e284385 100644
--- a/test/functional/options/defaults_spec.lua
+++ b/test/functional/options/defaults_spec.lua
@@ -204,9 +204,8 @@ describe('startup defaults', function()
end)
describe('$NVIM_LOG_FILE', function()
- local datasubdir = iswin() and 'nvim-data' or 'nvim'
local xdgdir = 'Xtest-startup-xdg-logpath'
- local xdgdatadir = xdgdir..'/'..datasubdir
+ local xdgcachedir = xdgdir..'/nvim'
after_each(function()
os.remove('Xtest-logpath')
rmdir(xdgdir)
@@ -218,28 +217,21 @@ describe('startup defaults', function()
}})
eq('Xtest-logpath', eval('$NVIM_LOG_FILE'))
end)
- it('defaults to stdpath("data")/log if empty', function()
- eq(true, mkdir(xdgdir) and mkdir(xdgdatadir))
+ it('defaults to stdpath("cache")/log if empty', function()
+ eq(true, mkdir(xdgdir) and mkdir(xdgcachedir))
clear({env={
- XDG_DATA_HOME=xdgdir,
+ XDG_CACHE_HOME=xdgdir,
NVIM_LOG_FILE='', -- Empty is invalid.
}})
- eq(xdgdir..'/'..datasubdir..'/log', string.gsub(eval('$NVIM_LOG_FILE'), '\\', '/'))
+ eq(xdgcachedir..'/log', string.gsub(eval('$NVIM_LOG_FILE'), '\\', '/'))
end)
- it('defaults to stdpath("data")/log if invalid', function()
- eq(true, mkdir(xdgdir) and mkdir(xdgdatadir))
+ it('defaults to stdpath("cache")/log if invalid', function()
+ eq(true, mkdir(xdgdir) and mkdir(xdgcachedir))
clear({env={
- XDG_DATA_HOME=xdgdir,
+ XDG_CACHE_HOME=xdgdir,
NVIM_LOG_FILE='.', -- Any directory is invalid.
}})
- eq(xdgdir..'/'..datasubdir..'/log', string.gsub(eval('$NVIM_LOG_FILE'), '\\', '/'))
- end)
- it('defaults to .nvimlog if stdpath("data") is invalid', function()
- clear({env={
- XDG_DATA_HOME='Xtest-missing-xdg-dir',
- NVIM_LOG_FILE='.', -- Any directory is invalid.
- }})
- eq('.nvimlog', eval('$NVIM_LOG_FILE'))
+ eq(xdgcachedir..'/log', string.gsub(eval('$NVIM_LOG_FILE'), '\\', '/'))
end)
end)
end)
diff --git a/test/functional/plugin/lsp/diagnostic_spec.lua b/test/functional/plugin/lsp/diagnostic_spec.lua
index 3a676359ab..4705a76465 100644
--- a/test/functional/plugin/lsp/diagnostic_spec.lua
+++ b/test/functional/plugin/lsp/diagnostic_spec.lua
@@ -12,41 +12,41 @@ describe('vim.lsp.diagnostic', function()
clear()
exec_lua [[
- require('vim.lsp')
-
- make_range = function(x1, y1, x2, y2)
- return { start = { line = x1, character = y1 }, ['end'] = { line = x2, character = y2 } }
- end
-
- make_error = function(msg, x1, y1, x2, y2)
- return {
- range = make_range(x1, y1, x2, y2),
- message = msg,
- severity = 1,
- }
- end
-
- make_warning = function(msg, x1, y1, x2, y2)
- return {
- range = make_range(x1, y1, x2, y2),
- message = msg,
- severity = 2,
- }
- end
-
- make_information = function(msg, x1, y1, x2, y2)
- return {
- range = make_range(x1, y1, x2, y2),
- message = msg,
- severity = 3,
- }
- end
-
- count_of_extmarks_for_client = function(bufnr, client_id)
- return #vim.api.nvim_buf_get_extmarks(
- bufnr, vim.lsp.diagnostic._get_diagnostic_namespace(client_id), 0, -1, {}
- )
- end
+ require('vim.lsp')
+
+ make_range = function(x1, y1, x2, y2)
+ return { start = { line = x1, character = y1 }, ['end'] = { line = x2, character = y2 } }
+ end
+
+ make_error = function(msg, x1, y1, x2, y2)
+ return {
+ range = make_range(x1, y1, x2, y2),
+ message = msg,
+ severity = 1,
+ }
+ end
+
+ make_warning = function(msg, x1, y1, x2, y2)
+ return {
+ range = make_range(x1, y1, x2, y2),
+ message = msg,
+ severity = 2,
+ }
+ end
+
+ make_information = function(msg, x1, y1, x2, y2)
+ return {
+ range = make_range(x1, y1, x2, y2),
+ message = msg,
+ severity = 3,
+ }
+ end
+
+ count_of_extmarks_for_client = function(bufnr, client_id)
+ return #vim.api.nvim_buf_get_extmarks(
+ bufnr, vim.lsp.diagnostic._get_diagnostic_namespace(client_id), 0, -1, {}
+ )
+ end
]]
fake_uri = "file://fake/uri"
@@ -640,6 +640,36 @@ describe('vim.lsp.diagnostic', function()
eq(expected_spacing, #spacing)
end)
+
+ it('allows filtering via severity limit', function()
+ local get_extmark_count_with_severity = function(severity_limit)
+ return exec_lua([[
+ PublishDiagnostics = vim.lsp.with(vim.lsp.diagnostic.on_publish_diagnostics, {
+ underline = false,
+ virtual_text = {
+ severity_limit = ...
+ },
+ })
+
+ PublishDiagnostics(nil, nil, {
+ uri = fake_uri,
+ diagnostics = {
+ make_warning('Delayed Diagnostic', 4, 4, 4, 4),
+ }
+ }, 1
+ )
+
+ return count_of_extmarks_for_client(diagnostic_bufnr, 1)
+ ]], severity_limit)
+ end
+
+ -- No messages with Error or higher
+ eq(0, get_extmark_count_with_severity("Error"))
+
+ -- But now we don't filter it
+ eq(1, get_extmark_count_with_severity("Warning"))
+ eq(1, get_extmark_count_with_severity("Hint"))
+ end)
end)
describe('lsp.util.show_line_diagnostics', function()
diff --git a/test/functional/plugin/lsp_spec.lua b/test/functional/plugin/lsp_spec.lua
index ec06cb0639..981e2a96a8 100644
--- a/test/functional/plugin/lsp_spec.lua
+++ b/test/functional/plugin/lsp_spec.lua
@@ -193,6 +193,12 @@ describe('LSP', function()
end)
describe('basic_init test', function()
+ after_each(function()
+ stop()
+ exec_lua("lsp.stop_client(lsp.get_active_clients())")
+ exec_lua("lsp._vim_exit_handler()")
+ end)
+
it('should run correctly', function()
local expected_callbacks = {
{NIL, "test", {}, 1};
@@ -303,6 +309,19 @@ describe('LSP', function()
end;
}
end)
+ it('workspace/configuration returns NIL per section if client was started without config.settings', function()
+ clear()
+ fake_lsp_server_setup('workspace/configuration no settings')
+ eq({ NIL, NIL, }, exec_lua [[
+ local params = {
+ items = {
+ {section = 'foo'},
+ {section = 'bar'},
+ }
+ }
+ return vim.lsp.handlers['workspace/configuration'](nil, nil, params, TEST_RPC_CLIENT_ID)
+ ]])
+ end)
it('should verify capabilities sent', function()
local expected_callbacks = {
@@ -1045,7 +1064,7 @@ describe('LSP', function()
return {
edits = {
make_edit(0, 0, 0, 3, "First ↥ 🤦 🦄")
- },
+ },
textDocument = {
uri = "file://fake/uri";
version = editVersion
@@ -1086,7 +1105,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(...)
+ vim.lsp.util.apply_text_document_edit(args[1])
]], edit, versionedBuf)
end
@@ -1109,6 +1128,7 @@ describe('LSP', function()
}, buf_lines(target_bufnr))
end)
end)
+
describe('workspace_apply_edit', function()
it('workspace/applyEdit returns ApplyWorkspaceEditResponse', function()
local expected = {
@@ -1124,6 +1144,106 @@ describe('LSP', function()
]])
end)
end)
+
+ describe('apply_workspace_edit', function()
+ local replace_line_edit = function(row, new_line, editVersion)
+ return {
+ edits = {
+ -- NOTE: This is a hack if you have a line longer than 1000 it won't replace it
+ make_edit(row, 0, row, 1000, new_line)
+ },
+ textDocument = {
+ uri = "file://fake/uri";
+ version = editVersion
+ }
+ }
+ end
+
+ -- Some servers send all the edits separately, but with the same version.
+ -- We should not stop applying the edits
+ local make_workspace_edit = function(changes)
+ return {
+ documentChanges = changes
+ }
+ end
+
+ local target_bufnr, changedtick = nil, nil
+
+ before_each(function()
+ local ret = exec_lua [[
+ local bufnr = vim.uri_to_bufnr("file://fake/uri")
+ local lines = {
+ "Original Line #1",
+ "Original Line #2"
+ }
+
+ 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')}
+ ]]
+
+ target_bufnr = ret[1]
+ changedtick = ret[2]
+ end)
+
+ it('apply_workspace_edit applies a single edit', function()
+ local new_lines = {
+ "First Line",
+ }
+
+ local edits = {}
+ for row, line in ipairs(new_lines) do
+ table.insert(edits, replace_line_edit(row - 1, line, changedtick))
+ end
+
+ eq({
+ "First Line",
+ "Original Line #2",
+ }, exec_lua([[
+ local args = {...}
+ local workspace_edits = args[1]
+ local target_bufnr = args[2]
+
+ vim.lsp.util.apply_workspace_edit(workspace_edits)
+
+ return vim.api.nvim_buf_get_lines(target_bufnr, 0, -1, false)
+ ]], make_workspace_edit(edits), target_bufnr))
+ end)
+
+ it('apply_workspace_edit applies multiple edits', function()
+ local new_lines = {
+ "First Line",
+ "Second Line",
+ }
+
+ local edits = {}
+ for row, line in ipairs(new_lines) do
+ table.insert(edits, replace_line_edit(row - 1, line, changedtick))
+ end
+
+ eq(new_lines, exec_lua([[
+ local args = {...}
+ local workspace_edits = args[1]
+ local target_bufnr = args[2]
+
+ vim.lsp.util.apply_workspace_edit(workspace_edits)
+
+ return vim.api.nvim_buf_get_lines(target_bufnr, 0, -1, false)
+ ]], make_workspace_edit(edits), target_bufnr))
+ end)
+ end)
+
describe('completion_list_to_complete_items', function()
-- Completion option precedence:
-- textEdit.newText > insertText > label
diff --git a/test/functional/treesitter/parser_spec.lua b/test/functional/treesitter/parser_spec.lua
index 520574c08a..f99362fbdf 100644
--- a/test/functional/treesitter/parser_spec.lua
+++ b/test/functional/treesitter/parser_spec.lua
@@ -245,7 +245,7 @@ void ui_refresh(void)
parser = vim.treesitter.get_parser(0, "c")
tree = parser:parse()[1]
res = {}
- for pattern, match in cquery:iter_matches(tree:root(), 0, 0, 1) do
+ for pattern, match in cquery:iter_matches(tree:root(), 0) do
-- can't transmit node over RPC. just check the name and range
local mrepr = {}
for cid,node in pairs(match) do
@@ -289,7 +289,7 @@ void ui_refresh(void)
local query = query.parse_query("c", ...)
local nodes = {}
- for _, node in query:iter_captures(parser:parse()[1]:root(), 0, 0, 19) do
+ for _, node in query:iter_captures(parser:parse()[1]:root(), 0) do
table.insert(nodes, {node:range()})
end
@@ -365,7 +365,7 @@ void ui_refresh(void)
query = vim.treesitter.parse_query("c", "(declaration) @decl")
local nodes = {}
- for _, node in query:iter_captures(parser:parse()[1]:root(), 0, 0, 19) do
+ for _, node in query:iter_captures(parser:parse()[1]:root(), 0) do
table.insert(nodes, node)
end
@@ -412,7 +412,7 @@ void ui_refresh(void)
local nodes = {}
local query = vim.treesitter.parse_query("c", '((identifier) @id (eq? @id "foo"))')
- for _, node in query:iter_captures(parser:parse()[1]:root(), str, 0, 2) do
+ for _, node in query:iter_captures(parser:parse()[1]:root(), str) do
table.insert(nodes, { node:range() })
end
@@ -421,6 +421,29 @@ void ui_refresh(void)
eq({ {0, 10, 0, 13} }, ret)
end)
+ it("should use node range when omitted", function()
+ local txt = [[
+ int foo = 42;
+ int bar = 13;
+ ]]
+
+ local ret = exec_lua([[
+ local str = ...
+ local parser = vim.treesitter.get_string_parser(str, "c")
+
+ local nodes = {}
+ local query = vim.treesitter.parse_query("c", '((identifier) @foo)')
+ local first_child = parser:parse()[1]:root():child(1)
+
+ for _, node in query:iter_captures(first_child, str) do
+ table.insert(nodes, { node:range() })
+ end
+
+ return nodes]], txt)
+
+ eq({ {1, 10, 1, 13} }, ret)
+ end)
+
describe("when creating a language tree", function()
local function get_ranges()
return exec_lua([[
@@ -539,7 +562,7 @@ int x = INT_MAX;
query = vim.treesitter.parse_query("c", '((number_literal) @number (#set! "key" "value"))')
parser = vim.treesitter.get_parser(0, "c")
- for pattern, match, metadata in query:iter_matches(parser:parse()[1]:root(), 0, 0, 1) do
+ for pattern, match, metadata in query:iter_matches(parser:parse()[1]:root(), 0) do
result = metadata.key
end
@@ -562,7 +585,7 @@ int x = INT_MAX;
query = vim.treesitter.parse_query("c", '((number_literal) @number (#set! @number "key" "value"))')
parser = vim.treesitter.get_parser(0, "c")
- for pattern, match, metadata in query:iter_matches(parser:parse()[1]:root(), 0, 0, 1) do
+ for pattern, match, metadata in query:iter_matches(parser:parse()[1]:root(), 0) do
result = metadata[pattern].key
end
diff --git a/test/functional/ui/sign_spec.lua b/test/functional/ui/sign_spec.lua
index d1b8de5e4e..1937102782 100644
--- a/test/functional/ui/sign_spec.lua
+++ b/test/functional/ui/sign_spec.lua
@@ -266,6 +266,111 @@ describe('Signs', function()
]]}
end)
+ it('auto-resize sign column with minimum size (#13783)', function()
+ feed('ia<cr>b<cr>c<cr><esc>')
+ command('set number')
+ -- sign column should always accommodate at the minimum size
+ command('set signcolumn=auto:1-3')
+ screen:expect([[
+ {2: }{6: 1 }a |
+ {2: }{6: 2 }b |
+ {2: }{6: 3 }c |
+ {2: }{6: 4 }^ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ |
+ ]])
+ -- should support up to 8 signs at minimum
+ command('set signcolumn=auto:8-9')
+ screen:expect([[
+ {2: }{6: 1 }a |
+ {2: }{6: 2 }b |
+ {2: }{6: 3 }c |
+ {2: }{6: 4 }^ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ |
+ ]])
+ -- should keep the same sign size when signs are not exceeding
+ -- the minimum
+ command('set signcolumn=auto:2-5')
+ command('sign define pietSearch text=>> texthl=Search')
+ command('sign place 1 line=1 name=pietSearch buffer=1')
+ screen:expect([[
+ {1:>>}{2: }{6: 1 }a |
+ {2: }{6: 2 }b |
+ {2: }{6: 3 }c |
+ {2: }{6: 4 }^ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ |
+ ]])
+ -- should resize itself when signs are exceeding minimum but
+ -- not over the maximum
+ command('sign place 2 line=1 name=pietSearch buffer=1')
+ command('sign place 3 line=1 name=pietSearch buffer=1')
+ command('sign place 4 line=1 name=pietSearch buffer=1')
+ screen:expect([[
+ {1:>>>>>>>>}{6: 1 }a |
+ {2: }{6: 2 }b |
+ {2: }{6: 3 }c |
+ {2: }{6:^ 4 } |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ |
+ ]])
+ -- should keep the column at maximum size when signs are
+ -- exceeding the maximum
+ command('sign place 5 line=1 name=pietSearch buffer=1')
+ command('sign place 6 line=1 name=pietSearch buffer=1')
+ command('sign place 7 line=1 name=pietSearch buffer=1')
+ command('sign place 8 line=1 name=pietSearch buffer=1')
+ screen:expect([[
+ {1:>>>>>>>>>>}{6: 1 }a |
+ {2: }{6: 2 }b |
+ {2: }{6: 3 }c |
+ {2: ^ }{6: 4 } |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ |
+ ]])
+ end)
+
it('ignores signs with no icon and text when calculting the signcolumn width', function()
feed('ia<cr>b<cr>c<cr><esc>')
command('set number')
diff --git a/test/functional/viml/completion_spec.lua b/test/functional/viml/completion_spec.lua
index 01fc50289d..a4241fe5aa 100644
--- a/test/functional/viml/completion_spec.lua
+++ b/test/functional/viml/completion_spec.lua
@@ -3,6 +3,7 @@ local Screen = require('test.functional.ui.screen')
local clear, feed = helpers.clear, helpers.feed
local eval, eq, neq = helpers.eval, helpers.eq, helpers.neq
local feed_command, source, expect = helpers.feed_command, helpers.source, helpers.expect
+local funcs = helpers.funcs
local curbufmeths = helpers.curbufmeths
local command = helpers.command
local meths = helpers.meths
@@ -26,6 +27,7 @@ describe('completion', function()
[7] = {foreground = Screen.colors.White, background = Screen.colors.Red},
[8] = {reverse = true},
[9] = {bold = true, reverse = true},
+ [10] = {foreground = Screen.colors.Grey0, background = Screen.colors.Yellow},
})
end)
@@ -895,8 +897,47 @@ describe('completion', function()
]])
end)
- describe('from the commandline window', function()
+ describe('lua completion', function()
+ it('expands when there is only one match', function()
+ feed(':lua CURRENT_TESTING_VAR = 1<CR>')
+ feed(':lua CURRENT_TESTING_<TAB>')
+ screen:expect{grid=[[
+ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ :lua CURRENT_TESTING_VAR^ |
+ ]]}
+ end)
+ it('expands when there is only one match', function()
+ feed(':lua CURRENT_TESTING_FOO = 1<CR>')
+ feed(':lua CURRENT_TESTING_BAR = 1<CR>')
+ feed(':lua CURRENT_TESTING_<TAB>')
+ screen:expect{ grid = [[
+ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {10:CURRENT_TESTING_BAR}{9: CURRENT_TESTING_FOO }|
+ :lua CURRENT_TESTING_BAR^ |
+ ]], unchanged = true }
+ end)
+
+ it('provides completion from `getcompletion()`', function()
+ eq({'vim'}, funcs.getcompletion('vi', 'lua'))
+ eq({'api'}, funcs.getcompletion('vim.ap', 'lua'))
+ eq({'tbl_filter'}, funcs.getcompletion('vim.tbl_fil', 'lua'))
+ eq({'vim'}, funcs.getcompletion('print(vi', 'lua'))
+ end)
+ end)
+
+ describe('from the commandline window', function()
it('is cleared after CTRL-C', function ()
feed('q:')
feed('ifoo faa fee f')
diff --git a/test/symbolic/klee/nvim/charset.c b/test/symbolic/klee/nvim/charset.c
index f9bc3fabc4..fd1c5ee4b9 100644
--- a/test/symbolic/klee/nvim/charset.c
+++ b/test/symbolic/klee/nvim/charset.c
@@ -62,7 +62,7 @@ void vim_str2nr(const char_u *const start, int *const prep, int *const len,
goto vim_str2nr_dec;
}
default: {
- assert(false);
+ abort();
}
}
} else if ((what & (STR2NR_HEX|STR2NR_OCT|STR2NR_BIN))
@@ -102,7 +102,7 @@ void vim_str2nr(const char_u *const start, int *const prep, int *const len,
}
// Do the string-to-numeric conversion "manually" to avoid sscanf quirks.
- assert(false); // Should’ve used goto earlier.
+ abort(); // Should’ve used goto earlier.
#define PARSE_NUMBER(base, cond, conv) \
do { \
while (!STRING_ENDED(ptr) && (cond)) { \
diff --git a/test/symbolic/klee/nvim/memory.c b/test/symbolic/klee/nvim/memory.c
index df422cea3e..1614f813d7 100644
--- a/test/symbolic/klee/nvim/memory.c
+++ b/test/symbolic/klee/nvim/memory.c
@@ -45,7 +45,7 @@ void xfree(void *const p)
return;
}
}
- assert(false);
+ abort();
}
void *xrealloc(void *const p, size_t new_size)
@@ -63,7 +63,7 @@ void *xrealloc(void *const p, size_t new_size)
return ret;
}
}
- assert(false);
+ abort();
return (void *)(intptr_t)1;
}
diff --git a/third-party/CMakeLists.txt b/third-party/CMakeLists.txt
index 5af5eb0a49..aab8eb4464 100644
--- a/third-party/CMakeLists.txt
+++ b/third-party/CMakeLists.txt
@@ -196,11 +196,11 @@ set(GETTEXT_SHA256 66415634c6e8c3fa8b71362879ec7575e27da43da562c798a8a2f223e6e47
set(LIBICONV_URL https://ftp.gnu.org/pub/gnu/libiconv/libiconv-1.15.tar.gz)
set(LIBICONV_SHA256 ccf536620a45458d26ba83887a983b96827001e92a13847b45e4925cc8913178)
-set(TREESITTER_C_URL https://github.com/tree-sitter/tree-sitter-c/archive/6002fcd.tar.gz)
-set(TREESITTER_C_SHA256 46f8d44fa886d9ddb92571bb6fa8b175992c8758eca749cb1217464e512b6e97)
+set(TREESITTER_C_URL https://github.com/tree-sitter/tree-sitter-c/archive/99151b1.tar.gz)
+set(TREESITTER_C_SHA256 950386f9ba77fb6a7e992198d4f219c34238a2bbc005c5f53c4212d0f8772b06)
-set(TREESITTER_URL https://github.com/tree-sitter/tree-sitter/archive/0.17.3.zip)
-set(TREESITTER_SHA256 19068b6663f5a4cacd5d805fa437419e3c29eb615ed9523e438b400b79f39c20)
+set(TREESITTER_URL https://github.com/tree-sitter/tree-sitter/archive/0.18.0.zip)
+set(TREESITTER_SHA256 ac53b7708ca47161dac7f8e852bd61accb8527d45b7ad72e29e12e8e72dbe440)
if(USE_BUNDLED_UNIBILIUM)
include(BuildUnibilium)