aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt2
-rw-r--r--config/config.h.in1
-rw-r--r--contrib/flake.lock43
-rw-r--r--contrib/flake.nix11
-rw-r--r--runtime/autoload/haskellcomplete.vim5
-rw-r--r--runtime/autoload/netrw.vim17
-rw-r--r--runtime/autoload/tar.vim277
-rw-r--r--runtime/doc/api.txt48
-rw-r--r--runtime/doc/editing.txt4
-rw-r--r--runtime/doc/eval.txt74
-rw-r--r--runtime/doc/insert.txt6
-rw-r--r--runtime/doc/lsp.txt28
-rw-r--r--runtime/doc/options.txt6
-rw-r--r--runtime/doc/pi_netrw.txt5
-rw-r--r--runtime/doc/pi_tar.txt109
-rw-r--r--runtime/doc/starting.txt2
-rw-r--r--runtime/doc/syntax.txt2
-rw-r--r--runtime/doc/usr_41.txt1
-rw-r--r--runtime/filetype.vim6
-rw-r--r--runtime/indent/tcl.vim4
-rw-r--r--runtime/lua/vim/lsp.lua58
-rw-r--r--runtime/lua/vim/lsp/buf.lua12
-rw-r--r--runtime/lua/vim/lsp/callbacks.lua4
-rw-r--r--runtime/lua/vim/lsp/diagnostic.lua22
-rw-r--r--runtime/lua/vim/lsp/handlers.lua4
-rw-r--r--runtime/lua/vim/lsp/log.lua4
-rw-r--r--runtime/lua/vim/lsp/protocol.lua2
-rw-r--r--runtime/lua/vim/lsp/rpc.lua5
-rw-r--r--runtime/lua/vim/lsp/util.lua82
-rw-r--r--runtime/lua/vim/treesitter/languagetree.lua16
-rw-r--r--runtime/menu.vim4
-rw-r--r--runtime/plugin/tarPlugin.vim6
-rw-r--r--runtime/syntax/cabal.vim30
-rw-r--r--runtime/syntax/cabalconfig.vim30
-rw-r--r--runtime/syntax/cabalproject.vim28
-rw-r--r--runtime/syntax/haskell.vim89
-rw-r--r--src/nvim/api/buffer.c88
-rw-r--r--src/nvim/api/vim.c4
-rw-r--r--src/nvim/charset.c2
-rw-r--r--src/nvim/decoration.c91
-rw-r--r--src/nvim/decoration.h8
-rw-r--r--src/nvim/edit.c15
-rw-r--r--src/nvim/eval.c13
-rw-r--r--src/nvim/eval.h13
-rw-r--r--src/nvim/eval.lua1
-rw-r--r--src/nvim/eval/funcs.c48
-rw-r--r--src/nvim/eval/typval.h1
-rw-r--r--src/nvim/eval/userfunc.c91
-rw-r--r--src/nvim/ex_cmds.c4
-rw-r--r--src/nvim/ex_cmds.lua4
-rw-r--r--src/nvim/ex_cmds2.c69
-rw-r--r--src/nvim/ex_getln.c2
-rw-r--r--src/nvim/globals.h16
-rw-r--r--src/nvim/memline.c2
-rw-r--r--src/nvim/misc1.c2
-rw-r--r--src/nvim/mouse.c71
-rw-r--r--src/nvim/normal.c47
-rw-r--r--src/nvim/ops.c9
-rw-r--r--src/nvim/path.c2
-rw-r--r--src/nvim/pos.h7
-rw-r--r--src/nvim/screen.c65
-rw-r--r--src/nvim/search.c10
-rw-r--r--src/nvim/tag.c2
-rw-r--r--src/nvim/testdir/test_alot.vim1
-rw-r--r--src/nvim/testdir/test_exit.vim29
-rw-r--r--src/nvim/testdir/test_filetype.vim2
-rw-r--r--src/nvim/testdir/test_functions.vim25
-rw-r--r--src/nvim/testdir/test_options.vim42
-rw-r--r--src/nvim/testdir/test_statusline.vim16
-rw-r--r--src/nvim/testdir/test_user_func.vim53
-rw-r--r--src/nvim/tui/input.c4
-rw-r--r--src/nvim/undo.c114
-rw-r--r--src/nvim/window.c12
-rw-r--r--test/functional/ex_cmds/source_spec.lua47
-rw-r--r--test/functional/fixtures/fake-lsp-server.lua4
-rw-r--r--test/functional/legacy/options_spec.lua47
-rw-r--r--test/functional/lua/buffer_updates_spec.lua54
-rw-r--r--test/functional/plugin/lsp/diagnostic_spec.lua63
-rw-r--r--test/functional/plugin/lsp_spec.lua39
-rw-r--r--test/functional/ui/decorations_spec.lua95
-rw-r--r--test/functional/ui/fold_spec.lua367
81 files changed, 2185 insertions, 563 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index e3c67c55cd..4e427eea26 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -83,6 +83,8 @@ if(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
endif()
if(WIN32 OR CMAKE_SYSTEM_NAME STREQUAL "Darwin")
+ # Ignore case when comparing filenames on Windows and Mac.
+ set(CASE_INSENSITIVE_FILENAME TRUE)
# Enable fixing case-insensitive filenames for Windows and Mac.
set(USE_FNAME_CASE TRUE)
endif()
diff --git a/config/config.h.in b/config/config.h.in
index 95e2c872a3..275bff79a0 100644
--- a/config/config.h.in
+++ b/config/config.h.in
@@ -40,6 +40,7 @@
#cmakedefine HAVE_WORKING_LIBINTL
#cmakedefine HAVE_WSL
#cmakedefine UNIX
+#cmakedefine CASE_INSENSITIVE_FILENAME
#cmakedefine USE_FNAME_CASE
#cmakedefine HAVE_SYS_UIO_H
#ifdef HAVE_SYS_UIO_H
diff --git a/contrib/flake.lock b/contrib/flake.lock
new file mode 100644
index 0000000000..521b7629d9
--- /dev/null
+++ b/contrib/flake.lock
@@ -0,0 +1,43 @@
+{
+ "nodes": {
+ "flake-utils": {
+ "locked": {
+ "lastModified": 1610051610,
+ "narHash": "sha256-U9rPz/usA1/Aohhk7Cmc2gBrEEKRzcW4nwPWMPwja4Y=",
+ "owner": "numtide",
+ "repo": "flake-utils",
+ "rev": "3982c9903e93927c2164caa727cd3f6a0e6d14cc",
+ "type": "github"
+ },
+ "original": {
+ "owner": "numtide",
+ "repo": "flake-utils",
+ "type": "github"
+ }
+ },
+ "nixpkgs": {
+ "locked": {
+ "lastModified": 1613226215,
+ "narHash": "sha256-3rA5cGIrBHD6yeKhNhsF7/t461ww25oJY8KyBb0IhjU=",
+ "owner": "nixos",
+ "repo": "nixpkgs",
+ "rev": "ff96a0fa5635770390b184ae74debea75c3fd534",
+ "type": "github"
+ },
+ "original": {
+ "owner": "nixos",
+ "ref": "nixos-unstable",
+ "repo": "nixpkgs",
+ "type": "github"
+ }
+ },
+ "root": {
+ "inputs": {
+ "flake-utils": "flake-utils",
+ "nixpkgs": "nixpkgs"
+ }
+ }
+ },
+ "root": "root",
+ "version": 7
+}
diff --git a/contrib/flake.nix b/contrib/flake.nix
index d18534215c..08126a48e9 100644
--- a/contrib/flake.nix
+++ b/contrib/flake.nix
@@ -27,15 +27,20 @@
});
# a development binary to help debug issues
- neovim-debug = (neovim.override {
- stdenv = if pkgs.stdenv.isLinux then pkgs.llvmPackages_latest.stdenv else pkgs.stdenv;
+ neovim-debug = let
+ stdenv = pkgs.stdenvAdapters.keepDebugInfo (if pkgs.stdenv.isLinux then pkgs.llvmPackages_latest.stdenv else pkgs.stdenv);
+ in
+ pkgs.enableDebugging ((neovim.override {
lua = pkgs.enableDebugging pkgs.luajit;
+ inherit stdenv;
}).overrideAttrs (oa: {
cmakeBuildType = "Debug";
cmakeFlags = oa.cmakeFlags ++ [
"-DMIN_LOG_LEVEL=0"
];
- });
+
+ disallowedReferences = [];
+ }));
# for neovim developers, very slow
# brings development tools as well
diff --git a/runtime/autoload/haskellcomplete.vim b/runtime/autoload/haskellcomplete.vim
index 520ab93700..48fbac7f9f 100644
--- a/runtime/autoload/haskellcomplete.vim
+++ b/runtime/autoload/haskellcomplete.vim
@@ -2,7 +2,7 @@
" Language: Haskell
" Maintainer: Daniel Campoverde <alx@sillybytes.net>
" URL: https://github.com/alx741/haskellcomplete.vim
-" Last Change: 2018 Aug 26
+" Last Change: 2019 May 14
" Usage: setlocal omnifunc=haskellcomplete#Complete
@@ -63,6 +63,7 @@ function! haskellcomplete#Complete(findstart, base)
call add(l:matches, extension)
endif
endfor
+ let b:completingLangExtension = 0
return l:matches
endif
@@ -78,6 +79,7 @@ function! haskellcomplete#Complete(findstart, base)
call add(l:matches, flag)
endif
endfor
+ let b:completingOptionsGHC = 0
return l:matches
endif
@@ -93,6 +95,7 @@ function! haskellcomplete#Complete(findstart, base)
call add(l:matches, module)
endif
endfor
+ let b:completingModule = 0
return l:matches
endif
diff --git a/runtime/autoload/netrw.vim b/runtime/autoload/netrw.vim
index 1fe4ec5a89..7a799abb13 100644
--- a/runtime/autoload/netrw.vim
+++ b/runtime/autoload/netrw.vim
@@ -5781,22 +5781,7 @@ fun! s:NetrwHome()
if exists("g:netrw_home")
let home= expand(g:netrw_home)
else
- " go to vim plugin home
- for home in split(&rtp,',') + ['']
- if isdirectory(s:NetrwFile(home)) && filewritable(s:NetrwFile(home)) | break | endif
- let basehome= substitute(home,'[/\\]\.vim$','','')
- if isdirectory(s:NetrwFile(basehome)) && filewritable(s:NetrwFile(basehome))
- let home= basehome."/.vim"
- break
- endif
- endfor
- if home == ""
- " just pick the first directory
- let home= substitute(&rtp,',.*$','','')
- endif
- if (has("win32") || has("win95") || has("win64") || has("win16"))
- let home= substitute(home,'/','\\','g')
- endif
+ let home = stdpath('data')
endif
" insure that the home directory exists
if g:netrw_dirhistmax > 0 && !isdirectory(s:NetrwFile(home))
diff --git a/runtime/autoload/tar.vim b/runtime/autoload/tar.vim
index dc670dbd14..b6c4c660b8 100644
--- a/runtime/autoload/tar.vim
+++ b/runtime/autoload/tar.vim
@@ -1,13 +1,13 @@
" tar.vim: Handles browsing tarfiles
" AUTOLOAD PORTION
-" Date: Apr 17, 2013
-" Version: 29
-" Maintainer: Charles E Campbell <NdrOchip@ScampbellPfamily.AbizM-NOSPAM>
-" License: Vim License (see vim's :help license)
+" Date: Jan 07, 2020
+" Version: 32
+" Maintainer: Charles E Campbell <NcampObell@SdrPchip.AorgM-NOSPAM>
+" License: Vim License (see vim's :help license)
"
" Contains many ideas from Michael Toren's <tar.vim>
"
-" Copyright: Copyright (C) 2005-2011 Charles E. Campbell {{{1
+" Copyright: Copyright (C) 2005-2017 Charles E. Campbell {{{1
" Permission is hereby granted to use and distribute this code,
" with or without modifications, provided that this copyright
" notice is copied with it. Like anything else that's free,
@@ -22,7 +22,7 @@
if &cp || exists("g:loaded_tar")
finish
endif
-let g:loaded_tar= "v29"
+let g:loaded_tar= "v32"
if v:version < 702
echohl WarningMsg
echo "***warning*** this version of tar needs vim 7.2"
@@ -48,6 +48,9 @@ endif
if !exists("g:tar_writeoptions")
let g:tar_writeoptions= "uf"
endif
+if !exists("g:tar_delfile")
+ let g:tar_delfile="--delete -f"
+endif
if !exists("g:netrw_cygwin")
if has("win32") || has("win95") || has("win64") || has("win16")
if &shell =~ '\%(\<bash\>\|\<zsh\>\)\%(\.exe\)\=$'
@@ -109,6 +112,7 @@ fun! tar#Browse(tarfile)
" sanity checks
if !executable(g:tar_cmd)
redraw!
+" call Decho('***error*** (tar#Browse) "'.g:tar_cmd.'" not available on your system')
echohl Error | echo '***error*** (tar#Browse) "'.g:tar_cmd.'" not available on your system'
let &report= repkeep
" call Dret("tar#Browse")
@@ -119,6 +123,7 @@ fun! tar#Browse(tarfile)
if a:tarfile !~# '^\a\+://'
" if it's an url, don't complain, let url-handlers such as vim do its thing
redraw!
+" call Decho("***error*** (tar#Browse) File not readable<".a:tarfile.">")
echohl Error | echo "***error*** (tar#Browse) File not readable<".a:tarfile.">" | echohl None
endif
let &report= repkeep
@@ -152,12 +157,29 @@ fun! tar#Browse(tarfile)
" assuming cygwin
let tarfile=substitute(system("cygpath -u ".shellescape(tarfile,0)),'\n$','','e')
endif
-
let curlast= line("$")
- if tarfile =~# '\.\(gz\|tgz\)$'
- let gzip_command = s:get_gzip_command(tarfile)
+
+ if tarfile =~# '\.\(gz\)$'
" call Decho("1: exe silent r! gzip -d -c -- ".shellescape(tarfile,1)." | ".g:tar_cmd." -".g:tar_browseoptions." - ")
- exe "sil! r! " . gzip_command . " -d -c -- ".shellescape(tarfile,1)." | ".g:tar_cmd." -".g:tar_browseoptions." - "
+ exe "sil! r! gzip -d -c -- ".shellescape(tarfile,1)." | ".g:tar_cmd." -".g:tar_browseoptions." - "
+
+ elseif tarfile =~# '\.\(tgz\)$' || tarfile =~# '\.\(tbz\)$' || tarfile =~# '\.\(txz\)$' || tarfile =~# '\.\(tzs\)$'
+ if has("unix") && executable("file")
+ let filekind= system("file ".shellescape(tarfile,1)) =~ "bzip2"
+ else
+ let filekind= ""
+ endif
+
+ if filekind =~ "bzip2"
+ exe "sil! r! bzip2 -d -c -- ".shellescape(tarfile,1)." | ".g:tar_cmd." -".g:tar_browseoptions." - "
+ elseif filekind =~ "XZ"
+ exe "sil! r! xz -d -c -- ".shellescape(tarfile,1)." | ".g:tar_cmd." -".g:tar_browseoptions." - "
+ elseif filekind =~ "Zstandard"
+ exe "sil! r! zstd --decompress --stdout -- ".shellescape(tarfile,1)." | ".g:tar_cmd." -".g:tar_browseoptions." - "
+ else
+ exe "sil! r! gzip -d -c -- ".shellescape(tarfile,1)." | ".g:tar_cmd." -".g:tar_browseoptions." - "
+ endif
+
elseif tarfile =~# '\.lrp'
" call Decho("2: exe silent r! cat -- ".shellescape(tarfile,1)."|gzip -d -c -|".g:tar_cmd." -".g:tar_browseoptions." - ")
exe "sil! r! cat -- ".shellescape(tarfile,1)."|gzip -d -c -|".g:tar_cmd." -".g:tar_browseoptions." - "
@@ -170,6 +192,8 @@ fun! tar#Browse(tarfile)
elseif tarfile =~# '\.\(xz\|txz\)$'
" call Decho("3: exe silent r! xz --decompress --stdout -- ".shellescape(tarfile,1)." | ".g:tar_cmd." -".g:tar_browseoptions." - ")
exe "sil! r! xz --decompress --stdout -- ".shellescape(tarfile,1)." | ".g:tar_cmd." -".g:tar_browseoptions." - "
+ elseif tarfile =~# '\.\(zst\|tzs\)$'
+ exe "sil! r! zstd --decompress --stdout -- ".shellescape(tarfile,1)." | ".g:tar_cmd." -".g:tar_browseoptions." - "
else
if tarfile =~ '^\s*-'
" A file name starting with a dash is taken as an option. Prepend ./ to avoid that.
@@ -184,7 +208,7 @@ fun! tar#Browse(tarfile)
" call Dret("tar#Browse : a:tarfile<".a:tarfile.">")
return
endif
- if line("$") == curlast || ( line("$") == (curlast + 1) && getline("$") =~ '\c\%(warning\|error\|inappropriate\|unrecognized\)')
+ if line("$") == curlast || ( line("$") == (curlast + 1) && getline("$") =~# '\c\%(warning\|error\|inappropriate\|unrecognized\)')
redraw!
echohl WarningMsg | echo "***warning*** (tar#Browse) ".a:tarfile." doesn't appear to be a tar file" | echohl None
keepj sil! %d
@@ -197,8 +221,13 @@ fun! tar#Browse(tarfile)
return
endif
+ " set up maps supported for tar
setlocal noma nomod ro
- noremap <silent> <buffer> <cr> :call <SID>TarBrowseSelect()<cr>
+ noremap <silent> <buffer> <cr> :call <SID>TarBrowseSelect()<cr>
+ noremap <silent> <buffer> x :call tar#Extract()<cr>
+ if &mouse != ""
+ noremap <silent> <buffer> <leftmouse> <leftmouse>:call <SID>TarBrowseSelect()<cr>
+ endif
let &report= repkeep
" call Dret("tar#Browse : b:tarfile<".b:tarfile.">")
@@ -235,7 +264,8 @@ fun! s:TarBrowseSelect()
let tarfile=substitute(system("cygpath -u ".shellescape(tarfile,0)),'\n$','','e')
endif
- new
+ " open a new window (tar#Read will read a file into it)
+ noswapfile new
if !exists("g:tar_nomax") || g:tar_nomax == 0
wincmd _
endif
@@ -267,7 +297,7 @@ fun! tar#Read(fname,mode)
if fname =~ '\.bz2$' && executable("bzcat")
let decmp= "|bzcat"
let doro = 1
- elseif fname =~ '\.gz$' && executable("zcat")
+ elseif fname =~ '\.t\=gz$' && executable("zcat")
let decmp= "|zcat"
let doro = 1
elseif fname =~ '\.lzma$' && executable("lzcat")
@@ -276,6 +306,9 @@ fun! tar#Read(fname,mode)
elseif fname =~ '\.xz$' && executable("xzcat")
let decmp= "|xzcat"
let doro = 1
+ elseif fname =~ '\.zst$' && executable("zstdcat")
+ let decmp= "|zstdcat"
+ let doro = 1
else
let decmp=""
let doro = 0
@@ -291,20 +324,31 @@ fun! tar#Read(fname,mode)
endif
if tarfile =~# '\.bz2$'
-" call Decho("7: exe silent r! bzip2 -d -c ".shellescape(tarfile,1)."| ".g:tar_cmd." -".g:tar_readoptions." - ".tar_secure.shellescape(fname,1).decmp)
exe "sil! r! bzip2 -d -c -- ".shellescape(tarfile,1)."| ".g:tar_cmd." -".g:tar_readoptions." - ".tar_secure.shellescape(fname,1).decmp
- elseif tarfile =~# '\.\(gz\|tgz\)$'
- let gzip_command = s:get_gzip_command(tarfile)
-" call Decho("5: exe silent r! gzip -d -c -- ".shellescape(tarfile,1)."| ".g:tar_cmd.' -'.g:tar_readoptions.' - '.tar_secure.shellescape(fname,1))
- exe "sil! r! " . gzip_command . " -d -c -- ".shellescape(tarfile,1)."| ".g:tar_cmd." -".g:tar_readoptions." - ".tar_secure.shellescape(fname,1).decmp
+ elseif tarfile =~# '\.\(gz\)$'
+ exe "sil! r! gzip -d -c -- ".shellescape(tarfile,1)."| ".g:tar_cmd." -".g:tar_readoptions." - ".tar_secure.shellescape(fname,1).decmp
+
+ elseif tarfile =~# '\(\.tgz\|\.tbz\|\.txz\)'
+ if has("unix") && executable("file")
+ let filekind= system("file ".shellescape(tarfile,1))
+ else
+ let filekind= ""
+ endif
+ if filekind =~ "bzip2"
+ exe "sil! r! bzip2 -d -c -- ".shellescape(tarfile,1)."| ".g:tar_cmd." -".g:tar_readoptions." - ".tar_secure.shellescape(fname,1).decmp
+ elseif filekind =~ "XZ"
+ exe "sil! r! xz -d -c -- ".shellescape(tarfile,1)."| ".g:tar_cmd." -".g:tar_readoptions." - ".tar_secure.shellescape(fname,1).decmp
+ elseif filekind =~ "Zstandard"
+ exe "sil! r! zstd --decompress --stdout -- ".shellescape(tarfile,1)."| ".g:tar_cmd." -".g:tar_readoptions." - ".tar_secure.shellescape(fname,1).decmp
+ else
+ exe "sil! r! gzip -d -c -- ".shellescape(tarfile,1)."| ".g:tar_cmd." -".g:tar_readoptions." - ".tar_secure.shellescape(fname,1).decmp
+ endif
+
elseif tarfile =~# '\.lrp$'
-" call Decho("6: exe silent r! cat ".shellescape(tarfile,1)." | gzip -d -c - | ".g:tar_cmd." -".g:tar_readoptions." - ".tar_secure.shellescape(fname,1).decmp)
exe "sil! r! cat -- ".shellescape(tarfile,1)." | gzip -d -c - | ".g:tar_cmd." -".g:tar_readoptions." - ".tar_secure.shellescape(fname,1).decmp
elseif tarfile =~# '\.lzma$'
-" call Decho("7: exe silent r! lzma -d -c ".shellescape(tarfile,1)."| ".g:tar_cmd." -".g:tar_readoptions." - ".tar_secure.shellescape(fname,1).decmp)
exe "sil! r! lzma -d -c -- ".shellescape(tarfile,1)."| ".g:tar_cmd." -".g:tar_readoptions." - ".tar_secure.shellescape(fname,1).decmp
elseif tarfile =~# '\.\(xz\|txz\)$'
-" call Decho("3: exe silent r! xz --decompress --stdout -- ".shellescape(tarfile,1)." | ".g:tar_cmd." -".g:tar_readoptions." - ".tar_secure.shellescape(fname,1).decmp)
exe "sil! r! xz --decompress --stdout -- ".shellescape(tarfile,1)." | ".g:tar_cmd." -".g:tar_readoptions." - ".tar_secure.shellescape(fname,1).decmp
else
if tarfile =~ '^\s*-'
@@ -348,13 +392,14 @@ fun! tar#Write(fname)
" sanity checks
if !executable(g:tar_cmd)
redraw!
- echohl Error | echo '***error*** (tar#Browse) "'.g:tar_cmd.'" not available on your system'
+" call Decho('***error*** (tar#Browse) "'.g:tar_cmd.'" not available on your system')
let &report= repkeep
" call Dret("tar#Write")
return
endif
if !exists("*mkdir")
redraw!
+" call Decho("***error*** (tar#Write) sorry, mkdir() doesn't work on your system")
echohl Error | echo "***error*** (tar#Write) sorry, mkdir() doesn't work on your system" | echohl None
let &report= repkeep
" call Dret("tar#Write")
@@ -375,6 +420,7 @@ fun! tar#Write(fname)
exe "cd ".fnameescape(tmpdir)
catch /^Vim\%((\a\+)\)\=:E344/
redraw!
+" call Decho("***error*** (tar#Write) cannot cd to temporary directory")
echohl Error | echo "***error*** (tar#Write) cannot cd to temporary directory" | Echohl None
let &report= repkeep
" call Dret("tar#Write")
@@ -393,8 +439,6 @@ fun! tar#Write(fname)
let tarfile = substitute(b:tarfile,'tarfile:\(.\{-}\)::.*$','\1','')
let fname = substitute(b:tarfile,'tarfile:.\{-}::\(.*\)$','\1','')
- let gzip_command = s:get_gzip_command(tarfile)
-
" handle compressed archives
if tarfile =~# '\.bz2'
call system("bzip2 -d -- ".shellescape(tarfile,0))
@@ -402,12 +446,12 @@ fun! tar#Write(fname)
let compress= "bzip2 -- ".shellescape(tarfile,0)
" call Decho("compress<".compress.">")
elseif tarfile =~# '\.gz'
- call system(gzip_command . " -d -- ".shellescape(tarfile,0))
+ call system("gzip -d -- ".shellescape(tarfile,0))
let tarfile = substitute(tarfile,'\.gz','','e')
let compress= "gzip -- ".shellescape(tarfile,0)
" call Decho("compress<".compress.">")
elseif tarfile =~# '\.tgz'
- call system(gzip_command . " -d -- ".shellescape(tarfile,0))
+ call system("gzip -d -- ".shellescape(tarfile,0))
let tarfile = substitute(tarfile,'\.tgz','.tar','e')
let compress= "gzip -- ".shellescape(tarfile,0)
let tgz = 1
@@ -417,6 +461,10 @@ fun! tar#Write(fname)
let tarfile = substitute(tarfile,'\.xz','','e')
let compress= "xz -- ".shellescape(tarfile,0)
" call Decho("compress<".compress.">")
+ elseif tarfile =~# '\.zst'
+ call system("zstd --decompress -- ".shellescape(tarfile,0))
+ let tarfile = substitute(tarfile,'\.zst','','e')
+ let compress= "zstd -- ".shellescape(tarfile,0)
elseif tarfile =~# '\.lzma'
call system("lzma -d -- ".shellescape(tarfile,0))
let tarfile = substitute(tarfile,'\.lzma','','e')
@@ -427,6 +475,7 @@ fun! tar#Write(fname)
if v:shell_error != 0
redraw!
+" call Decho("***error*** (tar#Write) sorry, unable to update ".tarfile." with ".fname)
echohl Error | echo "***error*** (tar#Write) sorry, unable to update ".tarfile." with ".fname | echohl None
else
@@ -459,10 +508,11 @@ fun! tar#Write(fname)
endif
" delete old file from tarfile
-" call Decho("system(".g:tar_cmd." --delete -f ".shellescape(tarfile,0)." -- ".shellescape(fname,0).")")
- call system(g:tar_cmd." --delete -f ".shellescape(tarfile,0).tar_secure.shellescape(fname,0))
+" call Decho("system(".g:tar_cmd." ".g:tar_delfile." ".shellescape(tarfile,0)." -- ".shellescape(fname,0).")")
+ call system(g:tar_cmd." ".g:tar_delfile." ".shellescape(tarfile,0).tar_secure.shellescape(fname,0))
if v:shell_error != 0
redraw!
+" call Decho("***error*** (tar#Write) sorry, unable to update ".fnameescape(tarfile)." with ".fnameescape(fname))
echohl Error | echo "***error*** (tar#Write) sorry, unable to update ".fnameescape(tarfile)." with ".fnameescape(fname) | echohl None
else
@@ -471,6 +521,7 @@ fun! tar#Write(fname)
call system(g:tar_cmd." -".g:tar_writeoptions." ".shellescape(tarfile,0).tar_secure.shellescape(fname,0))
if v:shell_error != 0
redraw!
+" call Decho("***error*** (tar#Write) sorry, unable to update ".fnameescape(tarfile)." with ".fnameescape(fname))
echohl Error | echo "***error*** (tar#Write) sorry, unable to update ".fnameescape(tarfile)." with ".fnameescape(fname) | echohl None
elseif exists("compress")
" call Decho("call system(".compress.")")
@@ -486,11 +537,11 @@ fun! tar#Write(fname)
if s:tblfile_{winnr()} =~ '^\a\+://'
" call Decho("handle writing <".tarfile."> across network to <".s:tblfile_{winnr()}.">")
let tblfile= s:tblfile_{winnr()}
- 1split|enew
+ 1split|noswapfile enew
let binkeep= &l:binary
let eikeep = &ei
set binary ei=all
- exe "e! ".fnameescape(tarfile)
+ exe "noswapfile e! ".fnameescape(tarfile)
call netrw#NetWrite(tblfile)
let &ei = eikeep
let &l:binary = binkeep
@@ -524,7 +575,7 @@ fun! tar#Diff(userfname,fname)
" sets up b:tardiff_otherbuf variables so each buffer knows about the other (for closing purposes)
diffthis
wincmd v
- exe "e ".fnameescape(fname)
+ exe "noswapfile e ".fnameescape(fname)
diffthis
else
redraw!
@@ -534,6 +585,141 @@ fun! tar#Diff(userfname,fname)
endfun
" ---------------------------------------------------------------------
+" tar#Extract: extract a file from a (possibly compressed) tar archive {{{2
+fun! tar#Extract()
+" call Dfunc("tar#Extract()")
+
+ let repkeep= &report
+ set report=10
+ let fname= getline(".")
+" call Decho("fname<".fname.">")
+
+ if !exists("g:tar_secure") && fname =~ '^\s*-\|\s\+-'
+ redraw!
+ echohl WarningMsg | echo '***warning*** (tar#BrowseSelect) rejecting tarfile member<'.fname.'> because of embedded "-"'
+" call Dret('tar#BrowseSelect : rejecting tarfile member<'.fname.'> because of embedded "-"')
+ return
+ endif
+
+ " sanity check
+ if fname =~ '^"'
+ let &report= repkeep
+" call Dret("TarBrowseSelect")
+ return
+ endif
+
+ let tarball = expand("%")
+" call Decho("tarball<".tarball.">")
+ let tarbase = substitute(tarball,'\..*$','','')
+" call Decho("tarbase<".tarbase.">")
+
+ let extractcmd= netrw#WinPath(g:tar_extractcmd)
+ if filereadable(tarbase.".tar")
+" call Decho("system(".extractcmd." ".shellescape(tarbase).".tar ".shellescape(fname).")")
+ call system(extractcmd." ".shellescape(tarbase).".tar ".shellescape(fname))
+ if v:shell_error != 0
+ echohl Error | echo "***error*** ".extractcmd." ".tarbase.".tar ".fname.": failed!" | echohl NONE
+" call Decho("***error*** ".extractcmd." ".tarbase.".tar ".fname.": failed!")
+ else
+ echo "***note*** successfully extracted ".fname
+ endif
+
+ elseif filereadable(tarbase.".tgz")
+ let extractcmd= substitute(extractcmd,"-","-z","")
+" call Decho("system(".extractcmd." ".shellescape(tarbase).".tgz ".shellescape(fname).")")
+ call system(extractcmd." ".shellescape(tarbase).".tgz ".shellescape(fname))
+ if v:shell_error != 0
+ echohl Error | echo "***error*** ".extractcmd." ".tarbase.".tgz ".fname.": failed!" | echohl NONE
+" call Decho("***error*** ".extractcmd."t ".tarbase.".tgz ".fname.": failed!")
+ else
+ echo "***note*** successfully extracted ".fname
+ endif
+
+ elseif filereadable(tarbase.".tar.gz")
+ let extractcmd= substitute(extractcmd,"-","-z","")
+" call Decho("system(".extractcmd." ".shellescape(tarbase).".tar.gz ".shellescape(fname).")")
+ call system(extractcmd." ".shellescape(tarbase).".tar.gz ".shellescape(fname))
+ if v:shell_error != 0
+ echohl Error | echo "***error*** ".extractcmd." ".tarbase.".tar.gz ".fname.": failed!" | echohl NONE
+" call Decho("***error*** ".extractcmd." ".tarbase.".tar.gz ".fname.": failed!")
+ else
+ echo "***note*** successfully extracted ".fname
+ endif
+
+ elseif filereadable(tarbase.".tbz")
+ let extractcmd= substitute(extractcmd,"-","-j","")
+" call Decho("system(".extractcmd." ".shellescape(tarbase).".tbz ".shellescape(fname).")")
+ call system(extractcmd." ".shellescape(tarbase).".tbz ".shellescape(fname))
+ if v:shell_error != 0
+ echohl Error | echo "***error*** ".extractcmd."j ".tarbase.".tbz ".fname.": failed!" | echohl NONE
+" call Decho("***error*** ".extractcmd."j ".tarbase.".tbz ".fname.": failed!")
+ else
+ echo "***note*** successfully extracted ".fname
+ endif
+
+ elseif filereadable(tarbase.".tar.bz2")
+ let extractcmd= substitute(extractcmd,"-","-j","")
+" call Decho("system(".extractcmd." ".shellescape(tarbase).".tar.bz2 ".shellescape(fname).")")
+ call system(extractcmd." ".shellescape(tarbase).".tar.bz2 ".shellescape(fname))
+ if v:shell_error != 0
+ echohl Error | echo "***error*** ".extractcmd."j ".tarbase.".tar.bz2 ".fname.": failed!" | echohl NONE
+" call Decho("***error*** ".extractcmd."j ".tarbase.".tar.bz2 ".fname.": failed!")
+ else
+ echo "***note*** successfully extracted ".fname
+ endif
+
+ elseif filereadable(tarbase.".txz")
+ let extractcmd= substitute(extractcmd,"-","-J","")
+" call Decho("system(".extractcmd." ".shellescape(tarbase).".txz ".shellescape(fname).")")
+ call system(extractcmd." ".shellescape(tarbase).".txz ".shellescape(fname))
+ if v:shell_error != 0
+ echohl Error | echo "***error*** ".extractcmd." ".tarbase.".txz ".fname.": failed!" | echohl NONE
+" call Decho("***error*** ".extractcmd." ".tarbase.".txz ".fname.": failed!")
+ else
+ echo "***note*** successfully extracted ".fname
+ endif
+
+ elseif filereadable(tarbase.".tar.xz")
+ let extractcmd= substitute(extractcmd,"-","-J","")
+" call Decho("system(".extractcmd." ".shellescape(tarbase).".tar.xz ".shellescape(fname).")")
+ call system(extractcmd." ".shellescape(tarbase).".tar.xz ".shellescape(fname))
+ if v:shell_error != 0
+ echohl Error | echo "***error*** ".extractcmd." ".tarbase.".tar.xz ".fname.": failed!" | echohl NONE
+" call Decho("***error*** ".extractcmd." ".tarbase.".tar.xz ".fname.": failed!")
+ else
+ echo "***note*** successfully extracted ".fname
+ endif
+
+ elseif filereadable(tarbase.".tzs")
+ let extractcmd= substitute(extractcmd,"-","--zstd","")
+" call Decho("system(".extractcmd." ".shellescape(tarbase).".tzs ".shellescape(fname).")")
+ call system(extractcmd." ".shellescape(tarbase).".txz ".shellescape(fname))
+ if v:shell_error != 0
+ echohl Error | echo "***error*** ".extractcmd." ".tarbase.".tzs ".fname.": failed!" | echohl NONE
+" call Decho("***error*** ".extractcmd." ".tarbase.".tzs ".fname.": failed!")
+ else
+ echo "***note*** successfully extracted ".fname
+ endif
+
+ elseif filereadable(tarbase.".tar.zst")
+ let extractcmd= substitute(extractcmd,"-","--zstd","")
+" call Decho("system(".extractcmd." ".shellescape(tarbase).".tar.zst ".shellescape(fname).")")
+ call system(extractcmd." ".shellescape(tarbase).".tar.xz ".shellescape(fname))
+ if v:shell_error != 0
+ echohl Error | echo "***error*** ".extractcmd." ".tarbase.".tar.zst ".fname.": failed!" | echohl NONE
+" call Decho("***error*** ".extractcmd." ".tarbase.".tar.zst ".fname.": failed!")
+ else
+ echo "***note*** successfully extracted ".fname
+ endif
+ endif
+
+ " restore option
+ let &report= repkeep
+
+" call Dret("tar#Extract")
+endfun
+
+" ---------------------------------------------------------------------
" s:Rmdir: {{{2
fun! s:Rmdir(fname)
" call Dfunc("Rmdir(fname<".a:fname.">)")
@@ -587,10 +773,7 @@ fun! tar#Vimuntar(...)
" if necessary, decompress the tarball; then, extract it
if tartail =~ '\.tgz'
- let gzip_command = s:get_gzip_command(tarfile)
- if executable(gzip_command)
- silent exe "!" . gzip_command . " -d ".shellescape(tartail)
- elseif executable("gunzip")
+ if executable("gunzip")
silent exe "!gunzip ".shellescape(tartail)
elseif executable("gzip")
silent exe "!gzip -d ".shellescape(tartail)
@@ -628,28 +811,6 @@ fun! tar#Vimuntar(...)
" call Dret("tar#Vimuntar")
endfun
-func s:get_gzip_command(file)
- " Try using the "file" command to get the actual compression type, since
- " there is no standard way for the naming: ".tgz", ".tbz", ".txz", etc.
- " If the "file" command doesn't work fall back to just using the file name.
- if a:file =~# 'z$'
- let filetype = system('file ' . a:file)
- if filetype =~ 'bzip2 compressed' && executable('bzip2')
- return 'bzip2'
- endif
- if filetype =~ 'XZ compressed' && executable('xz')
- return 'xz'
- endif
- endif
- if a:file =~# 'bz2$'
- return 'bzip2'
- endif
- if a:file =~# 'xz$'
- return 'xz'
- endif
- return 'gzip'
-endfunc
-
" =====================================================================
" Modelines And Restoration: {{{1
let &cpo= s:keepcpo
diff --git a/runtime/doc/api.txt b/runtime/doc/api.txt
index dd3469372e..bd34411065 100644
--- a/runtime/doc/api.txt
+++ b/runtime/doc/api.txt
@@ -1148,6 +1148,18 @@ nvim_load_context({dict}) *nvim_load_context()*
Parameters: ~
{dict} |Context| map.
+nvim_notify({msg}, {log_level}, {opts}) *nvim_notify()*
+ Notify the user with a message
+
+ Relays the call to vim.notify . By default forwards your
+ message in the echo area but can be overriden to trigger
+ desktop notifications.
+
+ Parameters: ~
+ {msg} Message to display to the user
+ {log_level} The log level
+ {opts} Reserved for future use.
+
nvim_open_win({buffer}, {enter}, {config}) *nvim_open_win()*
Open a new window.
@@ -1403,9 +1415,9 @@ nvim_put({lines}, {type}, {after}, {follow}) *nvim_put()*
• "c" |charwise| mode
• "l" |linewise| mode
• "" guess by contents, see |setreg()|
- {after} Insert after cursor (like |p|), or before (like
+ {after} If true insert after cursor (like |p|), or before (like
|P|).
- {follow} Place cursor at end of inserted text.
+ {follow} If true place cursor at end of inserted text.
*nvim_replace_termcodes()*
nvim_replace_termcodes({str}, {from_part}, {do_lt}, {special})
@@ -1800,6 +1812,25 @@ nvim_buf_attach({buffer}, {send_buffer}, {opts}) *nvim_buf_attach()*
• deleted_codeunits (if `utf_sizes` is
true)
+ • on_bytes: lua callback invoked on change.
+ This callback receives more granular
+ information about the change compared to
+ on_lines. Return`true`to detach. Args:
+ • the string "bytes"
+ • buffer handle
+ • b:changedtick
+ • start row of the changed text
+ (zero-indexed)
+ • start column of the changed text
+ • byte offset of the changed text (from
+ the start of the buffer)
+ • old end row of the changed text
+ • old end column of the changed text
+ • old end byte length of the changed text
+ • new end row of the changed text
+ • new end column of the changed text
+ • new end byte length of the changed text
+
• on_changedtick: Lua callback invoked on
changedtick increment without text
change. Args:
@@ -1812,6 +1843,12 @@ nvim_buf_attach({buffer}, {send_buffer}, {opts}) *nvim_buf_attach()*
• the string "detach"
• buffer handle
+ • on_reload: Lua callback invoked on
+ reload. The entire buffer content should
+ be considered changed. Args:
+ • the string "detach"
+ • buffer handle
+
• utf_sizes: include UTF-32 and UTF-16 size
of the replaced region, as args to
`on_lines` .
@@ -2158,6 +2195,13 @@ nvim_buf_set_extmark({buffer}, {ns_id}, {line}, {col}, {opts})
• hl_group : name of the highlight group used to
highlight this mark.
• virt_text : virtual text to link to this mark.
+ • virt_text_pos : positioning of virtual text.
+ Possible values:
+ • "eol": right after eol character (default)
+ • "overlay": display over the specified
+ column, without shifting the underlying
+ text.
+
• ephemeral : for use with
|nvim_set_decoration_provider| callbacks. The
mark will only be used for the current redraw
diff --git a/runtime/doc/editing.txt b/runtime/doc/editing.txt
index ac398ec494..aa964a521f 100644
--- a/runtime/doc/editing.txt
+++ b/runtime/doc/editing.txt
@@ -90,7 +90,7 @@ g CTRL-G Prints the current position of the cursor in five
:buffers
:files
:ls List all the currently known file names. See
- 'windows.txt' |:files| |:buffers| |:ls|.
+ |windows.txt| |:files| |:buffers| |:ls|.
Vim will remember the full path name of a file name that you enter. In most
cases when the file name is displayed only the name you typed is shown, but
@@ -1190,7 +1190,7 @@ The syntax is best shown via some examples: >
< Open the browser in the C:/bar directory, with the current
buffer filename as default, and save the buffer under the
filename chosen.
-Also see the |'browsedir'| option.
+Also see the 'browsedir' option.
For versions of Vim where browsing is not supported, the command is executed
unmodified.
diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt
index b96fc4ac01..be7c026f5a 100644
--- a/runtime/doc/eval.txt
+++ b/runtime/doc/eval.txt
@@ -1541,7 +1541,10 @@ v:dying Normally zero. When a deadly signal is caught it's set to
VimLeave autocommands will not be executed.
*v:exiting* *exiting-variable*
-v:exiting Exit code, or |v:null| if not exiting. |VimLeave|
+v:exiting Exit code, or |v:null| before invoking the |VimLeavePre|
+ and |VimLeave| autocmds. See |:q|, |:x| and |:cquit|.
+ Example: >
+ :au VimLeave * echo "Exit value is " .. v:exiting
*v:echospace* *echospace-variable*
v:echospace Number of screen cells that can be used for an `:echo` message
@@ -2074,6 +2077,8 @@ changenr() Number current change number
chanclose({id}[, {stream}]) Number Closes a channel or one of its streams
chansend({id}, {data}) Number Writes {data} to channel
char2nr({expr}[, {utf8}]) Number ASCII/UTF8 value of first char in {expr}
+charidx({string}, {idx} [, {countcc}])
+ Number char index of byte {idx} in {string}
cindent({lnum}) Number C indent for line {lnum}
clearmatches([{win}]) none clear all matches
col({expr}) Number column nr of cursor or mark
@@ -3024,6 +3029,29 @@ char2nr({expr} [, {utf8}]) *char2nr()*
A combining character is a separate character.
|nr2char()| does the opposite.
+ *charidx()*
+charidx({string}, {idx} [, {countcc}])
+ Return the character index of the byte at {idx} in {string}.
+ The index of the first character is zero.
+ If there are no multibyte characters the returned value is
+ equal to {idx}.
+ When {countcc} is omitted or zero, then composing characters
+ are not counted separately, their byte length is added to the
+ preceding base character.
+ When {countcc} is set to 1, then composing characters are
+ counted as separate characters.
+ Returns -1 if the arguments are invalid or if {idx} is greater
+ than the index of the last byte in {string}. An error is
+ given if the first argument is not a string, the second
+ argument is not a number or when the third argument is present
+ and is not zero or one.
+ See |byteidx()| and |byteidxcomp()| for getting the byte index
+ from the character index.
+ Examples: >
+ echo charidx('áb́ć', 3) returns 1
+ echo charidx('áb́ć', 6, 1) returns 4
+ echo charidx('áb́ć', 16) returns -1
+
cindent({lnum}) *cindent()*
Get the amount of indent for line {lnum} according the C
indenting rules, as with 'cindent'.
@@ -5097,6 +5125,8 @@ has({feature}) Returns 1 if {feature} is supported, 0 otherwise. The
iconv Can use |iconv()| for conversion.
+shellslash Can use backslashes in filenames (Windows)
clipboard |clipboard| provider is available.
+ fname_case Case in file names matters (for Darwin and MS-Windows
+ this is not present).
mac MacOS system.
nvim This is Nvim.
python2 Legacy Vim |python2| interface. |has-python|
@@ -9776,15 +9806,49 @@ change their contents. Thus you can pass a |List| to a function and have the
function add an item to it. If you want to make sure the function cannot
change a |List| or |Dictionary| use |:lockvar|.
-When not using "...", the number of arguments in a function call must be equal
-to the number of named arguments. When using "...", the number of arguments
-may be larger.
-
It is also possible to define a function without any arguments. You must
still supply the () then.
It is allowed to define another function inside a function body.
+ *optional-function-argument*
+You can provide default values for positional named arguments. This makes
+them optional for function calls. When a positional argument is not
+specified at a call, the default expression is used to initialize it.
+This only works for functions declared with |function|, not for lambda
+expressions |expr-lambda|.
+
+Example: >
+ function Something(key, value = 10)
+ echo a:key .. ": " .. a:value
+ endfunction
+ call Something('empty') "empty: 10"
+ call Something('key', 20) "key: 20"
+
+The argument default expressions are evaluated at the time of the function
+call, not definition. Thus it is possible to use an expression which is
+invalid the moment the function is defined. The expressions are also only
+evaluated when arguments are not specified during a call.
+
+ *E989*
+Optional arguments with default expressions must occur after any mandatory
+arguments. You can use "..." after all optional named arguments.
+
+It is possible for later argument defaults to refer to prior arguments,
+but not the other way around. They must be prefixed with "a:", as with all
+arguments.
+
+Example that works: >
+ :function Okay(mandatory, optional = a:mandatory)
+ :endfunction
+Example that does NOT work: >
+ :function NoGood(first = a:second, second = 10)
+ :endfunction
+<
+When not using "...", the number of arguments in a function call must be equal
+to the number of mandatory named arguments. When using "...", the number of
+arguments may be larger.
+
*local-variables*
Inside a function local variables can be used. These will disappear when the
function returns. Global variables need to be accessed with "g:".
diff --git a/runtime/doc/insert.txt b/runtime/doc/insert.txt
index c4b93a2a27..6902ed5fd4 100644
--- a/runtime/doc/insert.txt
+++ b/runtime/doc/insert.txt
@@ -287,8 +287,7 @@ character is written at the end of each line. Thus if you want to insert a
*i_CTRL-X* *insert_expand*
CTRL-X enters a sub-mode where several commands can be used. Most of these
-commands do keyword completion; see |ins-completion|. These are not available
-when Vim was compiled without the |+insert_expand| feature.
+commands do keyword completion; see |ins-completion|.
Two commands can be used to scroll the window up or down, without exiting
insert mode:
@@ -592,9 +591,6 @@ In Insert and Replace mode, there are several commands to complete part of a
keyword or line that has been typed. This is useful if you are using
complicated keywords (e.g., function names with capitals and underscores).
-These commands are not available when the |+insert_expand| feature was
-disabled at compile time.
-
Completion can be done for:
1. Whole lines |i_CTRL-X_CTRL-L|
diff --git a/runtime/doc/lsp.txt b/runtime/doc/lsp.txt
index 06666c3a27..d2d88fb9ba 100644
--- a/runtime/doc/lsp.txt
+++ b/runtime/doc/lsp.txt
@@ -397,6 +397,11 @@ LSP HIGHLIGHT *lsp-highlight*
Reference Highlights:
+Highlight groups that are meant to be used by |vim.lsp.buf.document_highlight()|.
+
+You can see more about the differences in types here:
+https://microsoft.github.io/language-server-protocol/specification#textDocument_documentHighlight
+
*hl-LspReferenceText*
LspReferenceText used for highlighting "text" references
*hl-LspReferenceRead*
@@ -932,15 +937,21 @@ definition() *vim.lsp.buf.definition()*
Jumps to the definition of the symbol under the cursor.
document_highlight() *vim.lsp.buf.document_highlight()*
- Send request to server to resolve document highlights for the
- current text document position. This request can be associated
- to key mapping or to events such as `CursorHold` , eg:
+ Send request to the server to resolve document highlights for
+ the current text document position. This request can be
+ triggered by a key mapping or by events such as `CursorHold` ,
+ eg:
>
vim.api.nvim_command [[autocmd CursorHold <buffer> lua vim.lsp.buf.document_highlight()]]
vim.api.nvim_command [[autocmd CursorHoldI <buffer> lua vim.lsp.buf.document_highlight()]]
vim.api.nvim_command [[autocmd CursorMoved <buffer> lua vim.lsp.buf.clear_references()]]
<
+ Note: Usage of |vim.lsp.buf.document_highlight()| requires the
+ following highlight groups to be defined or you won't be able
+ to see the actual highlights. |LspReferenceText|
+ |LspReferenceRead| |LspReferenceWrite|
+
document_symbol() *vim.lsp.buf.document_symbol()*
Lists all symbols in the current buffer in the quickfix
window.
@@ -1307,6 +1318,17 @@ on_publish_diagnostics({_}, {_}, {params}, {client_id}, {_}, {config})
• Update diagnostics in InsertMode or wait
until InsertLeave
+reset({client_id}, {buffer_client_map}) *vim.lsp.diagnostic.reset()*
+ Clear diagnotics and diagnostic cache
+
+ Handles saving diagnostics from multiple clients in the same
+ buffer.
+
+ Parameters: ~
+ {client_id} number
+ {buffer_client_map} table map of buffers to active
+ clients
+
save({diagnostics}, {bufnr}, {client_id}) *vim.lsp.diagnostic.save()*
Save diagnostics to the current buffer.
diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt
index ce3788e0fc..c4d5df84cf 100644
--- a/runtime/doc/options.txt
+++ b/runtime/doc/options.txt
@@ -4090,8 +4090,6 @@ A jump table for the options with a short description can be found at |Q_op|.
In the "popup" model the right mouse button produces a pop-up menu.
You need to define this first, see |popup-menu|.
- In a terminal the popup menu works if Vim is compiled with the
- |+insert_expand| option.
Note that you can further refine the meaning of buttons with mappings.
See |mouse-overview|. But mappings are NOT used for modeless selection.
@@ -4858,7 +4856,9 @@ A jump table for the options with a short description can be found at |Q_op|.
local to window
Number of lines to scroll with CTRL-U and CTRL-D commands. Will be
set to half the number of lines in the window when the window size
- changes. If you give a count to the CTRL-U or CTRL-D command it will
+ changes. This may happen when enabling the |status-line| or
+ 'tabline' option after setting the 'scroll' option.
+ If you give a count to the CTRL-U or CTRL-D command it will
be used as the new value for 'scroll'. Reset to half the window
height with ":set scroll=0".
diff --git a/runtime/doc/pi_netrw.txt b/runtime/doc/pi_netrw.txt
index d5dfd37fab..7312ab721b 100644
--- a/runtime/doc/pi_netrw.txt
+++ b/runtime/doc/pi_netrw.txt
@@ -2744,9 +2744,8 @@ your browsing preferences. (see also: |netrw-settings|)
*g:netrw_home* The home directory for where bookmarks and
history are saved (as .netrwbook and
.netrwhist).
- Netrw uses |expand()|on the string.
- default: the first directory on the
- |'runtimepath'|
+ Netrw uses |expand()| on the string.
+ default: stdpath('data') (see |stdpath()|)
*g:netrw_keepdir* =1 (default) keep current directory immune from
the browsing directory.
diff --git a/runtime/doc/pi_tar.txt b/runtime/doc/pi_tar.txt
index 59b318b7fd..c6c0596ea0 100644
--- a/runtime/doc/pi_tar.txt
+++ b/runtime/doc/pi_tar.txt
@@ -1,12 +1,12 @@
-*pi_tar.txt* Nvim
+*pi_tar.txt* For Vim version 8.2. Last change: 2020 Jan 07
+====================+
| Tar File Interface |
+====================+
-Author: Charles E. Campbell <NdrOchip@ScampbellPfamily.AbizM>
+Author: Charles E. Campbell <NcampObell@SdrPchip.AorgM-NOSPAM>
(remove NOSPAM from Campbell's email first)
-Copyright 2005-2012: *tar-copyright*
+Copyright 2005-2017: *tar-copyright*
The VIM LICENSE (see |copyright|) applies to the files in this
package, including tarPlugin.vim, tar.vim, and pi_tar.txt. Like
anything else that's except use "tar.vim" instead of "VIM". Like
@@ -104,48 +104,67 @@ Copyright 2005-2012: *tar-copyright*
==============================================================================
4. History *tar-history*
-
- v28 Jun 23, 2011 * a few more decompression options (tbz tb2 txz)
- v27 May 31, 2011 * moved cygwin detection before g:tar_copycmd handling
- * inserted additional |:keepj| modifiers
- * changed silent to sil! (|:silent|)
- v26 Aug 09, 2010 * uses buffer-local instead of window variables to hold
- tarfile name
- * inserted keepj before 0d to protect jump list
- v25 Jun 19, 2010 * (Jan Steffens) added support for xz compression
- v24 Apr 07, 2009 * :Untarvim command implemented
- Sep 28, 2009 * Added lzma support
- v22 Aug 08, 2008 * security fixes
- v16 Jun 06, 2008 * tarfile:: used instead of tarfile: when editing files
- inside tarballs. Fixes a problem with tarballs called
- things like c:\abc.tar. (tnx to Bill McCarthy)
- v14 May 09, 2008 * arno caught a security bug
- May 28, 2008 * various security improvements. Now requires patch 299
- which provides the fnameescape() function
- May 30, 2008 * allows one to view *.gz and *.bz2 files that are in
- *.tar files.
- v12 Sep 07, 2007 * &shq now used if not the empty string for g:tar_shq
- v10 May 02, 2006 * now using "redraw then echo" to show messages, instead
- of "echo and prompt user"
- v9 May 02, 2006 * improved detection of masquerading as tar file
- v8 May 02, 2006 * allows editing of files that merely masquerade as tar
- files
- v7 Mar 22, 2006 * work on making tar plugin work across network
- Mar 27, 2006 * g:tar_cmd now available for users to change the name
- of the tar program to be used. By default, of course,
- it's "tar".
- v6 Dec 21, 2005 * writing to files not in directories caused problems -
- fixed (pointed out by Christian Robinson)
- v5 Nov 22, 2005 * report option workaround installed
- v3 Sep 16, 2005 * handles writing files in an archive back to the
- archive
- Oct 18, 2005 * <amatch> used instead of <afile> in autocmds
- Oct 18, 2005 * handles writing to compressed archives
- Nov 03, 2005 * handles writing tarfiles across a network using
- netrw#NetWrite()
- v2 * converted to use Vim7's new autoload feature by
- Bram Moolenaar
- v1 (original) * Michael Toren (see http://michael.toren.net/code/)
+ v31 Apr 02, 2017 * (klartext) reported that browsing encrypted
+ files in a zip archive created unencrypted
+ swap files. I am applying a similar fix
+ used on zip.vim to tar.vim: new buffers
+ are opened with |:noswapfile|.
+ May 16, 2017 * When the mouse option isn't empty, the
+ leftmouse can be used to select a file
+ in the tar-file listing.
+ v30 Apr 22, 2014 * .tgz files are ambiguous: they may have been
+ compressed with either gzip or bzip2. Tar.vim
+ disambiguates by using unix's "file" command.
+ Feb 18, 2016 * Changed =~ to =~# where appropriate
+ Feb 18, 2017 * Now also permits xz decompression
+ v28 Jun 23, 2011 * a few more decompression options (tbz tb2 txz)
+ v27 May 31, 2011 * moved cygwin detection before g:tar_copycmd
+ handling
+ * inserted additional |:keepj| modifiers
+ * changed silent to sil! (|:silent|)
+ v26 Aug 09, 2010 * uses buffer-local instead of window variables
+ to hold tarfile name
+ * inserted keepj before 0d to protect jump list
+ v25 Jun 19, 2010 * (Jan Steffens) added support for xz
+ compression
+ v24 Apr 07, 2009 * :Untarvim command implemented
+ Sep 28, 2009 * Added lzma support
+ v22 Aug 08, 2008 * security fixes
+ v16 Jun 06, 2008 * tarfile:: used instead of tarfile: when
+ editing files inside tarballs. Fixes a
+ problem with tarballs called things like
+ c:\abc.tar. (tnx to Bill McCarthy)
+ v14 May 09, 2008 * arno caught a security bug
+ May 28, 2008 * various security improvements. Now requires
+ patch 299 which provides the fnameescape()
+ function
+ May 30, 2008 * allows one to view *.gz and *.bz2 files that
+ are in *.tar files.
+ v12 Sep 07, 2007 * &shq now used if not the empty string for
+ g:tar_shq
+ v10 May 02, 2006 * now using "redraw then echo" to show messages,
+ instead of "echo and prompt user"
+ v9 May 02, 2006 * improved detection of masquerading as tar file
+ v8 May 02, 2006 * allows editing of files that merely masquerade
+ as tar files
+ v7 Mar 22, 2006 * work on making tar plugin work across network
+ Mar 27, 2006 * g:tar_cmd now available for users to change
+ the name of the tar program to be used. By
+ default, of course, it's "tar".
+ v6 Dec 21, 2005 * writing to files not in directories caused
+ problems - fixed (pointed out by
+ Christian Robinson)
+ v5 Nov 22, 2005 * report option workaround installed
+ v3 Sep 16, 2005 * handles writing files in an archive back to
+ the archive
+ Oct 18, 2005 * <amatch> used instead of <afile> in autocmds
+ Oct 18, 2005 * handles writing to compressed archives
+ Nov 03, 2005 * handles writing tarfiles across a network
+ using netrw#NetWrite()
+ v2 * converted to use Vim7's new autoload feature
+ by Bram Moolenaar
+ v1 (original) * Michael Toren
+ (see http://michael.toren.net/code/)
==============================================================================
vim:tw=78:ts=8:noet:ft=help
diff --git a/runtime/doc/starting.txt b/runtime/doc/starting.txt
index 4a99aa47bf..d3647246fa 100644
--- a/runtime/doc/starting.txt
+++ b/runtime/doc/starting.txt
@@ -106,8 +106,6 @@ argument.
This can be used to find out where time is spent while loading
your |config|, plugins and opening the first file.
When {fname} already exists new messages are appended.
- (Only available when compiled with the |+startuptime|
- feature).
*-+*
+[num] The cursor will be positioned on line "num" for the first
diff --git a/runtime/doc/syntax.txt b/runtime/doc/syntax.txt
index 7da886dabd..b45e9ed450 100644
--- a/runtime/doc/syntax.txt
+++ b/runtime/doc/syntax.txt
@@ -1715,7 +1715,7 @@ There are several html preprocessor languages out there. html.vim has been
written such that it should be trivial to include it. To do so add the
following two lines to the syntax coloring file for that language
(the example comes from the asp.vim file):
-
+>
runtime! syntax/html.vim
syn cluster htmlPreproc add=asp
diff --git a/runtime/doc/usr_41.txt b/runtime/doc/usr_41.txt
index e92e464c6a..63c899da0c 100644
--- a/runtime/doc/usr_41.txt
+++ b/runtime/doc/usr_41.txt
@@ -613,6 +613,7 @@ String manipulation: *string-functions*
iconv() convert text from one encoding to another
byteidx() byte index of a character in a string
byteidxcomp() like byteidx() but count composing characters
+ charidx() character index of a byte in a string
repeat() repeat a string multiple times
eval() evaluate a string expression
execute() execute an Ex command and get the output
diff --git a/runtime/filetype.vim b/runtime/filetype.vim
index 53fd66c4df..6a13e67ac5 100644
--- a/runtime/filetype.vim
+++ b/runtime/filetype.vim
@@ -212,6 +212,9 @@ au BufNewFile,BufRead *.bc setf bc
" BDF font
au BufNewFile,BufRead *.bdf setf bdf
+" Beancount
+au BufNewFile,BufRead *.beancount setf beancount
+
" BibTeX bibliography database file
au BufNewFile,BufRead *.bib setf bib
@@ -1491,6 +1494,9 @@ au BufNewFile,BufRead *.sdl,*.pr setf sdl
" sed
au BufNewFile,BufRead *.sed setf sed
+" svelte
+au BufNewFile,BufRead *.svelte setf svelte
+
" Sieve (RFC 3028, 5228)
au BufNewFile,BufRead *.siv,*.sieve setf sieve
diff --git a/runtime/indent/tcl.vim b/runtime/indent/tcl.vim
index d77081841d..eafb8dd568 100644
--- a/runtime/indent/tcl.vim
+++ b/runtime/indent/tcl.vim
@@ -1,8 +1,8 @@
" Vim indent file
" Language: Tcl
-" Previous Maintainer: Nikolai Weibull <now@bitwi.se>
" Latest Update: Chris Heithoff <chrisheithoff@gmail.com>
-" Latest Revision: 2018-12-05
+" Previous Maintainer: Nikolai Weibull <now@bitwi.se>
+" Latest Revision: 2018-12-05
if exists("b:did_indent")
finish
diff --git a/runtime/lua/vim/lsp.lua b/runtime/lua/vim/lsp.lua
index a6f118abde..841c365cbe 100644
--- a/runtime/lua/vim/lsp.lua
+++ b/runtime/lua/vim/lsp.lua
@@ -16,10 +16,7 @@ local validate = vim.validate
local lsp = {
protocol = protocol;
- -- TODO(tjdevries): Add in the warning that `callbacks` is no longer supported.
- -- util.warn_once("vim.lsp.callbacks is deprecated. Use vim.lsp.handlers instead.")
handlers = default_handlers;
- callbacks = default_handlers;
buf = require'vim.lsp.buf';
diagnostic = require'vim.lsp.diagnostic';
@@ -219,8 +216,6 @@ local function validate_client_config(config)
}
validate {
root_dir = { config.root_dir, is_dir, "directory" };
- -- TODO(remove-callbacks)
- callbacks = { config.callbacks, "t", true };
handlers = { config.handlers, "t", true };
capabilities = { config.capabilities, "t", true };
cmd_cwd = { config.cmd_cwd, optional_validator(is_dir), "directory" };
@@ -235,13 +230,6 @@ local function validate_client_config(config)
flags = { config.flags, "t", true };
}
- -- TODO(remove-callbacks)
- if config.handlers and config.callbacks then
- error(debug.traceback(
- "Unable to configure LSP with both 'config.handlers' and 'config.callbacks'. Use 'config.handlers' exclusively."
- ))
- end
-
local cmd, cmd_args = lsp._cmd_parts(config.cmd)
local offset_encoding = valid_encodings.UTF16
if config.offset_encoding then
@@ -473,8 +461,7 @@ function lsp.start_client(config)
local client_id = next_client_id()
- -- TODO(remove-callbacks)
- local handlers = config.handlers or config.callbacks or {}
+ local handlers = config.handlers or {}
local name = config.name or tostring(client_id)
local log_prefix = string.format("LSP[%s]", name)
@@ -548,19 +535,20 @@ function lsp.start_client(config)
function dispatch.on_exit(code, signal)
active_clients[client_id] = nil
uninitialized_clients[client_id] = nil
- local active_buffers = {}
- for bufnr, client_ids in pairs(all_buffer_active_clients) do
- if client_ids[client_id] then
- table.insert(active_buffers, bufnr)
- end
+
+ lsp.diagnostic.reset(client_id, all_buffer_active_clients)
+ all_client_active_buffers[client_id] = nil
+ for _, client_ids in pairs(all_buffer_active_clients) do
client_ids[client_id] = nil
end
- -- Buffer level cleanup
- vim.schedule(function()
- for _, bufnr in ipairs(active_buffers) do
- lsp.diagnostic.clear(bufnr)
- end
- end)
+
+ if code ~= 0 or (signal ~= 0 and signal ~= 15) then
+ local msg = string.format("Client %s quit with exit code %s and signal %s", client_id, code, signal)
+ vim.schedule(function()
+ vim.notify(msg, vim.log.levels.WARN)
+ end)
+ end
+
if config.on_exit then
pcall(config.on_exit, code, signal, client_id)
end
@@ -579,8 +567,6 @@ function lsp.start_client(config)
offset_encoding = offset_encoding;
config = config;
- -- TODO(remove-callbacks)
- callbacks = handlers;
handlers = handlers;
-- for $/progress report
messages = { name = name, messages = {}, progress = {}, status = {} }
@@ -751,6 +737,13 @@ function lsp.start_client(config)
---
--@param force (bool, optional)
function client.stop(force)
+
+ lsp.diagnostic.reset(client_id, all_buffer_active_clients)
+ all_client_active_buffers[client_id] = nil
+ for _, client_ids in pairs(all_buffer_active_clients) do
+ client_ids[client_id] = nil
+ end
+
local handle = rpc.handle
if handle:is_closing() then
return
@@ -1016,23 +1009,12 @@ 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/buf.lua b/runtime/lua/vim/lsp/buf.lua
index 00219b6d98..31116985e2 100644
--- a/runtime/lua/vim/lsp/buf.lua
+++ b/runtime/lua/vim/lsp/buf.lua
@@ -310,15 +310,21 @@ function M.workspace_symbol(query)
request('workspace/symbol', params)
end
---- Send request to server to resolve document highlights for the
---- current text document position. This request can be associated
---- to key mapping or to events such as `CursorHold`, eg:
+--- Send request to the server to resolve document highlights for the current
+--- text document position. This request can be triggered by a key mapping or
+--- by events such as `CursorHold`, eg:
---
--- <pre>
--- vim.api.nvim_command [[autocmd CursorHold <buffer> lua vim.lsp.buf.document_highlight()]]
--- vim.api.nvim_command [[autocmd CursorHoldI <buffer> lua vim.lsp.buf.document_highlight()]]
--- vim.api.nvim_command [[autocmd CursorMoved <buffer> lua vim.lsp.buf.clear_references()]]
--- </pre>
+---
+--- Note: Usage of |vim.lsp.buf.document_highlight()| requires the following highlight groups
+--- to be defined or you won't be able to see the actual highlights.
+--- |LspReferenceText|
+--- |LspReferenceRead|
+--- |LspReferenceWrite|
function M.document_highlight()
local params = util.make_position_params()
request('textDocument/documentHighlight', params)
diff --git a/runtime/lua/vim/lsp/callbacks.lua b/runtime/lua/vim/lsp/callbacks.lua
deleted file mode 100644
index 1da92b900d..0000000000
--- a/runtime/lua/vim/lsp/callbacks.lua
+++ /dev/null
@@ -1,4 +0,0 @@
-local util = require 'vim.lsp.util'
-
-util._warn_once("require('vim.lsp.callbacks') is deprecated. Use vim.lsp.handlers instead.")
-return require('vim.lsp.handlers')
diff --git a/runtime/lua/vim/lsp/diagnostic.lua b/runtime/lua/vim/lsp/diagnostic.lua
index a625098bab..a1f24706c0 100644
--- a/runtime/lua/vim/lsp/diagnostic.lua
+++ b/runtime/lua/vim/lsp/diagnostic.lua
@@ -264,10 +264,14 @@ local function set_diagnostic_cache(diagnostics, bufnr, client_id)
-- The diagnostic's severity. Can be omitted. If omitted it is up to the
-- client to interpret diagnostics as error, warning, info or hint.
-- TODO: Replace this with server-specific heuristics to infer severity.
+ local buf_line_count = vim.api.nvim_buf_line_count(bufnr)
for _, diagnostic in ipairs(diagnostics) do
if diagnostic.severity == nil then
diagnostic.severity = DiagnosticSeverity.Error
end
+ -- Account for servers that place diagnostics on terminating newline
+ local start = diagnostic.range.start
+ start.line = math.min(start.line, buf_line_count - 1)
end
diagnostic_cache[bufnr][client_id] = diagnostics
@@ -1158,6 +1162,24 @@ local loclist_type_map = {
[DiagnosticSeverity.Hint] = 'I',
}
+
+--- Clear diagnotics and diagnostic cache
+---
+--- Handles saving diagnostics from multiple clients in the same buffer.
+---@param client_id number
+---@param buffer_client_map table map of buffers to active clients
+function M.reset(client_id, buffer_client_map)
+ buffer_client_map = vim.deepcopy(buffer_client_map)
+ vim.schedule(function()
+ for bufnr, client_ids in pairs(buffer_client_map) do
+ if client_ids[client_id] then
+ clear_diagnostic_cache(bufnr, client_id)
+ M.clear(bufnr, client_id)
+ end
+ end
+ end)
+end
+
--- Sets the location list
---@param opts table|nil Configuration table. Keys:
--- - {open_loclist}: (boolean, default true)
diff --git a/runtime/lua/vim/lsp/handlers.lua b/runtime/lua/vim/lsp/handlers.lua
index 7eac3febd9..7819bddcb9 100644
--- a/runtime/lua/vim/lsp/handlers.lua
+++ b/runtime/lua/vim/lsp/handlers.lua
@@ -13,7 +13,7 @@ local M = {}
--- Writes to error buffer.
--@param ... (table of strings) Will be concatenated before being written
local function err_message(...)
- api.nvim_err_writeln(table.concat(vim.tbl_flatten{...}))
+ vim.notify(table.concat(vim.tbl_flatten{...}), vim.log.levels.ERROR)
api.nvim_command("redraw")
end
@@ -409,7 +409,7 @@ for k, fn in pairs(M) do
})
if err then
- error(tostring(err))
+ return err_message(tostring(err))
end
return fn(err, method, params, client_id, bufnr, config)
diff --git a/runtime/lua/vim/lsp/log.lua b/runtime/lua/vim/lsp/log.lua
index 4e8d2d4202..331e980e67 100644
--- a/runtime/lua/vim/lsp/log.lua
+++ b/runtime/lua/vim/lsp/log.lua
@@ -32,6 +32,8 @@ do
vim.fn.mkdir(vim.fn.stdpath('cache'), "p")
local logfile = assert(io.open(logfilename, "a+"))
+ -- Start message for logging
+ logfile:write(string.format("[ START ] %s ] LSP logging initiated\n", os.date(log_date_format)))
for level, levelnr in pairs(log.levels) do
-- Also export the log level on the root object.
log[level] = levelnr
@@ -68,8 +70,6 @@ do
logfile:flush()
end
end
- -- Add some space to make it easier to distinguish different neovim runs.
- logfile:write("\n")
end
-- This is put here on purpose after the loop above so that it doesn't
diff --git a/runtime/lua/vim/lsp/protocol.lua b/runtime/lua/vim/lsp/protocol.lua
index 3e111c154a..388f65c180 100644
--- a/runtime/lua/vim/lsp/protocol.lua
+++ b/runtime/lua/vim/lsp/protocol.lua
@@ -938,7 +938,7 @@ function protocol.resolve_capabilities(server_capabilities)
text_document_did_change = textDocumentSync;
text_document_will_save = false;
text_document_will_save_wait_until = false;
- text_document_save = false;
+ text_document_save = true;
text_document_save_include_text = false;
}
elseif type(textDocumentSync) == 'table' then
diff --git a/runtime/lua/vim/lsp/rpc.lua b/runtime/lua/vim/lsp/rpc.lua
index 90f51dfc5a..4e2dd7c8e8 100644
--- a/runtime/lua/vim/lsp/rpc.lua
+++ b/runtime/lua/vim/lsp/rpc.lua
@@ -376,6 +376,9 @@ local function start(cmd, cmd_args, dispatchers, extra_spawn_params)
spawn_params.env = env_merge(extra_spawn_params.env)
end
handle, pid = uv.spawn(cmd, spawn_params, onexit)
+ if handle == nil then
+ error(string.format("start `%s` failed: %s", cmd, pid))
+ end
end
--@private
@@ -386,7 +389,7 @@ local function start(cmd, cmd_args, dispatchers, extra_spawn_params)
--@returns true if the payload could be scheduled, false if the main event-loop is in the process of closing.
local function encode_and_send(payload)
local _ = log.debug() and log.debug("rpc.send.payload", payload)
- if handle:is_closing() then return false end
+ if handle == nil or handle:is_closing() then return false end
-- TODO(ashkan) remove this once we have a Lua json_encode
schedule(function()
local encoded = assert(json_encode(payload))
diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua
index 00bdeecef3..6fb9f09c99 100644
--- a/runtime/lua/vim/lsp/util.lua
+++ b/runtime/lua/vim/lsp/util.lua
@@ -18,14 +18,6 @@ end
local M = {}
--- TODO(remove-callbacks)
-M.diagnostics_by_buf = setmetatable({}, {
- __index = function(_, bufnr)
- warn_once("diagnostics_by_buf is deprecated. Use 'vim.lsp.diagnostic.get'")
- return vim.lsp.diagnostic.get(bufnr)
- end
-})
-
--@private
local function split_lines(value)
return split(value, '\n', true)
@@ -211,7 +203,7 @@ function M.apply_text_edits(text_edits, bufnr)
local lines = api.nvim_buf_get_lines(bufnr, start_line, finish_line + 1, false)
local fix_eol = api.nvim_buf_get_option(bufnr, 'fixeol')
local set_eol = fix_eol and api.nvim_buf_line_count(bufnr) <= finish_line + 1
- if set_eol and #lines[#lines] ~= 0 then
+ if set_eol and (#lines == 0 or #lines[#lines] ~= 0) then
table.insert(lines, '')
end
@@ -1027,78 +1019,6 @@ function M.open_floating_preview(contents, filetype, opts)
return floating_bufnr, floating_winnr
end
--- TODO(remove-callbacks)
-do
- --@deprecated
- function M.get_severity_highlight_name(severity)
- warn_once("vim.lsp.util.get_severity_highlight_name is deprecated.")
- return vim.lsp.diagnostic._get_severity_highlight_name(severity)
- end
-
- --@deprecated
- function M.buf_clear_diagnostics(bufnr, client_id)
- warn_once("buf_clear_diagnostics is deprecated. Use vim.lsp.diagnostic.clear")
- return vim.lsp.diagnostic.clear(bufnr, client_id)
- end
-
- --@deprecated
- function M.get_line_diagnostics()
- warn_once("get_line_diagnostics is deprecated. Use vim.lsp.diagnostic.get_line_diagnostics")
-
- local bufnr = api.nvim_get_current_buf()
- local line_nr = api.nvim_win_get_cursor(0)[1] - 1
-
- return vim.lsp.diagnostic.get_line_diagnostics(bufnr, line_nr)
- end
-
- --@deprecated
- function M.show_line_diagnostics()
- warn_once("show_line_diagnostics is deprecated. Use vim.lsp.diagnostic.show_line_diagnostics")
-
- local bufnr = api.nvim_get_current_buf()
- local line_nr = api.nvim_win_get_cursor(0)[1] - 1
-
- return vim.lsp.diagnostic.show_line_diagnostics(bufnr, line_nr)
- end
-
- --@deprecated
- function M.buf_diagnostics_save_positions(bufnr, diagnostics, client_id)
- warn_once("buf_diagnostics_save_positions is deprecated. Use vim.lsp.diagnostic.save")
- return vim.lsp.diagnostic.save(diagnostics, bufnr, client_id)
- end
-
- --@deprecated
- function M.buf_diagnostics_get_positions(bufnr, client_id)
- warn_once("buf_diagnostics_get_positions is deprecated. Use vim.lsp.diagnostic.get")
- return vim.lsp.diagnostic.get(bufnr, client_id)
- end
-
- --@deprecated
- function M.buf_diagnostics_underline(bufnr, diagnostics, client_id)
- warn_once("buf_diagnostics_underline is deprecated. Use 'vim.lsp.diagnostic.set_underline'")
- return vim.lsp.diagnostic.set_underline(diagnostics, bufnr, client_id)
- end
-
- --@deprecated
- function M.buf_diagnostics_virtual_text(bufnr, diagnostics, client_id)
- warn_once("buf_diagnostics_virtual_text is deprecated. Use 'vim.lsp.diagnostic.set_virtual_text'")
- return vim.lsp.diagnostic.set_virtual_text(diagnostics, bufnr, client_id)
- end
-
- --@deprecated
- function M.buf_diagnostics_signs(bufnr, diagnostics, client_id)
- warn_once("buf_diagnostics_signs is deprecated. Use 'vim.lsp.diagnostic.set_signs'")
- return vim.lsp.diagnostic.set_signs(diagnostics, bufnr, client_id)
- end
-
- --@deprecated
- function M.buf_diagnostics_count(kind, client_id)
- warn_once("buf_diagnostics_count is deprecated. Use 'vim.lsp.diagnostic.get_count'")
- return vim.lsp.diagnostic.get_count(vim.api.nvim_get_current_buf(), client_id, kind)
- end
-
-end
-
do --[[ References ]]
local reference_ns = api.nvim_create_namespace("vim_lsp_references")
diff --git a/runtime/lua/vim/treesitter/languagetree.lua b/runtime/lua/vim/treesitter/languagetree.lua
index 28a87f26c7..4168c1e365 100644
--- a/runtime/lua/vim/treesitter/languagetree.lua
+++ b/runtime/lua/vim/treesitter/languagetree.lua
@@ -249,17 +249,17 @@ end
--
-- @param regions A list of regions this tree should manage and parse.
function LanguageTree:set_included_regions(regions)
- -- Transform the tables from 4 element long to 6 element long (with byte offset)
- for _, region in ipairs(regions) do
- for i, range in ipairs(region) do
- if type(range) == "table" and #range == 4 then
- -- TODO(vigoux): I don't think string parsers are useful for now
- if type(self._source) == "number" then
+ -- TODO(vigoux): I don't think string parsers are useful for now
+ if type(self._source) == "number" then
+ -- Transform the tables from 4 element long to 6 element long (with byte offset)
+ for _, region in ipairs(regions) do
+ for i, range in ipairs(region) do
+ if type(range) == "table" and #range == 4 then
local start_row, start_col, end_row, end_col = unpack(range)
-- Easy case, this is a buffer parser
-- TODO(vigoux): proper byte computation here, and account for EOL ?
- local start_byte = a.nvim_buf_get_offset(self.bufnr, start_row) + start_col
- local end_byte = a.nvim_buf_get_offset(self.bufnr, end_row) + end_col
+ local start_byte = a.nvim_buf_get_offset(self._source, start_row) + start_col
+ local end_byte = a.nvim_buf_get_offset(self._source, end_row) + end_col
region[i] = { start_row, start_col, start_byte, end_row, end_col, end_byte }
end
diff --git a/runtime/menu.vim b/runtime/menu.vim
index 3756787e7f..cd56eb5583 100644
--- a/runtime/menu.vim
+++ b/runtime/menu.vim
@@ -356,8 +356,8 @@ func! s:SetupColorSchemes() abort
let s:did_setup_color_schemes = 1
let n = globpath(&runtimepath, "colors/*.vim", 1, 1)
- let n += globpath(&runtimepath, "pack/*/start/*/colors/*.vim", 1, 1)
- let n += globpath(&runtimepath, "pack/*/opt/*/colors/*.vim", 1, 1)
+ let n += globpath(&packpath, "pack/*/start/*/colors/*.vim", 1, 1)
+ let n += globpath(&packpath, "pack/*/opt/*/colors/*.vim", 1, 1)
" Ignore case for VMS and windows, sort on name
let names = sort(map(n, 'substitute(v:val, "\\c.*[/\\\\:\\]]\\([^/\\\\:]*\\)\\.vim", "\\1", "")'), 1)
diff --git a/runtime/plugin/tarPlugin.vim b/runtime/plugin/tarPlugin.vim
index 6d9e6bd540..d55492a93e 100644
--- a/runtime/plugin/tarPlugin.vim
+++ b/runtime/plugin/tarPlugin.vim
@@ -14,7 +14,7 @@
if &cp || exists("g:loaded_tarPlugin")
finish
endif
-let g:loaded_tarPlugin = "v29"
+let g:loaded_tarPlugin = "v32"
let s:keepcpo = &cpo
set cpo&vim
@@ -39,11 +39,13 @@ augroup tar
au BufReadCmd *.lrp call tar#Browse(expand("<amatch>"))
au BufReadCmd *.tar.bz2 call tar#Browse(expand("<amatch>"))
au BufReadCmd *.tar.Z call tar#Browse(expand("<amatch>"))
- au BufReadCmd *.tgz call tar#Browse(expand("<amatch>"))
au BufReadCmd *.tbz call tar#Browse(expand("<amatch>"))
+ au BufReadCmd *.tgz call tar#Browse(expand("<amatch>"))
au BufReadCmd *.tar.lzma call tar#Browse(expand("<amatch>"))
au BufReadCmd *.tar.xz call tar#Browse(expand("<amatch>"))
au BufReadCmd *.txz call tar#Browse(expand("<amatch>"))
+ au BufReadCmd *.tar.zst call tar#Browse(expand("<amatch>"))
+ au BufReadCmd *.tzs call tar#Browse(expand("<amatch>"))
augroup END
com! -nargs=? -complete=file Vimuntar call tar#Vimuntar(<q-args>)
diff --git a/runtime/syntax/cabal.vim b/runtime/syntax/cabal.vim
index 8af47d4042..92e6b8331e 100644
--- a/runtime/syntax/cabal.vim
+++ b/runtime/syntax/cabal.vim
@@ -4,7 +4,7 @@
" Maintainer: Marcin Szamotulski <profunctor@pm.me>
" Previous Maintainer: Vincent Berthoux <twinside@gmail.com>
" File Types: .cabal
-" Last Change: 15 May 2018
+" Last Change: 21 Nov 2020
" v1.5: Incorporated changes from
" https://github.com/sdiehl/haskell-vim-proto/blob/master/vim/syntax/cabal.vim
" Use `syn keyword` instead of `syn match`.
@@ -62,11 +62,12 @@ syn keyword cabalCategory contained
\ source-repository
\ flag
\ custom-setup
+ \ common
syn match cabalCategoryTitle contained /[^{]*\ze{\?/
syn match cabalCategoryRegion
\ contains=cabalCategory,cabalCategoryTitle
\ nextgroup=cabalCategory skipwhite
- \ /^\c\s*\(contained\|executable\|library\|benchmark\|test-suite\|source-repository\|flag\|custom-setup\)\+\s*\%(.*$\|$\)/
+ \ /^\c\s*\(contained\|executable\|library\|benchmark\|test-suite\|source-repository\|flag\|custom-setup\|common\)\+\s*\%(.*$\|$\)/
syn keyword cabalTruth true false
" cabalStatementRegion which limits the scope of cabalStatement keywords, this
@@ -76,10 +77,14 @@ syn keyword cabalStatement contained containedin=cabalStatementRegion
\ default-language
\ default-extensions
\ author
+ \ autogen-modules
+ \ asm-sources
+ \ asm-options
\ branch
\ bug-reports
\ build-depends
\ build-tools
+ \ build-tools-depends
\ build-type
\ buildable
\ c-sources
@@ -87,32 +92,46 @@ syn keyword cabalStatement contained containedin=cabalStatementRegion
\ category
\ cc-options
\ copyright
+ \ cmm-sources
+ \ cmm-options
\ cpp-options
+ \ cxx-sources
\ data-dir
\ data-files
\ default
+ \ default-extensions
\ description
\ executable
\ exposed-modules
\ exposed
\ extensions
- \ extra-tmp-files
+ \ extra-bundled-libraries
\ extra-doc-files
+ \ extra-dynamic-library-flavours
+ \ extra-framework-dirs
+ \ extra-ghci-libraries
\ extra-lib-dirs
\ extra-libraries
+ \ extra-library-flavours
\ extra-source-files
- \ exta-tmp-files
+ \ extra-tmp-files
\ for example
\ frameworks
\ ghc-options
\ ghc-prof-options
\ ghc-shared-options
+ \ ghcjs-options
+ \ ghcjs-prof-options
+ \ ghcjs-shared-options
\ homepage
+ \ hs-source-dir
\ hs-source-dirs
\ hugs-options
+ \ import
\ include-dirs
\ includes
\ install-includes
+ \ js-sources
\ ld-options
\ license
\ license-file
@@ -120,10 +139,13 @@ syn keyword cabalStatement contained containedin=cabalStatementRegion
\ main-is
\ maintainer
\ manual
+ \ mixins
\ module
\ name
\ nhc98-options
\ other-extensions
+ \ other-language
+ \ other-languages
\ other-modules
\ package-url
\ pkgconfig-depends
diff --git a/runtime/syntax/cabalconfig.vim b/runtime/syntax/cabalconfig.vim
new file mode 100644
index 0000000000..0165725c06
--- /dev/null
+++ b/runtime/syntax/cabalconfig.vim
@@ -0,0 +1,30 @@
+" Vim syntax file
+" Language: Cabal Config
+" Maintainer: profunctor@pm.me
+" Last Change: Marcin Szamotulski
+" Original Author: Marcin Szamotulski
+
+if exists("b:current_syntax")
+ finish
+endif
+
+syn match CabalConfigSection /^\S[[:alpha:]]\+\%(-[[:alpha:]]\+\)*[^:]*$/
+syn region CabalConfigRegion matchgroup=CabalConfigKey start=/^\s*[[:alpha:]]\+\%(-[[:alpha:]]\+\)*:/ matchgroup=NONE end=/$/ contains=CabalConfigSeparator,CabalConfigKeyword,CabalConfigPath keepend
+syn match CabalConfigComment /^\s*--.*$/
+syn match CabalConfigValue /.*$/ contained
+syn match CabalConfigKey /[[:alpha:]]\+\%(-[[:alpha:]]\+\)*\ze:/
+syn keyword CabalConfigSeparator : contained
+syn match CabalConfigVariable /\$[[:alpha:]]\+/
+syn keyword CabalConfigKeyword True False ghc
+syn match CabalConfigPath /\%([[:alpha:]]\+:\)\?\%(\/[[:print:]]\+\)\+/
+
+hi def link CabalConfigComment Comment
+hi def link CabalConfigSection Title
+hi def link CabalConfigKey Statement
+hi def link CabalConfigSeparator NonText
+hi def link CabalConfigValue Normal
+hi def link CabalConfigVariable Identifier
+hi def link CabalConfigKeyword Keyword
+hi def link CabalConfigPath Directory
+
+let b:current_syntax = "cabal.config"
diff --git a/runtime/syntax/cabalproject.vim b/runtime/syntax/cabalproject.vim
new file mode 100644
index 0000000000..12143b9ee9
--- /dev/null
+++ b/runtime/syntax/cabalproject.vim
@@ -0,0 +1,28 @@
+" Vim syntax file
+" Language: Cabal Project
+" Maintainer: profunctor@pm.me
+" Last Change: Marcin Szamotulski
+" Original Author: Marcin Szamotulski
+
+if exists("b:current_syntax")
+ finish
+endif
+
+syn match CabalProjectComment /^\s*--.*/ contains=@Spell
+syn match CabalProjectField /^\w\%(\w\|-\)\+/ contains=@NoSpell
+
+syn keyword CabalProjectBoolean true false True False
+syn keyword CabalProjectCompiler ghc ghcjs jhc lhc uhc haskell-suite
+syn match CabalProjectNat /\<\d\+\>/
+syn keyword CabalProjectJobs $ncpus
+syn keyword CabalProjectProfilingLevel default none exported-functions toplevel-functions all-functions
+
+hi def link CabalProjectComment Comment
+hi def link CabalProjectField Statement
+hi def link CabalProjectBoolean Boolean
+hi def link CabalProjectCompiler Identifier
+hi def link CabalProjectNat Number
+hi def link CabalProjectJobs Number
+hi def link CabalProjectProfilingLevel Statement
+
+let b:current_syntax = "cabal.project"
diff --git a/runtime/syntax/haskell.vim b/runtime/syntax/haskell.vim
index e5128a12ab..1b70b9344a 100644
--- a/runtime/syntax/haskell.vim
+++ b/runtime/syntax/haskell.vim
@@ -1,7 +1,7 @@
" Vim syntax file
" Language: Haskell
" Maintainer: Haskell Cafe mailinglist <haskell-cafe@haskell.org>
-" Last Change: 2018 Mar 29 by Marcin Szamotulski
+" Last Change: 2020 Oct 4 by Marcin Szamotulski <profunctor@pm.me>
" Original Author: John Williams <jrw@pobox.com>
"
" Thanks to Ryan Crumley for suggestions and John Meacham for
@@ -38,8 +38,8 @@ if exists("b:current_syntax")
endif
" (Qualified) identifiers (no default highlighting)
-syn match ConId "\(\<[A-Z][a-zA-Z0-9_']*\.\)\=\<[A-Z][a-zA-Z0-9_']*\>" contains=@NoSpell
-syn match VarId "\(\<[A-Z][a-zA-Z0-9_']*\.\)\=\<[a-z][a-zA-Z0-9_']*\>" contains=@NoSpell
+syn match ConId "\(\<[A-Z][a-zA-Z0-9_']*\.\)*\<[A-Z][a-zA-Z0-9_']*\>" contains=@NoSpell
+syn match VarId "\(\<[A-Z][a-zA-Z0-9_']*\.\)*\<[a-z][a-zA-Z0-9_']*\>" contains=@NoSpell
" Infix operators--most punctuation characters and any (qualified) identifier
" enclosed in `backquotes`. An operator starting with : is a constructor,
@@ -49,8 +49,11 @@ syn match hsConSym "\(\<[A-Z][a-zA-Z0-9_']*\.\)\=:[-!#$%&\*\+./<=>\?@\\^|~:]*"
syn match hsVarSym "`\(\<[A-Z][a-zA-Z0-9_']*\.\)\=[a-z][a-zA-Z0-9_']*`"
syn match hsConSym "`\(\<[A-Z][a-zA-Z0-9_']*\.\)\=[A-Z][a-zA-Z0-9_']*`"
+" (Non-qualified) identifiers which start with # are labels
+syn match hsLabel "#[a-z][a-zA-Z0-9_']*\>"
+
" Reserved symbols--cannot be overloaded.
-syn match hsDelimiter "(\|)\|\[\|\]\|,\|;\|_\|{\|}"
+syn match hsDelimiter "(\|)\|\[\|\]\|,\|;\|{\|}"
" Strings and constants
syn match hsSpecialChar contained "\\\([0-9]\+\|o[0-7]\+\|x[0-9a-fA-F]\+\|[\"\\'&\\abfnrtv]\|^[A-Z^_\[\\\]]\)"
@@ -62,37 +65,41 @@ syn match hsCharacter "^'\([^\\]\|\\[^']\+\|\\'\)'" contains=hsSpecialChar,hs
syn match hsNumber "\v<[0-9]%(_*[0-9])*>|<0[xX]_*[0-9a-fA-F]%(_*[0-9a-fA-F])*>|<0[oO]_*%(_*[0-7])*>|<0[bB]_*[01]%(_*[01])*>"
syn match hsFloat "\v<[0-9]%(_*[0-9])*\.[0-9]%(_*[0-9])*%(_*[eE][-+]?[0-9]%(_*[0-9])*)?>|<[0-9]%(_*[0-9])*_*[eE][-+]?[0-9]%(_*[0-9])*>|<0[xX]_*[0-9a-fA-F]%(_*[0-9a-fA-F])*\.[0-9a-fA-F]%(_*[0-9a-fA-F])*%(_*[pP][-+]?[0-9]%(_*[0-9])*)?>|<0[xX]_*[0-9a-fA-F]%(_*[0-9a-fA-F])*_*[pP][-+]?[0-9]%(_*[0-9])*>"
-" Keyword definitions. These must be patterns instead of keywords
-" because otherwise they would match as keywords at the start of a
-" "literate" comment (see lhs.vim).
-syn match hsModule "\<module\>"
-syn match hsImport "\<import\>.*"he=s+6 contains=hsImportMod,hsLineComment,hsBlockComment,@NoSpell
-syn match hsImportMod contained "\<\(as\|qualified\|hiding\)\>" contains=@NoSpell
-syn match hsInfix "\<\(infix\|infixl\|infixr\)\>"
-syn match hsStructure "\<\(class\|data\|deriving\|instance\|default\|where\)\>"
-syn match hsTypedef "\<\(type\|newtype\)\>"
-syn match hsStatement "\<\(do\|case\|of\|let\|in\)\>"
-syn match hsConditional "\<\(if\|then\|else\)\>"
+" Keyword definitions.
+syn keyword hsModule module
+syn match hsImportGroup "\<import\>.*" contains=hsImport,hsImportModuleName,hsImportMod,hsLineComment,hsBlockComment,hsImportList,@NoSpell nextgroup=hsImport
+syn keyword hsImport import contained nextgroup=hsImportModuleName
+syn match hsImportModuleName '\<[A-Z][A-Za-z.]*' contained
+syn region hsImportList start='(' skip='([^)]\{-})' end=')' keepend contained contains=ConId,VarId,hsDelimiter,hsBlockComment,hsTypedef,@NoSpell
+
+syn keyword hsImportMod contained as qualified hiding
+syn keyword hsInfix infix infixl infixr
+syn keyword hsStructure class data deriving instance default where
+syn keyword hsTypedef type
+syn keyword hsNewtypedef newtype
+syn keyword hsTypeFam family
+syn keyword hsStatement mdo do case of let in
+syn keyword hsConditional if then else
" Not real keywords, but close.
if exists("hs_highlight_boolean")
" Boolean constants from the standard prelude.
- syn match hsBoolean "\<\(True\|False\)\>"
+ syn keyword hsBoolean True False
endif
if exists("hs_highlight_types")
" Primitive types from the standard prelude and libraries.
- syn match hsType "\<\(Int\|Integer\|Char\|Bool\|Float\|Double\|IO\|Void\|Addr\|Array\|String\)\>"
+ syn keyword hsType Int Integer Char Bool Float Double IO Void Addr Array String
endif
if exists("hs_highlight_more_types")
" Types from the standard prelude libraries.
- syn match hsType "\<\(Maybe\|Either\|Ratio\|Complex\|Ordering\|IOError\|IOResult\|ExitCode\)\>"
- syn match hsMaybe "\<Nothing\>"
- syn match hsExitCode "\<\(ExitSuccess\)\>"
- syn match hsOrdering "\<\(GT\|LT\|EQ\)\>"
+ syn keyword hsType Maybe Either Ratio Complex Ordering IOError IOResult ExitCode
+ syn keyword hsMaybe Nothing
+ syn keyword hsExitCode ExitSuccess
+ syn keyword hsOrdering GT LT EQ
endif
if exists("hs_highlight_debug")
" Debugging functions from the standard prelude.
- syn match hsDebug "\<\(undefined\|error\|trace\)\>"
+ syn keyword hsDebug undefined error trace
endif
@@ -133,12 +140,14 @@ hi def link hsImportMod hsImport
hi def link hsInfix PreProc
hi def link hsStructure Structure
hi def link hsStatement Statement
-hi def link hsConditional Conditional
-hi def link hsSpecialChar SpecialChar
+hi def link hsConditional Conditional
+hi def link hsSpecialChar SpecialChar
hi def link hsTypedef Typedef
+hi def link hsNewtypedef Typedef
hi def link hsVarSym hsOperator
hi def link hsConSym hsOperator
hi def link hsOperator Operator
+hi def link hsTypeFam Structure
if exists("hs_highlight_delimiters")
" Some people find this highlighting distracting.
hi def link hsDelimiter Delimiter
@@ -160,22 +169,22 @@ hi def link hsMaybe hsEnumConst
hi def link hsOrdering hsEnumConst
hi def link hsEnumConst Constant
hi def link hsDebug Debug
-
-hi def link cCppString hsString
-hi def link cCommentStart hsComment
-hi def link cCommentError hsError
-hi def link cCommentStartError hsError
-hi def link cInclude Include
-hi def link cPreProc PreProc
-hi def link cDefine Macro
-hi def link cIncluded hsString
-hi def link cError Error
-hi def link cPreCondit PreCondit
-hi def link cComment Comment
-hi def link cCppSkip cCppOut
-hi def link cCppOut2 cCppOut
-hi def link cCppOut Comment
-
+hi def link hsLabel Special
+
+hi def link cCppString hsString
+hi def link cCommentStart hsComment
+hi def link cCommentError hsError
+hi def link cCommentStartError hsError
+hi def link cInclude Include
+hi def link cPreProc PreProc
+hi def link cDefine Macro
+hi def link cIncluded hsString
+hi def link cError Error
+hi def link cPreCondit PreCondit
+hi def link cComment Comment
+hi def link cCppSkip cCppOut
+hi def link cCppOut2 cCppOut
+hi def link cCppOut Comment
let b:current_syntax = "haskell"
diff --git a/src/nvim/api/buffer.c b/src/nvim/api/buffer.c
index 0e97b36506..2c2e8a024f 100644
--- a/src/nvim/api/buffer.c
+++ b/src/nvim/api/buffer.c
@@ -111,6 +111,24 @@ Integer nvim_buf_line_count(Buffer buffer, Error *err)
/// - byte count of previous contents
/// - deleted_codepoints (if `utf_sizes` is true)
/// - deleted_codeunits (if `utf_sizes` is true)
+/// - on_bytes: lua callback invoked on change.
+/// This callback receives more granular information about the
+/// change compared to on_lines.
+/// Return `true` to detach.
+/// Args:
+/// - the string "bytes"
+/// - buffer handle
+/// - b:changedtick
+/// - start row of the changed text (zero-indexed)
+/// - start column of the changed text
+/// - byte offset of the changed text (from the start of
+/// the buffer)
+/// - old end row of the changed text
+/// - old end column of the changed text
+/// - old end byte length of the changed text
+/// - new end row of the changed text
+/// - new end column of the changed text
+/// - new end byte length of the changed text
/// - on_changedtick: Lua callback invoked on changedtick
/// increment without text change. Args:
/// - the string "changedtick"
@@ -1407,6 +1425,11 @@ Array nvim_buf_get_extmarks(Buffer buffer, Integer ns_id,
/// - hl_group : name of the highlight group used to highlight
/// this mark.
/// - virt_text : virtual text to link to this mark.
+/// - virt_text_pos : positioning of virtual text. Possible
+/// values:
+/// - "eol": right after eol character (default)
+/// - "overlay": display over the specified column, without
+/// shifting the underlying text.
/// - ephemeral : for use with |nvim_set_decoration_provider|
/// callbacks. The mark will only be used for the current
/// redraw cycle, and not be permantently stored in the
@@ -1456,8 +1479,9 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id,
uint64_t id = 0;
int line2 = -1, hl_id = 0;
DecorPriority priority = DECOR_PRIORITY_BASE;
- colnr_T col2 = 0;
+ colnr_T col2 = -1;
VirtText virt_text = KV_INITIAL_VALUE;
+ VirtTextPos virt_text_pos = kVTEndOfLine;
bool right_gravity = true;
bool end_right_gravity = false;
bool end_gravity_set = false;
@@ -1526,6 +1550,22 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id,
if (ERROR_SET(err)) {
goto error;
}
+ } else if (strequal("virt_text_pos", k.data)) {
+ if (v->type != kObjectTypeString) {
+ api_set_error(err, kErrorTypeValidation,
+ "virt_text_pos is not a String");
+ goto error;
+ }
+ String str = v->data.string;
+ if (strequal("eol", str.data)) {
+ virt_text_pos = kVTEndOfLine;
+ } else if (strequal("overlay", str.data)) {
+ virt_text_pos = kVTOverlay;
+ } else {
+ api_set_error(err, kErrorTypeValidation,
+ "virt_text_pos: invalid value");
+ goto error;
+ }
} else if (strequal("ephemeral", k.data)) {
ephemeral = api_object_to_bool(*v, "ephemeral", false, err);
if (ERROR_SET(err)) {
@@ -1567,7 +1607,7 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id,
// 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) {
+ if (line2 == -1 && col2 == -1 && end_gravity_set) {
api_set_error(err, kErrorTypeValidation,
"cannot set end_right_gravity "
"without setting end_line or end_col");
@@ -1591,30 +1631,28 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id,
col2 = 0;
}
+ Decoration *decor = NULL, tmp = { 0 };
+
+ if (kv_size(virt_text) || priority != DECOR_PRIORITY_BASE) {
+ // TODO(bfredl): this is a bit sketchy. eventually we should
+ // have predefined decorations for both marks/ephemerals
+ decor = ephemeral ? &tmp : xcalloc(1, sizeof(*decor));
+ decor->hl_id = hl_id;
+ decor->virt_text = virt_text;
+ decor->priority = priority;
+ decor->virt_text_pos = virt_text_pos;
+ } else if (hl_id) {
+ decor = decor_hl(hl_id);
+ }
+
// TODO(bfredl): synergize these two branches even more
if (ephemeral && decor_state.buf == buf) {
- int attr_id = hl_id > 0 ? syn_id2attr(hl_id) : 0;
- VirtText *vt_allocated = NULL;
- if (kv_size(virt_text)) {
- vt_allocated = xmalloc(sizeof *vt_allocated);
- *vt_allocated = virt_text;
- }
- decor_add_ephemeral(attr_id, (int)line, (colnr_T)col,
- (int)line2, (colnr_T)col2, priority, vt_allocated);
+ decor_add_ephemeral((int)line, (int)col, line2, col2, decor, 0);
} else {
if (ephemeral) {
api_set_error(err, kErrorTypeException, "not yet implemented");
goto error;
}
- Decoration *decor = NULL;
- if (kv_size(virt_text)) {
- decor = xcalloc(1, sizeof(*decor));
- decor->hl_id = hl_id;
- decor->virt_text = virt_text;
- } else if (hl_id) {
- decor = decor_hl(hl_id);
- decor->priority = priority;
- }
id = extmark_set(buf, (uint64_t)ns_id, id, (int)line, (colnr_T)col,
line2, col2, decor, right_gravity,
@@ -1685,7 +1723,7 @@ Boolean nvim_buf_del_extmark(Buffer buffer,
/// @param[out] err Error details, if any
/// @return The ns_id that was used
Integer nvim_buf_add_highlight(Buffer buffer,
- Integer src_id,
+ Integer ns_id,
String hl_group,
Integer line,
Integer col_start,
@@ -1710,18 +1748,18 @@ Integer nvim_buf_add_highlight(Buffer buffer,
col_end = MAXCOL;
}
- uint64_t ns_id = src2ns(&src_id);
+ uint64_t ns = src2ns(&ns_id);
if (!(line < buf->b_ml.ml_line_count)) {
// safety check, we can't add marks outside the range
- return src_id;
+ return ns_id;
}
int hl_id = 0;
if (hl_group.size > 0) {
hl_id = syn_check_group((char_u *)hl_group.data, (int)hl_group.size);
} else {
- return src_id;
+ return ns_id;
}
int end_line = (int)line;
@@ -1730,11 +1768,11 @@ Integer nvim_buf_add_highlight(Buffer buffer,
end_line++;
}
- extmark_set(buf, ns_id, 0,
+ extmark_set(buf, ns, 0,
(int)line, (colnr_T)col_start,
end_line, (colnr_T)col_end,
decor_hl(hl_id), true, false, kExtmarkNoUndo);
- return src_id;
+ return ns_id;
}
/// Clears namespaced objects (highlights, extmarks, virtual text) from
diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c
index b94c99dc5e..586123aac1 100644
--- a/src/nvim/api/vim.c
+++ b/src/nvim/api/vim.c
@@ -1546,8 +1546,8 @@ theend:
/// - "c" |charwise| mode
/// - "l" |linewise| mode
/// - "" guess by contents, see |setreg()|
-/// @param after Insert after cursor (like |p|), or before (like |P|).
-/// @param follow Place cursor at end of inserted text.
+/// @param after If true insert after cursor (like |p|), or before (like |P|).
+/// @param follow If true place cursor at end of inserted text.
/// @param[out] err Error details, if any
void nvim_put(ArrayOf(String) lines, String type, Boolean after,
Boolean follow, Error *err)
diff --git a/src/nvim/charset.c b/src/nvim/charset.c
index be265e3f27..5ad1fe0dfd 100644
--- a/src/nvim/charset.c
+++ b/src/nvim/charset.c
@@ -708,7 +708,7 @@ int ptr2cells(const char_u *p)
/// @return number of character cells.
int vim_strsize(char_u *s)
{
- return vim_strnsize(s, (int)MAXCOL);
+ return vim_strnsize(s, MAXCOL);
}
/// Return the number of character cells string "s[len]" will take on the
diff --git a/src/nvim/decoration.c b/src/nvim/decoration.c
index f3ee42fab1..a1289f202a 100644
--- a/src/nvim/decoration.c
+++ b/src/nvim/decoration.c
@@ -188,20 +188,21 @@ bool decor_redraw_start(buf_T *buf, int top_row, DecorState *state)
goto next_mark;
}
- int attr_id = decor->hl_id > 0 ? syn_id2attr(decor->hl_id) : 0;
- VirtText *vt = kv_size(decor->virt_text) ? &decor->virt_text : NULL;
- HlRange range;
if (mark.id&MARKTREE_END_FLAG) {
- range = (HlRange){ altpos.row, altpos.col, mark.row, mark.col,
- attr_id, decor->priority, vt, false };
+ decor_add(state, altpos.row, altpos.col, mark.row, mark.col,
+ decor, false, 0);
} else {
- range = (HlRange){ mark.row, mark.col, altpos.row,
- altpos.col, attr_id, decor->priority, vt, false };
+ if (altpos.row == -1) {
+ altpos.row = mark.row;
+ altpos.col = mark.col;
+ }
+ decor_add(state, mark.row, mark.col, altpos.row, altpos.col,
+ decor, false, 0);
}
- hlrange_activate(range, state);
next_mark:
if (marktree_itr_node_done(state->itr)) {
+ marktree_itr_next(buf->b_marktree, state->itr);
break;
}
marktree_itr_next(buf->b_marktree, state->itr);
@@ -220,41 +221,39 @@ bool decor_redraw_line(buf_T *buf, int row, DecorState *state)
return true; // TODO(bfredl): be more precise
}
-static void hlrange_activate(HlRange range, DecorState *state)
+static void decor_add(DecorState *state, int start_row, int start_col,
+ int end_row, int end_col, Decoration *decor, bool owned,
+ DecorPriority priority)
{
- // Get size before preparing the push, to have the number of elements
- size_t s = kv_size(state->active);
-
- kv_pushp(state->active);
+ int attr_id = decor->hl_id > 0 ? syn_id2attr(decor->hl_id) : 0;
- size_t dest_index = 0;
+ HlRange range = { start_row, start_col, end_row, end_col,
+ attr_id, MAX(priority, decor->priority),
+ kv_size(decor->virt_text) ? &decor->virt_text : NULL,
+ decor->virt_text_pos,
+ kv_size(decor->virt_text) && owned, -1 };
- // Determine insertion dest_index
- while (dest_index < s) {
- HlRange item = kv_A(state->active, dest_index);
- if (item.priority > range.priority) {
+ kv_pushp(state->active);
+ size_t index;
+ for (index = kv_size(state->active)-1; index > 0; index--) {
+ HlRange item = kv_A(state->active, index-1);
+ if (item.priority <= range.priority) {
break;
}
-
- dest_index++;
- }
-
- // Splice
- for (size_t index = s; index > dest_index; index--) {
kv_A(state->active, index) = kv_A(state->active, index-1);
}
-
- // Insert
- kv_A(state->active, dest_index) = range;
+ kv_A(state->active, index) = range;
}
-int decor_redraw_col(buf_T *buf, int col, DecorState *state)
+int decor_redraw_col(buf_T *buf, int col, int virt_col, DecorState *state)
{
if (col <= state->col_until) {
return state->current;
}
state->col_until = MAXCOL;
while (true) {
+ // TODO(bfredl): check duplicate entry in "intersection"
+ // branch
mtmark_t mark = marktree_itr_current(state->itr);
if (mark.row < 0 || mark.row > state->row) {
break;
@@ -278,6 +277,11 @@ int decor_redraw_col(buf_T *buf, int col, DecorState *state)
}
Decoration *decor = item->decor;
+ if (endpos.row == -1) {
+ endpos.row = mark.row;
+ endpos.col = mark.col;
+ }
+
if (endpos.row < mark.row
|| (endpos.row == mark.row && endpos.col <= mark.col)) {
if (!kv_size(decor->virt_text)) {
@@ -285,12 +289,8 @@ int decor_redraw_col(buf_T *buf, int col, DecorState *state)
}
}
- int attr_id = decor->hl_id > 0 ? syn_id2attr(decor->hl_id) : 0;
- VirtText *vt = kv_size(decor->virt_text) ? &decor->virt_text : NULL;
- hlrange_activate((HlRange){ mark.row, mark.col,
- endpos.row, endpos.col,
- attr_id, decor->priority,
- vt, false }, state);
+ decor_add(state, mark.row, mark.col, endpos.row, endpos.col,
+ decor, false, 0);
next_mark:
marktree_itr_next(buf->b_marktree, state->itr);
@@ -310,7 +310,7 @@ next_mark:
if (item.start_row < state->row
|| (item.start_row == state->row && item.start_col <= col)) {
active = true;
- if (item.end_row == state->row) {
+ if (item.end_row == state->row && item.end_col > col) {
state->col_until = MIN(state->col_until, item.end_col-1);
}
} else {
@@ -322,8 +322,12 @@ next_mark:
if (active && item.attr_id > 0) {
attr = hl_combine_attr(attr, item.attr_id);
}
+ if ((item.start_row == state->row && item.start_col <= col)
+ && item.virt_text && item.virt_col == -1) {
+ item.virt_col = virt_col;
+ }
if (keep) {
- kv_A(state->active, j++) = kv_A(state->active, i);
+ kv_A(state->active, j++) = item;
} else if (item.virt_text_owned) {
clear_virttext(item.virt_text);
xfree(item.virt_text);
@@ -341,21 +345,20 @@ void decor_redraw_end(DecorState *state)
VirtText *decor_redraw_virt_text(buf_T *buf, DecorState *state)
{
- decor_redraw_col(buf, MAXCOL, state);
+ decor_redraw_col(buf, MAXCOL, MAXCOL, state);
for (size_t i = 0; i < kv_size(state->active); i++) {
HlRange item = kv_A(state->active, i);
- if (item.start_row == state->row && item.virt_text) {
+ if (item.start_row == state->row && item.virt_text
+ && item.virt_text_pos == kVTEndOfLine) {
return item.virt_text;
}
}
return NULL;
}
-void decor_add_ephemeral(int attr_id, int start_row, int start_col,
- int end_row, int end_col, DecorPriority priority,
- VirtText *virt_text)
+void decor_add_ephemeral(int start_row, int start_col, int end_row, int end_col,
+ Decoration *decor, DecorPriority priority)
{
-hlrange_activate(((HlRange){ start_row, start_col, end_row, end_col, attr_id,
- priority, virt_text, virt_text != NULL }),
- &decor_state);
+ decor_add(&decor_state, start_row, start_col, end_row, end_col, decor, true,
+ priority);
}
diff --git a/src/nvim/decoration.h b/src/nvim/decoration.h
index 2533a641dd..47bd9abbc3 100644
--- a/src/nvim/decoration.h
+++ b/src/nvim/decoration.h
@@ -18,10 +18,16 @@ typedef kvec_t(VirtTextChunk) VirtText;
typedef uint16_t DecorPriority;
#define DECOR_PRIORITY_BASE 0x1000
+typedef enum {
+ kVTEndOfLine,
+ kVTOverlay,
+} VirtTextPos;
+
struct Decoration
{
int hl_id; // highlight group
VirtText virt_text;
+ VirtTextPos virt_text_pos;
// TODO(bfredl): style, signs, etc
DecorPriority priority;
bool shared; // shared decoration, don't free
@@ -35,7 +41,9 @@ typedef struct {
int attr_id;
DecorPriority priority;
VirtText *virt_text;
+ VirtTextPos virt_text_pos;
bool virt_text_owned;
+ int virt_col;
} HlRange;
typedef struct {
diff --git a/src/nvim/edit.c b/src/nvim/edit.c
index 100e88e261..53717229f6 100644
--- a/src/nvim/edit.c
+++ b/src/nvim/edit.c
@@ -1627,11 +1627,11 @@ static void init_prompt(int cmdchar_todo)
ml_append(curbuf->b_ml.ml_line_count, prompt, 0, false);
}
curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
- coladvance((colnr_T)MAXCOL);
+ coladvance(MAXCOL);
changed_bytes(curbuf->b_ml.ml_line_count, 0);
}
if (cmdchar_todo == 'A') {
- coladvance((colnr_T)MAXCOL);
+ coladvance(MAXCOL);
}
if (cmdchar_todo == 'I' || curwin->w_cursor.col <= (int)STRLEN(prompt)) {
curwin->w_cursor.col = STRLEN(prompt);
@@ -6246,9 +6246,10 @@ void auto_format(
if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count) {
// "cannot happen"
curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
- coladvance((colnr_T)MAXCOL);
- } else
+ coladvance(MAXCOL);
+ } else {
check_cursor_col();
+ }
// Insert mode: If the cursor is now after the end of the line while it
// previously wasn't, the line was broken. Because of the rule above we
@@ -8432,8 +8433,8 @@ static void ins_left(void)
// if 'whichwrap' set for cursor in insert mode may go to previous line.
// always break undo when moving upwards/downwards, else undo may break
start_arrow(&tpos);
- --(curwin->w_cursor.lnum);
- coladvance((colnr_T)MAXCOL);
+ curwin->w_cursor.lnum--;
+ coladvance(MAXCOL);
curwin->w_set_curswant = true; // so we stay at the end
} else {
vim_beep(BO_CRSR);
@@ -8467,7 +8468,7 @@ static void ins_end(int c)
tpos = curwin->w_cursor;
if (c == K_C_END)
curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
- coladvance((colnr_T)MAXCOL);
+ coladvance(MAXCOL);
curwin->w_curswant = MAXCOL;
start_arrow(&tpos);
diff --git a/src/nvim/eval.c b/src/nvim/eval.c
index d07618d2c0..6d97310c1c 100644
--- a/src/nvim/eval.c
+++ b/src/nvim/eval.c
@@ -176,7 +176,6 @@ static struct vimvar {
VV(VV_DYING, "dying", VAR_NUMBER, VV_RO),
VV(VV_EXCEPTION, "exception", VAR_STRING, VV_RO),
VV(VV_THROWPOINT, "throwpoint", VAR_STRING, VV_RO),
- VV(VV_STDERR, "stderr", VAR_NUMBER, VV_RO),
VV(VV_REG, "register", VAR_STRING, VV_RO),
VV(VV_CMDBANG, "cmdbang", VAR_NUMBER, VV_RO),
VV(VV_INSERTMODE, "insertmode", VAR_STRING, VV_RO),
@@ -211,13 +210,9 @@ static struct vimvar {
VV(VV_OPTION_OLD, "option_old", VAR_STRING, VV_RO),
VV(VV_OPTION_TYPE, "option_type", VAR_STRING, VV_RO),
VV(VV_ERRORS, "errors", VAR_LIST, 0),
- VV(VV_MSGPACK_TYPES, "msgpack_types", VAR_DICT, VV_RO),
- VV(VV_EVENT, "event", VAR_DICT, VV_RO),
VV(VV_FALSE, "false", VAR_BOOL, VV_RO),
VV(VV_TRUE, "true", VAR_BOOL, VV_RO),
VV(VV_NULL, "null", VAR_SPECIAL, VV_RO),
- VV(VV__NULL_LIST, "_null_list", VAR_LIST, VV_RO),
- VV(VV__NULL_DICT, "_null_dict", VAR_DICT, VV_RO),
VV(VV_VIM_DID_ENTER, "vim_did_enter", VAR_NUMBER, VV_RO),
VV(VV_TESTING, "testing", VAR_NUMBER, 0),
VV(VV_TYPE_NUMBER, "t_number", VAR_NUMBER, VV_RO),
@@ -227,10 +222,16 @@ static struct vimvar {
VV(VV_TYPE_DICT, "t_dict", VAR_NUMBER, VV_RO),
VV(VV_TYPE_FLOAT, "t_float", VAR_NUMBER, VV_RO),
VV(VV_TYPE_BOOL, "t_bool", VAR_NUMBER, VV_RO),
+ VV(VV_EVENT, "event", VAR_DICT, VV_RO),
VV(VV_ECHOSPACE, "echospace", VAR_NUMBER, VV_RO),
+ VV(VV_ARGV, "argv", VAR_LIST, VV_RO),
VV(VV_EXITING, "exiting", VAR_NUMBER, VV_RO),
+ // Neovim
+ VV(VV_STDERR, "stderr", VAR_NUMBER, VV_RO),
+ VV(VV_MSGPACK_TYPES, "msgpack_types", VAR_DICT, VV_RO),
+ VV(VV__NULL_LIST, "_null_list", VAR_LIST, VV_RO),
+ VV(VV__NULL_DICT, "_null_dict", VAR_DICT, VV_RO),
VV(VV_LUA, "lua", VAR_PARTIAL, VV_RO),
- VV(VV_ARGV, "argv", VAR_LIST, VV_RO),
};
#undef VV
diff --git a/src/nvim/eval.h b/src/nvim/eval.h
index c1891758ea..4f03d5d259 100644
--- a/src/nvim/eval.h
+++ b/src/nvim/eval.h
@@ -105,7 +105,6 @@ typedef enum {
VV_DYING,
VV_EXCEPTION,
VV_THROWPOINT,
- VV_STDERR,
VV_REG,
VV_CMDBANG,
VV_INSERTMODE,
@@ -140,13 +139,9 @@ typedef enum {
VV_OPTION_OLD,
VV_OPTION_TYPE,
VV_ERRORS,
- VV_MSGPACK_TYPES,
- VV_EVENT,
VV_FALSE,
VV_TRUE,
VV_NULL,
- VV__NULL_LIST, // List with NULL value. For test purposes only.
- VV__NULL_DICT, // Dictionary with NULL value. For test purposes only.
VV_VIM_DID_ENTER,
VV_TESTING,
VV_TYPE_NUMBER,
@@ -156,10 +151,16 @@ typedef enum {
VV_TYPE_DICT,
VV_TYPE_FLOAT,
VV_TYPE_BOOL,
+ VV_EVENT,
VV_ECHOSPACE,
+ VV_ARGV,
VV_EXITING,
+ // Neovim
+ VV_STDERR,
+ VV_MSGPACK_TYPES,
+ VV__NULL_LIST, // List with NULL value. For test purposes only.
+ VV__NULL_DICT, // Dictionary with NULL value. For test purposes only.
VV_LUA,
- VV_ARGV,
} VimVarIndex;
/// All recognized msgpack types
diff --git a/src/nvim/eval.lua b/src/nvim/eval.lua
index 952fa35b83..eac0feafcf 100644
--- a/src/nvim/eval.lua
+++ b/src/nvim/eval.lua
@@ -63,6 +63,7 @@ return {
chanclose={args={1, 2}},
chansend={args=2},
char2nr={args={1, 2}},
+ charidx={args={2, 3}},
cindent={args=1},
clearmatches={args={0, 1}},
col={args=1},
diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c
index d54e49bbd4..8c8e0d568b 100644
--- a/src/nvim/eval/funcs.c
+++ b/src/nvim/eval/funcs.c
@@ -940,6 +940,52 @@ static void f_char2nr(typval_T *argvars, typval_T *rettv, FunPtr fptr)
(const char_u *)tv_get_string(&argvars[0]));
}
+// "charidx()" function
+static void f_charidx(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+{
+ rettv->vval.v_number = -1;
+
+ if (argvars[0].v_type != VAR_STRING
+ || argvars[1].v_type != VAR_NUMBER
+ || (argvars[2].v_type != VAR_UNKNOWN
+ && argvars[2].v_type != VAR_NUMBER)) {
+ EMSG(_(e_invarg));
+ return;
+ }
+
+ const char *str = tv_get_string_chk(&argvars[0]);
+ varnumber_T idx = tv_get_number_chk(&argvars[1], NULL);
+ if (str == NULL || idx < 0) {
+ return;
+ }
+ int countcc = 0;
+ if (argvars[2].v_type != VAR_UNKNOWN) {
+ countcc = (int)tv_get_number(&argvars[2]);
+ }
+ if (countcc < 0 || countcc > 1) {
+ EMSG(_(e_invarg));
+ return;
+ }
+
+ int (*ptr2len)(const char_u *);
+ if (countcc) {
+ ptr2len = utf_ptr2len;
+ } else {
+ ptr2len = utfc_ptr2len;
+ }
+
+ const char *p;
+ int len;
+ for (p = str, len = 0; p <= str + idx; len++) {
+ if (*p == NUL) {
+ return;
+ }
+ p += ptr2len((const char_u *)p);
+ }
+
+ rettv->vval.v_number = len > 0 ? len - 1 : 0;
+}
+
/*
* "cindent(lnum)" function
*/
@@ -4085,7 +4131,9 @@ static void f_has(typval_T *argvars, typval_T *rettv, FunPtr fptr)
#ifdef _WIN64
"win64",
#endif
+#ifndef CASE_INSENSITIVE_FILENAME
"fname_case",
+#endif
#ifdef HAVE_ACL
"acl",
#endif
diff --git a/src/nvim/eval/typval.h b/src/nvim/eval/typval.h
index d8ede1e3ba..6fcb01aace 100644
--- a/src/nvim/eval/typval.h
+++ b/src/nvim/eval/typval.h
@@ -315,6 +315,7 @@ struct ufunc {
int uf_calls; ///< nr of active calls
bool uf_cleared; ///< func_clear() was already called
garray_T uf_args; ///< arguments
+ garray_T uf_def_args; ///< default argument expressions
garray_T uf_lines; ///< function lines
int uf_profiling; ///< true when func is being profiled
int uf_prof_initialized;
diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c
index 70c998ef39..689d05e079 100644
--- a/src/nvim/eval/userfunc.c
+++ b/src/nvim/eval/userfunc.c
@@ -67,7 +67,7 @@ void func_init(void)
/// Get function arguments.
static int get_function_args(char_u **argp, char_u endchar, garray_T *newargs,
- int *varargs, bool skip)
+ int *varargs, garray_T *default_args, bool skip)
{
bool mustend = false;
char_u *arg = *argp;
@@ -78,12 +78,16 @@ static int get_function_args(char_u **argp, char_u endchar, garray_T *newargs,
if (newargs != NULL) {
ga_init(newargs, (int)sizeof(char_u *), 3);
}
+ if (default_args != NULL) {
+ ga_init(default_args, (int)sizeof(char_u *), 3);
+ }
if (varargs != NULL) {
*varargs = false;
}
// Isolate the arguments: "arg1, arg2, ...)"
+ bool any_default = false;
while (*p != endchar) {
if (p[0] == '.' && p[1] == '.' && p[2] == '.') {
if (varargs != NULL) {
@@ -123,6 +127,38 @@ static int get_function_args(char_u **argp, char_u endchar, garray_T *newargs,
*p = c;
}
+ if (*skipwhite(p) == '=' && default_args != NULL) {
+ typval_T rettv;
+
+ any_default = true;
+ p = skipwhite(p) + 1;
+ p = skipwhite(p);
+ char_u *expr = p;
+ if (eval1(&p, &rettv, false) != FAIL) {
+ ga_grow(default_args, 1);
+
+ // trim trailing whitespace
+ while (p > expr && ascii_iswhite(p[-1])) {
+ p--;
+ }
+ c = *p;
+ *p = NUL;
+ expr = vim_strsave(expr);
+ if (expr == NULL) {
+ *p = c;
+ goto err_ret;
+ }
+ ((char_u **)(default_args->ga_data))
+ [default_args->ga_len] = expr;
+ default_args->ga_len++;
+ *p = c;
+ } else {
+ mustend = true;
+ }
+ } else if (any_default) {
+ EMSG(_("E989: Non-default argument follows default argument"));
+ mustend = true;
+ }
if (*p == ',') {
p++;
} else {
@@ -149,6 +185,9 @@ err_ret:
if (newargs != NULL) {
ga_clear_strings(newargs);
}
+ if (default_args != NULL) {
+ ga_clear_strings(default_args);
+ }
return FAIL;
}
@@ -195,7 +234,7 @@ int get_lambda_tv(char_u **arg, typval_T *rettv, bool evaluate)
bool eval_lavars = false;
// First, check if this is a lambda expression. "->" must exists.
- ret = get_function_args(&start, '-', NULL, NULL, true);
+ ret = get_function_args(&start, '-', NULL, NULL, NULL, true);
if (ret == FAIL || *start != '>') {
return NOTDONE;
}
@@ -207,7 +246,7 @@ int get_lambda_tv(char_u **arg, typval_T *rettv, bool evaluate)
pnewargs = NULL;
}
*arg = skipwhite(*arg + 1);
- ret = get_function_args(arg, '-', pnewargs, &varargs, false);
+ ret = get_function_args(arg, '-', pnewargs, &varargs, NULL, false);
if (ret == FAIL || **arg != '>') {
goto errret;
}
@@ -259,6 +298,7 @@ int get_lambda_tv(char_u **arg, typval_T *rettv, bool evaluate)
STRCPY(fp->uf_name, name);
hash_add(&func_hashtab, UF2HIKEY(fp));
fp->uf_args = newargs;
+ ga_init(&fp->uf_def_args, (int)sizeof(char_u *), 1);
fp->uf_lines = newlines;
if (current_funccal != NULL && eval_lavars) {
flags |= FC_CLOSURE;
@@ -715,6 +755,7 @@ static bool func_remove(ufunc_T *fp)
static void func_clear_items(ufunc_T *fp)
{
ga_clear_strings(&(fp->uf_args));
+ ga_clear_strings(&(fp->uf_def_args));
ga_clear_strings(&(fp->uf_lines));
if (fp->uf_cb_free != NULL) {
@@ -857,12 +898,13 @@ void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars,
}
// Init a: variables, unless none found (in lambda).
- // Set a:0 to "argcount".
+ // Set a:0 to "argcount" less number of named arguments, if >= 0.
// Set a:000 to a list with room for the "..." arguments.
init_var_dict(&fc->l_avars, &fc->l_avars_var, VAR_SCOPE);
if ((fp->uf_flags & FC_NOARGS) == 0) {
add_nr_var(&fc->l_avars, (dictitem_T *)&fc->fixvar[fixvar_idx++], "0",
- (varnumber_T)(argcount - fp->uf_args.ga_len));
+ (varnumber_T)(argcount >= fp->uf_args.ga_len
+ ? argcount - fp->uf_args.ga_len : 0));
}
fc->l_avars.dv_lock = VAR_FIXED;
if ((fp->uf_flags & FC_NOARGS) == 0) {
@@ -892,8 +934,11 @@ void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars,
add_nr_var(&fc->l_avars, (dictitem_T *)&fc->fixvar[fixvar_idx++],
"lastline", (varnumber_T)lastline);
}
- for (int i = 0; i < argcount; i++) {
+ bool default_arg_err = false;
+ for (int i = 0; i < argcount || i < fp->uf_args.ga_len; i++) {
bool addlocal = false;
+ bool isdefault = false;
+ typval_T def_rettv;
ai = i - fp->uf_args.ga_len;
if (ai < 0) {
@@ -902,6 +947,21 @@ void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars,
if (islambda) {
addlocal = true;
}
+
+ // evaluate named argument default expression
+ isdefault = ai + fp->uf_def_args.ga_len >= 0 && i >= argcount;
+ if (isdefault) {
+ char_u *default_expr = NULL;
+ def_rettv.v_type = VAR_NUMBER;
+ def_rettv.vval.v_number = -1;
+
+ default_expr = ((char_u **)(fp->uf_def_args.ga_data))
+ [ai + fp->uf_def_args.ga_len];
+ if (eval1(&default_expr, &def_rettv, true) == FAIL) {
+ default_arg_err = true;
+ break;
+ }
+ }
} else {
if ((fp->uf_flags & FC_NOARGS) != 0) {
// Bail out if no a: arguments used (in lambda).
@@ -922,7 +982,7 @@ void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars,
// Note: the values are copied directly to avoid alloc/free.
// "argvars" must have VAR_FIXED for v_lock.
- v->di_tv = argvars[i];
+ v->di_tv = isdefault ? def_rettv : argvars[i];
v->di_tv.v_lock = VAR_FIXED;
if (addlocal) {
@@ -1046,7 +1106,9 @@ void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars,
save_did_emsg = did_emsg;
did_emsg = FALSE;
- if (islambda) {
+ if (default_arg_err && (fp->uf_flags & FC_ABORT)) {
+ did_emsg = true;
+ } else if (islambda) {
char_u *p = *(char_u **)fp->uf_lines.ga_data + 7;
// A Lambda always has the command "return {expr}". It is much faster
@@ -1490,7 +1552,7 @@ call_func(
if (fp->uf_flags & FC_RANGE) {
*doesrange = true;
}
- if (argcount < fp->uf_args.ga_len) {
+ if (argcount < fp->uf_args.ga_len - fp->uf_def_args.ga_len) {
error = ERROR_TOOFEW;
} else if (!fp->uf_varargs && argcount > fp->uf_args.ga_len) {
error = ERROR_TOOMANY;
@@ -1573,6 +1635,11 @@ static void list_func_head(ufunc_T *fp, int indent, bool force)
msg_puts(", ");
}
msg_puts((const char *)FUNCARG(fp, j));
+ if (j >= fp->uf_args.ga_len - fp->uf_def_args.ga_len) {
+ msg_puts(" = ");
+ msg_puts(((char **)(fp->uf_def_args.ga_data))
+ [j - fp->uf_args.ga_len + fp->uf_def_args.ga_len]);
+ }
}
if (fp->uf_varargs) {
if (j) {
@@ -1836,6 +1903,7 @@ void ex_function(exarg_T *eap)
char_u *arg;
char_u *line_arg = NULL;
garray_T newargs;
+ garray_T default_args;
garray_T newlines;
int varargs = false;
int flags = 0;
@@ -2039,7 +2107,8 @@ void ex_function(exarg_T *eap)
}
}
- if (get_function_args(&p, ')', &newargs, &varargs, eap->skip) == FAIL) {
+ if (get_function_args(&p, ')', &newargs, &varargs,
+ &default_args, eap->skip) == FAIL) {
goto errret_2;
}
@@ -2458,6 +2527,7 @@ void ex_function(exarg_T *eap)
fp->uf_refcount = 1;
}
fp->uf_args = newargs;
+ fp->uf_def_args = default_args;
fp->uf_lines = newlines;
if ((flags & FC_CLOSURE) != 0) {
register_closure(fp);
@@ -2480,6 +2550,7 @@ void ex_function(exarg_T *eap)
erret:
ga_clear_strings(&newargs);
+ ga_clear_strings(&default_args);
errret_2:
ga_clear_strings(&newlines);
ret_free:
diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c
index b220b034dd..103c081143 100644
--- a/src/nvim/ex_cmds.c
+++ b/src/nvim/ex_cmds.c
@@ -4198,7 +4198,7 @@ skip:
// when interactive leave cursor on the match
if (!subflags.do_ask) {
if (endcolumn) {
- coladvance((colnr_T)MAXCOL);
+ coladvance(MAXCOL);
} else {
beginline(BL_WHITE | BL_FIX);
}
@@ -5020,7 +5020,7 @@ int find_help_tags(const char_u *arg, int *num_matches, char_u ***matches,
if (keep_lang) {
flags |= TAG_KEEP_LANG;
}
- if (find_tags(IObuff, num_matches, matches, flags, (int)MAXCOL, NULL) == OK
+ if (find_tags(IObuff, num_matches, matches, flags, MAXCOL, NULL) == OK
&& *num_matches > 0) {
/* Sort the matches found on the heuristic number that is after the
* tag name. */
diff --git a/src/nvim/ex_cmds.lua b/src/nvim/ex_cmds.lua
index 10dd7d68ca..2965ea7496 100644
--- a/src/nvim/ex_cmds.lua
+++ b/src/nvim/ex_cmds.lua
@@ -2521,8 +2521,8 @@ module.cmds = {
},
{
command='source',
- flags=bit.bor(BANG, FILE1, TRLBAR, SBOXOK, CMDWIN),
- addr_type='ADDR_NONE',
+ flags=bit.bor(RANGE, DFLALL, WHOLEFOLD, BANG, FILE1, TRLBAR, SBOXOK, CMDWIN),
+ addr_type='ADDR_LINES',
func='ex_source',
},
{
diff --git a/src/nvim/ex_cmds2.c b/src/nvim/ex_cmds2.c
index bb53f4d373..c4c18c4324 100644
--- a/src/nvim/ex_cmds2.c
+++ b/src/nvim/ex_cmds2.c
@@ -29,6 +29,7 @@
#include "nvim/getchar.h"
#include "nvim/mark.h"
#include "nvim/mbyte.h"
+#include "nvim/memline.h"
#include "nvim/message.h"
#include "nvim/misc1.h"
#include "nvim/garray.h"
@@ -2526,7 +2527,7 @@ void ex_pyxdo(exarg_T *eap)
}
}
-/// ":source {fname}"
+/// ":source [{fname}]"
void ex_source(exarg_T *eap)
{
cmd_source(eap->arg, eap);
@@ -2535,7 +2536,7 @@ void ex_source(exarg_T *eap)
static void cmd_source(char_u *fname, exarg_T *eap)
{
if (*fname == NUL) {
- EMSG(_(e_argreq));
+ cmd_source_buffer(eap);
} else if (eap != NULL && eap->forceit) {
// ":source!": read Normal mode commands
// Need to execute the commands directly. This is required at least
@@ -2553,6 +2554,37 @@ static void cmd_source(char_u *fname, exarg_T *eap)
}
}
+typedef struct {
+ linenr_T curr_lnum;
+ const linenr_T final_lnum;
+} GetBufferLineCookie;
+
+/// Get one line from the current selection in the buffer.
+/// Called by do_cmdline() when it's called from cmd_source_buffer().
+///
+/// @return pointer to allocated line, or NULL for end-of-file or
+/// some error.
+static char_u *get_buffer_line(int c, void *cookie, int indent, bool do_concat)
+{
+ GetBufferLineCookie *p = cookie;
+ if (p->curr_lnum > p->final_lnum) {
+ return NULL;
+ }
+ char_u *curr_line = ml_get(p->curr_lnum);
+ p->curr_lnum++;
+ return (char_u *)xstrdup((const char *)curr_line);
+}
+
+static void cmd_source_buffer(exarg_T *eap)
+{
+ GetBufferLineCookie cookie = {
+ .curr_lnum = eap->line1,
+ .final_lnum = eap->line2,
+ };
+ source_using_linegetter((void *)&cookie, get_buffer_line,
+ ":source (no file)");
+}
+
/// ":source" and associated commands.
///
/// @return address holding the next breakpoint line for a source cookie
@@ -2624,10 +2656,9 @@ static char_u *get_str_line(int c, void *cookie, int indent, bool do_concat)
return (char_u *)xstrdup(buf);
}
-/// Executes lines in `src` as Ex commands.
-///
-/// @see do_source()
-int do_source_str(const char *cmd, const char *traceback_name)
+static int source_using_linegetter(void *cookie,
+ LineGetter fgetline,
+ const char *traceback_name)
{
char_u *save_sourcing_name = sourcing_name;
linenr_T save_sourcing_lnum = sourcing_lnum;
@@ -2642,22 +2673,33 @@ int do_source_str(const char *cmd, const char *traceback_name)
}
sourcing_lnum = 0;
- GetStrLineCookie cookie = {
- .buf = (char_u *)cmd,
- .offset = 0,
- };
const sctx_T save_current_sctx = current_sctx;
current_sctx.sc_sid = SID_STR;
current_sctx.sc_seq = 0;
current_sctx.sc_lnum = save_sourcing_lnum;
- int retval = do_cmdline(NULL, get_str_line, (void *)&cookie,
+ funccal_entry_T entry;
+ save_funccal(&entry);
+ int retval = do_cmdline(NULL, fgetline, cookie,
DOCMD_VERBOSE | DOCMD_NOWAIT | DOCMD_REPEAT);
- current_sctx = save_current_sctx;
sourcing_lnum = save_sourcing_lnum;
sourcing_name = save_sourcing_name;
+ current_sctx = save_current_sctx;
+ restore_funccal();
return retval;
}
+/// Executes lines in `src` as Ex commands.
+///
+/// @see do_source()
+int do_source_str(const char *cmd, const char *traceback_name)
+{
+ GetStrLineCookie cookie = {
+ .buf = (char_u *)cmd,
+ .offset = 0,
+ };
+ return source_using_linegetter((void *)&cookie, get_str_line, traceback_name);
+}
+
/// Reads the file `fname` and executes its lines as Ex commands.
///
/// This function may be called recursively!
@@ -2982,6 +3024,7 @@ void scriptnames_slash_adjust(void)
# endif
/// Get a pointer to a script name. Used for ":verbose set".
+/// Message appended to "Last set from "
char_u *get_scriptname(LastSet last_set, bool *should_free)
{
*should_free = false;
@@ -2997,6 +3040,8 @@ char_u *get_scriptname(LastSet last_set, bool *should_free)
return (char_u *)_("environment variable");
case SID_ERROR:
return (char_u *)_("error handler");
+ case SID_WINLAYOUT:
+ return (char_u *)_("changed window size");
case SID_LUA:
return (char_u *)_("Lua");
case SID_API_CLIENT:
diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c
index c66ae13f53..d470bfb418 100644
--- a/src/nvim/ex_getln.c
+++ b/src/nvim/ex_getln.c
@@ -6774,6 +6774,6 @@ static void set_search_match(pos_T *t)
t->col = search_match_endcol;
if (t->lnum > curbuf->b_ml.ml_line_count) {
t->lnum = curbuf->b_ml.ml_line_count;
- coladvance((colnr_T)MAXCOL);
+ coladvance(MAXCOL);
}
}
diff --git a/src/nvim/globals.h b/src/nvim/globals.h
index 22f06941aa..7b8e809de7 100644
--- a/src/nvim/globals.h
+++ b/src/nvim/globals.h
@@ -180,6 +180,11 @@ EXTERN int compl_cont_status INIT(= 0);
# define CONT_LOCAL 32 // for ctrl_x_mode 0, ^X^P/^X^N do a local
// expansion, (eg use complete=.)
+EXTERN char_u *edit_submode INIT(= NULL); // msg for CTRL-X submode
+EXTERN char_u *edit_submode_pre INIT(= NULL); // prepended to edit_submode
+EXTERN char_u *edit_submode_extra INIT(= NULL); // appended to edit_submode
+EXTERN hlf_T edit_submode_highl; // highl. method for extra info
+
// state for putting characters in the message area
EXTERN int cmdmsg_rl INIT(= false); // cmdline is drawn right to left
EXTERN int msg_col;
@@ -328,9 +333,10 @@ EXTERN int garbage_collect_at_exit INIT(= false);
#define SID_ENV -4 // for sourcing environment variable
#define SID_ERROR -5 // option was reset because of an error
#define SID_NONE -6 // don't set scriptID
-#define SID_LUA -7 // for Lua scripts/chunks
-#define SID_API_CLIENT -8 // for API clients
-#define SID_STR -9 // for sourcing a string
+#define SID_WINLAYOUT -7 // changing window size
+#define SID_LUA -8 // for Lua scripts/chunks
+#define SID_API_CLIENT -9 // for API clients
+#define SID_STR -10 // for sourcing a string
// Script CTX being sourced or was sourced to define the current function.
EXTERN sctx_T current_sctx INIT(= { 0 COMMA 0 COMMA 0 });
@@ -639,10 +645,6 @@ EXTERN int arrow_used; // Normally false, set to true after
// to call u_sync()
EXTERN bool ins_at_eol INIT(= false); // put cursor after eol when
// restarting edit after CTRL-O
-EXTERN char_u *edit_submode INIT(= NULL); // msg for CTRL-X submode
-EXTERN char_u *edit_submode_pre INIT(= NULL); // prepended to edit_submode
-EXTERN char_u *edit_submode_extra INIT(= NULL); // appended to edit_submode
-EXTERN hlf_T edit_submode_highl; // highl. method for extra info
EXTERN int no_abbr INIT(= true); // true when no abbreviations loaded
diff --git a/src/nvim/memline.c b/src/nvim/memline.c
index 31dc6b3649..293a4d01db 100644
--- a/src/nvim/memline.c
+++ b/src/nvim/memline.c
@@ -4142,7 +4142,7 @@ void goto_byte(long cnt)
if (lnum < 1) { // past the end
curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
curwin->w_curswant = MAXCOL;
- coladvance((colnr_T)MAXCOL);
+ coladvance(MAXCOL);
} else {
curwin->w_cursor.lnum = lnum;
curwin->w_cursor.col = (colnr_T)boff;
diff --git a/src/nvim/misc1.c b/src/nvim/misc1.c
index fcffe64595..34c43da0f7 100644
--- a/src/nvim/misc1.c
+++ b/src/nvim/misc1.c
@@ -412,7 +412,7 @@ int plines_win_nofold(win_T *wp, linenr_T lnum)
s = ml_get_buf(wp->w_buffer, lnum, FALSE);
if (*s == NUL) /* empty line */
return 1;
- col = win_linetabsize(wp, s, (colnr_T)MAXCOL);
+ col = win_linetabsize(wp, s, MAXCOL);
// If list mode is on, then the '$' at the end of the line may take up one
// extra column.
diff --git a/src/nvim/mouse.c b/src/nvim/mouse.c
index ff471ea978..f28658aa29 100644
--- a/src/nvim/mouse.c
+++ b/src/nvim/mouse.c
@@ -72,9 +72,7 @@ int jump_to_mouse(int flags,
int row = mouse_row;
int col = mouse_col;
int grid = mouse_grid;
- int mouse_char;
int fdc = 0;
- ScreenGrid *gp = &default_grid;
mouse_past_bottom = false;
mouse_past_eol = false;
@@ -303,25 +301,6 @@ retnomove:
}
}
- // Remember the character under the mouse, might be one of foldclose or
- // foldopen fillchars in the fold column.
- if (ui_has(kUIMultigrid)) {
- gp = &curwin->w_grid;
- }
- if (row >= 0 && row < Rows && col >= 0 && col <= Columns
- && gp->chars != NULL) {
- mouse_char = utf_ptr2char(gp->chars[gp->line_offset[row]
- + (unsigned)col]);
- } else {
- mouse_char = ' ';
- }
-
- // Check for position outside of the fold column.
- if (curwin->w_p_rl ? col < curwin->w_width_inner - fdc :
- col >= fdc + (cmdwin_type == 0 ? 0 : 1)) {
- mouse_char = ' ';
- }
-
// compute the position in the buffer line from the posn on the screen
if (mouse_comp_pos(curwin, &row, &col, &curwin->w_cursor.lnum)) {
mouse_past_bottom = true;
@@ -362,11 +341,7 @@ retnomove:
count |= CURSOR_MOVED; // Cursor has moved
}
- if (mouse_char == curwin->w_p_fcs_chars.foldclosed) {
- count |= MOUSE_FOLD_OPEN;
- } else if (mouse_char != ' ') {
- count |= MOUSE_FOLD_CLOSE;
- }
+ count |= mouse_check_fold();
return count;
}
@@ -738,3 +713,47 @@ static int mouse_adjust_click(win_T *wp, int row, int col)
return col + nudge;
}
+
+// Check clicked cell is foldcolumn
+int mouse_check_fold(void)
+{
+ int grid = mouse_grid;
+ int row = mouse_row;
+ int col = mouse_col;
+ int mouse_char = ' ';
+
+ win_T *wp;
+
+ wp = mouse_find_win(&grid, &row, &col);
+
+ if (wp && mouse_row >= 0 && mouse_row < Rows
+ && mouse_col >= 0 && mouse_col <= Columns) {
+ int multigrid = ui_has(kUIMultigrid);
+ ScreenGrid *gp = multigrid ? &wp->w_grid : &default_grid;
+ int fdc = win_fdccol_count(wp);
+
+ row = multigrid && mouse_grid == 0 ? row : mouse_row;
+ col = multigrid && mouse_grid == 0 ? col : mouse_col;
+
+ // Remember the character under the mouse, might be one of foldclose or
+ // foldopen fillchars in the fold column.
+ if (gp->chars != NULL) {
+ mouse_char = utf_ptr2char(gp->chars[gp->line_offset[row]
+ + (unsigned)col]);
+ }
+
+ // Check for position outside of the fold column.
+ if (wp->w_p_rl ? col < wp->w_width_inner - fdc :
+ col >= fdc + (cmdwin_type == 0 ? 0 : 1)) {
+ mouse_char = ' ';
+ }
+ }
+
+ if (mouse_char == wp->w_p_fcs_chars.foldclosed) {
+ return MOUSE_FOLD_OPEN;
+ } else if (mouse_char != ' ') {
+ return MOUSE_FOLD_CLOSE;
+ }
+
+ return 0;
+}
diff --git a/src/nvim/normal.c b/src/nvim/normal.c
index 8f22243348..4d8b11f832 100644
--- a/src/nvim/normal.c
+++ b/src/nvim/normal.c
@@ -2404,8 +2404,8 @@ do_mouse (
start_visual.lnum = 0;
- /* Check for clicking in the tab page line. */
- if (mouse_row == 0 && firstwin->w_winrow > 0) {
+ // Check for clicking in the tab page line.
+ if (mouse_grid <= 1 && mouse_row == 0 && firstwin->w_winrow > 0) {
if (is_drag) {
if (in_tab_line) {
move_tab_to_mouse();
@@ -5225,16 +5225,13 @@ static void nv_left(cmdarg_T *cap)
* 'h' wraps to previous line if 'whichwrap' has 'h'.
* CURS_LEFT wraps to previous line if 'whichwrap' has '<'.
*/
- if ( (((cap->cmdchar == K_BS
- || cap->cmdchar == Ctrl_H)
- && vim_strchr(p_ww, 'b') != NULL)
- || (cap->cmdchar == 'h'
- && vim_strchr(p_ww, 'h') != NULL)
- || (cap->cmdchar == K_LEFT
- && vim_strchr(p_ww, '<') != NULL))
- && curwin->w_cursor.lnum > 1) {
- --(curwin->w_cursor.lnum);
- coladvance((colnr_T)MAXCOL);
+ if ((((cap->cmdchar == K_BS || cap->cmdchar == Ctrl_H)
+ && vim_strchr(p_ww, 'b') != NULL)
+ || (cap->cmdchar == 'h' && vim_strchr(p_ww, 'h') != NULL)
+ || (cap->cmdchar == K_LEFT && vim_strchr(p_ww, '<') != NULL))
+ && curwin->w_cursor.lnum > 1) {
+ curwin->w_cursor.lnum--;
+ coladvance(MAXCOL);
curwin->w_set_curswant = true;
// When the NL before the first char has to be deleted we
@@ -5792,16 +5789,20 @@ static void nv_percent(cmdarg_T *cap)
} else {
cap->oap->motion_type = kMTLineWise;
setpcmark();
- /* Round up, so CTRL-G will give same value. Watch out for a
- * large line count, the line number must not go negative! */
- if (curbuf->b_ml.ml_line_count > 1000000)
+ // Round up, so 'normal 100%' always jumps at the line line.
+ // Beyond 21474836 lines, (ml_line_count * 100 + 99) would
+ // overflow on 32-bits, so use a formula with less accuracy
+ // to avoid overflows.
+ if (curbuf->b_ml.ml_line_count >= 21474836) {
curwin->w_cursor.lnum = (curbuf->b_ml.ml_line_count + 99L)
/ 100L * cap->count0;
- else
+ } else {
curwin->w_cursor.lnum = (curbuf->b_ml.ml_line_count *
cap->count0 + 99L) / 100L;
- if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count)
+ }
+ if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count) {
curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
+ }
beginline(BL_SOL | BL_FIX);
}
} else { // "%" : go to matching paren
@@ -6467,7 +6468,7 @@ static void nv_visual(cmdarg_T *cap)
}
if (resel_VIsual_vcol == MAXCOL) {
curwin->w_curswant = MAXCOL;
- coladvance((colnr_T)MAXCOL);
+ coladvance(MAXCOL);
} else if (VIsual_mode == Ctrl_V) {
validate_virtcol();
assert(cap->count0 >= INT_MIN && cap->count0 <= INT_MAX);
@@ -7570,6 +7571,12 @@ static void nv_esc(cmdarg_T *cap)
got_int = false; /* don't stop executing autocommands et al. */
return;
}
+ } else if (cmdwin_type != 0 && ex_normal_busy) {
+ // When :normal runs out of characters while in the command line window
+ // vgetorpeek() will return ESC. Exit the cmdline window to break the
+ // loop.
+ cmdwin_result = K_IGNORE;
+ return;
}
if (VIsual_active) {
@@ -7600,7 +7607,7 @@ void set_cursor_for_append_to_line(void)
// Pretend Insert mode here to allow the cursor on the
// character past the end of the line
State = INSERT;
- coladvance((colnr_T)MAXCOL);
+ coladvance(MAXCOL);
State = save_State;
} else {
curwin->w_cursor.col += (colnr_T)STRLEN(get_cursor_pos_ptr());
@@ -7988,7 +7995,7 @@ static void nv_put_opt(cmdarg_T *cap, bool fix_indent)
* line. */
if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count) {
curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
- coladvance((colnr_T)MAXCOL);
+ coladvance(MAXCOL);
}
}
auto_format(false, true);
diff --git a/src/nvim/ops.c b/src/nvim/ops.c
index ea52d6a3d3..3038fad894 100644
--- a/src/nvim/ops.c
+++ b/src/nvim/ops.c
@@ -4305,11 +4305,12 @@ format_lines(
* tabs and spaces, according to current options */
(void)set_indent(get_indent(), SIN_CHANGED);
- /* put cursor on last non-space */
- State = NORMAL; /* don't go past end-of-line */
- coladvance((colnr_T)MAXCOL);
- while (curwin->w_cursor.col && ascii_isspace(gchar_cursor()))
+ // put cursor on last non-space
+ State = NORMAL; // don't go past end-of-line
+ coladvance(MAXCOL);
+ while (curwin->w_cursor.col && ascii_isspace(gchar_cursor())) {
dec_cursor();
+ }
/* do the formatting, without 'showmode' */
State = INSERT; /* for open_line() */
diff --git a/src/nvim/path.c b/src/nvim/path.c
index 2de7e00ddb..3e1713fbdd 100644
--- a/src/nvim/path.c
+++ b/src/nvim/path.c
@@ -342,7 +342,7 @@ int path_fnamencmp(const char *const fname1, const char *const fname2,
p1 += utfc_ptr2len((const char_u *)p1);
p2 += utfc_ptr2len((const char_u *)p2);
}
- return c1 - c2;
+ return p_fic ? CH_FOLD(c1) - CH_FOLD(c2) : c1 - c2;
#else
if (p_fic) {
return mb_strnicmp((const char_u *)fname1, (const char_u *)fname2, len);
diff --git a/src/nvim/pos.h b/src/nvim/pos.h
index 8e86ea08c5..b7c4b6ef92 100644
--- a/src/nvim/pos.h
+++ b/src/nvim/pos.h
@@ -1,6 +1,9 @@
#ifndef NVIM_POS_H
#define NVIM_POS_H
+// for INT_MAX, LONG_MAX et al.
+#include <limits.h>
+
typedef long linenr_T; // line number type
/// Format used to print values which have linenr_T type
#define PRIdLINENR "ld"
@@ -12,8 +15,8 @@ typedef int colnr_T;
/// Maximal (invalid) line number
enum { MAXLNUM = 0x7fffffff };
-/// Maximal column number, 31 bits
-enum { MAXCOL = 0x7fffffff };
+/// Maximal column number
+enum { MAXCOL = INT_MAX };
// Minimum line number
enum { MINLNUM = 1 };
// minimum column number
diff --git a/src/nvim/screen.c b/src/nvim/screen.c
index c16fe46955..20e3cc0a2e 100644
--- a/src/nvim/screen.c
+++ b/src/nvim/screen.c
@@ -143,7 +143,7 @@ long tab_page_click_defs_size = 0;
// for line_putchar. Contains the state that needs to be remembered from
// putting one character to the next.
typedef struct {
- const char_u *p;
+ const char *p;
int prev_c; // previous Arabic character
int prev_c1; // first composing char for prev_c
} LineState;
@@ -1857,7 +1857,7 @@ static int compute_foldcolumn(win_T *wp, int col)
/// Handles composing chars and arabic shaping state.
static int line_putchar(LineState *s, schar_T *dest, int maxcells, bool rl)
{
- const char_u *p = s->p;
+ const char_u *p = (char_u *)s->p;
int cells = utf_ptr2cells(p);
int c_len = utfc_ptr2len(p);
int u8c, u8cc[MAX_MCO];
@@ -2870,6 +2870,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow,
&& vcol >= (long)wp->w_virtcol)
|| (number_only && draw_state > WL_NR))
&& filler_todo <= 0) {
+ draw_virt_text(buf, &col, grid->Columns);
grid_put_linebuf(grid, row, 0, col, -grid->Columns, wp->w_p_rl, wp,
wp->w_hl_attr_normal, false);
// Pretend we have finished updating the window. Except when
@@ -3397,7 +3398,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow,
}
if (has_decor && v > 0) {
- int extmark_attr = decor_redraw_col(wp->w_buffer, (colnr_T)v-1,
+ int extmark_attr = decor_redraw_col(wp->w_buffer, (colnr_T)v-1, off,
&decor_state);
if (extmark_attr != 0) {
if (!attr_pri) {
@@ -3919,7 +3920,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow,
int i;
size_t virt_pos = 0;
- LineState s = LINE_STATE((char_u *)"");
+ LineState s = LINE_STATE("");
int virt_attr = 0;
// Make sure alignment is the same regardless
@@ -3963,7 +3964,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow,
if (do_virttext && !delay_virttext) {
if (*s.p == NUL) {
if (virt_pos < virt_text.size) {
- s.p = (char_u *)kv_A(virt_text, virt_pos).text;
+ s.p = kv_A(virt_text, virt_pos).text;
int hl_id = kv_A(virt_text, virt_pos).hl_id;
virt_attr = hl_id > 0 ? syn_id2attr(hl_id) : 0;
virt_pos++;
@@ -4029,6 +4030,8 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow,
col += n;
}
}
+
+ draw_virt_text(buf, &col, grid->Columns);
grid_put_linebuf(grid, row, 0, col, grid->Columns, wp->w_p_rl, wp,
wp->w_hl_attr_normal, false);
row++;
@@ -4247,7 +4250,10 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow,
&& (grid->Columns == Columns // Window spans the width of the screen,
|| ui_has(kUIMultigrid)) // or has dedicated grid.
&& !wp->w_p_rl; // Not right-to-left.
- grid_put_linebuf(grid, row, 0, col - boguscols, grid->Columns, wp->w_p_rl,
+
+ int draw_col = col - boguscols;
+ draw_virt_text(buf, &draw_col, grid->Columns);
+ grid_put_linebuf(grid, row, 0, draw_col, grid->Columns, wp->w_p_rl,
wp, wp->w_hl_attr_normal, wrap);
if (wrap) {
ScreenGrid *current_grid = grid;
@@ -4323,6 +4329,43 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow,
return row;
}
+void draw_virt_text(buf_T *buf, int *end_col, int max_col)
+{
+ DecorState *state = &decor_state;
+ for (size_t i = 0; i < kv_size(state->active); i++) {
+ HlRange *item = &kv_A(state->active, i);
+ if (item->start_row == state->row && item->virt_text
+ && item->virt_text_pos == kVTOverlay
+ && item->virt_col >= 0) {
+ VirtText vt = *item->virt_text;
+ LineState s = LINE_STATE("");
+ int virt_attr = 0;
+ int col = item->virt_col;
+ size_t virt_pos = 0;
+ item->virt_col = -2; // deactivate
+
+ while (col < max_col) {
+ if (!*s.p) {
+ if (virt_pos == kv_size(vt)) {
+ break;
+ }
+ s.p = kv_A(vt, virt_pos).text;
+ int hl_id = kv_A(vt, virt_pos).hl_id;
+ virt_attr = hl_id > 0 ? syn_id2attr(hl_id) : 0;
+ virt_pos++;
+ continue;
+ }
+ int cells = line_putchar(&s, &linebuf_char[col], 2, false);
+ linebuf_attr[col++] = virt_attr;
+ if (cells > 1) {
+ linebuf_attr[col++] = virt_attr;
+ }
+ }
+ *end_col = MAX(*end_col, col);
+ }
+ }
+}
+
/// Determine if dedicated window grid should be used or the default_grid
///
/// If UI did not request multigrid support, draw all windows on the
@@ -7109,11 +7152,13 @@ static void win_redr_ruler(win_T *wp, int always)
if (wp->w_cursor.lnum > wp->w_buffer->b_ml.ml_line_count)
return;
- /* Don't draw the ruler while doing insert-completion, it might overwrite
- * the (long) mode message. */
- if (wp == lastwin && lastwin->w_status_height == 0)
- if (edit_submode != NULL)
+ // Don't draw the ruler while doing insert-completion, it might overwrite
+ // the (long) mode message.
+ if (wp == lastwin && lastwin->w_status_height == 0) {
+ if (edit_submode != NULL) {
return;
+ }
+ }
if (*p_ruf) {
int save_called_emsg = called_emsg;
diff --git a/src/nvim/search.c b/src/nvim/search.c
index 2802da6f7f..84b71d56a0 100644
--- a/src/nvim/search.c
+++ b/src/nvim/search.c
@@ -2685,8 +2685,9 @@ fwd_word(
while (--count >= 0) {
/* When inside a range of folded lines, move to the last char of the
* last line. */
- if (hasFolding(curwin->w_cursor.lnum, NULL, &curwin->w_cursor.lnum))
- coladvance((colnr_T)MAXCOL);
+ if (hasFolding(curwin->w_cursor.lnum, NULL, &curwin->w_cursor.lnum)) {
+ coladvance(MAXCOL);
+ }
sclass = cls();
/*
@@ -2803,8 +2804,9 @@ int end_word(long count, int bigword, int stop, int empty)
while (--count >= 0) {
/* When inside a range of folded lines, move to the last char of the
* last line. */
- if (hasFolding(curwin->w_cursor.lnum, NULL, &curwin->w_cursor.lnum))
- coladvance((colnr_T)MAXCOL);
+ if (hasFolding(curwin->w_cursor.lnum, NULL, &curwin->w_cursor.lnum)) {
+ coladvance(MAXCOL);
+ }
sclass = cls();
if (inc_cursor() == -1)
return FAIL;
diff --git a/src/nvim/tag.c b/src/nvim/tag.c
index 84ca240734..4ea298fba9 100644
--- a/src/nvim/tag.c
+++ b/src/nvim/tag.c
@@ -3152,7 +3152,7 @@ int get_tags(list_T *list, char_u *pat, char_u *buf_fname)
bool is_static;
ret = find_tags(pat, &num_matches, &matches,
- TAG_REGEXP | TAG_NOIC, (int)MAXCOL, buf_fname);
+ TAG_REGEXP | TAG_NOIC, MAXCOL, buf_fname);
if (ret == OK && num_matches > 0) {
for (i = 0; i < num_matches; ++i) {
int parse_result = parse_match(matches[i], &tp);
diff --git a/src/nvim/testdir/test_alot.vim b/src/nvim/testdir/test_alot.vim
index 4f056abdc0..daf3c9c110 100644
--- a/src/nvim/testdir/test_alot.vim
+++ b/src/nvim/testdir/test_alot.vim
@@ -37,7 +37,6 @@ source test_recover.vim
source test_scroll_opt.vim
source test_sort.vim
source test_sha256.vim
-source test_statusline.vim
source test_suspend.vim
source test_syn_attr.vim
source test_tabline.vim
diff --git a/src/nvim/testdir/test_exit.vim b/src/nvim/testdir/test_exit.vim
index 99a401d4a4..bd3e9eb4d4 100644
--- a/src/nvim/testdir/test_exit.vim
+++ b/src/nvim/testdir/test_exit.vim
@@ -81,3 +81,32 @@ func Test_exiting()
endif
call delete('Xtestout')
endfunc
+
+" Test for getting the Vim exit code from v:exiting
+func Test_exit_code()
+ call assert_equal(v:null, v:exiting)
+
+ let before =<< trim [CODE]
+ au QuitPre * call writefile(['qp = ' .. v:exiting], 'Xtestout', 'a')
+ au ExitPre * call writefile(['ep = ' .. v:exiting], 'Xtestout', 'a')
+ au VimLeavePre * call writefile(['lp = ' .. v:exiting], 'Xtestout', 'a')
+ au VimLeave * call writefile(['l = ' .. v:exiting], 'Xtestout', 'a')
+ [CODE]
+
+ if RunVim(before, ['quit'], '')
+ call assert_equal(['qp = null', 'ep = null', 'lp = 0', 'l = 0'], readfile('Xtestout'))
+ endif
+ call delete('Xtestout')
+
+ if RunVim(before, ['cquit'], '')
+ call assert_equal(['lp = 1', 'l = 1'], readfile('Xtestout'))
+ endif
+ call delete('Xtestout')
+
+ if RunVim(before, ['cquit 4'], '')
+ call assert_equal(['lp = 4', 'l = 4'], readfile('Xtestout'))
+ endif
+ call delete('Xtestout')
+endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_filetype.vim b/src/nvim/testdir/test_filetype.vim
index f9f0ade1f6..6bc5fba5db 100644
--- a/src/nvim/testdir/test_filetype.vim
+++ b/src/nvim/testdir/test_filetype.vim
@@ -79,6 +79,7 @@ let s:filename_checks = {
\ 'bc': ['file.bc'],
\ 'bdf': ['file.bdf'],
\ 'bib': ['file.bib'],
+ \ 'beancount': ['file.beancount'],
\ 'bindzone': ['named.root'],
\ 'blank': ['file.bl'],
\ 'bsdl': ['file.bsd', 'file.bsdl'],
@@ -427,6 +428,7 @@ let s:filename_checks = {
\ 'slrnrc': ['.slrnrc'],
\ 'slrnsc': ['file.score'],
\ 'sm': ['sendmail.cf'],
+ \ 'svelte': ['file.svelte'],
\ 'smarty': ['file.tpl'],
\ 'smcl': ['file.hlp', 'file.ihlp', 'file.smcl'],
\ 'smith': ['file.smt', 'file.smith'],
diff --git a/src/nvim/testdir/test_functions.vim b/src/nvim/testdir/test_functions.vim
index f0c1a1c7f9..5dae8d681a 100644
--- a/src/nvim/testdir/test_functions.vim
+++ b/src/nvim/testdir/test_functions.vim
@@ -833,6 +833,31 @@ func Test_byte2line_line2byte()
bw!
endfunc
+" Test for charidx()
+func Test_charidx()
+ let a = 'xáb́y'
+ call assert_equal(0, charidx(a, 0))
+ call assert_equal(1, charidx(a, 3))
+ call assert_equal(2, charidx(a, 4))
+ call assert_equal(3, charidx(a, 7))
+ call assert_equal(-1, charidx(a, 8))
+ call assert_equal(-1, charidx('', 0))
+
+ " count composing characters
+ call assert_equal(0, charidx(a, 0, 1))
+ call assert_equal(2, charidx(a, 2, 1))
+ call assert_equal(3, charidx(a, 4, 1))
+ call assert_equal(5, charidx(a, 7, 1))
+ call assert_equal(-1, charidx(a, 8, 1))
+ call assert_equal(-1, charidx('', 0, 1))
+
+ call assert_fails('let x = charidx([], 1)', 'E474:')
+ call assert_fails('let x = charidx("abc", [])', 'E474:')
+ call assert_fails('let x = charidx("abc", 1, [])', 'E474:')
+ call assert_fails('let x = charidx("abc", 1, -1)', 'E474:')
+ call assert_fails('let x = charidx("abc", 1, 2)', 'E474:')
+endfunc
+
func Test_count()
let l = ['a', 'a', 'A', 'b']
call assert_equal(2, count(l, 'a'))
diff --git a/src/nvim/testdir/test_options.vim b/src/nvim/testdir/test_options.vim
index 5a10c9baa6..1202b842fd 100644
--- a/src/nvim/testdir/test_options.vim
+++ b/src/nvim/testdir/test_options.vim
@@ -1,5 +1,7 @@
" Test for options
+source check.vim
+
func Test_whichwrap()
set whichwrap=b,s
call assert_equal('b,s', &whichwrap)
@@ -604,6 +606,27 @@ func Test_opt_boolean()
set number&
endfunc
+func Test_opt_winminheight_term()
+ " See test/functional/legacy/options_spec.lua
+ CheckRunVimInTerminal
+
+ " The tabline should be taken into account.
+ let lines =<< trim END
+ set wmh=0 stal=2
+ below sp | wincmd _
+ below sp | wincmd _
+ below sp | wincmd _
+ below sp
+ END
+ call writefile(lines, 'Xwinminheight')
+ let buf = RunVimInTerminal('-S Xwinminheight', #{rows: 11})
+ call term_sendkeys(buf, ":set wmh=1\n")
+ call WaitForAssert({-> assert_match('E36: Not enough room', term_getline(buf, 11))})
+
+ call StopVimInTerminal(buf)
+ call delete('Xwinminheight')
+endfunc
+
" Test for setting option value containing spaces with isfname+=32
func Test_isfname_with_options()
set isfname+=32
@@ -613,4 +636,23 @@ func Test_isfname_with_options()
setlocal keywordprg&
endfunc
+" Test that resetting laststatus does change scroll option
+func Test_opt_reset_scroll()
+ " See test/functional/legacy/options_spec.lua
+ CheckRunVimInTerminal
+ let vimrc =<< trim [CODE]
+ set scroll=2
+ set laststatus=2
+ [CODE]
+ call writefile(vimrc, 'Xscroll')
+ let buf = RunVimInTerminal('-S Xscroll', {'rows': 16, 'cols': 45})
+ call term_sendkeys(buf, ":verbose set scroll?\n")
+ call WaitForAssert({-> assert_match('Last set.*window size', term_getline(buf, 15))})
+ call assert_match('^\s*scroll=7$', term_getline(buf, 14))
+ call StopVimInTerminal(buf)
+
+ " clean up
+ call delete('Xscroll')
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_statusline.vim b/src/nvim/testdir/test_statusline.vim
index 4e38f7ebd8..ce2ef4dcd8 100644
--- a/src/nvim/testdir/test_statusline.vim
+++ b/src/nvim/testdir/test_statusline.vim
@@ -1,12 +1,12 @@
" Test 'statusline'
"
" Not tested yet:
-" %a
" %N
" %T
" %X
source view_util.vim
+source check.vim
source term_util.vim
func s:get_statusline()
@@ -61,7 +61,19 @@ func Test_statusline_will_be_disabled_with_error()
endfunc
func Test_statusline()
- new Xstatusline
+ CheckFeature quickfix
+
+ " %a: Argument list ({current} of {max})
+ set statusline=%a
+ call assert_match('^\s*$', s:get_statusline())
+ arglocal a1 a2
+ rewind
+ call assert_match('^ (1 of 2)\s*$', s:get_statusline())
+ next
+ call assert_match('^ (2 of 2)\s*$', s:get_statusline())
+ e Xstatusline
+ call assert_match('^ ((2) of 2)\s*$', s:get_statusline())
+
only
set laststatus=2
set splitbelow
diff --git a/src/nvim/testdir/test_user_func.vim b/src/nvim/testdir/test_user_func.vim
index 67701ee3ca..e9e181ce3d 100644
--- a/src/nvim/testdir/test_user_func.vim
+++ b/src/nvim/testdir/test_user_func.vim
@@ -95,6 +95,59 @@ func Test_user_func()
enew!
endfunc
+func Log(val, base = 10)
+ return log(a:val) / log(a:base)
+endfunc
+
+func Args(mandatory, optional = v:null, ...)
+ return deepcopy(a:)
+endfunc
+
+func Args2(a = 1, b = 2, c = 3)
+ return deepcopy(a:)
+endfunc
+
+func MakeBadFunc()
+ func s:fcn(a, b=1, c)
+ endfunc
+endfunc
+
+func Test_default_arg()
+ call assert_equal(1.0, Log(10))
+ call assert_equal(log(10), Log(10, exp(1)))
+ call assert_fails("call Log(1,2,3)", 'E118')
+
+ let res = Args(1)
+ call assert_equal(res.mandatory, 1)
+ call assert_equal(res.optional, v:null)
+ call assert_equal(res['0'], 0)
+
+ let res = Args(1,2)
+ call assert_equal(res.mandatory, 1)
+ call assert_equal(res.optional, 2)
+ call assert_equal(res['0'], 0)
+
+ let res = Args(1,2,3)
+ call assert_equal(res.mandatory, 1)
+ call assert_equal(res.optional, 2)
+ call assert_equal(res['0'], 1)
+
+ call assert_fails("call MakeBadFunc()", 'E989')
+ call assert_fails("fu F(a=1 ,) | endf", 'E475')
+
+ " Since neovim does not have v:none, the ability to use the default
+ " argument with the intermediate argument set to v:none has been omitted.
+ " Therefore, this test is not performed.
+ " let d = Args2(7, v:none, 9)
+ " call assert_equal([7, 2, 9], [d.a, d.b, d.c])
+
+ call assert_equal("\n"
+ \ .. " function Args2(a = 1, b = 2, c = 3)\n"
+ \ .. "1 return deepcopy(a:)\n"
+ \ .. " endfunction",
+ \ execute('func Args2'))
+endfunc
+
func Test_failed_call_in_try()
try | call UnknownFunc() | catch | endtry
endfunc
diff --git a/src/nvim/tui/input.c b/src/nvim/tui/input.c
index 3e683a4926..6705ab98c2 100644
--- a/src/nvim/tui/input.c
+++ b/src/nvim/tui/input.c
@@ -557,8 +557,8 @@ HandleState ut_handle_background_color(TermInput *input)
static void handle_raw_buffer(TermInput *input, bool force)
{
- HandleState is_paste;
- HandleState is_bc;
+ HandleState is_paste = kNotApplicable;
+ HandleState is_bc = kNotApplicable;
do {
if (!force
diff --git a/src/nvim/undo.c b/src/nvim/undo.c
index 8c2ae3bc35..f52850f6f3 100644
--- a/src/nvim/undo.c
+++ b/src/nvim/undo.c
@@ -594,13 +594,20 @@ int u_savecommon(linenr_T top, linenr_T bot, linenr_T newbot, int reload)
}
-# define UF_START_MAGIC "Vim\237UnDo\345" /* magic at start of undofile */
+// magic at start of undofile
+# define UF_START_MAGIC "Vim\237UnDo\345"
# define UF_START_MAGIC_LEN 9
-# define UF_HEADER_MAGIC 0x5fd0 /* magic at start of header */
-# define UF_HEADER_END_MAGIC 0xe7aa /* magic after last header */
-# define UF_ENTRY_MAGIC 0xf518 /* magic at start of entry */
-# define UF_ENTRY_END_MAGIC 0x3581 /* magic after last entry */
-# define UF_VERSION 2 /* 2-byte undofile version number */
+// magic at start of header
+# define UF_HEADER_MAGIC 0x5fd0
+// magic after last header
+# define UF_HEADER_END_MAGIC 0xe7aa
+// magic at start of entry
+# define UF_ENTRY_MAGIC 0xf518
+// magic after last entry
+# define UF_ENTRY_END_MAGIC 0x3581
+
+// 2-byte undofile version number
+# define UF_VERSION 3
/* extra fields for header */
# define UF_LAST_SAVE_NR 1
@@ -847,6 +854,15 @@ static bool serialize_uhp(bufinfo_T *bi, u_header_T *uhp)
}
}
undo_write_bytes(bi, (uintmax_t)UF_ENTRY_END_MAGIC, 2);
+
+ // Write all extmark undo objects
+ for (size_t i = 0; i < kv_size(uhp->uh_extmark); i++) {
+ if (!serialize_extmark(bi, kv_A(uhp->uh_extmark, i))) {
+ return false;
+ }
+ }
+ undo_write_bytes(bi, (uintmax_t)UF_ENTRY_END_MAGIC, 2);
+
return true;
}
@@ -928,9 +944,95 @@ static u_header_T *unserialize_uhp(bufinfo_T *bi,
return NULL;
}
+ // Unserialize all extmark undo information
+ ExtmarkUndoObject *extup;
+ kv_init(uhp->uh_extmark);
+
+ while ((c = undo_read_2c(bi)) == UF_ENTRY_MAGIC) {
+ bool error = false;
+ extup = unserialize_extmark(bi, &error, file_name);
+ if (error) {
+ kv_destroy(uhp->uh_extmark);
+ xfree(extup);
+ return NULL;
+ }
+ kv_push(uhp->uh_extmark, *extup);
+ xfree(extup);
+ }
+ if (c != UF_ENTRY_END_MAGIC) {
+ corruption_error("entry end", file_name);
+ u_free_uhp(uhp);
+ return NULL;
+ }
+
return uhp;
}
+static bool serialize_extmark(bufinfo_T *bi, ExtmarkUndoObject extup)
+{
+ if (extup.type == kExtmarkSplice) {
+ undo_write_bytes(bi, (uintmax_t)UF_ENTRY_MAGIC, 2);
+ undo_write_bytes(bi, (uintmax_t)extup.type, 4);
+ if (!undo_write(bi, (uint8_t *)&(extup.data.splice),
+ sizeof(ExtmarkSplice))) {
+ return false;
+ }
+ } else if (extup.type == kExtmarkMove) {
+ undo_write_bytes(bi, (uintmax_t)UF_ENTRY_MAGIC, 2);
+ undo_write_bytes(bi, (uintmax_t)extup.type, 4);
+ if (!undo_write(bi, (uint8_t *)&(extup.data.move), sizeof(ExtmarkMove))) {
+ return false;
+ }
+ }
+ // Note: We do not serialize ExtmarkSavePos information, since
+ // buffer marktrees are not retained when closing/reopening a file
+ return true;
+}
+
+static ExtmarkUndoObject *unserialize_extmark(bufinfo_T *bi, bool *error,
+ const char *filename)
+{
+ UndoObjectType type;
+ uint8_t *buf = NULL;
+ size_t n_elems;
+
+ ExtmarkUndoObject *extup = xmalloc(sizeof(ExtmarkUndoObject));
+
+ type = (UndoObjectType)undo_read_4c(bi);
+ extup->type = type;
+ if (type == kExtmarkSplice) {
+ n_elems = (size_t)sizeof(ExtmarkSplice) / sizeof(uint8_t);
+ buf = xcalloc(sizeof(uint8_t), n_elems);
+ if (!undo_read(bi, buf, n_elems)) {
+ goto error;
+ }
+ extup->data.splice = *(ExtmarkSplice *)buf;
+ } else if (type == kExtmarkMove) {
+ n_elems = (size_t)sizeof(ExtmarkMove) / sizeof(uint8_t);
+ buf = xcalloc(sizeof(uint8_t), n_elems);
+ if (!undo_read(bi, buf, n_elems)) {
+ goto error;
+ }
+ extup->data.move = *(ExtmarkMove *)buf;
+ } else {
+ goto error;
+ }
+
+ if (buf) {
+ xfree(buf);
+ }
+
+ return extup;
+
+error:
+ xfree(extup);
+ if (buf) {
+ xfree(buf);
+ }
+ *error = true;
+ return NULL;
+}
+
/// Serializes "uep".
///
/// @param bi The buffer information
diff --git a/src/nvim/window.c b/src/nvim/window.c
index 00f49724b6..0f717a2f90 100644
--- a/src/nvim/window.c
+++ b/src/nvim/window.c
@@ -5501,7 +5501,7 @@ void win_setminheight(void)
// loop until there is a 'winminheight' that is possible
while (p_wmh > 0) {
- const int room = Rows - p_ch;
+ const int room = Rows - p_ch - tabline_height();
const int needed = frame_minheight(topframe, NULL);
if (room >= needed) {
break;
@@ -5960,9 +5960,17 @@ void win_new_width(win_T *wp, int width)
void win_comp_scroll(win_T *wp)
{
+ const long old_w_p_scr = wp->w_p_scr;
+
wp->w_p_scr = wp->w_height / 2;
- if (wp->w_p_scr == 0)
+ if (wp->w_p_scr == 0) {
wp->w_p_scr = 1;
+ }
+ if (wp->w_p_scr != old_w_p_scr) {
+ // Used by "verbose set scroll".
+ wp->w_p_script_ctx[WV_SCROLL].script_ctx.sc_sid = SID_WINLAYOUT;
+ wp->w_p_script_ctx[WV_SCROLL].script_ctx.sc_lnum = 0;
+ }
}
/*
diff --git a/test/functional/ex_cmds/source_spec.lua b/test/functional/ex_cmds/source_spec.lua
new file mode 100644
index 0000000000..16d0dfb6a1
--- /dev/null
+++ b/test/functional/ex_cmds/source_spec.lua
@@ -0,0 +1,47 @@
+local helpers = require('test.functional.helpers')(after_each)
+local command = helpers.command
+local insert = helpers.insert
+local eq = helpers.eq
+local clear = helpers.clear
+local meths = helpers.meths
+local feed = helpers.feed
+local feed_command = helpers.feed_command
+
+describe(':source', function()
+ before_each(function()
+ clear()
+ end)
+
+ it('current buffer', function()
+ insert('let a = 2')
+ command('source')
+ eq('2', meths.exec('echo a', true))
+ end)
+
+ it('selection in current buffer', function()
+ insert(
+ 'let a = 2\n'..
+ 'let a = 3\n'..
+ 'let a = 4\n')
+
+ -- Source the 2nd line only
+ feed('ggjV')
+ feed_command(':source')
+ eq('3', meths.exec('echo a', true))
+
+ -- Source from 2nd line to end of file
+ feed('ggjVG')
+ feed_command(':source')
+ eq('4', meths.exec('echo a', true))
+ end)
+
+ it('multiline heredoc command', function()
+ insert(
+ 'lua << EOF\n'..
+ 'y = 4\n'..
+ 'EOF\n')
+
+ command('source')
+ eq('4', meths.exec('echo luaeval("y")', true))
+ end)
+end)
diff --git a/test/functional/fixtures/fake-lsp-server.lua b/test/functional/fixtures/fake-lsp-server.lua
index 252db88b6b..3bbb4c4517 100644
--- a/test/functional/fixtures/fake-lsp-server.lua
+++ b/test/functional/fixtures/fake-lsp-server.lua
@@ -70,11 +70,11 @@ local function expect_notification(method, params, ...)
..., "expect_notification", "message")
end
-local function expect_request(method, callback, ...)
+local function expect_request(method, handler, ...)
local req = read_message()
assert_eq(method, req.method,
..., "expect_request", "method")
- local err, result = callback(req.params)
+ local err, result = handler(req.params)
respond(req.id, err, result)
end
diff --git a/test/functional/legacy/options_spec.lua b/test/functional/legacy/options_spec.lua
index 1db7afc7a7..d7f5df3a1e 100644
--- a/test/functional/legacy/options_spec.lua
+++ b/test/functional/legacy/options_spec.lua
@@ -1,6 +1,10 @@
+-- See also: src/nvim/testdir/test_options.vim
local helpers = require('test.functional.helpers')(after_each)
local command, clear = helpers.command, helpers.clear
local source, expect = helpers.source, helpers.expect
+local exc_exec = helpers.exc_exec;
+local matches = helpers.matches;
+local Screen = require('test.functional.ui.screen')
describe('options', function()
setup(clear)
@@ -11,7 +15,7 @@ describe('options', function()
end)
describe('set', function()
- setup(clear)
+ before_each(clear)
it("should keep two comma when 'path' is changed", function()
source([[
@@ -24,4 +28,45 @@ describe('set', function()
foo,,bar]])
end)
+
+ it('winminheight works', function()
+ local screen = Screen.new(20, 11)
+ screen:attach()
+ source([[
+ set wmh=0 stal=2
+ below sp | wincmd _
+ below sp | wincmd _
+ below sp | wincmd _
+ below sp
+ ]])
+ matches('E36: Not enough room', exc_exec('set wmh=1'))
+ end)
+
+ it('scroll works', function()
+ local screen = Screen.new(42, 16)
+ screen:attach()
+ source([[
+ set scroll=2
+ set laststatus=2
+ ]])
+ command('verbose set scroll?')
+ screen:expect([[
+ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ |
+ scroll=7 |
+ Last set from changed window size |
+ Press ENTER or type command to continue^ |
+ ]])
+ end)
end)
diff --git a/test/functional/lua/buffer_updates_spec.lua b/test/functional/lua/buffer_updates_spec.lua
index 8c5e936906..7a6b5be8bc 100644
--- a/test/functional/lua/buffer_updates_spec.lua
+++ b/test/functional/lua/buffer_updates_spec.lua
@@ -666,8 +666,62 @@ describe('lua: nvim_buf_attach on_bytes', function()
}
end)
+ it("sends events when undoing with undofile", function()
+ write_file("Xtest-undofile", dedent([[
+ 12345
+ hello world
+ ]]))
+
+ command("e! Xtest-undofile")
+ command("set undodir=. | set undofile")
+
+ local ns = helpers.request('nvim_create_namespace', "ns1")
+ meths.buf_set_extmark(0, ns, 0, 0, {})
+
+ eq({"12345", "hello world"}, meths.buf_get_lines(0, 0, -1, true))
+
+ -- splice
+ feed("gg0d2l")
+
+ eq({"345", "hello world"}, meths.buf_get_lines(0, 0, -1, true))
+
+ -- move
+ command(".m+1")
+
+ eq({"hello world", "345"}, meths.buf_get_lines(0, 0, -1, true))
+
+ -- reload undofile and undo changes
+ command("w")
+ command("set noundofile")
+ command("bw!")
+ command("e! Xtest-undofile")
+
+ command("set undofile")
+
+ local check_events = setup_eventcheck(verify, nil)
+
+ feed("u")
+ eq({"345", "hello world"}, meths.buf_get_lines(0, 0, -1, true))
+
+ check_events {
+ { "test1", "bytes", 2, 6, 1, 0, 12, 1, 0, 4, 0, 0, 0 },
+ { "test1", "bytes", 2, 6, 0, 0, 0, 0, 0, 0, 1, 0, 4 }
+ }
+
+ feed("u")
+ eq({"12345", "hello world"}, meths.buf_get_lines(0, 0, -1, true))
+
+ check_events {
+ { "test1", "bytes", 2, 8, 0, 0, 0, 0, 0, 0, 0, 2, 2 }
+ }
+ command("bw!")
+ end)
+
+
teardown(function()
os.remove "Xtest-reload"
+ os.remove "Xtest-undofile"
+ os.remove ".Xtest-undofile.un~"
end)
end
diff --git a/test/functional/plugin/lsp/diagnostic_spec.lua b/test/functional/plugin/lsp/diagnostic_spec.lua
index 4705a76465..8c91c4ab2c 100644
--- a/test/functional/plugin/lsp/diagnostic_spec.lua
+++ b/test/functional/plugin/lsp/diagnostic_spec.lua
@@ -208,6 +208,69 @@ describe('vim.lsp.diagnostic', function()
]]))
end)
+ describe('reset', function()
+ it('diagnostic count is 0 and displayed diagnostics are 0 after call', function()
+ -- 1 Error (1)
+ -- 1 Warning (2)
+ -- 1 Warning (2) + 1 Warning (1)
+ -- 2 highlights and 2 underlines (since error)
+ -- 1 highlight + 1 underline
+ local all_highlights = {1, 1, 2, 4, 2}
+ eq(all_highlights, exec_lua [[
+ local server_1_diags = {
+ make_error("Error 1", 1, 1, 1, 5),
+ make_warning("Warning on Server 1", 2, 1, 2, 5),
+ }
+ local server_2_diags = {
+ make_warning("Warning 1", 2, 1, 2, 5),
+ }
+
+ vim.lsp.diagnostic.on_publish_diagnostics(nil, nil, { uri = fake_uri, diagnostics = server_1_diags }, 1)
+ vim.lsp.diagnostic.on_publish_diagnostics(nil, nil, { uri = fake_uri, diagnostics = server_2_diags }, 2)
+ return {
+ vim.lsp.diagnostic.get_count(diagnostic_bufnr, "Error", 1),
+ vim.lsp.diagnostic.get_count(diagnostic_bufnr, "Warning", 2),
+ vim.lsp.diagnostic.get_count(diagnostic_bufnr, "Warning", nil),
+ count_of_extmarks_for_client(diagnostic_bufnr, 1),
+ count_of_extmarks_for_client(diagnostic_bufnr, 2),
+ }
+ ]])
+
+ -- Reset diagnostics from server 1
+ exec_lua([[ vim.lsp.diagnostic.reset(1, { [ diagnostic_bufnr ] = { [ 1 ] = true ; [ 2 ] = true } } )]])
+
+ -- Make sure we have the right diagnostic count
+ eq({0, 1, 1, 0, 2} , exec_lua [[
+ local diagnostic_count = {}
+ vim.wait(100, function () diagnostic_count = {
+ vim.lsp.diagnostic.get_count(diagnostic_bufnr, "Error", 1),
+ vim.lsp.diagnostic.get_count(diagnostic_bufnr, "Warning", 2),
+ vim.lsp.diagnostic.get_count(diagnostic_bufnr, "Warning", nil),
+ count_of_extmarks_for_client(diagnostic_bufnr, 1),
+ count_of_extmarks_for_client(diagnostic_bufnr, 2),
+ } end )
+ return diagnostic_count
+ ]])
+
+ -- Reset diagnostics from server 2
+ exec_lua([[ vim.lsp.diagnostic.reset(2, { [ diagnostic_bufnr ] = { [ 1 ] = true ; [ 2 ] = true } } )]])
+
+ -- Make sure we have the right diagnostic count
+ eq({0, 0, 0, 0, 0}, exec_lua [[
+ local diagnostic_count = {}
+ vim.wait(100, function () diagnostic_count = {
+ vim.lsp.diagnostic.get_count(diagnostic_bufnr, "Error", 1),
+ vim.lsp.diagnostic.get_count(diagnostic_bufnr, "Warning", 2),
+ vim.lsp.diagnostic.get_count(diagnostic_bufnr, "Warning", nil),
+ count_of_extmarks_for_client(diagnostic_bufnr, 1),
+ count_of_extmarks_for_client(diagnostic_bufnr, 2),
+ } end )
+ return diagnostic_count
+ ]])
+
+ end)
+ end)
+
describe('get_next_diagnostic_pos', function()
it('can find the next pos with only one client', function()
eq({1, 1}, exec_lua [[
diff --git a/test/functional/plugin/lsp_spec.lua b/test/functional/plugin/lsp_spec.lua
index 981e2a96a8..8ac81daeef 100644
--- a/test/functional/plugin/lsp_spec.lua
+++ b/test/functional/plugin/lsp_spec.lua
@@ -41,10 +41,10 @@ local function fake_lsp_server_setup(test_name, timeout_ms)
"-c", string.format("lua TIMEOUT = %d", timeout),
"-c", "luafile "..fixture_filename,
};
- callbacks = setmetatable({}, {
+ handlers = setmetatable({}, {
__index = function(t, method)
return function(...)
- return vim.rpcrequest(1, 'callback', ...)
+ return vim.rpcrequest(1, 'handler', ...)
end
end;
});
@@ -89,7 +89,7 @@ local function test_rpc_server(config)
end
return NIL
end
- if method == 'callback' then
+ if method == 'handler' then
if config.on_callback then
config.on_callback(unpack(args))
end
@@ -205,7 +205,7 @@ describe('LSP', function()
}
test_rpc_server {
test_name = "basic_init";
- on_init = function(client, _init_result)
+ on_init = function(client, _)
-- client is a dummy object which will queue up commands to be run
-- once the server initializes. It can't accept lua callbacks or
-- other types that may be unserializable for now.
@@ -333,6 +333,7 @@ describe('LSP', function()
client.stop()
local full_kind = exec_lua("return require'vim.lsp.protocol'.TextDocumentSyncKind.Full")
eq(full_kind, client.resolved_capabilities().text_document_did_change)
+ eq(true, client.resolved_capabilities().text_document_save)
end;
on_exit = function(code, signal)
eq(0, code, "exit code", fake_lsp_logfile)
@@ -386,7 +387,7 @@ describe('LSP', function()
exec_lua([=[
BUFFER = vim.api.nvim_get_current_buf()
lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID)
- vim.lsp.callbacks['textDocument/typeDefinition'] = function(err, method)
+ vim.lsp.handlers['textDocument/typeDefinition'] = function(err, method)
vim.lsp._last_lsp_callback = { err = err; method = method }
end
vim.lsp._unsupported_method = function(method)
@@ -425,7 +426,7 @@ describe('LSP', function()
test_name = "capabilities_for_client_supports_method";
on_setup = function()
exec_lua([=[
- vim.lsp.callbacks['textDocument/typeDefinition'] = function(err, method)
+ vim.lsp.handlers['textDocument/typeDefinition'] = function(err, method)
vim.lsp._last_lsp_callback = { err = err; method = method }
end
vim.lsp._unsupported_method = function(method)
@@ -897,8 +898,8 @@ describe('LSP', function()
eq(0, code, "exit code", fake_lsp_logfile)
eq(0, signal, "exit signal", fake_lsp_logfile)
end;
- on_callback = function(err, method, params, client_id)
- eq(table.remove(expected_callbacks), {err, method, params, client_id}, "expected callback")
+ on_handler = function(err, method, params, client_id)
+ eq(table.remove(expected_callbacks), {err, method, params, client_id}, "expected handler")
end;
}
end)
@@ -1032,6 +1033,20 @@ describe('LSP', function()
'å ä ɧ 汉语 ↥ 🤦 🦄';
}, buf_lines(1))
end)
+ it('applies text edits at the end of the document', function()
+ local edits = {
+ make_edit(5, 0, 5, 0, "foobar");
+ }
+ exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1)
+ eq({
+ 'First line of text';
+ 'Second line of text';
+ 'Third line of text';
+ 'Fourth line of text';
+ 'å å ɧ 汉语 ↥ 🤦 🦄';
+ 'foobar';
+ }, buf_lines(1))
+ end)
describe('with LSP end line after what Vim considers to be the end line', function()
it('applies edits when the last linebreak is considered a new line', function()
@@ -1765,8 +1780,8 @@ describe('LSP', function()
uri = "file:///src/main.rs"
}
} }
- local callback = require'vim.lsp.handlers'['callHierarchy/outgoingCalls']
- callback(nil, nil, rust_analyzer_response)
+ local handler = require'vim.lsp.handlers'['callHierarchy/outgoingCalls']
+ handler(nil, nil, rust_analyzer_response)
return vim.fn.getqflist()
]=])
@@ -1837,8 +1852,8 @@ describe('LSP', function()
} }
} }
- local callback = require'vim.lsp.handlers'['callHierarchy/incomingCalls']
- callback(nil, nil, rust_analyzer_response)
+ local handler = require'vim.lsp.handlers'['callHierarchy/incomingCalls']
+ handler(nil, nil, rust_analyzer_response)
return vim.fn.getqflist()
]=])
diff --git a/test/functional/ui/decorations_spec.lua b/test/functional/ui/decorations_spec.lua
index 781fdf7203..7a87521a6b 100644
--- a/test/functional/ui/decorations_spec.lua
+++ b/test/functional/ui/decorations_spec.lua
@@ -302,3 +302,98 @@ describe('decorations providers', function()
]]}
end)
end)
+
+describe('extmark decorations', function()
+ local screen
+ before_each( function()
+ clear()
+ screen = Screen.new(50, 15)
+ screen:attach()
+ screen:set_default_attr_ids {
+ [1] = {bold=true, foreground=Screen.colors.Blue};
+ [2] = {foreground = Screen.colors.Brown};
+ [3] = {bold = true, foreground = Screen.colors.SeaGreen};
+ [4] = {background = Screen.colors.Red1, foreground = Screen.colors.Gray100};
+ }
+ end)
+
+ it('can have virtual text of overlay style', function()
+ insert [[
+for _,item in ipairs(items) do
+ local text, hl_id_cell, count = unpack(item)
+ if hl_id_cell ~= nil then
+ hl_id = hl_id_cell
+ end
+ for _ = 1, (count or 1) do
+ local cell = line[colpos]
+ cell.text = text
+ cell.hl_id = hl_id
+ colpos = colpos+1
+ end
+end]]
+ feed 'gg'
+
+ local ns = meths.create_namespace 'test'
+ for i = 1,9 do
+ meths.buf_set_extmark(0, ns, i, 0, { virt_text={{'|', 'LineNr'}}, virt_text_pos='overlay'})
+ if i == 3 or (i >= 6 and i <= 9) then
+ meths.buf_set_extmark(0, ns, i, 4, { virt_text={{'|', 'NonText'}}, virt_text_pos='overlay'})
+ end
+ end
+ meths.buf_set_extmark(0, ns, 9, 10, { virt_text={{'foo'}, {'bar', 'MoreMsg'}, {'!!', 'ErrorMsg'}}, virt_text_pos='overlay'})
+
+ -- can "float" beyond end of line
+ meths.buf_set_extmark(0, ns, 5, 28, { virt_text={{'loopy', 'ErrorMsg'}}, virt_text_pos='overlay'})
+ -- bound check: right edge of window
+ meths.buf_set_extmark(0, ns, 2, 26, { virt_text={{'bork bork bork ' }, {'bork bork bork', 'ErrorMsg'}}, virt_text_pos='overlay'})
+
+ screen:expect{grid=[[
+ ^for _,item in ipairs(items) do |
+ {2:|} local text, hl_id_cell, count = unpack(item) |
+ {2:|} if hl_id_cell ~= nil tbork bork bork {4:bork bork}|
+ {2:|} {1:|} hl_id = hl_id_cell |
+ {2:|} end |
+ {2:|} for _ = 1, (count or 1) {4:loopy} |
+ {2:|} {1:|} local cell = line[colpos] |
+ {2:|} {1:|} cell.text = text |
+ {2:|} {1:|} cell.hl_id = hl_id |
+ {2:|} {1:|} cofoo{3:bar}{4:!!}olpos+1 |
+ end |
+ end |
+ {1:~ }|
+ {1:~ }|
+ |
+ ]]}
+
+
+ -- handles broken lines
+ screen:try_resize(22, 25)
+ screen:expect{grid=[[
+ ^for _,item in ipairs(i|
+ tems) do |
+ {2:|} local text, hl_id_|
+ cell, count = unpack(i|
+ tem) |
+ {2:|} if hl_id_cell ~= n|
+ il tbork bork bork {4:bor}|
+ {2:|} {1:|} hl_id = hl_id_|
+ cell |
+ {2:|} end |
+ {2:|} for _ = 1, (count |
+ or 1) {4:loopy} |
+ {2:|} {1:|} local cell = l|
+ ine[colpos] |
+ {2:|} {1:|} cell.text = te|
+ xt |
+ {2:|} {1:|} cell.hl_id = h|
+ l_id |
+ {2:|} {1:|} cofoo{3:bar}{4:!!}olpo|
+ s+1 |
+ end |
+ end |
+ {1:~ }|
+ {1:~ }|
+ |
+ ]]}
+ end)
+end)
diff --git a/test/functional/ui/fold_spec.lua b/test/functional/ui/fold_spec.lua
index 6ce8b33a63..d3b1d33956 100644
--- a/test/functional/ui/fold_spec.lua
+++ b/test/functional/ui/fold_spec.lua
@@ -38,7 +38,9 @@ describe("folded lines", function()
[6] = {background = Screen.colors.Yellow},
[7] = {foreground = Screen.colors.DarkBlue, background = Screen.colors.WebGray},
[8] = {foreground = Screen.colors.Brown },
- [9] = {bold = true, foreground = Screen.colors.Brown}
+ [9] = {bold = true, foreground = Screen.colors.Brown},
+ [10] = {background = Screen.colors.LightGrey, underline = true},
+ [11] = {bold=true},
})
end)
@@ -290,6 +292,369 @@ describe("folded lines", function()
end
end)
+ it("works with split", function()
+ insert([[
+ aa
+ bb
+ cc
+ dd
+ ee
+ ff]])
+ feed_command('2')
+ command("set foldcolumn=1")
+ feed('zf3j')
+ feed_command('1')
+ feed('zf2j')
+ feed('zO')
+ feed_command("rightbelow new")
+ insert([[
+ aa
+ bb
+ cc
+ dd
+ ee
+ ff]])
+ feed_command('2')
+ command("set foldcolumn=1")
+ feed('zf3j')
+ feed_command('1')
+ feed('zf2j')
+ if multigrid then
+ meths.input_mouse('left', 'press', '', 4, 0, 0)
+ screen:expect([[
+ ## grid 1
+ [2:---------------------------------------------]|
+ [2:---------------------------------------------]|
+ {2:[No Name] [+] }|
+ [4:---------------------------------------------]|
+ [4:---------------------------------------------]|
+ [4:---------------------------------------------]|
+ {3:[No Name] [+] }|
+ [3:---------------------------------------------]|
+ ## grid 2
+ {7:-}aa |
+ {7:-}bb |
+ ## grid 3
+ :1 |
+ ## grid 4
+ {7:-}^aa |
+ {7:+}{5:+--- 4 lines: bb···························}|
+ {7:│}ff |
+ ]])
+ else
+ meths.input_mouse('left', 'press', '', 0, 3, 0)
+ screen:expect([[
+ {7:-}aa |
+ {7:-}bb |
+ {2:[No Name] [+] }|
+ {7:-}^aa |
+ {7:+}{5:+--- 4 lines: bb···························}|
+ {7:│}ff |
+ {3:[No Name] [+] }|
+ :1 |
+ ]])
+ end
+
+ if multigrid then
+ meths.input_mouse('left', 'press', '', 4, 1, 0)
+ screen:expect([[
+ ## grid 1
+ [2:---------------------------------------------]|
+ [2:---------------------------------------------]|
+ {2:[No Name] [+] }|
+ [4:---------------------------------------------]|
+ [4:---------------------------------------------]|
+ [4:---------------------------------------------]|
+ {3:[No Name] [+] }|
+ [3:---------------------------------------------]|
+ ## grid 2
+ {7:-}aa |
+ {7:-}bb |
+ ## grid 3
+ :1 |
+ ## grid 4
+ {7:-}^aa |
+ {7:-}bb |
+ {7:2}cc |
+ ]])
+ else
+ meths.input_mouse('left', 'press', '', 0, 4, 0)
+ screen:expect([[
+ {7:-}aa |
+ {7:-}bb |
+ {2:[No Name] [+] }|
+ {7:-}^aa |
+ {7:-}bb |
+ {7:2}cc |
+ {3:[No Name] [+] }|
+ :1 |
+ ]])
+ end
+
+ if multigrid then
+ meths.input_mouse('left', 'press', '', 2, 1, 0)
+ screen:expect([[
+ ## grid 1
+ [2:---------------------------------------------]|
+ [2:---------------------------------------------]|
+ {3:[No Name] [+] }|
+ [4:---------------------------------------------]|
+ [4:---------------------------------------------]|
+ [4:---------------------------------------------]|
+ {2:[No Name] [+] }|
+ [3:---------------------------------------------]|
+ ## grid 2
+ {7:-}aa |
+ {7:+}{5:^+--- 4 lines: bb···························}|
+ ## grid 3
+ :1 |
+ ## grid 4
+ {7:-}aa |
+ {7:-}bb |
+ {7:2}cc |
+ ]])
+ else
+ meths.input_mouse('left', 'press', '', 0, 1, 0)
+ screen:expect([[
+ {7:-}aa |
+ {7:+}{5:^+--- 4 lines: bb···························}|
+ {3:[No Name] [+] }|
+ {7:-}aa |
+ {7:-}bb |
+ {7:2}cc |
+ {2:[No Name] [+] }|
+ :1 |
+ ]])
+ end
+
+ if multigrid then
+ meths.input_mouse('left', 'press', '', 2, 0, 0)
+ screen:expect([[
+ ## grid 1
+ [2:---------------------------------------------]|
+ [2:---------------------------------------------]|
+ {3:[No Name] [+] }|
+ [4:---------------------------------------------]|
+ [4:---------------------------------------------]|
+ [4:---------------------------------------------]|
+ {2:[No Name] [+] }|
+ [3:---------------------------------------------]|
+ ## grid 2
+ {7:+}{5:^+-- 6 lines: aa····························}|
+ {1:~ }|
+ ## grid 3
+ :1 |
+ ## grid 4
+ {7:-}aa |
+ {7:-}bb |
+ {7:2}cc |
+ ]])
+ else
+ meths.input_mouse('left', 'press', '', 0, 0, 0)
+ screen:expect([[
+ {7:+}{5:^+-- 6 lines: aa····························}|
+ {1:~ }|
+ {3:[No Name] [+] }|
+ {7:-}aa |
+ {7:-}bb |
+ {7:2}cc |
+ {2:[No Name] [+] }|
+ :1 |
+ ]])
+ end
+ end)
+
+ it("works with tab", function()
+ insert([[
+ aa
+ bb
+ cc
+ dd
+ ee
+ ff]])
+ feed_command('2')
+ command("set foldcolumn=2")
+ feed('zf3j')
+ feed_command('1')
+ feed('zf2j')
+ feed('zO')
+ feed_command("tab split")
+ if multigrid then
+ meths.input_mouse('left', 'press', '', 4, 1, 1)
+ screen:expect([[
+ ## grid 1
+ {10: + [No Name] }{11: + [No Name] }{2: }{10:X}|
+ [4:---------------------------------------------]|
+ [4:---------------------------------------------]|
+ [4:---------------------------------------------]|
+ [4:---------------------------------------------]|
+ [4:---------------------------------------------]|
+ [4:---------------------------------------------]|
+ [3:---------------------------------------------]|
+ ## grid 2 (hidden)
+ {7:- }aa |
+ {7:│-}bb |
+ {7:││}cc |
+ {7:││}dd |
+ {7:││}ee |
+ {7:│ }ff |
+ {1:~ }|
+ ## grid 3
+ :tab split |
+ ## grid 4
+ {7:- }^aa |
+ {7:│+}{5:+--- 4 lines: bb··························}|
+ {7:│ }ff |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ ]])
+ else
+ meths.input_mouse('left', 'press', '', 0, 2, 1)
+ screen:expect([[
+ {10: + [No Name] }{11: + [No Name] }{2: }{10:X}|
+ {7:- }^aa |
+ {7:│+}{5:+--- 4 lines: bb··························}|
+ {7:│ }ff |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ :tab split |
+ ]])
+ end
+
+ if multigrid then
+ meths.input_mouse('left', 'press', '', 4, 0, 0)
+ screen:expect([[
+ ## grid 1
+ {10: + [No Name] }{11: + [No Name] }{2: }{10:X}|
+ [4:---------------------------------------------]|
+ [4:---------------------------------------------]|
+ [4:---------------------------------------------]|
+ [4:---------------------------------------------]|
+ [4:---------------------------------------------]|
+ [4:---------------------------------------------]|
+ [3:---------------------------------------------]|
+ ## grid 2 (hidden)
+ {7:- }aa |
+ {7:│-}bb |
+ {7:││}cc |
+ {7:││}dd |
+ {7:││}ee |
+ {7:│ }ff |
+ {1:~ }|
+ ## grid 3
+ :tab split |
+ ## grid 4
+ {7:+ }{5:^+-- 6 lines: aa···························}|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ ]])
+ else
+ meths.input_mouse('left', 'press', '', 0, 1, 0)
+ screen:expect([[
+ {10: + [No Name] }{11: + [No Name] }{2: }{10:X}|
+ {7:+ }{5:^+-- 6 lines: aa···························}|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ :tab split |
+ ]])
+ end
+
+ feed_command("tabnext")
+ if multigrid then
+ meths.input_mouse('left', 'press', '', 2, 1, 1)
+ screen:expect([[
+ ## grid 1
+ {11: + [No Name] }{10: + [No Name] }{2: }{10:X}|
+ [2:---------------------------------------------]|
+ [2:---------------------------------------------]|
+ [2:---------------------------------------------]|
+ [2:---------------------------------------------]|
+ [2:---------------------------------------------]|
+ [2:---------------------------------------------]|
+ [3:---------------------------------------------]|
+ ## grid 2
+ {7:- }^aa |
+ {7:│+}{5:+--- 4 lines: bb··························}|
+ {7:│ }ff |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ ## grid 3
+ :tabnext |
+ ## grid 4 (hidden)
+ {7:+ }{5:+-- 6 lines: aa···························}|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ ]])
+ else
+ meths.input_mouse('left', 'press', '', 0, 2, 1)
+ screen:expect([[
+ {11: + [No Name] }{10: + [No Name] }{2: }{10:X}|
+ {7:- }^aa |
+ {7:│+}{5:+--- 4 lines: bb··························}|
+ {7:│ }ff |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ :tabnext |
+ ]])
+ end
+
+ if multigrid then
+ meths.input_mouse('left', 'press', '', 2, 0, 0)
+ screen:expect([[
+ ## grid 1
+ {11: + [No Name] }{10: + [No Name] }{2: }{10:X}|
+ [2:---------------------------------------------]|
+ [2:---------------------------------------------]|
+ [2:---------------------------------------------]|
+ [2:---------------------------------------------]|
+ [2:---------------------------------------------]|
+ [2:---------------------------------------------]|
+ [3:---------------------------------------------]|
+ ## grid 2
+ {7:+ }{5:^+-- 6 lines: aa···························}|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ ## grid 3
+ :tabnext |
+ ## grid 4 (hidden)
+ {7:+ }{5:+-- 6 lines: aa···························}|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ ]])
+ else
+ meths.input_mouse('left', 'press', '', 0, 1, 0)
+ screen:expect([[
+ {11: + [No Name] }{10: + [No Name] }{2: }{10:X}|
+ {7:+ }{5:^+-- 6 lines: aa···························}|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ :tabnext |
+ ]])
+ end
+ end)
+
it("works with multibyte text", function()
-- Currently the only allowed value of 'maxcombine'
eq(6, meths.get_option('maxcombine'))