aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore13
-rw-r--r--CMakeLists.txt4
-rw-r--r--appveyor.yml5
-rw-r--r--ci/build.ps128
-rw-r--r--man/nvim.139
-rw-r--r--runtime/autoload/dist/ft.vim741
-rw-r--r--runtime/doc/autocmd.txt11
-rw-r--r--runtime/doc/deprecated.txt4
-rw-r--r--runtime/doc/eval.txt45
-rw-r--r--runtime/doc/insert.txt9
-rw-r--r--runtime/doc/msgpack_rpc.txt5
-rw-r--r--runtime/doc/options.txt15
-rw-r--r--runtime/doc/starting.txt20
-rw-r--r--runtime/doc/syntax.txt2
-rw-r--r--runtime/doc/vim_diff.txt5
-rw-r--r--runtime/filetype.vim834
-rw-r--r--runtime/scripts.vim191
-rw-r--r--runtime/syntax/dircolors.vim10
-rwxr-xr-xscripts/run-api-tests.exp50
-rw-r--r--src/nvim/CMakeLists.txt5
-rw-r--r--src/nvim/api/private/helpers.c11
-rw-r--r--src/nvim/api/private/helpers.h1
-rw-r--r--src/nvim/api/ui.c15
-rw-r--r--src/nvim/api/vim.c18
-rw-r--r--src/nvim/auevents.lua2
-rw-r--r--src/nvim/channel.c34
-rw-r--r--src/nvim/edit.c27
-rw-r--r--src/nvim/eval.c61
-rw-r--r--src/nvim/eval.h1
-rw-r--r--src/nvim/eval.lua1
-rw-r--r--src/nvim/ex_docmd.c139
-rw-r--r--src/nvim/ex_eval.c323
-rw-r--r--src/nvim/fileio.c151
-rw-r--r--src/nvim/getchar.c4
-rw-r--r--src/nvim/globals.h10
-rw-r--r--src/nvim/highlight_defs.h4
-rw-r--r--src/nvim/keymap.h2
-rw-r--r--src/nvim/macros.h18
-rw-r--r--src/nvim/main.c108
-rw-r--r--src/nvim/map.h5
-rw-r--r--src/nvim/message.c20
-rw-r--r--src/nvim/msgpack_rpc/server.c43
-rw-r--r--src/nvim/option.c452
-rw-r--r--src/nvim/option_defs.h4
-rw-r--r--src/nvim/options.lua2
-rw-r--r--src/nvim/os/process.c16
-rw-r--r--src/nvim/os/shell.c41
-rw-r--r--src/nvim/os/stdpaths.c2
-rw-r--r--src/nvim/po/CMakeLists.txt36
-rw-r--r--src/nvim/quickfix.c2
-rw-r--r--src/nvim/screen.c60
-rw-r--r--src/nvim/shada.c253
-rw-r--r--src/nvim/syntax.c1
-rw-r--r--src/nvim/testdir/Makefile2
-rw-r--r--src/nvim/testdir/runtest.vim3
-rw-r--r--src/nvim/testdir/setup.vim8
-rw-r--r--src/nvim/testdir/test_cmdline.vim6
-rw-r--r--src/nvim/testdir/test_find_complete.vim3
-rw-r--r--src/nvim/testdir/test_help_tagjump.vim2
-rw-r--r--src/nvim/testdir/test_makeencoding.vim9
-rw-r--r--src/nvim/testdir/test_options.vim3
-rw-r--r--src/nvim/testdir/test_quickfix.vim16
-rw-r--r--src/nvim/testdir/test_recover.vim5
-rw-r--r--src/nvim/testdir/test_stat.vim2
-rw-r--r--src/nvim/testdir/test_system.vim10
-rw-r--r--src/nvim/testdir/test_timers.vim2
-rw-r--r--src/nvim/tui/tui.c17
-rw-r--r--src/nvim/ui.c6
-rw-r--r--src/nvim/viml/parser/expressions.c3
-rw-r--r--test/functional/api/highlight_spec.lua9
-rw-r--r--test/functional/api/ui_spec.lua37
-rw-r--r--test/functional/api/vim_spec.lua17
-rw-r--r--test/functional/autocmd/cmdline_spec.lua9
-rw-r--r--test/functional/clipboard/clipboard_provider_spec.lua28
-rw-r--r--test/functional/core/job_spec.lua15
-rw-r--r--test/functional/eval/execute_spec.lua16
-rw-r--r--test/functional/eval/input_spec.lua25
-rw-r--r--test/functional/eval/server_spec.lua76
-rw-r--r--test/functional/eval/system_spec.lua8
-rw-r--r--test/functional/ex_cmds/cmd_map_spec.lua43
-rw-r--r--test/functional/ex_cmds/oldfiles_spec.lua1
-rw-r--r--test/functional/helpers.lua4
-rw-r--r--test/functional/insert/insert_spec.lua41
-rw-r--r--test/functional/insert/last_inserted_spec.lua22
-rw-r--r--test/functional/legacy/077_mf_hash_grow_spec.lua3
-rw-r--r--test/functional/lua/overrides_spec.lua1
-rw-r--r--test/functional/options/defaults_spec.lua276
-rw-r--r--test/functional/options/num_options_spec.lua97
-rw-r--r--test/functional/shada/merging_spec.lua109
-rw-r--r--test/functional/shada/shada_spec.lua6
-rw-r--r--test/functional/terminal/tui_spec.lua14
-rw-r--r--test/functional/ui/cmdline_highlight_spec.lua17
-rw-r--r--test/functional/ui/cursor_spec.lua4
-rw-r--r--test/functional/ui/highlight_spec.lua135
-rw-r--r--test/functional/ui/inccommand_spec.lua1
-rw-r--r--test/functional/ui/input_spec.lua6
-rw-r--r--test/functional/ui/mouse_spec.lua1
-rw-r--r--test/functional/ui/output_spec.lua18
-rw-r--r--test/functional/ui/screen_basic_spec.lua62
-rw-r--r--test/helpers.lua17
-rw-r--r--third-party/CMakeLists.txt5
-rw-r--r--third-party/cmake/BuildGperf.cmake3
-rw-r--r--third-party/cmake/BuildLibtermkey.cmake24
-rw-r--r--third-party/cmake/BuildLibuv.cmake2
-rw-r--r--third-party/cmake/BuildLuajit.cmake6
-rw-r--r--third-party/cmake/BuildLuv.cmake19
-rw-r--r--third-party/cmake/PatchLuv.cmake29
-rw-r--r--third-party/cmake/libtermkeyCMakeLists.txt34
-rw-r--r--third-party/patches/libtermkey-Add-support-for-Windows.patch170
-rw-r--r--third-party/patches/libvterm-Remove-VLAs-for-MSVC.patch4
-rw-r--r--third-party/patches/luv-Add-missing-definitions-for-MinGW.patch24
111 files changed, 3400 insertions, 2038 deletions
diff --git a/.gitignore b/.gitignore
index ddbcc9c60d..85b371b926 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,6 @@
+# Tools
+.ropeproject/
+
# Build/deps dir
/build/
/cmake-build-debug/
@@ -17,13 +20,13 @@ tags
/src/nvim/po/vim.pot
/src/nvim/po/*.ck
-# generated by tests with $NVIM_LOG_FILE set.
+# Generated by tests with $NVIM_LOG_FILE set.
/.nvimlog
-# Files generated by scripts/vim-patch.sh
+# Generated by scripts/vim-patch.sh
/.vim-src/
-# Files generated by the tests
+# Generated by old (Vim) tests.
/src/nvim/testdir/del
/src/nvim/testdir/test*.out
/src/nvim/testdir/test*.res
@@ -36,10 +39,10 @@ tags
/src/nvim/testdir/valgrind.*
/src/nvim/testdir/.gdbinit
-# Folder generated by the unit tests
+# Generated by unit tests.
/test/includes/post/
-# generated by luacheck during `make testlint'
+# Generated by luacheck during `make testlint'
/test/.luacheckcache
# local make targets
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 4b021ad6e7..47e873a845 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -67,8 +67,8 @@ set_property(CACHE CMAKE_BUILD_TYPE PROPERTY
# If not in a git repo (e.g., a tarball) these tokens define the complete
# version string, else they are combined with the result of `git describe`.
set(NVIM_VERSION_MAJOR 0)
-set(NVIM_VERSION_MINOR 2)
-set(NVIM_VERSION_PATCH 3)
+set(NVIM_VERSION_MINOR 3)
+set(NVIM_VERSION_PATCH 0)
set(NVIM_VERSION_PRERELEASE "-dev") # for package maintainers
# API level
diff --git a/appveyor.yml b/appveyor.yml
index 957efc0e47..75ca74d0d5 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -3,14 +3,13 @@ environment:
APPVEYOR_CACHE_ENTRY_ZIP_ARGS: "-t7z -m0=lzma -mx=9"
image: Visual Studio 2017
configuration:
+- MSVC_64
+- MSVC_32
- MINGW_64
- MINGW_32
-- MSVC_64
-# - MSVC_32
- MINGW_64-gcov
matrix:
allow_failures:
- - configuration: MSVC_64
- configuration: MINGW_64-gcov
install: []
before_build:
diff --git a/ci/build.ps1 b/ci/build.ps1
index 7075775bcd..8eb237ccd1 100644
--- a/ci/build.ps1
+++ b/ci/build.ps1
@@ -11,7 +11,11 @@ $depsCmakeVars = @{
$nvimCmakeVars = @{
CMAKE_BUILD_TYPE = $cmakeBuildType;
BUSTED_OUTPUT_TYPE = 'nvim';
- GPERF_PRG = 'C:\msys64\usr\bin\gperf.exe';
+}
+
+# For pull requests, skip some build configurations to save time.
+if ($env:APPVEYOR_PULL_REQUEST_HEAD_COMMIT -and $env:CONFIGURATION -match '^(MSVC_64|MINGW_32)$') {
+ exit 0
}
function exitIfFailed() {
@@ -39,12 +43,10 @@ if ($compiler -eq 'MINGW') {
# Add MinGW to the PATH
$env:PATH = "C:\msys64\mingw$bits\bin;$env:PATH"
- # Remove the Git sh.exe from the PATH
- $env:PATH = $env:PATH.Replace('C:\Program Files\Git\usr\bin', '')
# Build third-party dependencies
C:\msys64\usr\bin\bash -lc "pacman --verbose --noconfirm -Su" ; exitIfFailed
- C:\msys64\usr\bin\bash -lc "pacman --verbose --noconfirm --needed -S mingw-w64-$arch-cmake mingw-w64-$arch-perl mingw-w64-$arch-diffutils mingw-w64-$arch-unibilium gperf" ; exitIfFailed
+ C:\msys64\usr\bin\bash -lc "pacman --verbose --noconfirm --needed -S mingw-w64-$arch-cmake mingw-w64-$arch-perl mingw-w64-$arch-diffutils mingw-w64-$arch-unibilium" ; exitIfFailed
}
elseif ($compiler -eq 'MSVC') {
$cmakeGeneratorArgs = '/verbosity:normal'
@@ -56,6 +58,9 @@ elseif ($compiler -eq 'MSVC') {
}
}
+# Remove Git Unix utilities from the PATH
+$env:PATH = $env:PATH.Replace('C:\Program Files\Git\usr\bin', '')
+
# Setup python (use AppVeyor system python)
C:\Python27\python.exe -m pip install neovim ; exitIfFailed
C:\Python35\python.exe -m pip install neovim ; exitIfFailed
@@ -91,14 +96,25 @@ cmake --build . --config $cmakeBuildType -- $cmakeGeneratorArgs ; exitIfFailed
bin\nvim --version ; exitIfFailed
# Functional tests
-cmake --build . --config $cmakeBuildType --target functionaltest -- $cmakeGeneratorArgs ; exitIfFailed
+# The $LastExitCode from MSBuild can't be trusted
+$failed = $false
+# Temporarily turn off tracing to reduce log file output
+Set-PSDebug -Off
+cmake --build . --config $cmakeBuildType --target functionaltest -- $cmakeGeneratorArgs 2>&1 |
+ foreach { $failed = $failed -or
+ $_ -match 'Running functional tests failed with error'; $_ }
+Set-PSDebug -Trace 1
+if ($failed) {
+ exit $LastExitCode
+}
+
if ($uploadToCodecov) {
C:\msys64\usr\bin\bash -lc "cd /c/projects/neovim; bash <(curl -s https://codecov.io/bash) -c -F functionaltest || echo 'codecov upload failed.'"
}
# Old tests
-$env:PATH += ';C:\msys64\usr\bin'
+$env:PATH = "C:\msys64\usr\bin;$env:PATH"
& "C:\msys64\mingw$bits\bin\mingw32-make.exe" -C $(Convert-Path ..\src\nvim\testdir) VERBOSE=1
if ($uploadToCodecov) {
diff --git a/man/nvim.1 b/man/nvim.1
index d2a3ea5c43..12f342247e 100644
--- a/man/nvim.1
+++ b/man/nvim.1
@@ -25,7 +25,7 @@ To enter commands in
type a colon
.Pq Sq \&:
which is also used in this manual to denote commands.
-For more information, consult the on-line help system with the
+For more information, consult the online help system with the
.Ic :help
command.
.Bl -tag -width Fl
@@ -329,6 +329,8 @@ Implies
.Fl -headless .
.It Fl -headless
Do not start a user interface.
+.It Fl -listen Ar address
+Start RPC server on this pipe or TCP socket.
.It Fl h , -help
Print usage information and exit.
.It Fl v , -version
@@ -337,12 +339,12 @@ Print version information and exit.
.Sh ENVIRONMENT
.Bl -tag -width Fl
.It Ev VIM
-Used to locate various user files, such as the user's init.vim.
+Used to locate various user files, such as init.vim.
.It Ev VIMRUNTIME
-Used to locate run time files, such as on-line documentation and
+Used to locate runtime files, such as online documentation and
syntax highlighting definitions.
.It Ev XDG_CONFIG_HOME
-Path to use for the user-local configuration directory, see
+Path to the user-local configuration directory, see
.Sx FILES .
Defaults to
.Pa ~/.config
@@ -356,7 +358,7 @@ Defaults to
.Pa ~/.local/share
if not set.
.It Ev VIMINIT
-A string of Ex commands to be executed at startup.
+Ex commands to be executed at startup.
For example, the command to quit is
.Ic :q ,
so to have
@@ -375,41 +377,32 @@ command.
.Sh FILES
.Bl -tag -width "~/.config/nvim/init.vim"
.It Pa ~/.config/nvim/init.vim
-The user-local
+User-local
.Nm
configuration file.
-See
-.Ev XDG_CONFIG_HOME
-above.
.It Pa ~/.config/nvim
-The user-local
+User-local
.Nm
configuration directory.
-See
-.Ev XDG_CONFIG_HOME
-above.
+See also
+.Ev XDG_CONFIG_HOME .
.It Pa $VIM/sysinit.vim
-The system-global
+System-global
.Nm
configuration file.
.It Pa /usr/local/share/nvim
-The system-global
+System-global
.Nm
runtime directory.
.El
.Sh AUTHORS
-.Nm
-was started by
-.An Thiago de Arruda ,
-with a lot of help from others.
-.Pp
+Nvim was started by
+.An Thiago de Arruda .
Most of Vim was written by
.An -nosplit
-.An Bram Moolenaar ,
-with a lot of help from others.
+.An Bram Moolenaar .
See
.Ic :help credits .
-.Pp
Vim is based on Stevie, worked on by
.An Tim Thompson ,
.An Tony Andrews ,
diff --git a/runtime/autoload/dist/ft.vim b/runtime/autoload/dist/ft.vim
new file mode 100644
index 0000000000..2603c6822f
--- /dev/null
+++ b/runtime/autoload/dist/ft.vim
@@ -0,0 +1,741 @@
+" Vim functions for file type detection
+"
+" Maintainer: Bram Moolenaar <Bram@vim.org>
+" Last Change: 2017 Nov 11
+
+" These functions are moved here from runtime/filetype.vim to make startup
+" faster.
+
+" Line continuation is used here, remove 'C' from 'cpoptions'
+let s:cpo_save = &cpo
+set cpo&vim
+
+func dist#ft#Check_inp()
+ if getline(1) =~ '^\*'
+ setf abaqus
+ else
+ let n = 1
+ if line("$") > 500
+ let nmax = 500
+ else
+ let nmax = line("$")
+ endif
+ while n <= nmax
+ if getline(n) =~? "^header surface data"
+ setf trasys
+ break
+ endif
+ let n = n + 1
+ endwhile
+ endif
+endfunc
+
+" This function checks for the kind of assembly that is wanted by the user, or
+" can be detected from the first five lines of the file.
+func dist#ft#FTasm()
+ " make sure b:asmsyntax exists
+ if !exists("b:asmsyntax")
+ let b:asmsyntax = ""
+ endif
+
+ if b:asmsyntax == ""
+ call dist#ft#FTasmsyntax()
+ endif
+
+ " if b:asmsyntax still isn't set, default to asmsyntax or GNU
+ if b:asmsyntax == ""
+ if exists("g:asmsyntax")
+ let b:asmsyntax = g:asmsyntax
+ else
+ let b:asmsyntax = "asm"
+ endif
+ endif
+
+ exe "setf " . fnameescape(b:asmsyntax)
+endfunc
+
+func dist#ft#FTasmsyntax()
+ " see if file contains any asmsyntax=foo overrides. If so, change
+ " b:asmsyntax appropriately
+ let head = " ".getline(1)." ".getline(2)." ".getline(3)." ".getline(4).
+ \" ".getline(5)." "
+ let match = matchstr(head, '\sasmsyntax=\zs[a-zA-Z0-9]\+\ze\s')
+ if match != ''
+ let b:asmsyntax = match
+ elseif ((head =~? '\.title') || (head =~? '\.ident') || (head =~? '\.macro') || (head =~? '\.subtitle') || (head =~? '\.library'))
+ let b:asmsyntax = "vmasm"
+ endif
+endfunc
+
+" Check if one of the first five lines contains "VB_Name". In that case it is
+" probably a Visual Basic file. Otherwise it's assumed to be "alt" filetype.
+func dist#ft#FTVB(alt)
+ if getline(1).getline(2).getline(3).getline(4).getline(5) =~? 'VB_Name\|Begin VB\.\(Form\|MDIForm\|UserControl\)'
+ setf vb
+ else
+ exe "setf " . a:alt
+ endif
+endfunc
+
+func dist#ft#FTbtm()
+ if exists("g:dosbatch_syntax_for_btm") && g:dosbatch_syntax_for_btm
+ setf dosbatch
+ else
+ setf btm
+ endif
+endfunc
+
+func dist#ft#BindzoneCheck(default)
+ if getline(1).getline(2).getline(3).getline(4) =~ '^; <<>> DiG [0-9.]\+.* <<>>\|$ORIGIN\|$TTL\|IN\s\+SOA'
+ setf bindzone
+ elseif a:default != ''
+ exe 'setf ' . a:default
+ endif
+endfunc
+
+func dist#ft#FTlpc()
+ if exists("g:lpc_syntax_for_c")
+ let lnum = 1
+ while lnum <= 12
+ if getline(lnum) =~# '^\(//\|inherit\|private\|protected\|nosave\|string\|object\|mapping\|mixed\)'
+ setf lpc
+ return
+ endif
+ let lnum = lnum + 1
+ endwhile
+ endif
+ setf c
+endfunc
+
+func dist#ft#FTheader()
+ if match(getline(1, min([line("$"), 200])), '^@\(interface\|end\|class\)') > -1
+ if exists("g:c_syntax_for_h")
+ setf objc
+ else
+ setf objcpp
+ endif
+ elseif exists("g:c_syntax_for_h")
+ setf c
+ elseif exists("g:ch_syntax_for_h")
+ setf ch
+ else
+ setf cpp
+ endif
+endfunc
+
+" This function checks if one of the first ten lines start with a '@'. In
+" that case it is probably a change file.
+" If the first line starts with # or ! it's probably a ch file.
+" If a line has "main", "include", "//" ir "/*" it's probably ch.
+" Otherwise CHILL is assumed.
+func dist#ft#FTchange()
+ let lnum = 1
+ while lnum <= 10
+ if getline(lnum)[0] == '@'
+ setf change
+ return
+ endif
+ if lnum == 1 && (getline(1)[0] == '#' || getline(1)[0] == '!')
+ setf ch
+ return
+ endif
+ if getline(lnum) =~ "MODULE"
+ setf chill
+ return
+ endif
+ if getline(lnum) =~ 'main\s*(\|#\s*include\|//'
+ setf ch
+ return
+ endif
+ let lnum = lnum + 1
+ endwhile
+ setf chill
+endfunc
+
+func dist#ft#FTent()
+ " This function checks for valid cl syntax in the first five lines.
+ " Look for either an opening comment, '#', or a block start, '{".
+ " If not found, assume SGML.
+ let lnum = 1
+ while lnum < 6
+ let line = getline(lnum)
+ if line =~ '^\s*[#{]'
+ setf cl
+ return
+ elseif line !~ '^\s*$'
+ " Not a blank line, not a comment, and not a block start,
+ " so doesn't look like valid cl code.
+ break
+ endif
+ let lnum = lnum + 1
+ endw
+ setf dtd
+endfunc
+
+func dist#ft#EuphoriaCheck()
+ if exists('g:filetype_euphoria')
+ exe 'setf ' . g:filetype_euphoria
+ else
+ setf euphoria3
+ endif
+endfunc
+
+func dist#ft#DtraceCheck()
+ let lines = getline(1, min([line("$"), 100]))
+ if match(lines, '^module\>\|^import\>') > -1
+ " D files often start with a module and/or import statement.
+ setf d
+ elseif match(lines, '^#!\S\+dtrace\|#pragma\s\+D\s\+option\|:\S\{-}:\S\{-}:') > -1
+ setf dtrace
+ else
+ setf d
+ endif
+endfunc
+
+func dist#ft#FTe()
+ if exists('g:filetype_euphoria')
+ exe 'setf ' . g:filetype_euphoria
+ else
+ let n = 1
+ while n < 100 && n < line("$")
+ if getline(n) =~ "^\\s*\\(<'\\|'>\\)\\s*$"
+ setf specman
+ return
+ endif
+ let n = n + 1
+ endwhile
+ setf eiffel
+ endif
+endfunc
+
+" Distinguish between HTML, XHTML and Django
+func dist#ft#FThtml()
+ let n = 1
+ while n < 10 && n < line("$")
+ if getline(n) =~ '\<DTD\s\+XHTML\s'
+ setf xhtml
+ return
+ endif
+ if getline(n) =~ '{%\s*\(extends\|block\|load\)\>\|{#\s\+'
+ setf htmldjango
+ return
+ endif
+ let n = n + 1
+ endwhile
+ setf html
+endfunc
+
+" Distinguish between standard IDL and MS-IDL
+func dist#ft#FTidl()
+ let n = 1
+ while n < 50 && n < line("$")
+ if getline(n) =~ '^\s*import\s\+"\(unknwn\|objidl\)\.idl"'
+ setf msidl
+ return
+ endif
+ let n = n + 1
+ endwhile
+ setf idl
+endfunc
+
+" Distinguish between "default" and Cproto prototype file. */
+func dist#ft#ProtoCheck(default)
+ " Cproto files have a comment in the first line and a function prototype in
+ " the second line, it always ends in ";". Indent files may also have
+ " comments, thus we can't match comments to see the difference.
+ " IDL files can have a single ';' in the second line, require at least one
+ " chacter before the ';'.
+ if getline(2) =~ '.;$'
+ setf cpp
+ else
+ exe 'setf ' . a:default
+ endif
+endfunc
+
+func dist#ft#FTm()
+ let n = 1
+ let saw_comment = 0 " Whether we've seen a multiline comment leader.
+ while n < 100
+ let line = getline(n)
+ if line =~ '^\s*/\*'
+ " /* ... */ is a comment in Objective C and Murphi, so we can't conclude
+ " it's either of them yet, but track this as a hint in case we don't see
+ " anything more definitive.
+ let saw_comment = 1
+ endif
+ if line =~ '^\s*\(#\s*\(include\|import\)\>\|@import\>\|//\)'
+ setf objc
+ return
+ endif
+ if line =~ '^\s*%'
+ setf matlab
+ return
+ endif
+ if line =~ '^\s*(\*'
+ setf mma
+ return
+ endif
+ if line =~ '^\c\s*\(\(type\|var\)\>\|--\)'
+ setf murphi
+ return
+ endif
+ let n = n + 1
+ endwhile
+
+ if saw_comment
+ " We didn't see anything definitive, but this looks like either Objective C
+ " or Murphi based on the comment leader. Assume the former as it is more
+ " common.
+ setf objc
+ elseif exists("g:filetype_m")
+ " Use user specified default filetype for .m
+ exe "setf " . g:filetype_m
+ else
+ " Default is matlab
+ setf matlab
+ endif
+endfunc
+
+func dist#ft#FTmms()
+ let n = 1
+ while n < 10
+ let line = getline(n)
+ if line =~ '^\s*\(%\|//\)' || line =~ '^\*'
+ setf mmix
+ return
+ endif
+ if line =~ '^\s*#'
+ setf make
+ return
+ endif
+ let n = n + 1
+ endwhile
+ setf mmix
+endfunc
+
+" This function checks if one of the first five lines start with a dot. In
+" that case it is probably an nroff file: 'filetype' is set and 1 is returned.
+func dist#ft#FTnroff()
+ if getline(1)[0] . getline(2)[0] . getline(3)[0] . getline(4)[0] . getline(5)[0] =~ '\.'
+ setf nroff
+ return 1
+ endif
+ return 0
+endfunc
+
+func dist#ft#FTmm()
+ let n = 1
+ while n < 10
+ let line = getline(n)
+ if line =~ '^\s*\(#\s*\(include\|import\)\>\|@import\>\|/\*\)'
+ setf objcpp
+ return
+ endif
+ let n = n + 1
+ endwhile
+ setf nroff
+endfunc
+
+func dist#ft#FTpl()
+ if exists("g:filetype_pl")
+ exe "setf " . g:filetype_pl
+ else
+ " recognize Prolog by specific text in the first non-empty line
+ " require a blank after the '%' because Perl uses "%list" and "%translate"
+ let l = getline(nextnonblank(1))
+ if l =~ '\<prolog\>' || l =~ '^\s*\(%\+\(\s\|$\)\|/\*\)' || l =~ ':-'
+ setf prolog
+ else
+ setf perl
+ endif
+ endif
+endfunc
+
+func dist#ft#FTinc()
+ if exists("g:filetype_inc")
+ exe "setf " . g:filetype_inc
+ else
+ let lines = getline(1).getline(2).getline(3)
+ if lines =~? "perlscript"
+ setf aspperl
+ elseif lines =~ "<%"
+ setf aspvbs
+ elseif lines =~ "<?"
+ setf php
+ else
+ call dist#ft#FTasmsyntax()
+ if exists("b:asmsyntax")
+ exe "setf " . fnameescape(b:asmsyntax)
+ else
+ setf pov
+ endif
+ endif
+ endif
+endfunc
+
+func dist#ft#FTprogress_cweb()
+ if exists("g:filetype_w")
+ exe "setf " . g:filetype_w
+ return
+ endif
+ if getline(1) =~ '&ANALYZE' || getline(3) =~ '&GLOBAL-DEFINE'
+ setf progress
+ else
+ setf cweb
+ endif
+endfunc
+
+func dist#ft#FTprogress_asm()
+ if exists("g:filetype_i")
+ exe "setf " . g:filetype_i
+ return
+ endif
+ " This function checks for an assembly comment the first ten lines.
+ " If not found, assume Progress.
+ let lnum = 1
+ while lnum <= 10 && lnum < line('$')
+ let line = getline(lnum)
+ if line =~ '^\s*;' || line =~ '^\*'
+ call dist#ft#FTasm()
+ return
+ elseif line !~ '^\s*$' || line =~ '^/\*'
+ " Not an empty line: Doesn't look like valid assembly code.
+ " Or it looks like a Progress /* comment
+ break
+ endif
+ let lnum = lnum + 1
+ endw
+ setf progress
+endfunc
+
+func dist#ft#FTprogress_pascal()
+ if exists("g:filetype_p")
+ exe "setf " . g:filetype_p
+ return
+ endif
+ " This function checks for valid Pascal syntax in the first ten lines.
+ " Look for either an opening comment or a program start.
+ " If not found, assume Progress.
+ let lnum = 1
+ while lnum <= 10 && lnum < line('$')
+ let line = getline(lnum)
+ if line =~ '^\s*\(program\|unit\|procedure\|function\|const\|type\|var\)\>'
+ \ || line =~ '^\s*{' || line =~ '^\s*(\*'
+ setf pascal
+ return
+ elseif line !~ '^\s*$' || line =~ '^/\*'
+ " Not an empty line: Doesn't look like valid Pascal code.
+ " Or it looks like a Progress /* comment
+ break
+ endif
+ let lnum = lnum + 1
+ endw
+ setf progress
+endfunc
+
+func dist#ft#FTr()
+ let max = line("$") > 50 ? 50 : line("$")
+
+ for n in range(1, max)
+ " Rebol is easy to recognize, check for that first
+ if getline(n) =~? '\<REBOL\>'
+ setf rebol
+ return
+ endif
+ endfor
+
+ for n in range(1, max)
+ " R has # comments
+ if getline(n) =~ '^\s*#'
+ setf r
+ return
+ endif
+ " Rexx has /* comments */
+ if getline(n) =~ '^\s*/\*'
+ setf rexx
+ return
+ endif
+ endfor
+
+ " Nothing recognized, use user default or assume Rexx
+ if exists("g:filetype_r")
+ exe "setf " . g:filetype_r
+ else
+ " Rexx used to be the default, but R appears to be much more popular.
+ setf r
+ endif
+endfunc
+
+func dist#ft#McSetf()
+ " Rely on the file to start with a comment.
+ " MS message text files use ';', Sendmail files use '#' or 'dnl'
+ for lnum in range(1, min([line("$"), 20]))
+ let line = getline(lnum)
+ if line =~ '^\s*\(#\|dnl\)'
+ setf m4 " Sendmail .mc file
+ return
+ elseif line =~ '^\s*;'
+ setf msmessages " MS Message text file
+ return
+ endif
+ endfor
+ setf m4 " Default: Sendmail .mc file
+endfunc
+
+" Called from filetype.vim and scripts.vim.
+func dist#ft#SetFileTypeSH(name)
+ if expand("<amatch>") =~ g:ft_ignore_pat
+ return
+ endif
+ if a:name =~ '\<csh\>'
+ " Some .sh scripts contain #!/bin/csh.
+ call dist#ft#SetFileTypeShell("csh")
+ return
+ elseif a:name =~ '\<tcsh\>'
+ " Some .sh scripts contain #!/bin/tcsh.
+ call dist#ft#SetFileTypeShell("tcsh")
+ return
+ elseif a:name =~ '\<zsh\>'
+ " Some .sh scripts contain #!/bin/zsh.
+ call dist#ft#SetFileTypeShell("zsh")
+ return
+ elseif a:name =~ '\<ksh\>'
+ let b:is_kornshell = 1
+ if exists("b:is_bash")
+ unlet b:is_bash
+ endif
+ if exists("b:is_sh")
+ unlet b:is_sh
+ endif
+ elseif exists("g:bash_is_sh") || a:name =~ '\<bash\>' || a:name =~ '\<bash2\>'
+ let b:is_bash = 1
+ if exists("b:is_kornshell")
+ unlet b:is_kornshell
+ endif
+ if exists("b:is_sh")
+ unlet b:is_sh
+ endif
+ elseif a:name =~ '\<sh\>'
+ let b:is_sh = 1
+ if exists("b:is_kornshell")
+ unlet b:is_kornshell
+ endif
+ if exists("b:is_bash")
+ unlet b:is_bash
+ endif
+ endif
+ call dist#ft#SetFileTypeShell("sh")
+endfunc
+
+" For shell-like file types, check for an "exec" command hidden in a comment,
+" as used for Tcl.
+" Also called from scripts.vim, thus can't be local to this script.
+func dist#ft#SetFileTypeShell(name)
+ if expand("<amatch>") =~ g:ft_ignore_pat
+ return
+ endif
+ let l = 2
+ while l < 20 && l < line("$") && getline(l) =~ '^\s*\(#\|$\)'
+ " Skip empty and comment lines.
+ let l = l + 1
+ endwhile
+ if l < line("$") && getline(l) =~ '\s*exec\s' && getline(l - 1) =~ '^\s*#.*\\$'
+ " Found an "exec" line after a comment with continuation
+ let n = substitute(getline(l),'\s*exec\s\+\([^ ]*/\)\=', '', '')
+ if n =~ '\<tclsh\|\<wish'
+ setf tcl
+ return
+ endif
+ endif
+ exe "setf " . a:name
+endfunc
+
+func dist#ft#CSH()
+ if exists("g:filetype_csh")
+ call dist#ft#SetFileTypeShell(g:filetype_csh)
+ elseif &shell =~ "tcsh"
+ call dist#ft#SetFileTypeShell("tcsh")
+ else
+ call dist#ft#SetFileTypeShell("csh")
+ endif
+endfunc
+
+let s:ft_rules_udev_rules_pattern = '^\s*\cudev_rules\s*=\s*"\([^"]\{-1,}\)/*".*'
+func dist#ft#FTRules()
+ let path = expand('<amatch>:p')
+ if path =~ '^/\(etc/udev/\%(rules\.d/\)\=.*\.rules\|lib/udev/\%(rules\.d/\)\=.*\.rules\)$'
+ setf udevrules
+ return
+ endif
+ if path =~ '^/etc/ufw/'
+ setf conf " Better than hog
+ return
+ endif
+ if path =~ '^/\(etc\|usr/share\)/polkit-1/rules\.d'
+ setf javascript
+ return
+ endif
+ try
+ let config_lines = readfile('/etc/udev/udev.conf')
+ catch /^Vim\%((\a\+)\)\=:E484/
+ setf hog
+ return
+ endtry
+ let dir = expand('<amatch>:p:h')
+ for line in config_lines
+ if line =~ s:ft_rules_udev_rules_pattern
+ let udev_rules = substitute(line, s:ft_rules_udev_rules_pattern, '\1', "")
+ if dir == udev_rules
+ setf udevrules
+ endif
+ break
+ endif
+ endfor
+ setf hog
+endfunc
+
+func dist#ft#SQL()
+ if exists("g:filetype_sql")
+ exe "setf " . g:filetype_sql
+ else
+ setf sql
+ endif
+endfunc
+
+" If the file has an extension of 't' and is in a directory 't' or 'xt' then
+" it is almost certainly a Perl test file.
+" If the first line starts with '#' and contains 'perl' it's probably a Perl
+" file.
+" (Slow test) If a file contains a 'use' statement then it is almost certainly
+" a Perl file.
+func dist#ft#FTperl()
+ let dirname = expand("%:p:h:t")
+ if expand("%:e") == 't' && (dirname == 't' || dirname == 'xt')
+ setf perl
+ return 1
+ endif
+ if getline(1)[0] == '#' && getline(1) =~ 'perl'
+ setf perl
+ return 1
+ endif
+ if search('^use\s\s*\k', 'nc', 30)
+ setf perl
+ return 1
+ endif
+ return 0
+endfunc
+
+" Choose context, plaintex, or tex (LaTeX) based on these rules:
+" 1. Check the first line of the file for "%&<format>".
+" 2. Check the first 1000 non-comment lines for LaTeX or ConTeXt keywords.
+" 3. Default to "latex" or to g:tex_flavor, can be set in user's vimrc.
+func dist#ft#FTtex()
+ let firstline = getline(1)
+ if firstline =~ '^%&\s*\a\+'
+ let format = tolower(matchstr(firstline, '\a\+'))
+ let format = substitute(format, 'pdf', '', '')
+ if format == 'tex'
+ let format = 'latex'
+ elseif format == 'plaintex'
+ let format = 'plain'
+ endif
+ elseif expand('%') =~ 'tex/context/.*/.*.tex'
+ let format = 'context'
+ else
+ " Default value, may be changed later:
+ let format = exists("g:tex_flavor") ? g:tex_flavor : 'plain'
+ " Save position, go to the top of the file, find first non-comment line.
+ let save_cursor = getpos('.')
+ call cursor(1,1)
+ let firstNC = search('^\s*[^[:space:]%]', 'c', 1000)
+ if firstNC " Check the next thousand lines for a LaTeX or ConTeXt keyword.
+ let lpat = 'documentclass\>\|usepackage\>\|begin{\|newcommand\>\|renewcommand\>'
+ let cpat = 'start\a\+\|setup\a\+\|usemodule\|enablemode\|enableregime\|setvariables\|useencoding\|usesymbols\|stelle\a\+\|verwende\a\+\|stel\a\+\|gebruik\a\+\|usa\a\+\|imposta\a\+\|regle\a\+\|utilisemodule\>'
+ let kwline = search('^\s*\\\%(' . lpat . '\)\|^\s*\\\(' . cpat . '\)',
+ \ 'cnp', firstNC + 1000)
+ if kwline == 1 " lpat matched
+ let format = 'latex'
+ elseif kwline == 2 " cpat matched
+ let format = 'context'
+ endif " If neither matched, keep default set above.
+ " let lline = search('^\s*\\\%(' . lpat . '\)', 'cn', firstNC + 1000)
+ " let cline = search('^\s*\\\%(' . cpat . '\)', 'cn', firstNC + 1000)
+ " if cline > 0
+ " let format = 'context'
+ " endif
+ " if lline > 0 && (cline == 0 || cline > lline)
+ " let format = 'tex'
+ " endif
+ endif " firstNC
+ call setpos('.', save_cursor)
+ endif " firstline =~ '^%&\s*\a\+'
+
+ " Translation from formats to file types. TODO: add AMSTeX, RevTex, others?
+ if format == 'plain'
+ setf plaintex
+ elseif format == 'context'
+ setf context
+ else " probably LaTeX
+ setf tex
+ endif
+ return
+endfunc
+
+func dist#ft#FTxml()
+ let n = 1
+ while n < 100 && n < line("$")
+ let line = getline(n)
+ " DocBook 4 or DocBook 5.
+ let is_docbook4 = line =~ '<!DOCTYPE.*DocBook'
+ let is_docbook5 = line =~ ' xmlns="http://docbook.org/ns/docbook"'
+ if is_docbook4 || is_docbook5
+ let b:docbk_type = "xml"
+ if is_docbook5
+ let b:docbk_ver = 5
+ else
+ let b:docbk_ver = 4
+ endif
+ setf docbk
+ return
+ endif
+ if line =~ 'xmlns:xbl="http://www.mozilla.org/xbl"'
+ setf xbl
+ return
+ endif
+ let n += 1
+ endwhile
+ setf xml
+endfunc
+
+func dist#ft#FTy()
+ let n = 1
+ while n < 100 && n < line("$")
+ let line = getline(n)
+ if line =~ '^\s*%'
+ setf yacc
+ return
+ endif
+ if getline(n) =~ '^\s*\(#\|class\>\)' && getline(n) !~ '^\s*#\s*include'
+ setf racc
+ return
+ endif
+ let n = n + 1
+ endwhile
+ setf yacc
+endfunc
+
+func dist#ft#Redif()
+ let lnum = 1
+ while lnum <= 5 && lnum < line('$')
+ if getline(lnum) =~ "^\ctemplate-type:"
+ setf redif
+ return
+ endif
+ let lnum = lnum + 1
+ endwhile
+endfunc
+
+
+" Restore 'cpoptions'
+let &cpo = s:cpo_save
+unlet s:cpo_save
diff --git a/runtime/doc/autocmd.txt b/runtime/doc/autocmd.txt
index 9a04bf2824..06a016eddb 100644
--- a/runtime/doc/autocmd.txt
+++ b/runtime/doc/autocmd.txt
@@ -272,10 +272,11 @@ Name triggered by ~
|GUIEnter| after starting the GUI successfully
|GUIFailed| after starting the GUI failed
|TermResponse| after the terminal response to |t_RV| is received
-
|QuitPre| when using `:quit`, before deciding whether to quit
-|VimLeavePre| before exiting Vim, before writing the shada file
-|VimLeave| before exiting Vim, after writing the shada file
+|VimLeavePre| before exiting Nvim, before writing the shada file
+|VimLeave| before exiting Nvim, after writing the shada file
+|VimResume| after Nvim is resumed
+|VimSuspend| before Nvim is suspended
Various
|DirChanged| after the |current-directory| was changed
@@ -1009,6 +1010,10 @@ VimLeavePre Before exiting Vim, just before writing the
VimResized After the Vim window was resized, thus 'lines'
and/or 'columns' changed. Not when starting
up though.
+ *VimResume*
+VimResume After Nvim resumes from |suspend| state.
+ *VimSuspend*
+VimSuspend Before Nvim enters |suspend| state.
*WinEnter*
WinEnter After entering another window. Not done for
the first window, when Vim has just started.
diff --git a/runtime/doc/deprecated.txt b/runtime/doc/deprecated.txt
index ea61e847c7..03699b3dfb 100644
--- a/runtime/doc/deprecated.txt
+++ b/runtime/doc/deprecated.txt
@@ -22,6 +22,10 @@ Commands ~
*:wv*
*:wviminfo* Deprecated alias to |:wshada| command.
+Environment Variables ~
+*$NVIM_LISTEN_ADDRESS* Deprecated in favor of |--listen|. If both are given,
+ $NVIM_LISTEN_ADDRESS is ignored.
+
Events ~
*EncodingChanged* Never fired; 'encoding' is always "utf-8".
*FileEncoding* Never fired; equivalent to |EncodingChanged|.
diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt
index 767fc133d8..20f0eb303b 100644
--- a/runtime/doc/eval.txt
+++ b/runtime/doc/eval.txt
@@ -1788,9 +1788,9 @@ v:scrollstart String describing the script or function that caused the
hit-enter prompt.
*v:servername* *servername-variable*
- *$NVIM_LISTEN_ADDRESS*
-v:servername Default Nvim server address. Equivalent to
- |$NVIM_LISTEN_ADDRESS| on startup. |serverstop()|
+v:servername Primary listen-address of the current Nvim instance, the first
+ item returned by |serverlist()|. Can be set by |--listen| or
+ |$NVIM_LISTEN_ADDRESS| at startup. |serverstart()| |serverstop()|
Read-only.
@@ -2286,6 +2286,7 @@ split({expr} [, {pat} [, {keepempty}]])
List make |List| from {pat} separated {expr}
sqrt({expr}) Float square root of {expr}
stdioopen({dict}) Number open stdio in a headless instance.
+stdpath({what}) String/List returns the standard path(s) for {what}
str2float({expr}) Float convert String to Float
str2nr({expr} [, {base}]) Number convert String to Number
strchars({expr} [, {skipcc}]) Number character length of the String {expr}
@@ -4208,8 +4209,7 @@ getftype({fname}) *getftype()*
getftype("/home")
< Note that a type such as "link" will only be returned on
systems that support it. On some systems only "dir" and
- "file" are returned. On MS-Windows a symbolic link to a
- directory returns "dir" instead of "link".
+ "file" are returned.
*getline()*
getline({lnum} [, {end}])
@@ -6638,15 +6638,11 @@ server2client({clientid}, {string}) *server2client()*
:echo server2client(expand("<client>"), "HELLO")
<
serverlist() *serverlist()*
- Returns a list of available server names in a list.
- When there are no servers an empty string is returned.
+ Returns a list of server addresses, or empty if all servers
+ were stopped. |serverstart()| |serverstop()|
Example: >
:echo serverlist()
-< {Nvim} *--serverlist*
- The Vim command-line option `--serverlist` was removed from
- Nvim, but it can be imitated: >
- nvim --cmd "echo serverlist()" --cmd "q"
-<
+
serverstart([{address}]) *serverstart()*
Opens a socket or named pipe at {address} and listens for
|RPC| messages. Clients can send |API| commands to the address
@@ -6674,13 +6670,9 @@ serverstart([{address}]) *serverstart()*
< |$NVIM_LISTEN_ADDRESS| is set to {address} if not already set.
- *--servername*
- The Vim command-line option `--servername` can be imitated: >
- nvim --cmd "let g:server_addr = serverstart('foo')"
-<
serverstop({address}) *serverstop()*
- Closes the pipe or socket at {address}. Does nothing if
- {address} is empty or invalid.
+ Closes the pipe or socket at {address}.
+ Returns TRUE if {address} is valid, else FALSE.
If |$NVIM_LISTEN_ADDRESS| is stopped it is unset.
If |v:servername| is stopped it is set to the next available
address returned by |serverlist()|.
@@ -7271,6 +7263,23 @@ stdioopen({opts}) *stdioopen()*
- 0 on invalid arguments
+stdpath({what}) *stdpath()* *E6100*
+ Returns the standard path(s) for {what}.
+
+ These directories are the default locations for various files
+ used by Neovim.
+
+ {what} Type Description ~
+ cache String Cache directory. Useful for plugins
+ that need temporary files to work.
+ config String User configuration directory. The
+ |init.vim| is stored here.
+ config_dirs List Additional configuration directories.
+ data String User data directory. The |shada-file|
+ is stored here.
+ data_dirs List Additional data directories.
+
+
str2float({expr}) *str2float()*
Convert String {expr} to a Float. This mostly works the same
as when using a floating point number in an expression, see
diff --git a/runtime/doc/insert.txt b/runtime/doc/insert.txt
index 9ae35bea52..1feff0723b 100644
--- a/runtime/doc/insert.txt
+++ b/runtime/doc/insert.txt
@@ -40,10 +40,11 @@ char action ~
*i_CTRL-[* *i_<Esc>*
<Esc> or CTRL-[ End insert or Replace mode, go back to Normal mode. Finish
abbreviation.
- Note: If your <Esc> key is hard to hit on your keyboard, train
- yourself to use CTRL-[.
- If Esc doesn't work and you are using a Mac, try CTRL-Esc.
- Or disable Listening under Accessibility preferences.
+ Note: If your <Esc> key is hard to hit, try CTRL-[ instead.
+ *i_META* *i_ALT*
+ |ALT| (|META|) acts like <Esc> if the chord is not mapped.
+ For example <A-x> acts like <Esc>x if <A-x> does not have an
+ insert-mode mapping.
*i_CTRL-C*
CTRL-C Quit insert mode, go back to Normal mode. Do not check for
abbreviations. Does not trigger the |InsertLeave| autocommand
diff --git a/runtime/doc/msgpack_rpc.txt b/runtime/doc/msgpack_rpc.txt
index 11fad105b5..01d4e10cea 100644
--- a/runtime/doc/msgpack_rpc.txt
+++ b/runtime/doc/msgpack_rpc.txt
@@ -70,9 +70,8 @@ An rpc socket is automatically created with each instance. The socket
location is stored in |v:servername|. By default this is a named pipe
with an automatically generated address. See |XXX|.
-To make Nvim listen on a TCP/IP socket instead, set the
- |$NVIM_LISTEN_ADDRESS| environment variable before starting Nvim: >
- NVIM_LISTEN_ADDRESS=127.0.0.1:6666 nvim
+To make Nvim listen on a TCP/IP socket instead, specify |--listen|: >
+ nvim --listen 127.0.0.1:6666
<Also, more sockets and named pipes can be listened on using |serverstart()|.
Note that localhost TCP sockets are generally less secure than named pipes,
diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt
index f4bf49c7c5..0b7c61ea18 100644
--- a/runtime/doc/options.txt
+++ b/runtime/doc/options.txt
@@ -2036,6 +2036,11 @@ A jump table for the options with a short description can be found at |Q_op|.
column of the last screen line. Overrules "lastline".
uhex Show unprintable characters hexadecimal as <xx>
instead of using ^C and ~C.
+ msgsep When showing messages longer than 'cmdheight' lines,
+ only scroll the message lines and not the entire
+ screen. This also shows a separator line filled with
+ chars determined by 'fillchars' option, and
+ highlighted with the |MsgSeparator| group.
When neither "lastline" nor "truncate" is included, a last line that
doesn't fit is replaced with "@" lines.
@@ -2390,6 +2395,7 @@ A jump table for the options with a short description can be found at |Q_op|.
vert:c '│' or '|' vertical separators |:vsplit|
fold:c '·' or '-' filling 'foldtext'
diff:c '-' deleted lines of the 'diff' option
+ msgsep:c ' ' message separator 'display'
Any one that is omitted will fall back to the default. For "stl" and
"stlnc" the space will be used when there is highlighting, '^' or '='
@@ -6284,15 +6290,14 @@ A jump table for the options with a short description can be found at |Q_op|.
*'timeoutlen'* *'tm'*
'timeoutlen' 'tm' number (default 1000)
global
- The time in milliseconds that is waited for a mapped sequence to
- complete.
+ Time in milliseconds to wait for a mapped sequence to complete.
*'ttimeoutlen'* *'ttm'*
'ttimeoutlen' 'ttm' number (default 50)
global
- The time in milliseconds that is waited for a key code
- sequence to complete. Also used for CTRL-\ CTRL-N and CTRL-\ CTRL-G
- when part of a command has been typed.
+ Time in milliseconds to wait for a key code sequence to complete. Also
+ used for CTRL-\ CTRL-N and CTRL-\ CTRL-G when part of a command has
+ been typed.
*'title'* *'notitle'*
'title' boolean (default off)
diff --git a/runtime/doc/starting.txt b/runtime/doc/starting.txt
index e9188ba641..db3eb757c0 100644
--- a/runtime/doc/starting.txt
+++ b/runtime/doc/starting.txt
@@ -355,6 +355,10 @@ argument.
instead.
See also |silent-mode|, which does start a (limited) UI.
+--listen {addr} *--listen*
+ Start |RPC| server on pipe or TCP address {addr}. Sets the
+ primary listen address |v:servername| to {addr}. |serverstart()|
+
==============================================================================
2. Initialization *initialization* *startup*
@@ -683,25 +687,17 @@ CTRL-Z Suspend Vim, like ":stop".
Command-line mode, the CTRL-Z is inserted as a normal
character. In Visual mode Vim goes back to Normal
mode.
- Note: if CTRL-Z undoes a change see |mswin.vim|.
-
:sus[pend][!] or *:sus* *:suspend* *:st* *:stop*
-:st[op][!] Suspend Vim.
+:st[op][!] Suspend Vim. Vim will continue if you make it the
+ foreground job again.
If the '!' is not given and 'autowrite' is set, every
buffer with changes and a file name is written out.
If the '!' is given or 'autowrite' is not set, changed
buffers are not written, don't forget to bring Vim
back to the foreground later!
-In the GUI, suspending is implemented as iconising gvim. In Windows 95/NT,
-gvim is minimized.
-
-On many Unix systems, it is possible to suspend Vim with CTRL-Z. This is only
-possible in Normal and Visual mode (see next chapter, |vim-modes|). Vim will
-continue if you make it the foreground job again. On other systems, CTRL-Z
-will start a new shell. This is the same as the ":sh" command. Vim will
-continue if you exit from the shell.
+In the GUI, suspending is implementation-defined.
In X-windows the selection is disowned when Vim suspends. this means you
can't paste it in another application (since Vim is going to sleep an attempt
@@ -1391,4 +1387,4 @@ RPC clients for debugging. $NVIM_LOG_FILE contains the log file path: >
Usually the file is ~/.local/share/nvim/log unless that path is inaccessible
or if $NVIM_LOG_FILE was set before |startup|.
- vim:tw=78:ts=8:ft=help:norl:
+ vim:noet:tw=78:ts=8:ft=help:norl:
diff --git a/runtime/doc/syntax.txt b/runtime/doc/syntax.txt
index ff9773b136..fa66d9d071 100644
--- a/runtime/doc/syntax.txt
+++ b/runtime/doc/syntax.txt
@@ -4909,6 +4909,8 @@ MatchParen The character under the cursor or just before it, if it
*hl-ModeMsg*
ModeMsg 'showmode' message (e.g., "-- INSERT --")
+ *hl-MsgSeparator*
+MsgSeparator Separator for scrolled messages, `msgsep` flag of 'display'
*hl-MoreMsg*
MoreMsg |more-prompt|
*hl-NonText*
diff --git a/runtime/doc/vim_diff.txt b/runtime/doc/vim_diff.txt
index 3924dd4ebe..3575a420b7 100644
--- a/runtime/doc/vim_diff.txt
+++ b/runtime/doc/vim_diff.txt
@@ -34,7 +34,7 @@ a complete and centralized reference of those differences.
- 'complete' doesn't include "i"
- 'cscopeverbose' is enabled
- 'directory' defaults to ~/.local/share/nvim/swap// (|xdg|), auto-created
-- 'display' defaults to "lastline"
+- 'display' defaults to "lastline,msgsep"
- 'fillchars' defaults (in effect) to "vert:│,fold:·"
- 'formatoptions' defaults to "tcqj"
- 'history' defaults to 10000 (the maximum)
@@ -130,7 +130,9 @@ Some `CTRL-SHIFT-...` key chords are distinguished from `CTRL-...` variants
Options:
'cpoptions' flags: |cpo-_|
+ 'display' flag `msgsep` to minimize scrolling when showing messages
'guicursor' works in the terminal
+ 'fillchars' flag `msgsep` (see 'display' above)
'inccommand' shows interactive results for |:substitute|-like commands
'scrollback'
'statusline' supports unlimited alignment sections
@@ -164,6 +166,7 @@ Events:
Highlight groups:
|hl-NormalNC| highlights non-current windows
+ |hl-MsgSeparator| highlights separator for scrolled messages
|hl-QuickFixLine|
|hl-Substitute|
|hl-TermCursor|
diff --git a/runtime/filetype.vim b/runtime/filetype.vim
index 4e0f145c18..f8a29fa2b3 100644
--- a/runtime/filetype.vim
+++ b/runtime/filetype.vim
@@ -52,27 +52,7 @@ endfunc
au BufNewFile,BufRead $VIMRUNTIME/doc/*.txt setf help
" Abaqus or Trasys
-au BufNewFile,BufRead *.inp call s:Check_inp()
-
-func! s:Check_inp()
- if getline(1) =~ '^\*'
- setf abaqus
- else
- let n = 1
- if line("$") > 500
- let nmax = 500
- else
- let nmax = line("$")
- endif
- while n <= nmax
- if getline(n) =~? "^header surface data"
- setf trasys
- break
- endif
- let n = n + 1
- endwhile
- endif
-endfunc
+au BufNewFile,BufRead *.inp call dist#ft#Check_inp()
" A-A-P recipe
au BufNewFile,BufRead *.aap setf aap
@@ -170,44 +150,7 @@ au BufNewFile,BufRead */boot/grub/menu.lst,*/boot/grub/grub.conf,*/etc/grub.conf
" Assembly (all kinds)
" *.lst is not pure assembly, it has two extra columns (address, byte codes)
-au BufNewFile,BufRead *.asm,*.[sS],*.[aA],*.mac,*.lst call s:FTasm()
-
-" This function checks for the kind of assembly that is wanted by the user, or
-" can be detected from the first five lines of the file.
-func! s:FTasm()
- " make sure b:asmsyntax exists
- if !exists("b:asmsyntax")
- let b:asmsyntax = ""
- endif
-
- if b:asmsyntax == ""
- call s:FTasmsyntax()
- endif
-
- " if b:asmsyntax still isn't set, default to asmsyntax or GNU
- if b:asmsyntax == ""
- if exists("g:asmsyntax")
- let b:asmsyntax = g:asmsyntax
- else
- let b:asmsyntax = "asm"
- endif
- endif
-
- exe "setf " . fnameescape(b:asmsyntax)
-endfunc
-
-func! s:FTasmsyntax()
- " see if file contains any asmsyntax=foo overrides. If so, change
- " b:asmsyntax appropriately
- let head = " ".getline(1)." ".getline(2)." ".getline(3)." ".getline(4).
- \" ".getline(5)." "
- let match = matchstr(head, '\sasmsyntax=\zs[a-zA-Z0-9]\+\ze\s')
- if match != ''
- let b:asmsyntax = match
- elseif ((head =~? '\.title') || (head =~? '\.ident') || (head =~? '\.macro') || (head =~? '\.subtitle') || (head =~? '\.library'))
- let b:asmsyntax = "vmasm"
- endif
-endfunc
+au BufNewFile,BufRead *.asm,*.[sS],*.[aA],*.mac,*.lst call dist#ft#FTasm()
" Macro (VAX)
au BufNewFile,BufRead *.mar setf vmasm
@@ -237,17 +180,7 @@ au BufNewFile,BufRead *.awk setf awk
au BufNewFile,BufRead *.mch,*.ref,*.imp setf b
" BASIC or Visual Basic
-au BufNewFile,BufRead *.bas call s:FTVB("basic")
-
-" Check if one of the first five lines contains "VB_Name". In that case it is
-" probably a Visual Basic file. Otherwise it's assumed to be "alt" filetype.
-func! s:FTVB(alt)
- if getline(1).getline(2).getline(3).getline(4).getline(5) =~? 'VB_Name\|Begin VB\.\(Form\|MDIForm\|UserControl\)'
- setf vb
- else
- exe "setf " . a:alt
- endif
-endfunc
+au BufNewFile,BufRead *.bas call dist#ft#FTVB("basic")
" Visual Basic Script (close to Visual Basic) or Visual Basic .NET
au BufNewFile,BufRead *.vb,*.vbs,*.dsm,*.ctl setf vb
@@ -265,14 +198,7 @@ au BufNewFile,BufRead *.cmd
\ if getline(1) =~ '^/\*' | setf rexx | else | setf dosbatch | endif
" Batch file for 4DOS
-au BufNewFile,BufRead *.btm call s:FTbtm()
-func! s:FTbtm()
- if exists("g:dosbatch_syntax_for_btm") && g:dosbatch_syntax_for_btm
- setf dosbatch
- else
- setf btm
- endif
-endfunc
+au BufNewFile,BufRead *.btm call dist#ft#FTbtm()
" BC calculator
au BufNewFile,BufRead *.bc setf bc
@@ -292,15 +218,7 @@ au BufNewFile,BufRead named*.conf,rndc*.conf,rndc*.key setf named
" BIND zone
au BufNewFile,BufRead named.root setf bindzone
-au BufNewFile,BufRead *.db call s:BindzoneCheck('')
-
-func! s:BindzoneCheck(default)
- if getline(1).getline(2).getline(3).getline(4) =~ '^; <<>> DiG [0-9.]\+.* <<>>\|$ORIGIN\|$TTL\|IN\s\+SOA'
- setf bindzone
- elseif a:default != ''
- exe 'setf ' . a:default
- endif
-endfunc
+au BufNewFile,BufRead *.db call dist#ft#BindzoneCheck('')
" Blank
au BufNewFile,BufRead *.bl setf blank
@@ -309,27 +227,14 @@ au BufNewFile,BufRead *.bl setf blank
au BufNewFile,BufRead */etc/blkid.tab,*/etc/blkid.tab.old setf xml
" Bazel (http://bazel.io)
-autocmd BufRead,BufNewFile *.bzl,WORKSPACE setfiletype bzl
+autocmd BufRead,BufNewFile *.bzl,WORKSPACE setf bzl
if has("fname_case")
- autocmd BufRead,BufNewFile BUILD setfiletype bzl
+ " There is another check for BUILD further below.
+ autocmd BufRead,BufNewFile BUILD setf bzl
endif
" C or lpc
-au BufNewFile,BufRead *.c call s:FTlpc()
-
-func! s:FTlpc()
- if exists("g:lpc_syntax_for_c")
- let lnum = 1
- while lnum <= 12
- if getline(lnum) =~# '^\(//\|inherit\|private\|protected\|nosave\|string\|object\|mapping\|mixed\)'
- setf lpc
- return
- endif
- let lnum = lnum + 1
- endwhile
- endif
- setf c
-endfunc
+au BufNewFile,BufRead *.c call dist#ft#FTlpc()
" Calendar
au BufNewFile,BufRead calendar setf calendar
@@ -383,23 +288,7 @@ endif
" .h files can be C, Ch C++, ObjC or ObjC++.
" Set c_syntax_for_h if you want C, ch_syntax_for_h if you want Ch. ObjC is
" detected automatically.
-au BufNewFile,BufRead *.h call s:FTheader()
-
-func! s:FTheader()
- if match(getline(1, min([line("$"), 200])), '^@\(interface\|end\|class\)') > -1
- if exists("g:c_syntax_for_h")
- setf objc
- else
- setf objcpp
- endif
- elseif exists("g:c_syntax_for_h")
- setf c
- elseif exists("g:ch_syntax_for_h")
- setf ch
- else
- setf cpp
- endif
-endfunc
+au BufNewFile,BufRead *.h call dist#ft#FTheader()
" Ch (CHscript)
au BufNewFile,BufRead *.chf setf ch
@@ -433,36 +322,7 @@ au BufNewFile,BufRead NEWS
au BufNewFile,BufRead *..ch setf chill
" Changes for WEB and CWEB or CHILL
-au BufNewFile,BufRead *.ch call s:FTchange()
-
-" This function checks if one of the first ten lines start with a '@'. In
-" that case it is probably a change file.
-" If the first line starts with # or ! it's probably a ch file.
-" If a line has "main", "include", "//" ir "/*" it's probably ch.
-" Otherwise CHILL is assumed.
-func! s:FTchange()
- let lnum = 1
- while lnum <= 10
- if getline(lnum)[0] == '@'
- setf change
- return
- endif
- if lnum == 1 && (getline(1)[0] == '#' || getline(1)[0] == '!')
- setf ch
- return
- endif
- if getline(lnum) =~ "MODULE"
- setf chill
- return
- endif
- if getline(lnum) =~ 'main\s*(\|#\s*include\|//'
- setf ch
- return
- endif
- let lnum = lnum + 1
- endwhile
- setf chill
-endfunc
+au BufNewFile,BufRead *.ch call dist#ft#FTchange()
" ChordPro
au BufNewFile,BufRead *.chopro,*.crd,*.cho,*.crdpro,*.chordpro setf chordpro
@@ -474,27 +334,7 @@ au BufNewFile,BufRead *.dcl,*.icl setf clean
au BufNewFile,BufRead *.eni setf cl
" Clever or dtd
-au BufNewFile,BufRead *.ent call s:FTent()
-
-func! s:FTent()
- " This function checks for valid cl syntax in the first five lines.
- " Look for either an opening comment, '#', or a block start, '{".
- " If not found, assume SGML.
- let lnum = 1
- while lnum < 6
- let line = getline(lnum)
- if line =~ '^\s*[#{]'
- setf cl
- return
- elseif line !~ '^\s*$'
- " Not a blank line, not a comment, and not a block start,
- " so doesn't look like valid cl code.
- break
- endif
- let lnum = lnum + 1
- endw
- setf dtd
-endfunc
+au BufNewFile,BufRead *.ent call dist#ft#FTent()
" Clipper (or FoxPro; could also be eviews)
au BufNewFile,BufRead *.prg
@@ -549,19 +389,11 @@ au BufNewFile,BufRead *enlightenment/*.cfg setf c
au BufNewFile,BufRead *Eterm/*.cfg setf eterm
" Euphoria 3 or 4
-au BufNewFile,BufRead *.eu,*.ew,*.ex,*.exu,*.exw call s:EuphoriaCheck()
+au BufNewFile,BufRead *.eu,*.ew,*.ex,*.exu,*.exw call dist#ft#EuphoriaCheck()
if has("fname_case")
- au BufNewFile,BufRead *.EU,*.EW,*.EX,*.EXU,*.EXW call s:EuphoriaCheck()
+ au BufNewFile,BufRead *.EU,*.EW,*.EX,*.EXU,*.EXW call dist#ft#EuphoriaCheck()
endif
-func! s:EuphoriaCheck()
- if exists('g:filetype_euphoria')
- exe 'setf ' . g:filetype_euphoria
- else
- setf euphoria3
- endif
-endfunc
-
" Lynx config files
au BufNewFile,BufRead lynx.cfg setf lynx
@@ -606,19 +438,7 @@ au BufNewFile,BufRead */etc/dnsmasq.conf setf dnsmasq
au BufNewFile,BufRead *.desc setf desc
" the D language or dtrace
-au BufNewFile,BufRead *.d call s:DtraceCheck()
-
-func! s:DtraceCheck()
- let lines = getline(1, min([line("$"), 100]))
- if match(lines, '^module\>\|^import\>') > -1
- " D files often start with a module and/or import statement.
- setf d
- elseif match(lines, '^#!\S\+dtrace\|#pragma\s\+D\s\+option\|:\S\{-}:\S\{-}:') > -1
- setf dtrace
- else
- setf d
- endif
-endfunc
+au BufNewFile,BufRead *.d call dist#ft#DtraceCheck()
" Desktop files
au BufNewFile,BufRead *.desktop,.directory setf desktop
@@ -650,7 +470,7 @@ au BufNewFile,BufRead *.rul
\ endif
" DCL (Digital Command Language - vms) or DNS zone file
-au BufNewFile,BufRead *.com call s:BindzoneCheck('dcl')
+au BufNewFile,BufRead *.com call dist#ft#BindzoneCheck('dcl')
" DOT
au BufNewFile,BufRead *.dot setf dot
@@ -698,27 +518,11 @@ au BufNewFile,BufRead .editorconfig setf dosini
au BufNewFile,BufRead *.ecd setf ecd
" Eiffel or Specman or Euphoria
-au BufNewFile,BufRead *.e,*.E call s:FTe()
+au BufNewFile,BufRead *.e,*.E call dist#ft#FTe()
" Elinks configuration
au BufNewFile,BufRead */etc/elinks.conf,*/.elinks/elinks.conf setf elinks
-func! s:FTe()
- if exists('g:filetype_euphoria')
- exe 'setf ' . g:filetype_euphoria
- else
- let n = 1
- while n < 100 && n < line("$")
- if getline(n) =~ "^\\s*\\(<'\\|'>\\)\\s*$"
- setf specman
- return
- endif
- let n = n + 1
- endwhile
- setf eiffel
- endif
-endfunc
-
" ERicsson LANGuage; Yaws is erlang too
au BufNewFile,BufRead *.erl,*.hrl,*.yaws setf erlang
@@ -887,24 +691,7 @@ au BufNewFile,BufRead *.hex,*.h32 setf hex
au BufNewFile,BufRead *.t.html setf tilde
" HTML (.shtml and .stm for server side)
-au BufNewFile,BufRead *.html,*.htm,*.shtml,*.stm call s:FThtml()
-
-" Distinguish between HTML, XHTML and Django
-func! s:FThtml()
- let n = 1
- while n < 10 && n < line("$")
- if getline(n) =~ '\<DTD\s\+XHTML\s'
- setf xhtml
- return
- endif
- if getline(n) =~ '{%\s*\(extends\|block\|load\)\>\|{#\s\+'
- setf htmldjango
- return
- endif
- let n = n + 1
- endwhile
- setf html
-endfunc
+au BufNewFile,BufRead *.html,*.htm,*.shtml,*.stm call dist#ft#FThtml()
" HTML with Ruby - eRuby
au BufNewFile,BufRead *.erb,*.rhtml setf eruby
@@ -931,20 +718,7 @@ au BufNewFile,BufRead *.htt,*.htb setf httest
au BufNewFile,BufRead *.icn setf icon
" IDL (Interface Description Language)
-au BufNewFile,BufRead *.idl call s:FTidl()
-
-" Distinguish between standard IDL and MS-IDL
-func! s:FTidl()
- let n = 1
- while n < 50 && n < line("$")
- if getline(n) =~ '^\s*import\s\+"\(unknwn\|objidl\)\.idl"'
- setf msidl
- return
- endif
- let n = n + 1
- endwhile
- setf idl
-endfunc
+au BufNewFile,BufRead *.idl call dist#ft#FTidl()
" Microsoft IDL (Interface Description Language) Also *.idl
" MOF = WMI (Windows Management Instrumentation) Managed Object Format
@@ -955,25 +729,10 @@ au BufNewFile,BufRead */.icewm/menu setf icemenu
" Indent profile (must come before IDL *.pro!)
au BufNewFile,BufRead .indent.pro setf indent
-au BufNewFile,BufRead indent.pro call s:ProtoCheck('indent')
+au BufNewFile,BufRead indent.pro call dist#ft#ProtoCheck('indent')
" IDL (Interactive Data Language)
-au BufNewFile,BufRead *.pro call s:ProtoCheck('idlang')
-
-" Distinguish between "default" and Cproto prototype file. */
-func! s:ProtoCheck(default)
- " Cproto files have a comment in the first line and a function prototype in
- " the second line, it always ends in ";". Indent files may also have
- " comments, thus we can't match comments to see the difference.
- " IDL files can have a single ';' in the second line, require at least one
- " chacter before the ';'.
- if getline(2) =~ '.;$'
- setf cpp
- else
- exe 'setf ' . a:default
- endif
-endfunc
-
+au BufNewFile,BufRead *.pro call dist#ft#ProtoCheck('idlang')
" Indent RC
au BufNewFile,BufRead indentrc setf indent
@@ -1187,51 +946,7 @@ au BufNewFile,BufRead *.markdown,*.mdown,*.mkd,*.mkdn,*.mdwn,*.md setf markdown
au BufNewFile,BufRead *.mason,*.mhtml,*.comp setf mason
" Mathematica, Matlab, Murphi or Objective C
-au BufNewFile,BufRead *.m call s:FTm()
-
-func! s:FTm()
- let n = 1
- let saw_comment = 0 " Whether we've seen a multiline comment leader.
- while n < 100
- let line = getline(n)
- if line =~ '^\s*/\*'
- " /* ... */ is a comment in Objective C and Murphi, so we can't conclude
- " it's either of them yet, but track this as a hint in case we don't see
- " anything more definitive.
- let saw_comment = 1
- endif
- if line =~ '^\s*\(#\s*\(include\|import\)\>\|@import\>\|//\)'
- setf objc
- return
- endif
- if line =~ '^\s*%'
- setf matlab
- return
- endif
- if line =~ '^\s*(\*'
- setf mma
- return
- endif
- if line =~ '^\c\s*\(\(type\|var\)\>\|--\)'
- setf murphi
- return
- endif
- let n = n + 1
- endwhile
-
- if saw_comment
- " We didn't see anything definitive, but this looks like either Objective C
- " or Murphi based on the comment leader. Assume the former as it is more
- " common.
- setf objc
- elseif exists("g:filetype_m")
- " Use user specified default filetype for .m
- exe "setf " . g:filetype_m
- else
- " Default is matlab
- setf matlab
- endif
-endfunc
+au BufNewFile,BufRead *.m call dist#ft#FTm()
" Mathematica notebook
au BufNewFile,BufRead *.nb setf mma
@@ -1261,29 +976,11 @@ au BufNewFile,BufRead *.mgl setf mgl
au BufNewFile,BufRead *.mix,*.mixal setf mix
" MMIX or VMS makefile
-au BufNewFile,BufRead *.mms call s:FTmms()
+au BufNewFile,BufRead *.mms call dist#ft#FTmms()
" Symbian meta-makefile definition (MMP)
au BufNewFile,BufRead *.mmp setf mmp
-func! s:FTmms()
- let n = 1
- while n < 10
- let line = getline(n)
- if line =~ '^\s*\(%\|//\)' || line =~ '^\*'
- setf mmix
- return
- endif
- if line =~ '^\s*#'
- setf make
- return
- endif
- let n = n + 1
- endwhile
- setf mmix
-endfunc
-
-
" Modsim III (or LambdaProlog)
au BufNewFile,BufRead *.mod
\ if getline(1) =~ '\<module\>' |
@@ -1367,33 +1064,10 @@ au BufNewFile,BufRead *.me
\ setf nroff |
\ endif
au BufNewFile,BufRead *.tr,*.nr,*.roff,*.tmac,*.mom setf nroff
-au BufNewFile,BufRead *.[1-9] call s:FTnroff()
-
-" This function checks if one of the first five lines start with a dot. In
-" that case it is probably an nroff file: 'filetype' is set and 1 is returned.
-func! s:FTnroff()
- if getline(1)[0] . getline(2)[0] . getline(3)[0] . getline(4)[0] . getline(5)[0] =~ '\.'
- setf nroff
- return 1
- endif
- return 0
-endfunc
+au BufNewFile,BufRead *.[1-9] call dist#ft#FTnroff()
" Nroff or Objective C++
-au BufNewFile,BufRead *.mm call s:FTmm()
-
-func! s:FTmm()
- let n = 1
- while n < 10
- let line = getline(n)
- if line =~ '^\s*\(#\s*\(include\|import\)\>\|@import\>\|/\*\)'
- setf objcpp
- return
- endif
- let n = n + 1
- endwhile
- setf nroff
-endfunc
+au BufNewFile,BufRead *.mm call dist#ft#FTmm()
" Not Quite C
au BufNewFile,BufRead *.nqc setf nqc
@@ -1448,28 +1122,13 @@ au BufNewFile,BufRead *.pcmk setf pcmk
" Perl
if has("fname_case")
- au BufNewFile,BufRead *.pl,*.PL call s:FTpl()
+ au BufNewFile,BufRead *.pl,*.PL call dist#ft#FTpl()
else
- au BufNewFile,BufRead *.pl call s:FTpl()
+ au BufNewFile,BufRead *.pl call dist#ft#FTpl()
endif
au BufNewFile,BufRead *.plx,*.al,*.psgi setf perl
au BufNewFile,BufRead *.p6,*.pm6,*.pl6 setf perl6
-func! s:FTpl()
- if exists("g:filetype_pl")
- exe "setf " . g:filetype_pl
- else
- " recognize Prolog by specific text in the first non-empty line
- " require a blank after the '%' because Perl uses "%list" and "%translate"
- let l = getline(nextnonblank(1))
- if l =~ '\<prolog\>' || l =~ '^\s*\(%\+\(\s\|$\)\|/\*\)' || l =~ ':-'
- setf prolog
- else
- setf perl
- endif
- endif
-endfunc
-
" Perl, XPM or XPM2
au BufNewFile,BufRead *.pm
\ if getline(1) =~ "XPM2" |
@@ -1482,7 +1141,7 @@ au BufNewFile,BufRead *.pm
" Perl POD
au BufNewFile,BufRead *.pod setf pod
-au BufNewFile,BufRead *.pod6 setf pod6
+au BufNewFile,BufRead *.pod6 setf pod6
" Php, php3, php4, etc.
" Also Phtml (was used for PHP 2 in the past)
@@ -1532,29 +1191,7 @@ au BufNewFile,BufRead *.pov setf pov
au BufNewFile,BufRead .povrayrc setf povini
" Povray, PHP or assembly
-au BufNewFile,BufRead *.inc call s:FTinc()
-
-func! s:FTinc()
- if exists("g:filetype_inc")
- exe "setf " . g:filetype_inc
- else
- let lines = getline(1).getline(2).getline(3)
- if lines =~? "perlscript"
- setf aspperl
- elseif lines =~ "<%"
- setf aspvbs
- elseif lines =~ "<?"
- setf php
- else
- call s:FTasmsyntax()
- if exists("b:asmsyntax")
- exe "setf " . fnameescape(b:asmsyntax)
- else
- setf pov
- endif
- endif
- endif
-endfunc
+au BufNewFile,BufRead *.inc call dist#ft#FTinc()
" Printcap and Termcap
au BufNewFile,BufRead *printcap
@@ -1583,74 +1220,13 @@ au BufNewFile,BufRead *.action setf privoxy
au BufNewFile,BufRead .procmail,.procmailrc setf procmail
" Progress or CWEB
-au BufNewFile,BufRead *.w call s:FTprogress_cweb()
-
-func! s:FTprogress_cweb()
- if exists("g:filetype_w")
- exe "setf " . g:filetype_w
- return
- endif
- if getline(1) =~ '&ANALYZE' || getline(3) =~ '&GLOBAL-DEFINE'
- setf progress
- else
- setf cweb
- endif
-endfunc
+au BufNewFile,BufRead *.w call dist#ft#FTprogress_cweb()
" Progress or assembly
-au BufNewFile,BufRead *.i call s:FTprogress_asm()
-
-func! s:FTprogress_asm()
- if exists("g:filetype_i")
- exe "setf " . g:filetype_i
- return
- endif
- " This function checks for an assembly comment the first ten lines.
- " If not found, assume Progress.
- let lnum = 1
- while lnum <= 10 && lnum < line('$')
- let line = getline(lnum)
- if line =~ '^\s*;' || line =~ '^\*'
- call s:FTasm()
- return
- elseif line !~ '^\s*$' || line =~ '^/\*'
- " Not an empty line: Doesn't look like valid assembly code.
- " Or it looks like a Progress /* comment
- break
- endif
- let lnum = lnum + 1
- endw
- setf progress
-endfunc
+au BufNewFile,BufRead *.i call dist#ft#FTprogress_asm()
" Progress or Pascal
-au BufNewFile,BufRead *.p call s:FTprogress_pascal()
-
-func! s:FTprogress_pascal()
- if exists("g:filetype_p")
- exe "setf " . g:filetype_p
- return
- endif
- " This function checks for valid Pascal syntax in the first ten lines.
- " Look for either an opening comment or a program start.
- " If not found, assume Progress.
- let lnum = 1
- while lnum <= 10 && lnum < line('$')
- let line = getline(lnum)
- if line =~ '^\s*\(program\|unit\|procedure\|function\|const\|type\|var\)\>'
- \ || line =~ '^\s*{' || line =~ '^\s*(\*'
- setf pascal
- return
- elseif line !~ '^\s*$' || line =~ '^/\*'
- " Not an empty line: Doesn't look like valid Pascal code.
- " Or it looks like a Progress /* comment
- break
- endif
- let lnum = lnum + 1
- endw
- setf progress
-endfunc
-
+au BufNewFile,BufRead *.p call dist#ft#FTprogress_pascal()
" Software Distributor Product Specification File (POSIX 1387.2-1995)
au BufNewFile,BufRead *.psf setf psf
@@ -1736,40 +1312,7 @@ else
endif
" Rexx, Rebol or R
-au BufNewFile,BufRead *.r,*.R call s:FTr()
-
-func! s:FTr()
- let max = line("$") > 50 ? 50 : line("$")
-
- for n in range(1, max)
- " Rebol is easy to recognize, check for that first
- if getline(n) =~? '\<REBOL\>'
- setf rebol
- return
- endif
- endfor
-
- for n in range(1, max)
- " R has # comments
- if getline(n) =~ '^\s*#'
- setf r
- return
- endif
- " Rexx has /* comments */
- if getline(n) =~ '^\s*/\*'
- setf rexx
- return
- endif
- endfor
-
- " Nothing recognized, use user default or assume Rexx
- if exists("g:filetype_r")
- exe "setf " . g:filetype_r
- else
- " Rexx used to be the default, but R appears to be much more popular.
- setf r
- endif
-endfunc
+au BufNewFile,BufRead *.r,*.R call dist#ft#FTr()
" Remind
au BufNewFile,BufRead .reminders,*.remind,*.rem setf remind
@@ -1865,23 +1408,7 @@ au BufNewFile,BufRead *.siv setf sieve
au BufNewFile,BufRead sendmail.cf setf sm
" Sendmail .mc files are actually m4. Could also be MS Message text file.
-au BufNewFile,BufRead *.mc call s:McSetf()
-
-func! s:McSetf()
- " Rely on the file to start with a comment.
- " MS message text files use ';', Sendmail files use '#' or 'dnl'
- for lnum in range(1, min([line("$"), 20]))
- let line = getline(lnum)
- if line =~ '^\s*\(#\|dnl\)'
- setf m4 " Sendmail .mc file
- return
- elseif line =~ '^\s*;'
- setf msmessages " MS Message text file
- return
- endif
- endfor
- setf m4 " Default: Sendmail .mc file
-endfunc
+au BufNewFile,BufRead *.mc call dist#ft#McSetf()
" Services
au BufNewFile,BufRead */etc/services setf services
@@ -1922,101 +1449,23 @@ au BufNewFile,BufRead sgml.catalog* call s:StarSetf('catalog')
" Shell scripts (sh, ksh, bash, bash2, csh); Allow .profile_foo etc.
" Gentoo ebuilds and Arch Linux PKGBUILDs are actually bash scripts
-au BufNewFile,BufRead .bashrc*,bashrc,bash.bashrc,.bash[_-]profile*,.bash[_-]logout*,.bash[_-]aliases*,*.bash,*/{,.}bash[_-]completion{,.d,.sh}{,/*},*.ebuild,*.eclass,PKGBUILD* call SetFileTypeSH("bash")
-au BufNewFile,BufRead .kshrc*,*.ksh call SetFileTypeSH("ksh")
-au BufNewFile,BufRead */etc/profile,.profile*,*.sh,*.env call SetFileTypeSH(getline(1))
+au BufNewFile,BufRead .bashrc*,bashrc,bash.bashrc,.bash[_-]profile*,.bash[_-]logout*,.bash[_-]aliases*,*.bash,*/{,.}bash[_-]completion{,.d,.sh}{,/*},*.ebuild,*.eclass,PKGBUILD* call dist#ft#SetFileTypeSH("bash")
+au BufNewFile,BufRead .kshrc*,*.ksh call dist#ft#SetFileTypeSH("ksh")
+au BufNewFile,BufRead */etc/profile,.profile*,*.sh,*.env call dist#ft#SetFileTypeSH(getline(1))
" Shell script (Arch Linux) or PHP file (Drupal)
au BufNewFile,BufRead *.install
\ if getline(1) =~ '<?php' |
\ setf php |
\ else |
- \ call SetFileTypeSH("bash") |
+ \ call dist#ft#SetFileTypeSH("bash") |
\ endif
-" Also called from scripts.vim.
-func! SetFileTypeSH(name)
- if expand("<amatch>") =~ g:ft_ignore_pat
- return
- endif
- if a:name =~ '\<csh\>'
- " Some .sh scripts contain #!/bin/csh.
- call SetFileTypeShell("csh")
- return
- elseif a:name =~ '\<tcsh\>'
- " Some .sh scripts contain #!/bin/tcsh.
- call SetFileTypeShell("tcsh")
- return
- elseif a:name =~ '\<zsh\>'
- " Some .sh scripts contain #!/bin/zsh.
- call SetFileTypeShell("zsh")
- return
- elseif a:name =~ '\<ksh\>'
- let b:is_kornshell = 1
- if exists("b:is_bash")
- unlet b:is_bash
- endif
- if exists("b:is_sh")
- unlet b:is_sh
- endif
- elseif exists("g:bash_is_sh") || a:name =~ '\<bash\>' || a:name =~ '\<bash2\>'
- let b:is_bash = 1
- if exists("b:is_kornshell")
- unlet b:is_kornshell
- endif
- if exists("b:is_sh")
- unlet b:is_sh
- endif
- elseif a:name =~ '\<sh\>'
- let b:is_sh = 1
- if exists("b:is_kornshell")
- unlet b:is_kornshell
- endif
- if exists("b:is_bash")
- unlet b:is_bash
- endif
- endif
- call SetFileTypeShell("sh")
-endfunc
-
-" For shell-like file types, check for an "exec" command hidden in a comment,
-" as used for Tcl.
-" Also called from scripts.vim, thus can't be local to this script.
-func! SetFileTypeShell(name)
- if expand("<amatch>") =~ g:ft_ignore_pat
- return
- endif
- let l = 2
- while l < 20 && l < line("$") && getline(l) =~ '^\s*\(#\|$\)'
- " Skip empty and comment lines.
- let l = l + 1
- endwhile
- if l < line("$") && getline(l) =~ '\s*exec\s' && getline(l - 1) =~ '^\s*#.*\\$'
- " Found an "exec" line after a comment with continuation
- let n = substitute(getline(l),'\s*exec\s\+\([^ ]*/\)\=', '', '')
- if n =~ '\<tclsh\|\<wish'
- setf tcl
- return
- endif
- endif
- exe "setf " . a:name
-endfunc
-
" tcsh scripts
-au BufNewFile,BufRead .tcshrc*,*.tcsh,tcsh.tcshrc,tcsh.login call SetFileTypeShell("tcsh")
+au BufNewFile,BufRead .tcshrc*,*.tcsh,tcsh.tcshrc,tcsh.login call dist#ft#SetFileTypeShell("tcsh")
" csh scripts, but might also be tcsh scripts (on some systems csh is tcsh)
-au BufNewFile,BufRead .login*,.cshrc*,csh.cshrc,csh.login,csh.logout,*.csh,.alias call s:CSH()
-
-func! s:CSH()
- if exists("g:filetype_csh")
- call SetFileTypeShell(g:filetype_csh)
- elseif &shell =~ "tcsh"
- call SetFileTypeShell("tcsh")
- else
- call SetFileTypeShell("csh")
- endif
-endfunc
+au BufNewFile,BufRead .login*,.cshrc*,csh.cshrc,csh.login,csh.logout,*.csh,.alias call dist#ft#CSH()
" Z-Shell script
au BufNewFile,BufRead .zprofile,*/etc/zprofile,.zfbfmarks setf zsh
@@ -2087,42 +1536,7 @@ au BufNewFile,BufRead *.mib,*.my setf mib
" Snort Configuration
au BufNewFile,BufRead *.hog,snort.conf,vision.conf setf hog
-au BufNewFile,BufRead *.rules call s:FTRules()
-
-let s:ft_rules_udev_rules_pattern = '^\s*\cudev_rules\s*=\s*"\([^"]\{-1,}\)/*".*'
-func! s:FTRules()
- let path = expand('<amatch>:p')
- if path =~ '^/\(etc/udev/\%(rules\.d/\)\=.*\.rules\|lib/udev/\%(rules\.d/\)\=.*\.rules\)$'
- setf udevrules
- return
- endif
- if path =~ '^/etc/ufw/'
- setf conf " Better than hog
- return
- endif
- if path =~ '^/\(etc\|usr/share\)/polkit-1/rules\.d'
- setf javascript
- return
- endif
- try
- let config_lines = readfile('/etc/udev/udev.conf')
- catch /^Vim\%((\a\+)\)\=:E484/
- setf hog
- return
- endtry
- let dir = expand('<amatch>:p:h')
- for line in config_lines
- if line =~ s:ft_rules_udev_rules_pattern
- let udev_rules = substitute(line, s:ft_rules_udev_rules_pattern, '\1', "")
- if dir == udev_rules
- setf udevrules
- endif
- break
- endif
- endfor
- setf hog
-endfunc
-
+au BufNewFile,BufRead *.rules call dist#ft#FTRules()
" Spec (Linux RPM)
au BufNewFile,BufRead *.spec setf spec
@@ -2146,15 +1560,7 @@ au BufNewFile,BufRead squid.conf setf squid
au BufNewFile,BufRead *.tyb,*.typ,*.tyc,*.pkb,*.pks setf sql
" SQL
-au BufNewFile,BufRead *.sql call s:SQL()
-
-func! s:SQL()
- if exists("g:filetype_sql")
- exe "setf " . g:filetype_sql
- else
- setf sql
- endif
-endfunc
+au BufNewFile,BufRead *.sql call dist#ft#SQL()
" SQLJ
au BufNewFile,BufRead *.sqlj setf sqlj
@@ -2201,32 +1607,9 @@ au BufNewFile,BufRead */etc/sudoers,sudoers.tmp setf sudoers
" SVG (Scalable Vector Graphics)
au BufNewFile,BufRead *.svg setf svg
-" If the file has an extension of 't' and is in a directory 't' or 'xt' then
-" it is almost certainly a Perl test file.
-" If the first line starts with '#' and contains 'perl' it's probably a Perl
-" file.
-" (Slow test) If a file contains a 'use' statement then it is almost certainly
-" a Perl file.
-func! s:FTperl()
- let dirname = expand("%:p:h:t")
- if expand("%:e") == 't' && (dirname == 't' || dirname == 'xt')
- setf perl
- return 1
- endif
- if getline(1)[0] == '#' && getline(1) =~ 'perl'
- setf perl
- return 1
- endif
- if search('^use\s\s*\k', 'nc', 30)
- setf perl
- return 1
- endif
- return 0
-endfunc
-
" Tads (or Nroff or Perl test file)
au BufNewFile,BufRead *.t
- \ if !s:FTnroff() && !s:FTperl() | setf tads | endif
+ \ if !dist#ft#FTnroff() && !dist#ft#FTperl() | setf tads | endif
" Tags
au BufNewFile,BufRead tags setf tags
@@ -2255,63 +1638,7 @@ au BufNewFile,BufRead *.ti setf terminfo
" TeX
au BufNewFile,BufRead *.latex,*.sty,*.dtx,*.ltx,*.bbl setf tex
-au BufNewFile,BufRead *.tex call s:FTtex()
-
-" Choose context, plaintex, or tex (LaTeX) based on these rules:
-" 1. Check the first line of the file for "%&<format>".
-" 2. Check the first 1000 non-comment lines for LaTeX or ConTeXt keywords.
-" 3. Default to "latex" or to g:tex_flavor, can be set in user's vimrc.
-func! s:FTtex()
- let firstline = getline(1)
- if firstline =~ '^%&\s*\a\+'
- let format = tolower(matchstr(firstline, '\a\+'))
- let format = substitute(format, 'pdf', '', '')
- if format == 'tex'
- let format = 'latex'
- elseif format == 'plaintex'
- let format = 'plain'
- endif
- elseif expand('%') =~ 'tex/context/.*/.*.tex'
- let format = 'context'
- else
- " Default value, may be changed later:
- let format = exists("g:tex_flavor") ? g:tex_flavor : 'plain'
- " Save position, go to the top of the file, find first non-comment line.
- let save_cursor = getpos('.')
- call cursor(1,1)
- let firstNC = search('^\s*[^[:space:]%]', 'c', 1000)
- if firstNC " Check the next thousand lines for a LaTeX or ConTeXt keyword.
- let lpat = 'documentclass\>\|usepackage\>\|begin{\|newcommand\>\|renewcommand\>'
- let cpat = 'start\a\+\|setup\a\+\|usemodule\|enablemode\|enableregime\|setvariables\|useencoding\|usesymbols\|stelle\a\+\|verwende\a\+\|stel\a\+\|gebruik\a\+\|usa\a\+\|imposta\a\+\|regle\a\+\|utilisemodule\>'
- let kwline = search('^\s*\\\%(' . lpat . '\)\|^\s*\\\(' . cpat . '\)',
- \ 'cnp', firstNC + 1000)
- if kwline == 1 " lpat matched
- let format = 'latex'
- elseif kwline == 2 " cpat matched
- let format = 'context'
- endif " If neither matched, keep default set above.
- " let lline = search('^\s*\\\%(' . lpat . '\)', 'cn', firstNC + 1000)
- " let cline = search('^\s*\\\%(' . cpat . '\)', 'cn', firstNC + 1000)
- " if cline > 0
- " let format = 'context'
- " endif
- " if lline > 0 && (cline == 0 || cline > lline)
- " let format = 'tex'
- " endif
- endif " firstNC
- call setpos('.', save_cursor)
- endif " firstline =~ '^%&\s*\a\+'
-
- " Translation from formats to file types. TODO: add AMSTeX, RevTex, others?
- if format == 'plain'
- setf plaintex
- elseif format == 'context'
- setf context
- else " probably LaTeX
- setf tex
- endif
- return
-endfunc
+au BufNewFile,BufRead *.tex call dist#ft#FTtex()
" ConTeXt
au BufNewFile,BufRead *.mkii,*.mkiv,*.mkvi setf context
@@ -2412,7 +1739,7 @@ au BufRead,BufNewFile *.hw,*.module,*.pkg
\ endif
" Visual Basic (also uses *.bas) or FORM
-au BufNewFile,BufRead *.frm call s:FTVB("form")
+au BufNewFile,BufRead *.frm call dist#ft#FTVB("form")
" SaxBasic is close to Visual Basic
au BufNewFile,BufRead *.sba setf vb
@@ -2502,36 +1829,10 @@ au BufNewFile,BufRead .Xdefaults,.Xpdefaults,.Xresources,xdm-config,*.ad setf xd
" Xmath
au BufNewFile,BufRead *.msc,*.msf setf xmath
au BufNewFile,BufRead *.ms
- \ if !s:FTnroff() | setf xmath | endif
+ \ if !dist#ft#FTnroff() | setf xmath | endif
" XML specific variants: docbk and xbl
-au BufNewFile,BufRead *.xml call s:FTxml()
-
-func! s:FTxml()
- let n = 1
- while n < 100 && n < line("$")
- let line = getline(n)
- " DocBook 4 or DocBook 5.
- let is_docbook4 = line =~ '<!DOCTYPE.*DocBook'
- let is_docbook5 = line =~ ' xmlns="http://docbook.org/ns/docbook"'
- if is_docbook4 || is_docbook5
- let b:docbk_type = "xml"
- if is_docbook5
- let b:docbk_ver = 5
- else
- let b:docbk_ver = 4
- endif
- setf docbk
- return
- endif
- if line =~ 'xmlns:xbl="http://www.mozilla.org/xbl"'
- setf xbl
- return
- endif
- let n += 1
- endwhile
- setf xml
-endfunc
+au BufNewFile,BufRead *.xml call dist#ft#FTxml()
" XMI (holding UML models) is also XML
au BufNewFile,BufRead *.xmi setf xml
@@ -2574,25 +1875,7 @@ au BufNewFile,BufRead *.xsl,*.xslt setf xslt
au BufNewFile,BufRead *.yy,*.yxx,*.y++ setf yacc
" Yacc or racc
-au BufNewFile,BufRead *.y call s:FTy()
-
-func! s:FTy()
- let n = 1
- while n < 100 && n < line("$")
- let line = getline(n)
- if line =~ '^\s*%'
- setf yacc
- return
- endif
- if getline(n) =~ '^\s*\(#\|class\>\)' && getline(n) !~ '^\s*#\s*include'
- setf racc
- return
- endif
- let n = n + 1
- endwhile
- setf yacc
-endfunc
-
+au BufNewFile,BufRead *.y call dist#ft#FTy()
" Yaml
au BufNewFile,BufRead *.yaml,*.yml setf yaml
@@ -2608,9 +1891,9 @@ au BufNewFile,BufRead *.zut setf zimbutempl
" Zope
" dtml (zope dynamic template markup language), pt (zope page template),
" cpt (zope form controller page template)
-au BufNewFile,BufRead *.dtml,*.pt,*.cpt call s:FThtml()
+au BufNewFile,BufRead *.dtml,*.pt,*.cpt call dist#ft#FThtml()
" zsql (zope sql method)
-au BufNewFile,BufRead *.zsql call s:SQL()
+au BufNewFile,BufRead *.zsql call dist#ft#SQL()
" Z80 assembler asz80
au BufNewFile,BufRead *.z8a setf z8a
@@ -2652,6 +1935,11 @@ au BufNewFile,BufRead *asterisk*/*voicemail.conf* call s:StarSetf('asteriskvm')
" Bazaar version control
au BufNewFile,BufRead bzr_log.* setf bzr
+" Bazel build file
+if !has("fname_case")
+ au BufNewFile,BufRead BUILD setf bzl
+endif
+
" BIND zone
au BufNewFile,BufRead */named/db.*,*/bind/db.* call s:StarSetf('bindzone')
@@ -2759,17 +2047,7 @@ au BufNewFile,BufRead *termcap*
" ReDIF
" Only used when the .rdf file was not detected to be XML.
-au BufRead,BufNewFile *.rdf call s:Redif()
-func! s:Redif()
- let lnum = 1
- while lnum <= 5 && lnum < line('$')
- if getline(lnum) =~ "^\ctemplate-type:"
- setf redif
- return
- endif
- let lnum = lnum + 1
- endwhile
-endfunc
+au BufRead,BufNewFile *.rdf call dist#ft#Redif()
" Remind
au BufNewFile,BufRead .reminders* call s:StarSetf('remind')
diff --git a/runtime/scripts.vim b/runtime/scripts.vim
index 63bf9efcf9..18263e2842 100644
--- a/runtime/scripts.vim
+++ b/runtime/scripts.vim
@@ -1,11 +1,15 @@
" Vim support file to detect file types in scripts
"
" Maintainer: Bram Moolenaar <Bram@vim.org>
-" Last change: 2017 Aug 27
+" Last change: 2017 Nov 11
" This file is called by an autocommand for every file that has just been
" loaded into a buffer. It checks if the type of file can be recognized by
" the file contents. The autocommand is in $VIMRUNTIME/filetype.vim.
+"
+" Note that the pattern matches are done with =~# to avoid the value of the
+" 'ignorecase' option making a difference. Where case is to be ignored use
+" =~? instead. Do not use =~ anywhere.
" Only do the rest when the FileType autocommand has not been triggered yet.
@@ -28,12 +32,12 @@ set cpo&vim
let s:line1 = getline(1)
-if s:line1 =~ "^#!"
+if s:line1 =~# "^#!"
" A script that starts with "#!".
" Check for a line like "#!/usr/bin/env VAR=val bash". Turn it into
" "#!/usr/bin/bash" to make matching easier.
- if s:line1 =~ '^#!\s*\S*\<env\s'
+ if s:line1 =~# '^#!\s*\S*\<env\s'
let s:line1 = substitute(s:line1, '\S\+=\S\+', '', 'g')
let s:line1 = substitute(s:line1, '\<env\s\+', '', '')
endif
@@ -44,11 +48,11 @@ if s:line1 =~ "^#!"
" "#!/usr/bin/env perl [path/args]"
" If there is no path use the first word: "#!perl [path/args]".
" Otherwise get the last word after a slash: "#!/usr/bin/perl [path/args]".
- if s:line1 =~ '^#!\s*\a:[/\\]'
+ if s:line1 =~# '^#!\s*\a:[/\\]'
let s:name = substitute(s:line1, '^#!.*[/\\]\(\i\+\).*', '\1', '')
- elseif s:line1 =~ '^#!.*\<env\>'
+ elseif s:line1 =~# '^#!.*\<env\>'
let s:name = substitute(s:line1, '^#!.*\<env\>\s\+\(\i\+\).*', '\1', '')
- elseif s:line1 =~ '^#!\s*[^/\\ ]*\>\([^/\\]\|$\)'
+ elseif s:line1 =~# '^#!\s*[^/\\ ]*\>\([^/\\]\|$\)'
let s:name = substitute(s:line1, '^#!\s*\([^/\\ ]*\>\).*', '\1', '')
else
let s:name = substitute(s:line1, '^#!\s*\S*[/\\]\(\i\+\).*', '\1', '')
@@ -56,116 +60,116 @@ if s:line1 =~ "^#!"
" tcl scripts may have #!/bin/sh in the first line and "exec wish" in the
" third line. Suggested by Steven Atkinson.
- if getline(3) =~ '^exec wish'
+ if getline(3) =~# '^exec wish'
let s:name = 'wish'
endif
" Bourne-like shell scripts: bash bash2 ksh ksh93 sh
- if s:name =~ '^\(bash\d*\|\|ksh\d*\|sh\)\>'
- call SetFileTypeSH(s:line1) " defined in filetype.vim
+ if s:name =~# '^\(bash\d*\|\|ksh\d*\|sh\)\>'
+ call dist#ft#SetFileTypeSH(s:line1) " defined in filetype.vim
" csh scripts
- elseif s:name =~ '^csh\>'
+ elseif s:name =~# '^csh\>'
if exists("g:filetype_csh")
- call SetFileTypeShell(g:filetype_csh)
+ call dist#ft#SetFileTypeShell(g:filetype_csh)
else
- call SetFileTypeShell("csh")
+ call dist#ft#SetFileTypeShell("csh")
endif
" tcsh scripts
- elseif s:name =~ '^tcsh\>'
- call SetFileTypeShell("tcsh")
+ elseif s:name =~# '^tcsh\>'
+ call dist#ft#SetFileTypeShell("tcsh")
" Z shell scripts
- elseif s:name =~ '^zsh\>'
+ elseif s:name =~# '^zsh\>'
set ft=zsh
" TCL scripts
- elseif s:name =~ '^\(tclsh\|wish\|expectk\|itclsh\|itkwish\)\>'
+ elseif s:name =~# '^\(tclsh\|wish\|expectk\|itclsh\|itkwish\)\>'
set ft=tcl
" Expect scripts
- elseif s:name =~ '^expect\>'
+ elseif s:name =~# '^expect\>'
set ft=expect
" Gnuplot scripts
- elseif s:name =~ '^gnuplot\>'
+ elseif s:name =~# '^gnuplot\>'
set ft=gnuplot
" Makefiles
- elseif s:name =~ 'make\>'
+ elseif s:name =~# 'make\>'
set ft=make
" Lua
- elseif s:name =~ 'lua'
+ elseif s:name =~# 'lua'
set ft=lua
" Perl 6
- elseif s:name =~ 'perl6'
+ elseif s:name =~# 'perl6'
set ft=perl6
" Perl
- elseif s:name =~ 'perl'
+ elseif s:name =~# 'perl'
set ft=perl
" PHP
- elseif s:name =~ 'php'
+ elseif s:name =~# 'php'
set ft=php
" Python
- elseif s:name =~ 'python'
+ elseif s:name =~# 'python'
set ft=python
" Groovy
- elseif s:name =~ '^groovy\>'
+ elseif s:name =~# '^groovy\>'
set ft=groovy
" Ruby
- elseif s:name =~ 'ruby'
+ elseif s:name =~# 'ruby'
set ft=ruby
" JavaScript
- elseif s:name =~ 'node\(js\)\=\>' || s:name =~ 'rhino\>'
+ elseif s:name =~# 'node\(js\)\=\>' || s:name =~# 'rhino\>'
set ft=javascript
" BC calculator
- elseif s:name =~ '^bc\>'
+ elseif s:name =~# '^bc\>'
set ft=bc
" sed
- elseif s:name =~ 'sed\>'
+ elseif s:name =~# 'sed\>'
set ft=sed
" OCaml-scripts
- elseif s:name =~ 'ocaml'
+ elseif s:name =~# 'ocaml'
set ft=ocaml
" Awk scripts
- elseif s:name =~ 'awk\>'
+ elseif s:name =~# 'awk\>'
set ft=awk
" Website MetaLanguage
- elseif s:name =~ 'wml'
+ elseif s:name =~# 'wml'
set ft=wml
" Scheme scripts
- elseif s:name =~ 'scheme'
+ elseif s:name =~# 'scheme'
set ft=scheme
" CFEngine scripts
- elseif s:name =~ 'cfengine'
+ elseif s:name =~# 'cfengine'
set ft=cfengine
" Erlang scripts
- elseif s:name =~ 'escript'
+ elseif s:name =~# 'escript'
set ft=erlang
" Haskell
- elseif s:name =~ 'haskell'
+ elseif s:name =~# 'haskell'
set ft=haskell
" Scala
- elseif s:name =~ 'scala\>'
+ elseif s:name =~# 'scala\>'
set ft=scala
endif
@@ -180,28 +184,28 @@ else
let s:line5 = getline(5)
" Bourne-like shell scripts: sh ksh bash bash2
- if s:line1 =~ '^:$'
- call SetFileTypeSH(s:line1) " defined in filetype.vim
+ if s:line1 =~# '^:$'
+ call dist#ft#SetFileTypeSH(s:line1) " defined in filetype.vim
" Z shell scripts
- elseif s:line1 =~ '^#compdef\>' || s:line1 =~ '^#autoload\>' ||
- \ "\n".s:line1."\n".s:line2."\n".s:line3."\n".s:line4."\n".s:line5 =~ '\n\s*emulate\s\+\%(-[LR]\s\+\)\=[ckz]\=sh\>'
+ elseif s:line1 =~# '^#compdef\>' || s:line1 =~# '^#autoload\>' ||
+ \ "\n".s:line1."\n".s:line2."\n".s:line3."\n".s:line4."\n".s:line5 =~# '\n\s*emulate\s\+\%(-[LR]\s\+\)\=[ckz]\=sh\>'
set ft=zsh
" ELM Mail files
- elseif s:line1 =~ '^From \([a-zA-Z][a-zA-Z_0-9\.=-]*\(@[^ ]*\)\=\|-\) .* \(19\|20\)\d\d$'
+ elseif s:line1 =~# '^From \([a-zA-Z][a-zA-Z_0-9\.=-]*\(@[^ ]*\)\=\|-\) .* \(19\|20\)\d\d$'
set ft=mail
" Mason
- elseif s:line1 =~ '^<[%&].*>'
+ elseif s:line1 =~# '^<[%&].*>'
set ft=mason
" Vim scripts (must have '" vim' as the first line to trigger this)
- elseif s:line1 =~ '^" *[vV]im$'
+ elseif s:line1 =~# '^" *[vV]im$'
set ft=vim
" MOO
- elseif s:line1 =~ '^\*\* LambdaMOO Database, Format Version \%([1-3]\>\)\@!\d\+ \*\*$'
+ elseif s:line1 =~# '^\*\* LambdaMOO Database, Format Version \%([1-3]\>\)\@!\d\+ \*\*$'
set ft=moo
" Diff file:
@@ -215,40 +219,45 @@ else
" - "=== ", "--- ", "+++ " (bzr diff, common case)
" - "=== (removed|added|renamed|modified)" (bzr diff, alternative)
" - "# HG changeset patch" in first line (Mercurial export format)
- elseif s:line1 =~ '^\(diff\>\|Only in \|\d\+\(,\d\+\)\=[cda]\d\+\>\|# It was generated by makepatch \|Index:\s\+\f\+\r\=$\|===== \f\+ \d\+\.\d\+ vs edited\|==== //\f\+#\d\+\|# HG changeset patch\)'
- \ || (s:line1 =~ '^--- ' && s:line2 =~ '^+++ ')
- \ || (s:line1 =~ '^\* looking for ' && s:line2 =~ '^\* comparing to ')
- \ || (s:line1 =~ '^\*\*\* ' && s:line2 =~ '^--- ')
- \ || (s:line1 =~ '^=== ' && ((s:line2 =~ '^=\{66\}' && s:line3 =~ '^--- ' && s:line4 =~ '^+++') || (s:line2 =~ '^--- ' && s:line3 =~ '^+++ ')))
- \ || (s:line1 =~ '^=== \(removed\|added\|renamed\|modified\)')
+ elseif s:line1 =~# '^\(diff\>\|Only in \|\d\+\(,\d\+\)\=[cda]\d\+\>\|# It was generated by makepatch \|Index:\s\+\f\+\r\=$\|===== \f\+ \d\+\.\d\+ vs edited\|==== //\f\+#\d\+\|# HG changeset patch\)'
+ \ || (s:line1 =~# '^--- ' && s:line2 =~# '^+++ ')
+ \ || (s:line1 =~# '^\* looking for ' && s:line2 =~# '^\* comparing to ')
+ \ || (s:line1 =~# '^\*\*\* ' && s:line2 =~# '^--- ')
+ \ || (s:line1 =~# '^=== ' && ((s:line2 =~# '^=\{66\}' && s:line3 =~# '^--- ' && s:line4 =~# '^+++') || (s:line2 =~# '^--- ' && s:line3 =~# '^+++ ')))
+ \ || (s:line1 =~# '^=== \(removed\|added\|renamed\|modified\)')
set ft=diff
" PostScript Files (must have %!PS as the first line, like a2ps output)
- elseif s:line1 =~ '^%![ \t]*PS'
+ elseif s:line1 =~# '^%![ \t]*PS'
set ft=postscr
" M4 scripts: Guess there is a line that starts with "dnl".
- elseif s:line1 =~ '^\s*dnl\>'
- \ || s:line2 =~ '^\s*dnl\>'
- \ || s:line3 =~ '^\s*dnl\>'
- \ || s:line4 =~ '^\s*dnl\>'
- \ || s:line5 =~ '^\s*dnl\>'
+ elseif s:line1 =~# '^\s*dnl\>'
+ \ || s:line2 =~# '^\s*dnl\>'
+ \ || s:line3 =~# '^\s*dnl\>'
+ \ || s:line4 =~# '^\s*dnl\>'
+ \ || s:line5 =~# '^\s*dnl\>'
set ft=m4
+ " AmigaDos scripts
+ elseif $TERM == "amiga"
+ \ && (s:line1 =~# "^;" || s:line1 =~? '^\.bra')
+ set ft=amiga
+
" SiCAD scripts (must have procn or procd as the first line to trigger this)
elseif s:line1 =~? '^ *proc[nd] *$'
set ft=sicad
" Purify log files start with "**** Purify"
- elseif s:line1 =~ '^\*\*\*\* Purify'
+ elseif s:line1 =~# '^\*\*\*\* Purify'
set ft=purifylog
" XML
- elseif s:line1 =~ '<?\s*xml.*?>'
+ elseif s:line1 =~# '<?\s*xml.*?>'
set ft=xml
" XHTML (e.g.: PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN")
- elseif s:line1 =~ '\<DTD\s\+XHTML\s'
+ elseif s:line1 =~# '\<DTD\s\+XHTML\s'
set ft=xhtml
" HTML (e.g.: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN")
@@ -257,43 +266,43 @@ else
set ft=html
" PDF
- elseif s:line1 =~ '^%PDF-'
+ elseif s:line1 =~# '^%PDF-'
set ft=pdf
" XXD output
- elseif s:line1 =~ '^\x\{7}: \x\{2} \=\x\{2} \=\x\{2} \=\x\{2} '
+ elseif s:line1 =~# '^\x\{7}: \x\{2} \=\x\{2} \=\x\{2} \=\x\{2} '
set ft=xxd
" RCS/CVS log output
- elseif s:line1 =~ '^RCS file:' || s:line2 =~ '^RCS file:'
+ elseif s:line1 =~# '^RCS file:' || s:line2 =~# '^RCS file:'
set ft=rcslog
" CVS commit
- elseif s:line2 =~ '^CVS:' || getline("$") =~ '^CVS: '
+ elseif s:line2 =~# '^CVS:' || getline("$") =~# '^CVS: '
set ft=cvs
" Prescribe
- elseif s:line1 =~ '^!R!'
+ elseif s:line1 =~# '^!R!'
set ft=prescribe
" Send-pr
- elseif s:line1 =~ '^SEND-PR:'
+ elseif s:line1 =~# '^SEND-PR:'
set ft=sendpr
" SNNS files
- elseif s:line1 =~ '^SNNS network definition file'
+ elseif s:line1 =~# '^SNNS network definition file'
set ft=snnsnet
- elseif s:line1 =~ '^SNNS pattern definition file'
+ elseif s:line1 =~# '^SNNS pattern definition file'
set ft=snnspat
- elseif s:line1 =~ '^SNNS result file'
+ elseif s:line1 =~# '^SNNS result file'
set ft=snnsres
" Virata
- elseif s:line1 =~ '^%.\{-}[Vv]irata'
- \ || s:line2 =~ '^%.\{-}[Vv]irata'
- \ || s:line3 =~ '^%.\{-}[Vv]irata'
- \ || s:line4 =~ '^%.\{-}[Vv]irata'
- \ || s:line5 =~ '^%.\{-}[Vv]irata'
+ elseif s:line1 =~# '^%.\{-}[Vv]irata'
+ \ || s:line2 =~# '^%.\{-}[Vv]irata'
+ \ || s:line3 =~# '^%.\{-}[Vv]irata'
+ \ || s:line4 =~# '^%.\{-}[Vv]irata'
+ \ || s:line5 =~# '^%.\{-}[Vv]irata'
set ft=virata
" Strace
@@ -301,17 +310,17 @@ else
set ft=strace
" VSE JCL
- elseif s:line1 =~ '^\* $$ JOB\>' || s:line1 =~ '^// *JOB\>'
+ elseif s:line1 =~# '^\* $$ JOB\>' || s:line1 =~# '^// *JOB\>'
set ft=vsejcl
" TAK and SINDA
- elseif s:line4 =~ 'K & K Associates' || s:line2 =~ 'TAK 2000'
+ elseif s:line4 =~# 'K & K Associates' || s:line2 =~# 'TAK 2000'
set ft=takout
- elseif s:line3 =~ 'S Y S T E M S I M P R O V E D '
+ elseif s:line3 =~# 'S Y S T E M S I M P R O V E D '
set ft=sindaout
- elseif getline(6) =~ 'Run Date: '
+ elseif getline(6) =~# 'Run Date: '
set ft=takcmp
- elseif getline(9) =~ 'Node File 1'
+ elseif getline(9) =~# 'Node File 1'
set ft=sindacmp
" DNS zone files
@@ -319,34 +328,34 @@ else
set ft=bindzone
" BAAN
- elseif s:line1 =~ '|\*\{1,80}' && s:line2 =~ 'VRC '
- \ || s:line2 =~ '|\*\{1,80}' && s:line3 =~ 'VRC '
+ elseif s:line1 =~# '|\*\{1,80}' && s:line2 =~# 'VRC '
+ \ || s:line2 =~# '|\*\{1,80}' && s:line3 =~# 'VRC '
set ft=baan
" Valgrind
- elseif s:line1 =~ '^==\d\+== valgrind' || s:line3 =~ '^==\d\+== Using valgrind'
+ elseif s:line1 =~# '^==\d\+== valgrind' || s:line3 =~# '^==\d\+== Using valgrind'
set ft=valgrind
" Go docs
- elseif s:line1 =~ '^PACKAGE DOCUMENTATION$'
+ elseif s:line1 =~# '^PACKAGE DOCUMENTATION$'
set ft=godoc
" Renderman Interface Bytestream
- elseif s:line1 =~ '^##RenderMan'
+ elseif s:line1 =~# '^##RenderMan'
set ft=rib
" Scheme scripts
- elseif s:line1 =~ 'exec\s\+\S*scheme' || s:line2 =~ 'exec\s\+\S*scheme'
+ elseif s:line1 =~# 'exec\s\+\S*scheme' || s:line2 =~# 'exec\s\+\S*scheme'
set ft=scheme
" Git output
- elseif s:line1 =~ '^\(commit\|tree\|object\) \x\{40\}\>\|^tag \S\+$'
+ elseif s:line1 =~# '^\(commit\|tree\|object\) \x\{40\}\>\|^tag \S\+$'
set ft=git
" Gprof (gnu profiler)
elseif s:line1 == 'Flat profile:'
\ && s:line2 == ''
- \ && s:line3 =~ '^Each sample counts as .* seconds.$'
+ \ && s:line3 =~# '^Each sample counts as .* seconds.$'
set ft=gprof
" Erlang terms
@@ -357,18 +366,18 @@ else
" CVS diff
else
let s:lnum = 1
- while getline(s:lnum) =~ "^? " && s:lnum < line("$")
+ while getline(s:lnum) =~# "^? " && s:lnum < line("$")
let s:lnum += 1
endwhile
- if getline(s:lnum) =~ '^Index:\s\+\f\+$'
+ if getline(s:lnum) =~# '^Index:\s\+\f\+$'
set ft=diff
" locale input files: Formal Definitions of Cultural Conventions
" filename must be like en_US, fr_FR@euro or en_US.UTF-8
- elseif expand("%") =~ '\a\a_\a\a\($\|[.@]\)\|i18n$\|POSIX$\|translit_'
+ elseif expand("%") =~# '\a\a_\a\a\($\|[.@]\)\|i18n$\|POSIX$\|translit_'
let s:lnum = 1
while s:lnum < 100 && s:lnum < line("$")
- if getline(s:lnum) =~ '^LC_\(IDENTIFICATION\|CTYPE\|COLLATE\|MONETARY\|NUMERIC\|TIME\|MESSAGES\|PAPER\|TELEPHONE\|MEASUREMENT\|NAME\|ADDRESS\)$'
+ if getline(s:lnum) =~# '^LC_\(IDENTIFICATION\|CTYPE\|COLLATE\|MONETARY\|NUMERIC\|TIME\|MESSAGES\|PAPER\|TELEPHONE\|MEASUREMENT\|NAME\|ADDRESS\)$'
setf fdcc
break
endif
diff --git a/runtime/syntax/dircolors.vim b/runtime/syntax/dircolors.vim
index 1b598c39b5..3d7f63dc55 100644
--- a/runtime/syntax/dircolors.vim
+++ b/runtime/syntax/dircolors.vim
@@ -32,7 +32,7 @@ syntax match dircolorsEscape '\\[abefnrtv?_\\^#]'
syntax match dircolorsEscape '\\[0-9]\{3}'
syntax match dircolorsEscape '\\x[0-9a-f]\{3}'
-if !has('gui_running') && &t_Co == ''
+if !(has('gui_running') || &termguicolors) && &t_Co == ''
syntax match dircolorsNumber '\<\d\+\>'
highlight default link dircolorsNumber Number
endif
@@ -84,7 +84,7 @@ endfunction
function! s:get_hi_str(color, place) abort
if a:color >= 0 && a:color <= 255
- if has('gui_running')
+ if has('gui_running') || &termguicolors
return ' gui' . a:place . '=' . s:termguicolors[a:color]
elseif a:color <= 7 || &t_Co == 256 || &t_Co == 88
return ' cterm' . a:place . '=' . a:color
@@ -169,7 +169,7 @@ function! s:preview_color(linenr) abort
\ ' "\_s\zs' . colordef . '\ze\_s"'
let hi_attrs_str = ''
if !empty(hi_attrs)
- if has('gui_running')
+ if has('gui_running') || &termguicolors
let hi_attrs_str = ' gui=' . join(hi_attrs, ',')
else
let hi_attrs_str = ' cterm=' . join(hi_attrs, ',')
@@ -199,11 +199,11 @@ endfunction
let b:dc_next_index = 0
-if has('gui_running')
+if has('gui_running') || &termguicolors
call s:set_guicolors()
endif
-if has('gui_running') || &t_Co != ''
+if has('gui_running') || &termguicolors || &t_Co != ''
call s:reset_colors()
autocmd CursorMoved,CursorMovedI <buffer> call s:preview_color('.')
diff --git a/scripts/run-api-tests.exp b/scripts/run-api-tests.exp
deleted file mode 100755
index 27c9c963e5..0000000000
--- a/scripts/run-api-tests.exp
+++ /dev/null
@@ -1,50 +0,0 @@
-#!/usr/bin/env expect
-
-if {$argc < 2} {
- puts "Need commands for running the tests and for starting nvim"
- exit 1
-}
-
-set timeout 60
-set run_tests [split [lindex $argv 0] " "]
-set run_nvim [split [lindex $argv 1] " "]
-
-# don't echo to stdout
-log_user 0
-# set NVIM_LISTEN_ADDRESS, so nvim will listen on a known socket
-set env(NVIM_LISTEN_ADDRESS) "/tmp/nvim-[exec date +%s%N].sock"
-# start nvim
-spawn {*}$run_nvim
-# save the job descriptor
-set nvim_id $spawn_id
-# Reset function that can be invoked by test runners to put nvim in a cleaner
-# state
-send {
-:echo "read"."y"
-}
-# wait until nvim is ready
-expect "ready"
-# run tests
-spawn {*}$run_tests
-set tests_id $spawn_id
-set status 1
-# listen for test output in the background
-expect_background {
- * {
- # show test output to the user
- send_user -- $expect_out(buffer)
- }
- eof {
- # collect the exit status code
- set spawn_id $tests_id
- catch wait result
- set status [lindex $result 3]
- set spawn_id $nvim_id
- # quit nvim
- send ":qa!\r"
- }
-}
-# switch back nvim and wait until it exits
-set spawn_id $nvim_id
-expect eof
-exit $status
diff --git a/src/nvim/CMakeLists.txt b/src/nvim/CMakeLists.txt
index 606baff619..2d803792c8 100644
--- a/src/nvim/CMakeLists.txt
+++ b/src/nvim/CMakeLists.txt
@@ -359,6 +359,10 @@ endforeach()
# Our dependencies come first.
+if (CMAKE_SYSTEM_NAME MATCHES "OpenBSD")
+ list(APPEND NVIM_LINK_LIBRARIES pthread c++abi)
+endif()
+
if (LibIntl_FOUND)
list(APPEND NVIM_LINK_LIBRARIES ${LibIntl_LIBRARY})
endif()
@@ -437,6 +441,7 @@ if(WIN32)
COMMAND ${CMAKE_COMMAND} -E copy "${DEPS_PREFIX}/bin/tidy.exe" ${PROJECT_BINARY_DIR}/windows_runtime_deps/
COMMAND ${CMAKE_COMMAND} -E copy "${DEPS_PREFIX}/bin/win32yank.exe" ${PROJECT_BINARY_DIR}/windows_runtime_deps/
COMMAND ${CMAKE_COMMAND} -E copy "${DEPS_PREFIX}/bin/winpty-agent.exe" ${PROJECT_BINARY_DIR}/windows_runtime_deps/
+ COMMAND ${CMAKE_COMMAND} -E copy "${DEPS_PREFIX}/bin/xxd.exe" ${PROJECT_BINARY_DIR}/windows_runtime_deps/
COMMAND ${CMAKE_COMMAND} -E copy "${DEPS_PREFIX}/bin/D3Dcompiler_47.dll" ${PROJECT_BINARY_DIR}/windows_runtime_deps/
COMMAND ${CMAKE_COMMAND} -E copy "${DEPS_PREFIX}/bin/libEGL.dll" ${PROJECT_BINARY_DIR}/windows_runtime_deps/
diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c
index 1115faaeaf..12a4279dd7 100644
--- a/src/nvim/api/private/helpers.c
+++ b/src/nvim/api/private/helpers.c
@@ -47,13 +47,15 @@ typedef struct {
/// @param[out] tstate Location where try state should be saved.
void try_enter(TryState *const tstate)
{
+ // TODO(ZyX-I): Check whether try_enter()/try_leave() may use
+ // enter_cleanup()/leave_cleanup(). Or
+ // save_dbg_stuff()/restore_dbg_stuff().
*tstate = (TryState) {
.current_exception = current_exception,
.msg_list = (const struct msglist *const *)msg_list,
.private_msg_list = NULL,
.trylevel = trylevel,
.got_int = got_int,
- .did_throw = did_throw,
.need_rethrow = need_rethrow,
.did_emsg = did_emsg,
};
@@ -61,7 +63,6 @@ void try_enter(TryState *const tstate)
current_exception = NULL;
trylevel = 1;
got_int = false;
- did_throw = false;
need_rethrow = false;
did_emsg = false;
}
@@ -82,7 +83,6 @@ bool try_leave(const TryState *const tstate, Error *const err)
assert(trylevel == 0);
assert(!need_rethrow);
assert(!got_int);
- assert(!did_throw);
assert(!did_emsg);
assert(msg_list == &tstate->private_msg_list);
assert(*msg_list == NULL);
@@ -91,7 +91,6 @@ bool try_leave(const TryState *const tstate, Error *const err)
current_exception = tstate->current_exception;
trylevel = tstate->trylevel;
got_int = tstate->got_int;
- did_throw = tstate->did_throw;
need_rethrow = tstate->need_rethrow;
did_emsg = tstate->did_emsg;
return ret;
@@ -127,7 +126,7 @@ bool try_end(Error *err)
did_emsg = false;
if (got_int) {
- if (did_throw) {
+ if (current_exception) {
// If we got an interrupt, discard the current exception
discard_current_exception();
}
@@ -146,7 +145,7 @@ bool try_end(Error *err)
if (should_free) {
xfree(msg);
}
- } else if (did_throw) {
+ } else if (current_exception) {
api_set_error(err, kErrorTypeException, "%s", current_exception->value);
discard_current_exception();
}
diff --git a/src/nvim/api/private/helpers.h b/src/nvim/api/private/helpers.h
index 87f334ac30..0634764f13 100644
--- a/src/nvim/api/private/helpers.h
+++ b/src/nvim/api/private/helpers.h
@@ -93,7 +93,6 @@ typedef struct {
const struct msglist *const *msg_list;
int trylevel;
int got_int;
- int did_throw;
int need_rethrow;
int did_emsg;
} TryState;
diff --git a/src/nvim/api/ui.c b/src/nvim/api/ui.c
index 4870c3fb8a..4cd2657561 100644
--- a/src/nvim/api/ui.c
+++ b/src/nvim/api/ui.c
@@ -56,7 +56,8 @@ void nvim_ui_attach(uint64_t channel_id, Integer width, Integer height,
FUNC_API_SINCE(1) FUNC_API_REMOTE_ONLY
{
if (pmap_has(uint64_t)(connected_uis, channel_id)) {
- api_set_error(err, kErrorTypeException, "UI already attached for channel");
+ api_set_error(err, kErrorTypeException,
+ "UI already attached to channel: %" PRId64, channel_id);
return;
}
@@ -130,7 +131,8 @@ void nvim_ui_detach(uint64_t channel_id, Error *err)
FUNC_API_SINCE(1) FUNC_API_REMOTE_ONLY
{
if (!pmap_has(uint64_t)(connected_uis, channel_id)) {
- api_set_error(err, kErrorTypeException, "UI is not attached for channel");
+ api_set_error(err, kErrorTypeException,
+ "UI not attached to channel: %" PRId64, channel_id);
return;
}
remote_ui_disconnect(channel_id);
@@ -142,7 +144,8 @@ void nvim_ui_try_resize(uint64_t channel_id, Integer width,
FUNC_API_SINCE(1) FUNC_API_REMOTE_ONLY
{
if (!pmap_has(uint64_t)(connected_uis, channel_id)) {
- api_set_error(err, kErrorTypeException, "UI is not attached for channel");
+ api_set_error(err, kErrorTypeException,
+ "UI not attached to channel: %" PRId64, channel_id);
return;
}
@@ -163,7 +166,8 @@ void nvim_ui_set_option(uint64_t channel_id, String name,
FUNC_API_SINCE(1) FUNC_API_REMOTE_ONLY
{
if (!pmap_has(uint64_t)(connected_uis, channel_id)) {
- api_set_error(error, kErrorTypeException, "UI is not attached for channel");
+ api_set_error(error, kErrorTypeException,
+ "UI not attached to channel: %" PRId64, channel_id);
return;
}
UI *ui = pmap_get(uint64_t)(connected_uis, channel_id);
@@ -209,7 +213,8 @@ static void ui_set_option(UI *ui, String name, Object value, Error *error)
return;
}
- api_set_error(error, kErrorTypeValidation, "No such ui option");
+ api_set_error(error, kErrorTypeValidation, "No such UI option: %s",
+ name.data);
#undef UI_EXT_OPTION
}
diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c
index 962081cc23..07ec6e8c27 100644
--- a/src/nvim/api/vim.c
+++ b/src/nvim/api/vim.c
@@ -239,15 +239,17 @@ String nvim_command_output(String command, Error *err)
}
if (capture_local.ga_len > 1) {
- // redir always(?) prepends a newline; remove it.
- char *s = capture_local.ga_data;
- assert(s[0] == '\n');
- memmove(s, s + 1, (size_t)capture_local.ga_len);
- s[capture_local.ga_len - 1] = '\0';
- return (String) { // Caller will free the memory.
- .data = s,
- .size = (size_t)(capture_local.ga_len - 1),
+ String s = (String){
+ .data = capture_local.ga_data,
+ .size = (size_t)capture_local.ga_len,
};
+ // redir usually (except :echon) prepends a newline.
+ if (s.data[0] == '\n') {
+ memmove(s.data, s.data + 1, s.size);
+ s.data[s.size - 1] = '\0';
+ s.size = s.size - 1;
+ }
+ return s; // Caller will free the memory.
}
theend:
diff --git a/src/nvim/auevents.lua b/src/nvim/auevents.lua
index 7dfaf54ff0..1153314e76 100644
--- a/src/nvim/auevents.lua
+++ b/src/nvim/auevents.lua
@@ -92,6 +92,8 @@ return {
'VimLeave', -- before exiting Vim
'VimLeavePre', -- before exiting Vim and writing ShaDa file
'VimResized', -- after Vim window was resized
+ 'VimResume', -- after Nvim is resumed
+ 'VimSuspend', -- before Nvim is suspended
'WinNew', -- when entering a new window
'WinEnter', -- after entering a window
'WinLeave', -- before leaving a window
diff --git a/src/nvim/channel.c b/src/nvim/channel.c
index 2e32af2e9a..776e2bfa86 100644
--- a/src/nvim/channel.c
+++ b/src/nvim/channel.c
@@ -237,15 +237,16 @@ void channel_create_event(Channel *chan, const char *ext_source)
#endif
}
-void channel_incref(Channel *channel)
+void channel_incref(Channel *chan)
{
- channel->refcount++;
+ chan->refcount++;
}
-void channel_decref(Channel *channel)
+void channel_decref(Channel *chan)
{
- if (!(--channel->refcount)) {
- multiqueue_put(main_loop.fast_events, free_channel_event, 1, channel);
+ if (!(--chan->refcount)) {
+ // delay free, so that libuv is done with the handles
+ multiqueue_put(main_loop.events, free_channel_event, 1, chan);
}
}
@@ -267,18 +268,18 @@ void callback_reader_start(CallbackReader *reader)
static void free_channel_event(void **argv)
{
- Channel *channel = argv[0];
- if (channel->is_rpc) {
- rpc_free(channel);
+ Channel *chan = argv[0];
+ if (chan->is_rpc) {
+ rpc_free(chan);
}
- callback_reader_free(&channel->on_stdout);
- callback_reader_free(&channel->on_stderr);
- callback_free(&channel->on_exit);
+ callback_reader_free(&chan->on_stdout);
+ callback_reader_free(&chan->on_stderr);
+ callback_free(&chan->on_exit);
- pmap_del(uint64_t)(channels, channel->id);
- multiqueue_free(channel->events);
- xfree(channel);
+ pmap_del(uint64_t)(channels, chan->id);
+ multiqueue_free(chan->events);
+ xfree(chan);
}
static void channel_destroy_early(Channel *chan)
@@ -286,12 +287,15 @@ static void channel_destroy_early(Channel *chan)
if ((chan->id != --next_chan_id)) {
abort();
}
+ pmap_del(uint64_t)(channels, chan->id);
+ chan->id = 0;
if ((--chan->refcount != 0)) {
abort();
}
- free_channel_event((void **)&chan);
+ // uv will keep a reference to handles until next loop tick, so delay free
+ multiqueue_put(main_loop.events, free_channel_event, 1, chan);
}
diff --git a/src/nvim/edit.c b/src/nvim/edit.c
index b772a944f4..a0f6ce152b 100644
--- a/src/nvim/edit.c
+++ b/src/nvim/edit.c
@@ -847,7 +847,7 @@ static int insert_handle_key(InsertState *s)
case ' ':
- if (mod_mask != 4) {
+ if (mod_mask != MOD_MASK_CTRL) {
goto normalchar;
}
// FALLTHROUGH
@@ -1180,6 +1180,14 @@ static int insert_handle_key(InsertState *s)
normalchar:
// Insert a normal character.
+
+ if (mod_mask == MOD_MASK_ALT || mod_mask == MOD_MASK_META) {
+ // Unmapped ALT/META chord behaves like ESC+c. #8213
+ stuffcharReadbuff(ESC);
+ stuffcharReadbuff(s->c);
+ break;
+ }
+
if (!p_paste) {
// Trigger InsertCharPre.
char_u *str = do_insert_char_pre(s->c);
@@ -1432,7 +1440,7 @@ static void ins_ctrl_v(void)
* line and will not removed by the redraw */
edit_unputchar();
clear_showcmd();
- insert_special(c, FALSE, TRUE);
+ insert_special(c, true, true);
revins_chars++;
revins_legal++;
}
@@ -3615,6 +3623,9 @@ int ins_compl_add_tv(typval_T *const tv, const Direction dir)
memset(cptext, 0, sizeof(cptext));
}
if (word == NULL || (!aempty && *word == NUL)) {
+ for (size_t i = 0; i < CPT_COUNT; i++) {
+ xfree(cptext[i]);
+ }
return FAIL;
}
return ins_compl_add((char_u *)word, -1, icase, NULL,
@@ -5054,13 +5065,11 @@ static void insert_special(int c, int allow_modmask, int ctrlv)
char_u *p;
int len;
- /*
- * Special function key, translate into "<Key>". Up to the last '>' is
- * inserted with ins_str(), so as not to replace characters in replace
- * mode.
- * Only use mod_mask for special keys, to avoid things like <S-Space>,
- * unless 'allow_modmask' is TRUE.
- */
+ // Special function key, translate into "<Key>". Up to the last '>' is
+ // inserted with ins_str(), so as not to replace characters in replace
+ // mode.
+ // Only use mod_mask for special keys, to avoid things like <S-Space>,
+ // unless 'allow_modmask' is TRUE.
if (mod_mask & MOD_MASK_CMD) { // Command-key never produces a normal key.
allow_modmask = true;
}
diff --git a/src/nvim/eval.c b/src/nvim/eval.c
index 0f7a1eb004..713eb816f8 100644
--- a/src/nvim/eval.c
+++ b/src/nvim/eval.c
@@ -14403,8 +14403,11 @@ static void f_serverstop(typval_T *argvars, typval_T *rettv, FunPtr fptr)
return;
}
+ rettv->v_type = VAR_NUMBER;
+ rettv->vval.v_number = 0;
if (argvars[0].vval.v_string) {
- server_stop((char *) argvars[0].vval.v_string);
+ bool rv = server_stop((char *)argvars[0].vval.v_string);
+ rettv->vval.v_number = (rv ? 1 : 0);
}
}
@@ -15699,6 +15702,56 @@ static void f_split(typval_T *argvars, typval_T *rettv, FunPtr fptr)
p_cpo = save_cpo;
}
+/// "stdpath()" helper for list results
+static void get_xdg_var_list(const XDGVarType xdg, typval_T *rettv)
+ FUNC_ATTR_NONNULL_ALL
+{
+ const void *iter = NULL;
+ list_T *const list = tv_list_alloc(kListLenShouldKnow);
+ rettv->v_type = VAR_LIST;
+ rettv->vval.v_list = list;
+ tv_list_ref(list);
+ char *const dirs = stdpaths_get_xdg_var(xdg);
+ do {
+ size_t dir_len;
+ const char *dir;
+ iter = vim_env_iter(':', dirs, iter, &dir, &dir_len);
+ if (dir != NULL && dir_len > 0) {
+ char *dir_with_nvim = xmemdupz(dir, dir_len);
+ dir_with_nvim = concat_fnames_realloc(dir_with_nvim, "nvim", true);
+ tv_list_append_string(list, dir_with_nvim, strlen(dir_with_nvim));
+ xfree(dir_with_nvim);
+ }
+ } while (iter != NULL);
+ xfree(dirs);
+}
+
+/// "stdpath(type)" function
+static void f_stdpath(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+{
+ rettv->v_type = VAR_STRING;
+ rettv->vval.v_string = NULL;
+
+ const char *const p = tv_get_string_chk(&argvars[0]);
+ if (p == NULL) {
+ return; // Type error; errmsg already given.
+ }
+
+ if (strcmp(p, "config") == 0) {
+ rettv->vval.v_string = (char_u *)get_xdg_home(kXDGConfigHome);
+ } else if (strcmp(p, "data") == 0) {
+ rettv->vval.v_string = (char_u *)get_xdg_home(kXDGDataHome);
+ } else if (strcmp(p, "cache") == 0) {
+ rettv->vval.v_string = (char_u *)get_xdg_home(kXDGCacheHome);
+ } else if (strcmp(p, "config_dirs") == 0) {
+ get_xdg_var_list(kXDGConfigDirs, rettv);
+ } else if (strcmp(p, "data_dirs") == 0) {
+ get_xdg_var_list(kXDGDataDirs, rettv);
+ } else {
+ EMSG2(_("E6100: \"%s\" is not a valid stdpath"), p);
+ }
+}
+
/*
* "str2float()" function
*/
@@ -16861,6 +16914,12 @@ static void f_timer_pause(typval_T *argvars, typval_T *unused, FunPtr fptr)
int paused = (bool)tv_get_number(&argvars[1]);
timer_T *timer = pmap_get(uint64_t)(timers, tv_get_number(&argvars[0]));
if (timer != NULL) {
+ if (!timer->paused && paused) {
+ time_watcher_stop(&timer->tw);
+ } else if (timer->paused && !paused) {
+ time_watcher_start(&timer->tw, timer_due_cb, timer->timeout,
+ timer->timeout);
+ }
timer->paused = paused;
}
}
diff --git a/src/nvim/eval.h b/src/nvim/eval.h
index b798eae187..149dae688e 100644
--- a/src/nvim/eval.h
+++ b/src/nvim/eval.h
@@ -10,6 +10,7 @@
#include "nvim/event/rstream.h"
#include "nvim/event/wstream.h"
#include "nvim/channel.h"
+#include "nvim/os/stdpaths_defs.h"
#define COPYID_INC 2
#define COPYID_MASK (~0x1)
diff --git a/src/nvim/eval.lua b/src/nvim/eval.lua
index daa3b637a3..801d2cc468 100644
--- a/src/nvim/eval.lua
+++ b/src/nvim/eval.lua
@@ -280,6 +280,7 @@ return {
spellsuggest={args={1, 3}},
split={args={1, 3}},
sqrt={args=1, func="float_op_wrapper", data="&sqrt"},
+ stdpath={args=1},
str2float={args=1},
str2nr={args={1, 2}},
strcharpart={args={2, 3}},
diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c
index 99495aaa61..7cd6dbdeca 100644
--- a/src/nvim/ex_docmd.c
+++ b/src/nvim/ex_docmd.c
@@ -133,7 +133,6 @@ struct dbg_stuff {
char_u *vv_throwpoint;
int did_emsg;
int got_int;
- int did_throw;
int need_rethrow;
int check_cstack;
except_T *current_exception;
@@ -165,12 +164,11 @@ static void save_dbg_stuff(struct dbg_stuff *dsp)
dsp->vv_exception = v_exception(NULL);
dsp->vv_throwpoint = v_throwpoint(NULL);
- /* Necessary for debugging an inactive ":catch", ":finally", ":endtry" */
- dsp->did_emsg = did_emsg; did_emsg = FALSE;
- dsp->got_int = got_int; got_int = FALSE;
- dsp->did_throw = did_throw; did_throw = FALSE;
- dsp->need_rethrow = need_rethrow; need_rethrow = FALSE;
- dsp->check_cstack = check_cstack; check_cstack = FALSE;
+ // Necessary for debugging an inactive ":catch", ":finally", ":endtry".
+ dsp->did_emsg = did_emsg; did_emsg = false;
+ dsp->got_int = got_int; got_int = false;
+ dsp->need_rethrow = need_rethrow; need_rethrow = false;
+ dsp->check_cstack = check_cstack; check_cstack = false;
dsp->current_exception = current_exception; current_exception = NULL;
}
@@ -184,7 +182,6 @@ static void restore_dbg_stuff(struct dbg_stuff *dsp)
(void)v_throwpoint(dsp->vv_throwpoint);
did_emsg = dsp->did_emsg;
got_int = dsp->got_int;
- did_throw = dsp->did_throw;
need_rethrow = dsp->need_rethrow;
check_cstack = dsp->check_cstack;
current_exception = dsp->current_exception;
@@ -400,16 +397,11 @@ int do_cmdline(char_u *cmdline, LineGetter fgetline,
initial_trylevel = trylevel;
- /*
- * "did_throw" will be set to TRUE when an exception is being thrown.
- */
- did_throw = FALSE;
- /*
- * "did_emsg" will be set to TRUE when emsg() is used, in which case we
- * cancel the whole command line, and any if/endif or loop.
- * If force_abort is set, we cancel everything.
- */
- did_emsg = FALSE;
+ current_exception = NULL;
+ // "did_emsg" will be set to TRUE when emsg() is used, in which case we
+ // cancel the whole command line, and any if/endif or loop.
+ // If force_abort is set, we cancel everything.
+ did_emsg = false;
/*
* KeyTyped is only set when calling vgetc(). Reset it here when not
@@ -659,7 +651,7 @@ int do_cmdline(char_u *cmdline, LineGetter fgetline,
* not to use a cs_line[] from an entry that isn't a ":while"
* or ":for": It would make "current_line" invalid and can
* cause a crash. */
- if (!did_emsg && !got_int && !did_throw
+ if (!did_emsg && !got_int && !current_exception
&& cstack.cs_idx >= 0
&& (cstack.cs_flags[cstack.cs_idx]
& (CSF_WHILE | CSF_FOR))
@@ -707,7 +699,7 @@ int do_cmdline(char_u *cmdline, LineGetter fgetline,
}
/*
- * A ":finally" makes did_emsg, got_int, and did_throw pending for
+ * A ":finally" makes did_emsg, got_int and current_exception pending for
* being restored at the ":endtry". Reset them here and set the
* ACTIVE and FINALLY flags, so that the finally clause gets executed.
* This includes the case where a missing ":endif", ":endwhile" or
@@ -715,10 +707,11 @@ int do_cmdline(char_u *cmdline, LineGetter fgetline,
*/
if (cstack.cs_lflags & CSL_HAD_FINA) {
cstack.cs_lflags &= ~CSL_HAD_FINA;
- report_make_pending(cstack.cs_pending[cstack.cs_idx]
- & (CSTP_ERROR | CSTP_INTERRUPT | CSTP_THROW),
- did_throw ? (void *)current_exception : NULL);
- did_emsg = got_int = did_throw = FALSE;
+ report_make_pending((cstack.cs_pending[cstack.cs_idx]
+ & (CSTP_ERROR | CSTP_INTERRUPT | CSTP_THROW)),
+ current_exception);
+ did_emsg = got_int = false;
+ current_exception = NULL;
cstack.cs_flags[cstack.cs_idx] |= CSF_ACTIVE | CSF_FINALLY;
}
@@ -726,15 +719,14 @@ int do_cmdline(char_u *cmdline, LineGetter fgetline,
* within this loop. */
trylevel = initial_trylevel + cstack.cs_trylevel;
- /*
- * If the outermost try conditional (across function calls and sourced
- * files) is aborted because of an error, an interrupt, or an uncaught
- * exception, cancel everything. If it is left normally, reset
- * force_abort to get the non-EH compatible abortion behavior for
- * the rest of the script.
- */
- if (trylevel == 0 && !did_emsg && !got_int && !did_throw)
- force_abort = FALSE;
+ // If the outermost try conditional (across function calls and sourced
+ // files) is aborted because of an error, an interrupt, or an uncaught
+ // exception, cancel everything. If it is left normally, reset
+ // force_abort to get the non-EH compatible abortion behavior for
+ // the rest of the script.
+ if (trylevel == 0 && !did_emsg && !got_int && !current_exception) {
+ force_abort = false;
+ }
/* Convert an interrupt to an exception if appropriate. */
(void)do_intthrow(&cstack);
@@ -749,11 +741,8 @@ int do_cmdline(char_u *cmdline, LineGetter fgetline,
* - there is a command after '|', inside a :if, :while, :for or :try, or
* looping for ":source" command or function call.
*/
- while (!((got_int
- || (did_emsg && force_abort) || did_throw
- )
- && cstack.cs_trylevel == 0
- )
+ while (!((got_int || (did_emsg && force_abort) || current_exception)
+ && cstack.cs_trylevel == 0)
&& !(did_emsg
/* Keep going when inside try/catch, so that the error can be
* deal with, except when it is a syntax error, it may cause
@@ -775,7 +764,7 @@ int do_cmdline(char_u *cmdline, LineGetter fgetline,
* If a sourced file or executed function ran to its end, report the
* unclosed conditional.
*/
- if (!got_int && !did_throw
+ if (!got_int && !current_exception
&& ((getline_equal(fgetline, cookie, getsourceline)
&& !source_finished(fgetline, cookie))
|| (getline_equal(fgetline, cookie, get_func_line)
@@ -815,17 +804,16 @@ int do_cmdline(char_u *cmdline, LineGetter fgetline,
? (char_u *)"endfunction" : (char_u *)NULL);
if (trylevel == 0) {
- /*
- * When an exception is being thrown out of the outermost try
- * conditional, discard the uncaught exception, disable the conversion
- * of interrupts or errors to exceptions, and ensure that no more
- * commands are executed.
- */
- if (did_throw) {
- void *p = NULL;
- char_u *saved_sourcing_name;
+ // When an exception is being thrown out of the outermost try
+ // conditional, discard the uncaught exception, disable the conversion
+ // of interrupts or errors to exceptions, and ensure that no more
+ // commands are executed.
+ if (current_exception) {
+ void *p = NULL;
+ char_u *saved_sourcing_name;
int saved_sourcing_lnum;
- struct msglist *messages = NULL, *next;
+ struct msglist *messages = NULL;
+ struct msglist *next;
/*
* If the uncaught exception is a user exception, report it as an
@@ -885,22 +873,22 @@ int do_cmdline(char_u *cmdline, LineGetter fgetline,
suppress_errthrow = TRUE;
}
- /*
- * The current cstack will be freed when do_cmdline() returns. An uncaught
- * exception will have to be rethrown in the previous cstack. If a function
- * has just returned or a script file was just finished and the previous
- * cstack belongs to the same function or, respectively, script file, it
- * will have to be checked for finally clauses to be executed due to the
- * ":return" or ":finish". This is done in do_one_cmd().
- */
- if (did_throw)
- need_rethrow = TRUE;
+ // The current cstack will be freed when do_cmdline() returns. An uncaught
+ // exception will have to be rethrown in the previous cstack. If a function
+ // has just returned or a script file was just finished and the previous
+ // cstack belongs to the same function or, respectively, script file, it
+ // will have to be checked for finally clauses to be executed due to the
+ // ":return" or ":finish". This is done in do_one_cmd().
+ if (current_exception) {
+ need_rethrow = true;
+ }
if ((getline_equal(fgetline, cookie, getsourceline)
&& ex_nesting_level > source_level(real_cookie))
|| (getline_equal(fgetline, cookie, get_func_line)
&& ex_nesting_level > func_level(real_cookie) + 1)) {
- if (!did_throw)
- check_cstack = TRUE;
+ if (!current_exception) {
+ check_cstack = true;
+ }
} else {
/* When leaving a function, reduce nesting level. */
if (getline_equal(fgetline, cookie, get_func_line))
@@ -1480,10 +1468,11 @@ static char_u * do_one_cmd(char_u **cmdlinep,
}
char_u *after_modifier = ea.cmd;
- ea.skip = did_emsg || got_int || did_throw || (cstack->cs_idx >= 0
- && !(cstack->cs_flags[cstack->
- cs_idx]
- & CSF_ACTIVE));
+ ea.skip = (did_emsg
+ || got_int
+ || current_exception
+ || (cstack->cs_idx >= 0
+ && !(cstack->cs_flags[cstack->cs_idx] & CSF_ACTIVE)));
/* Count this line for profiling if ea.skip is FALSE. */
if (do_profiling == PROF_YES && !ea.skip) {
@@ -1782,13 +1771,14 @@ static char_u * do_one_cmd(char_u **cmdlinep,
));
- /* forced commands */
+ // Forced commands.
if (*p == '!' && ea.cmdidx != CMD_substitute
&& ea.cmdidx != CMD_smagic && ea.cmdidx != CMD_snomagic) {
- ++p;
- ea.forceit = TRUE;
- } else
- ea.forceit = FALSE;
+ p++;
+ ea.forceit = true;
+ } else {
+ ea.forceit = false;
+ }
/*
* 6. Parse arguments.
@@ -6310,15 +6300,18 @@ static void ex_stop(exarg_T *eap)
if (!eap->forceit) {
autowrite_all();
}
+ apply_autocmds(EVENT_VIMSUSPEND, NULL, NULL, false, NULL);
ui_cursor_goto((int)Rows - 1, 0);
ui_linefeed();
ui_flush();
ui_call_suspend(); // call machine specific function
+
ui_flush();
maketitle();
resettitle(); // force updating the title
redraw_later_clear();
ui_refresh(); // may have resized window
+ apply_autocmds(EVENT_VIMRESUME, NULL, NULL, false, NULL);
}
}
@@ -6985,12 +6978,10 @@ do_exedit (
ex_no_reprint = TRUE;
}
-/*
- * ":gui" and ":gvim" when there is no GUI.
- */
+/// ":gui" and ":gvim" when there is no GUI.
static void ex_nogui(exarg_T *eap)
{
- eap->errmsg = e_nogvim;
+ eap->errmsg = (char_u *)N_("E25: Nvim does not have a built-in GUI");
}
diff --git a/src/nvim/ex_eval.c b/src/nvim/ex_eval.c
index 4010a088c8..e23945c842 100644
--- a/src/nvim/ex_eval.c
+++ b/src/nvim/ex_eval.c
@@ -45,22 +45,21 @@
* there or even outside the try conditional. Try conditionals may be nested.
*/
-/*
- * Configuration whether an exception is thrown on error or interrupt. When
- * the preprocessor macros below evaluate to FALSE, an error (did_emsg) or
- * interrupt (got_int) under an active try conditional terminates the script
- * after the non-active finally clauses of all active try conditionals have been
- * executed. Otherwise, errors and/or interrupts are converted into catchable
- * exceptions (did_throw additionally set), which terminate the script only if
- * not caught. For user exceptions, only did_throw is set. (Note: got_int can
- * be set asynchronously afterwards by a SIGINT, so did_throw && got_int is not
- * a reliant test that the exception currently being thrown is an interrupt
- * exception. Similarly, did_emsg can be set afterwards on an error in an
- * (unskipped) conditional command inside an inactive conditional, so did_throw
- * && did_emsg is not a reliant test that the exception currently being thrown
- * is an error exception.) - The macros can be defined as expressions checking
- * for a variable that is allowed to be changed during execution of a script.
- */
+// Configuration whether an exception is thrown on error or interrupt. When
+// the preprocessor macros below evaluate to FALSE, an error (did_emsg) or
+// interrupt (got_int) under an active try conditional terminates the script
+// after the non-active finally clauses of all active try conditionals have been
+// executed. Otherwise, errors and/or interrupts are converted into catchable
+// exceptions, which terminate the script only if not caught. For user
+// exceptions, only current_exception is set. (Note: got_int can be set
+// asynchronously afterwards by a SIGINT, so current_exception && got_int is not
+// a reliant test that the exception currently being thrown is an interrupt
+// exception. Similarly, did_emsg can be set afterwards on an error in an
+// (unskipped) conditional command inside an inactive conditional, so
+// current_exception && did_emsg is not a reliant test that the exception
+// currently being thrown is an error exception.) - The macros can be defined
+// as expressions checking for a variable that is allowed to be changed during
+// execution of a script.
// Values used for the Vim release.
#define THROW_ON_ERROR true
@@ -68,6 +67,15 @@
#define THROW_ON_INTERRUPT true
#define THROW_ON_INTERRUPT_TRUE
+// Don't do something after an error, interrupt, or throw, or when
+// there is a surrounding conditional and it was not active.
+#define CHECK_SKIP \
+ (did_emsg \
+ || got_int \
+ || current_exception \
+ || (cstack->cs_idx > 0 \
+ && !(cstack->cs_flags[cstack->cs_idx - 1] & CSF_ACTIVE)))
+
#define discard_pending_return(p) tv_free((typval_T *)(p))
/*
@@ -94,7 +102,7 @@ static int cause_abort = FALSE;
*/
int aborting(void)
{
- return (did_emsg && force_abort) || got_int || did_throw;
+ return (did_emsg && force_abort) || got_int || current_exception;
}
/*
@@ -178,8 +186,9 @@ int cause_errthrow(char_u *mesg, int severe, int *ignore)
* currently throwing an exception, do nothing. The message text will
* then be stored to v:errmsg by emsg() without displaying it.
*/
- if (((trylevel == 0 && !cause_abort) || emsg_silent) && !did_throw)
- return FALSE;
+ if (((trylevel == 0 && !cause_abort) || emsg_silent) && !current_exception) {
+ return false;
+ }
/*
* Ignore an interrupt message when inside a try conditional or when an
@@ -208,12 +217,13 @@ int cause_errthrow(char_u *mesg, int severe, int *ignore)
* exception currently being thrown to prevent it from being caught. Just
* execute finally clauses and terminate.
*/
- if (did_throw) {
- /* When discarding an interrupt exception, reset got_int to prevent the
- * same interrupt being converted to an exception again and discarding
- * the error exception we are about to throw here. */
- if (current_exception->type == ET_INTERRUPT)
- got_int = FALSE;
+ if (current_exception) {
+ // When discarding an interrupt exception, reset got_int to prevent the
+ // same interrupt being converted to an exception again and discarding
+ // the error exception we are about to throw here.
+ if (current_exception->type == ET_INTERRUPT) {
+ got_int = false;
+ }
discard_current_exception();
}
@@ -333,45 +343,44 @@ void do_errthrow(struct condstack *cstack, char_u *cmdname)
*/
int do_intthrow(struct condstack *cstack)
{
- /*
- * If no interrupt occurred or no try conditional is active and no exception
- * is being thrown, do nothing (for compatibility of non-EH scripts).
- */
- if (!got_int || (trylevel == 0 && !did_throw))
- return FALSE;
+ // If no interrupt occurred or no try conditional is active and no exception
+ // is being thrown, do nothing (for compatibility of non-EH scripts).
+ if (!got_int || (trylevel == 0 && !current_exception)) {
+ return false;
+ }
-#ifdef THROW_TEST /* avoid warning for condition always true */
+#ifdef THROW_TEST // avoid warning for condition always true
if (!THROW_ON_INTERRUPT) {
- /*
- * The interrupt aborts everything except for executing finally clauses.
- * Discard any user or error or interrupt exception currently being
- * thrown.
- */
- if (did_throw)
+ // The interrupt aborts everything except for executing finally clauses.
+ // Discard any user or error or interrupt exception currently being
+ // thrown.
+ if (current_exception) {
discard_current_exception();
- } else
+ }
+ } else {
#endif
- {
- /*
- * Throw an interrupt exception, so that everything will be aborted
- * (except for executing finally clauses), until the interrupt exception
- * is caught; if still uncaught at the top level, the script processing
- * will be terminated then. - If an interrupt exception is already
- * being thrown, do nothing.
- *
- */
- if (did_throw) {
- if (current_exception->type == ET_INTERRUPT)
- return FALSE;
+ // Throw an interrupt exception, so that everything will be aborted
+ // (except for executing finally clauses), until the interrupt exception
+ // is caught; if still uncaught at the top level, the script processing
+ // will be terminated then. - If an interrupt exception is already
+ // being thrown, do nothing.
+
+ if (current_exception) {
+ if (current_exception->type == ET_INTERRUPT) {
+ return false;
+ }
- /* An interrupt exception replaces any user or error exception. */
+ // An interrupt exception replaces any user or error exception.
discard_current_exception();
}
- if (throw_exception("Vim:Interrupt", ET_INTERRUPT, NULL) != FAIL)
+ if (throw_exception("Vim:Interrupt", ET_INTERRUPT, NULL) != FAIL) {
do_throw(cstack);
+ }
+#ifdef THROW_TEST
}
+#endif
- return TRUE;
+ return true;
}
// Get an exception message that is to be stored in current_exception->value.
@@ -565,8 +574,7 @@ void discard_current_exception(void)
// Note: all globals manipulated here should be saved/restored in
// try_enter/try_leave.
current_exception = NULL;
- did_throw = FALSE;
- need_rethrow = FALSE;
+ need_rethrow = false;
}
/*
@@ -795,15 +803,7 @@ void ex_if(exarg_T *eap)
++cstack->cs_idx;
cstack->cs_flags[cstack->cs_idx] = 0;
- /*
- * Don't do something after an error, interrupt, or throw, or when there
- * is a surrounding conditional and it was not active.
- */
- skip = did_emsg || got_int || did_throw || (cstack->cs_idx > 0
- && !(cstack->cs_flags[cstack->
- cs_idx -
- 1] &
- CSF_ACTIVE));
+ skip = CHECK_SKIP;
bool error;
result = eval_to_bool(eap->arg, &error, &eap->nextcmd, skip);
@@ -854,15 +854,7 @@ void ex_else(exarg_T *eap)
int result;
struct condstack *cstack = eap->cstack;
- /*
- * Don't do something after an error, interrupt, or throw, or when there is
- * a surrounding conditional and it was not active.
- */
- skip = did_emsg || got_int || did_throw || (cstack->cs_idx > 0
- && !(cstack->cs_flags[cstack->
- cs_idx -
- 1] &
- CSF_ACTIVE));
+ skip = CHECK_SKIP;
if (cstack->cs_idx < 0
|| (cstack->cs_flags[cstack->cs_idx]
@@ -952,15 +944,7 @@ void ex_while(exarg_T *eap)
cstack->cs_flags[cstack->cs_idx] =
eap->cmdidx == CMD_while ? CSF_WHILE : CSF_FOR;
- /*
- * Don't do something after an error, interrupt, or throw, or when
- * there is a surrounding conditional and it was not active.
- */
- skip = did_emsg || got_int || did_throw || (cstack->cs_idx > 0
- && !(cstack->cs_flags[cstack->
- cs_idx -
- 1] &
- CSF_ACTIVE));
+ skip = CHECK_SKIP;
if (eap->cmdidx == CMD_while) {
/*
* ":while bool-expr"
@@ -1233,8 +1217,6 @@ void do_throw(struct condstack *cstack)
cstack->cs_flags[idx] &= ~CSF_ACTIVE;
cstack->cs_exception[idx] = current_exception;
}
-
- did_throw = TRUE;
}
/*
@@ -1253,15 +1235,7 @@ void ex_try(exarg_T *eap)
cstack->cs_flags[cstack->cs_idx] = CSF_TRY;
cstack->cs_pending[cstack->cs_idx] = CSTP_NONE;
- /*
- * Don't do something after an error, interrupt, or throw, or when there
- * is a surrounding conditional and it was not active.
- */
- skip = did_emsg || got_int || did_throw || (cstack->cs_idx > 0
- && !(cstack->cs_flags[cstack->
- cs_idx -
- 1] &
- CSF_ACTIVE));
+ skip = CHECK_SKIP;
if (!skip) {
/* Set ACTIVE and TRUE. TRUE means that the corresponding ":catch"
@@ -1353,8 +1327,9 @@ void ex_catch(exarg_T *eap)
* corresponding try block never got active (because of an inactive
* surrounding conditional or after an error or interrupt or throw).
*/
- if (!did_throw || !(cstack->cs_flags[idx] & CSF_TRUE))
- skip = TRUE;
+ if (!current_exception || !(cstack->cs_flags[idx] & CSF_TRUE)) {
+ skip = true;
+ }
/*
* Check for a match only if an exception is thrown but not caught by
@@ -1413,10 +1388,10 @@ void ex_catch(exarg_T *eap)
}
if (caught) {
- /* Make this ":catch" clause active and reset did_emsg, got_int,
- * and did_throw. Put the exception on the caught stack. */
+ /* Make this ":catch" clause active and reset did_emsg and got_int.
+ * Put the exception on the caught stack. */
cstack->cs_flags[idx] |= CSF_ACTIVE | CSF_CAUGHT;
- did_emsg = got_int = did_throw = FALSE;
+ did_emsg = got_int = false;
catch_exception((except_T *)cstack->cs_exception[idx]);
/* It's mandatory that the current exception is stored in the cstack
* so that it can be discarded at the next ":catch", ":finally", or
@@ -1426,6 +1401,10 @@ void ex_catch(exarg_T *eap)
if (cstack->cs_exception[cstack->cs_idx] != current_exception) {
internal_error("ex_catch()");
}
+ // Discarding current_exceptions happens based on what is stored in
+ // cstack->cs_exception, *all* calls to discard_current_exception() are
+ // (and must be) guarded by current_exception check.
+ current_exception = NULL;
} else {
/*
* If there is a preceding catch clause and it caught the exception,
@@ -1484,7 +1463,7 @@ void ex_finally(exarg_T *eap)
* interrupt or throw) or for a ":finally" without ":try" or a multiple
* ":finally". After every other error (did_emsg or the conditional
* errors detected above) or after an interrupt (got_int) or an
- * exception (did_throw), the finally clause must be executed.
+ * exception (current_exception), the finally clause must be executed.
*/
skip = !(cstack->cs_flags[cstack->cs_idx] & CSF_TRUE);
@@ -1511,30 +1490,31 @@ void ex_finally(exarg_T *eap)
cleanup_conditionals(cstack, CSF_TRY, FALSE);
/*
- * Make did_emsg, got_int, did_throw pending. If set, they overrule
- * a pending ":continue", ":break", ":return", or ":finish". Then
- * we have particularly to discard a pending return value (as done
+ * Make did_emsg, got_int, current_exception pending. If set, they
+ * overrule a pending ":continue", ":break", ":return", or ":finish".
+ * Then we have particularly to discard a pending return value (as done
* by the call to cleanup_conditionals() above when did_emsg or
* got_int is set). The pending values are restored by the
* ":endtry", except if there is a new error, interrupt, exception,
* ":continue", ":break", ":return", or ":finish" in the following
* finally clause. A missing ":endwhile", ":endfor" or ":endif"
- * detected here is treated as if did_emsg and did_throw had
+ * detected here is treated as if did_emsg and current_exception had
* already been set, respectively in case that the error is not
- * converted to an exception, did_throw had already been unset.
+ * converted to an exception, current_exception had already been unset.
* We must not set did_emsg here since that would suppress the
* error message.
*/
- if (pending == CSTP_ERROR || did_emsg || got_int || did_throw) {
+ if (pending == CSTP_ERROR || did_emsg || got_int || current_exception) {
if (cstack->cs_pending[cstack->cs_idx] == CSTP_RETURN) {
report_discard_pending(CSTP_RETURN,
cstack->cs_rettv[cstack->cs_idx]);
discard_pending_return(cstack->cs_rettv[cstack->cs_idx]);
}
- if (pending == CSTP_ERROR && !did_emsg)
- pending |= (THROW_ON_ERROR) ? CSTP_THROW : 0;
- else
- pending |= did_throw ? CSTP_THROW : 0;
+ if (pending == CSTP_ERROR && !did_emsg) {
+ pending |= (THROW_ON_ERROR ? CSTP_THROW : 0);
+ } else {
+ pending |= (current_exception ? CSTP_THROW : 0);
+ }
pending |= did_emsg ? CSTP_ERROR : 0;
pending |= got_int ? CSTP_INTERRUPT : 0;
assert(pending >= CHAR_MIN && pending <= CHAR_MAX);
@@ -1547,14 +1527,15 @@ void ex_finally(exarg_T *eap)
* exception. When emsg() is called for a missing ":endif" or
* a missing ":endwhile"/":endfor" detected here, the
* exception will be discarded. */
- if (did_throw && cstack->cs_exception[cstack->cs_idx]
- != current_exception)
+ if (current_exception
+ && cstack->cs_exception[cstack->cs_idx] != current_exception) {
internal_error("ex_finally()");
+ }
}
/*
* Set CSL_HAD_FINA, so do_cmdline() will reset did_emsg,
- * got_int, and did_throw and make the finally clause active.
+ * got_int, and current_exception and make the finally clause active.
* This will happen after emsg() has been called for a missing
* ":endif" or a missing ":endwhile"/":endfor" detected here, so
* that the following finally clause will be executed even then.
@@ -1589,7 +1570,7 @@ void ex_endtry(exarg_T *eap)
// made inactive by a ":continue", ":break", ":return", or ":finish" in
// the finally clause. The latter case need not be tested since then
// anything pending has already been discarded.
- skip = (did_emsg || got_int || did_throw
+ skip = (did_emsg || got_int || current_exception
|| !(cstack->cs_flags[cstack->cs_idx] & CSF_TRUE));
if (!(cstack->cs_flags[cstack->cs_idx] & CSF_TRY)) {
@@ -1606,12 +1587,13 @@ void ex_endtry(exarg_T *eap)
/*
* If an exception is being thrown, discard it to prevent it from
* being rethrown at the end of this function. It would be
- * discarded by the error message, anyway. Resets did_throw.
+ * discarded by the error message, anyway. Resets current_exception.
* This does not affect the script termination due to the error
* since "trylevel" is decremented after emsg() has been called.
*/
- if (did_throw)
+ if (current_exception) {
discard_current_exception();
+ }
} else {
idx = cstack->cs_idx;
@@ -1621,9 +1603,11 @@ void ex_endtry(exarg_T *eap)
* a finally clause, we need to rethrow it after closing the try
* conditional.
*/
- if (did_throw && (cstack->cs_flags[idx] & CSF_TRUE)
- && !(cstack->cs_flags[idx] & CSF_FINALLY))
- rethrow = TRUE;
+ if (current_exception
+ && (cstack->cs_flags[idx] & CSF_TRUE)
+ && !(cstack->cs_flags[idx] & CSF_FINALLY)) {
+ rethrow = true;
+ }
}
/* If there was no finally clause, show the user when debugging or
@@ -1644,11 +1628,12 @@ void ex_endtry(exarg_T *eap)
if (got_int) {
skip = TRUE;
(void)do_intthrow(cstack);
- /* The do_intthrow() call may have reset did_throw or
- * cstack->cs_pending[idx].*/
- rethrow = FALSE;
- if (did_throw && !(cstack->cs_flags[idx] & CSF_FINALLY))
- rethrow = TRUE;
+ // The do_intthrow() call may have reset current_exception or
+ // cstack->cs_pending[idx].
+ rethrow = false;
+ if (current_exception && !(cstack->cs_flags[idx] & CSF_FINALLY)) {
+ rethrow = true;
+ }
}
}
@@ -1710,26 +1695,30 @@ void ex_endtry(exarg_T *eap)
do_finish(eap, FALSE);
break;
- /* When the finally clause was entered due to an error,
- * interrupt or throw (as opposed to a ":continue", ":break",
- * ":return", or ":finish"), restore the pending values of
- * did_emsg, got_int, and did_throw. This is skipped, if there
- * was a new error, interrupt, throw, ":continue", ":break",
- * ":return", or ":finish". in the finally clause. */
+ // When the finally clause was entered due to an error,
+ // interrupt or throw (as opposed to a ":continue", ":break",
+ // ":return", or ":finish"), restore the pending values of
+ // did_emsg, got_int, and current_exception. This is skipped, if there
+ // was a new error, interrupt, throw, ":continue", ":break",
+ // ":return", or ":finish". in the finally clause.
default:
- if (pending & CSTP_ERROR)
- did_emsg = TRUE;
- if (pending & CSTP_INTERRUPT)
- got_int = TRUE;
- if (pending & CSTP_THROW)
- rethrow = TRUE;
+ if (pending & CSTP_ERROR) {
+ did_emsg = true;
+ }
+ if (pending & CSTP_INTERRUPT) {
+ got_int = true;
+ }
+ if (pending & CSTP_THROW) {
+ rethrow = true;
+ }
break;
}
}
- if (rethrow)
- /* Rethrow the current exception (within this cstack). */
+ if (rethrow) {
+ // Rethrow the current exception (within this cstack).
do_throw(cstack);
+ }
}
}
@@ -1759,33 +1748,34 @@ void enter_cleanup(cleanup_T *csp)
int pending = CSTP_NONE;
/*
- * Postpone did_emsg, got_int, did_throw. The pending values will be
+ * Postpone did_emsg, got_int, current_exception. The pending values will be
* restored by leave_cleanup() except if there was an aborting error,
* interrupt, or uncaught exception after this function ends.
*/
- if (did_emsg || got_int || did_throw || need_rethrow) {
- csp->pending = (did_emsg ? CSTP_ERROR : 0)
- | (got_int ? CSTP_INTERRUPT : 0)
- | (did_throw ? CSTP_THROW : 0)
- | (need_rethrow ? CSTP_THROW : 0);
-
- /* If we are currently throwing an exception (did_throw), save it as
- * well. On an error not yet converted to an exception, update
- * "force_abort" and reset "cause_abort" (as do_errthrow() would do).
- * This is needed for the do_cmdline() call that is going to be made
- * for autocommand execution. We need not save *msg_list because
- * there is an extra instance for every call of do_cmdline(), anyway.
+ if (did_emsg || got_int || current_exception || need_rethrow) {
+ csp->pending = (did_emsg ? CSTP_ERROR : 0)
+ | (got_int ? CSTP_INTERRUPT : 0)
+ | (current_exception ? CSTP_THROW : 0)
+ | (need_rethrow ? CSTP_THROW : 0);
+
+ /* If we are currently throwing an exception, save it as well. On an error
+ * not yet converted to an exception, update "force_abort" and reset
+ * "cause_abort" (as do_errthrow() would do). This is needed for the
+ * do_cmdline() call that is going to be made for autocommand execution. We
+ * need not save *msg_list because there is an extra instance for every call
+ * of do_cmdline(), anyway.
*/
- if (did_throw || need_rethrow)
+ if (current_exception || need_rethrow) {
csp->exception = current_exception;
- else {
+ } else {
csp->exception = NULL;
if (did_emsg) {
force_abort |= cause_abort;
cause_abort = FALSE;
}
}
- did_emsg = got_int = did_throw = need_rethrow = FALSE;
+ did_emsg = got_int = need_rethrow = false;
+ current_exception = NULL;
/* Report if required by the 'verbose' option or when debugging. */
report_make_pending(pending, csp->exception);
@@ -1857,19 +1847,20 @@ void leave_cleanup(cleanup_T *csp)
force_abort = FALSE;
}
- /*
- * Restore the pending values of did_emsg, got_int, and did_throw.
- */
- if (pending & CSTP_ERROR)
- did_emsg = TRUE;
- if (pending & CSTP_INTERRUPT)
- got_int = TRUE;
- if (pending & CSTP_THROW)
- need_rethrow = TRUE; /* did_throw will be set by do_one_cmd() */
+ // Restore the pending values of did_emsg, got_int, and current_exception.
+ if (pending & CSTP_ERROR) {
+ did_emsg = true;
+ }
+ if (pending & CSTP_INTERRUPT) {
+ got_int = true;
+ }
+ if (pending & CSTP_THROW) {
+ need_rethrow = true; // current_exception will be set by do_one_cmd()
+ }
- /* Report if required by the 'verbose' option or when debugging. */
- report_resume_pending(pending,
- (pending & CSTP_THROW) ? (void *)current_exception : NULL);
+ // Report if required by the 'verbose' option or when debugging.
+ report_resume_pending(
+ pending, ((pending & CSTP_THROW) ? (void *)current_exception : NULL));
}
}
diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c
index 52686f6651..4adff63b95 100644
--- a/src/nvim/fileio.c
+++ b/src/nvim/fileio.c
@@ -1,9 +1,7 @@
// This is an open source non-commercial project. Dear PVS-Studio, please check
// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
-/*
- * fileio.c: read from and write to a file
- */
+// fileio.c: read from and write to a file
#include <assert.h>
#include <errno.h>
@@ -65,57 +63,62 @@
#define BUFSIZE 8192 /* size of normal write buffer */
#define SMBUFSIZE 256 /* size of emergency write buffer */
-/*
- * The autocommands are stored in a list for each event.
- * Autocommands for the same pattern, that are consecutive, are joined
- * together, to avoid having to match the pattern too often.
- * The result is an array of Autopat lists, which point to AutoCmd lists:
- *
- * first_autopat[0] --> Autopat.next --> Autopat.next --> NULL
- * Autopat.cmds Autopat.cmds
- * | |
- * V V
- * AutoCmd.next AutoCmd.next
- * | |
- * V V
- * AutoCmd.next NULL
- * |
- * V
- * NULL
- *
- * first_autopat[1] --> Autopat.next --> NULL
- * Autopat.cmds
- * |
- * V
- * AutoCmd.next
- * |
- * V
- * NULL
- * etc.
- *
- * The order of AutoCmds is important, this is the order in which they were
- * defined and will have to be executed.
- */
+//
+// The autocommands are stored in a list for each event.
+// Autocommands for the same pattern, that are consecutive, are joined
+// together, to avoid having to match the pattern too often.
+// The result is an array of Autopat lists, which point to AutoCmd lists:
+//
+// last_autopat[0] -----------------------------+
+// V
+// first_autopat[0] --> Autopat.next --> Autopat.next --> NULL
+// Autopat.cmds Autopat.cmds
+// | |
+// V V
+// AutoCmd.next AutoCmd.next
+// | |
+// V V
+// AutoCmd.next NULL
+// |
+// V
+// NULL
+//
+// last_autopat[1] --------+
+// V
+// first_autopat[1] --> Autopat.next --> NULL
+// Autopat.cmds
+// |
+// V
+// AutoCmd.next
+// |
+// V
+// NULL
+// etc.
+//
+// The order of AutoCmds is important, this is the order in which they were
+// defined and will have to be executed.
+//
typedef struct AutoCmd {
- char_u *cmd; /* The command to be executed (NULL
- when command has been removed) */
- char nested; /* If autocommands nest here */
- char last; /* last command in list */
- scid_T scriptID; /* script ID where defined */
- struct AutoCmd *next; /* Next AutoCmd in list */
+ char_u *cmd; // The command to be executed (NULL
+ // when command has been removed)
+ char nested; // If autocommands nest here
+ char last; // last command in list
+ scid_T scriptID; // script ID where defined
+ struct AutoCmd *next; // Next AutoCmd in list
} AutoCmd;
typedef struct AutoPat {
- char_u *pat; /* pattern as typed (NULL when pattern
- has been removed) */
- regprog_T *reg_prog; /* compiled regprog for pattern */
- AutoCmd *cmds; /* list of commands to do */
- struct AutoPat *next; /* next AutoPat in AutoPat list */
- int group; /* group ID */
- int patlen; /* strlen() of pat */
- int buflocal_nr; /* !=0 for buffer-local AutoPat */
- char allow_dirs; /* Pattern may match whole path */
- char last; /* last pattern for apply_autocmds() */
+ struct AutoPat *next; // next AutoPat in AutoPat list; MUST
+ // be the first entry
+ char_u *pat; // pattern as typed (NULL when pattern
+ // has been removed)
+ regprog_T *reg_prog; // compiled regprog for pattern
+ AutoCmd *cmds; // list of commands to do
+ int group; // group ID
+ int patlen; // strlen() of pat
+ int buflocal_nr; // !=0 for buffer-local AutoPat
+ char allow_dirs; // Pattern may match whole path
+ char last; // last pattern for apply_autocmds()
} AutoPat;
/*
@@ -226,6 +229,15 @@ void filemess(buf_T *buf, char_u *name, char_u *s, int attr)
msg_scrolled_ign = FALSE;
}
+static AutoPat *last_autopat[NUM_EVENTS] = {
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
+};
+
/*
* Read lines from file "fname" into the buffer after line "from".
*
@@ -1725,9 +1737,17 @@ failed:
xfree(buffer);
if (read_stdin) {
- /* Use stderr for stdin, makes shell commands work. */
close(0);
+#ifndef WIN32
+ // On Unix, use stderr for stdin, makes shell commands work.
ignored = dup(2);
+#else
+ // On Windows, use the console input handle for stdin.
+ HANDLE conin = CreateFile("CONIN$", GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ, (LPSECURITY_ATTRIBUTES)NULL,
+ OPEN_EXISTING, 0, (HANDLE)NULL);
+ ignored = _open_osfhandle(conin, _O_RDONLY);
+#endif
}
if (tmpname != NULL) {
@@ -4440,7 +4460,7 @@ char *modname(const char *fname, const char *ext, bool prepend_dot)
/// @param size size of the buffer
/// @param fp file to read from
///
-/// @return true for end-of-file.
+/// @return true for EOF or error
bool vim_fgets(char_u *buf, int size, FILE *fp) FUNC_ATTR_NONNULL_ALL
{
char *retval;
@@ -4451,7 +4471,7 @@ bool vim_fgets(char_u *buf, int size, FILE *fp) FUNC_ATTR_NONNULL_ALL
do {
errno = 0;
retval = fgets((char *)buf, size, fp);
- } while (retval == NULL && errno == EINTR);
+ } while (retval == NULL && errno == EINTR && ferror(fp));
if (buf[size - 2] != NUL && buf[size - 2] != '\n') {
char tbuf[200];
@@ -4463,12 +4483,12 @@ bool vim_fgets(char_u *buf, int size, FILE *fp) FUNC_ATTR_NONNULL_ALL
tbuf[sizeof(tbuf) - 2] = NUL;
errno = 0;
retval = fgets((char *)tbuf, sizeof(tbuf), fp);
- if (retval == NULL && errno != EINTR) {
+ if (retval == NULL && (feof(fp) || errno != EINTR)) {
break;
}
} while (tbuf[sizeof(tbuf) - 2] != NUL && tbuf[sizeof(tbuf) - 2] != '\n');
}
- return retval ? false : feof(fp);
+ return retval == NULL;
}
/// Read 2 bytes from "fd" and turn them into an int, MSB first.
@@ -5528,6 +5548,15 @@ static void au_cleanup(void)
/* remove the pattern if it has been marked for deletion */
if (ap->pat == NULL) {
+ if (ap->next == NULL) {
+ if (prev_ap == &(first_autopat[(int)event])) {
+ last_autopat[(int)event] = NULL;
+ } else {
+ // this depends on the "next" field being the first in
+ // the struct
+ last_autopat[(int)event] = (AutoPat *)prev_ap;
+ }
+ }
*prev_ap = ap->next;
vim_regfree(ap->reg_prog);
xfree(ap);
@@ -6120,10 +6149,13 @@ static int do_autocmd_event(event_T event, char_u *pat, int nested, char_u *cmd,
patlen = (int)STRLEN(buflocal_pat); /* but not endpat */
}
- /*
- * Find AutoPat entries with this pattern.
- */
- prev_ap = &first_autopat[(int)event];
+ // Find AutoPat entries with this pattern. When adding a command it
+ // always goes at or after the last one, so start at the end.
+ if (!forceit && *cmd != NUL && last_autopat[(int)event] != NULL) {
+ prev_ap = &last_autopat[(int)event];
+ } else {
+ prev_ap = &first_autopat[(int)event];
+ }
while ((ap = *prev_ap) != NULL) {
if (ap->pat != NULL) {
/* Accept a pattern when:
@@ -6209,6 +6241,7 @@ static int do_autocmd_event(event_T event, char_u *pat, int nested, char_u *cmd,
}
ap->cmds = NULL;
*prev_ap = ap;
+ last_autopat[(int)event] = ap;
ap->next = NULL;
if (group == AUGROUP_ALL)
ap->group = current_augroup;
diff --git a/src/nvim/getchar.c b/src/nvim/getchar.c
index 5d4e61d56a..03929a58b6 100644
--- a/src/nvim/getchar.c
+++ b/src/nvim/getchar.c
@@ -1577,7 +1577,7 @@ vungetc ( /* unget one character (can only be done once!) */
old_mouse_col = mouse_col;
}
-/// get a character:
+/// Gets a character:
/// 1. from the stuffbuffer
/// This is used for abbreviated commands like "D" -> "d$".
/// Also used to redo a command for ".".
@@ -1595,7 +1595,7 @@ vungetc ( /* unget one character (can only be done once!) */
/// if "advance" is FALSE (vpeekc()):
/// just look whether there is a character available.
///
-/// When "no_mapping" is zero, checks for mappings in the current mode.
+/// When `no_mapping` (global) is zero, checks for mappings in the current mode.
/// Only returns one byte (of a multi-byte character).
/// K_SPECIAL and CSI may be escaped, need to get two more bytes then.
static int vgetorpeek(int advance)
diff --git a/src/nvim/globals.h b/src/nvim/globals.h
index e857f5ff5b..89d93310a6 100644
--- a/src/nvim/globals.h
+++ b/src/nvim/globals.h
@@ -317,17 +317,11 @@ EXTERN int do_profiling INIT(= PROF_NONE); /* PROF_ values */
/*
* The exception currently being thrown. Used to pass an exception to
* a different cstack. Also used for discarding an exception before it is
- * caught or made pending. Only valid when did_throw is TRUE.
+ * caught or made pending.
*/
EXTERN except_T *current_exception;
/*
- * did_throw: An exception is being thrown. Reset when the exception is caught
- * or as long as it is pending in a finally clause.
- */
-EXTERN int did_throw INIT(= FALSE);
-
-/*
* need_rethrow: set to TRUE when a throw that cannot be handled in do_cmdline()
* must be propagated to the cstack of the previously called do_cmdline().
*/
@@ -953,6 +947,7 @@ EXTERN int fill_stlnc INIT(= ' ');
EXTERN int fill_vert INIT(= 9474); // │
EXTERN int fill_fold INIT(= 183); // ·
EXTERN int fill_diff INIT(= '-');
+EXTERN int fill_msgsep INIT(= ' ');
/* Whether 'keymodel' contains "stopsel" and "startsel". */
EXTERN int km_stopsel INIT(= FALSE);
@@ -1075,7 +1070,6 @@ EXTERN char_u e_nesting[] INIT(= N_("E22: Scripts nested too deep"));
EXTERN char_u e_noalt[] INIT(= N_("E23: No alternate file"));
EXTERN char_u e_noabbr[] INIT(= N_("E24: No such abbreviation"));
EXTERN char_u e_nobang[] INIT(= N_("E477: No ! allowed"));
-EXTERN char_u e_nogvim[] INIT(= N_("E25: Nvim does not have a built-in GUI"));
EXTERN char_u e_nogroup[] INIT(= N_("E28: No such highlight group name: %s"));
EXTERN char_u e_noinstext[] INIT(= N_("E29: No inserted text yet"));
EXTERN char_u e_nolastcmd[] INIT(= N_("E30: No previous command line"));
diff --git a/src/nvim/highlight_defs.h b/src/nvim/highlight_defs.h
index 08157935f5..3518c8bdcc 100644
--- a/src/nvim/highlight_defs.h
+++ b/src/nvim/highlight_defs.h
@@ -87,6 +87,7 @@ typedef enum {
, HLF_QFL // selected quickfix line
, HLF_0 // Whitespace
, HLF_INACTIVE // NormalNC: Normal text in non-current windows
+ , HLF_MSGSEP // message separator line
, HLF_COUNT // MUST be the last one
} hlf_T;
@@ -137,7 +138,8 @@ EXTERN const char *hlf_names[] INIT(= {
[HLF_MC] = "ColorColumn",
[HLF_QFL] = "QuickFixLine",
[HLF_0] = "Whitespace",
- [HLF_INACTIVE] = "NormalNC"
+ [HLF_INACTIVE] = "NormalNC",
+ [HLF_MSGSEP] = "MsgSeparator",
});
diff --git a/src/nvim/keymap.h b/src/nvim/keymap.h
index 00e9cf6ed3..c64691e8ea 100644
--- a/src/nvim/keymap.h
+++ b/src/nvim/keymap.h
@@ -443,7 +443,7 @@ enum key_extra {
#define MOD_MASK_2CLICK 0x20 // use MOD_MASK_MULTI_CLICK
#define MOD_MASK_3CLICK 0x40 // use MOD_MASK_MULTI_CLICK
#define MOD_MASK_4CLICK 0x60 // use MOD_MASK_MULTI_CLICK
-#define MOD_MASK_CMD 0x80 // "super" key (OSX/Mac: command-key)
+#define MOD_MASK_CMD 0x80 // "super" key (macOS: command-key)
#define MOD_MASK_MULTI_CLICK (MOD_MASK_2CLICK|MOD_MASK_3CLICK| \
MOD_MASK_4CLICK)
diff --git a/src/nvim/macros.h b/src/nvim/macros.h
index 4e01265498..348df2d9b6 100644
--- a/src/nvim/macros.h
+++ b/src/nvim/macros.h
@@ -136,13 +136,21 @@
# define RESET_BINDING(wp) (wp)->w_p_scb = FALSE; (wp)->w_p_crb = FALSE
-/// Calculate the length of a C array.
+/// Calculate the length of a C array
///
/// This should be called with a real array. Calling this with a pointer is an
-/// error. A mechanism to detect many (though not all) of those errors at compile
-/// time is implemented. It works by the second division producing a division by
-/// zero in those cases (-Wdiv-by-zero in GCC).
-#define ARRAY_SIZE(arr) ((sizeof(arr)/sizeof((arr)[0])) / ((size_t)(!(sizeof(arr) % sizeof((arr)[0])))))
+/// error. A mechanism to detect many (though not all) of those errors at
+/// compile time is implemented. It works by the second division producing
+/// a division by zero in those cases (-Wdiv-by-zero in GCC).
+#define ARRAY_SIZE(arr) \
+ ((sizeof(arr)/sizeof((arr)[0])) \
+ / ((size_t)(!(sizeof(arr) % sizeof((arr)[0])))))
+
+/// Get last array entry
+///
+/// This should be called with a real array. Calling this with a pointer is an
+/// error.
+#define ARRAY_LAST_ENTRY(arr) (arr)[ARRAY_SIZE(arr) - 1]
// Duplicated in os/win_defs.h to avoid include-order sensitivity.
#define RGB_(r, g, b) ((r << 16) | (g << 8) | b)
diff --git a/src/nvim/main.c b/src/nvim/main.c
index 4288d7f9d7..ce9feedd16 100644
--- a/src/nvim/main.c
+++ b/src/nvim/main.c
@@ -72,30 +72,30 @@
# include "nvim/os/pty_process_unix.h"
#endif
-/* Maximum number of commands from + or -c arguments. */
+// Maximum number of commands from + or -c arguments.
#define MAX_ARG_CMDS 10
-/* values for "window_layout" */
-#define WIN_HOR 1 /* "-o" horizontally split windows */
-#define WIN_VER 2 /* "-O" vertically split windows */
-#define WIN_TABS 3 /* "-p" windows on tab pages */
+// values for "window_layout"
+#define WIN_HOR 1 // "-o" horizontally split windows
+#define WIN_VER 2 // "-O" vertically split windows
+#define WIN_TABS 3 // "-p" windows on tab pages
-/* Struct for various parameters passed between main() and other functions. */
+// Struct for various parameters passed between main() and other functions.
typedef struct {
int argc;
char **argv;
char *use_vimrc; // vimrc from -u argument
- int n_commands; /* no. of commands from + or -c */
+ int n_commands; // no. of commands from + or -c
char *commands[MAX_ARG_CMDS]; // commands from + or -c arg
- char_u cmds_tofree[MAX_ARG_CMDS]; /* commands that need free() */
- int n_pre_commands; /* no. of commands from --cmd */
+ char_u cmds_tofree[MAX_ARG_CMDS]; // commands that need free()
+ int n_pre_commands; // no. of commands from --cmd
char *pre_commands[MAX_ARG_CMDS]; // commands from --cmd argument
- int edit_type; /* type of editing to do */
- char_u *tagname; /* tag from -t argument */
- char_u *use_ef; /* 'errorfile' from -q argument */
+ int edit_type; // type of editing to do
+ char_u *tagname; // tag from -t argument
+ char_u *use_ef; // 'errorfile' from -q argument
int want_full_screen;
bool input_isatty; // stdin is a terminal
@@ -103,13 +103,15 @@ typedef struct {
bool err_isatty; // stderr is a terminal
int no_swap_file; // "-n" argument used
int use_debug_break_level;
- int window_count; /* number of windows to use */
- int window_layout; /* 0, WIN_HOR, WIN_VER or WIN_TABS */
+ int window_count; // number of windows to use
+ int window_layout; // 0, WIN_HOR, WIN_VER or WIN_TABS
#if !defined(UNIX)
- int literal; /* don't expand file names */
+ int literal; // don't expand file names
#endif
- int diff_mode; /* start with 'diff' set */
+ int diff_mode; // start with 'diff' set
+
+ char *listen_addr; // --listen {address}
} mparm_T;
/* Values for edit_type. */
@@ -150,7 +152,6 @@ void event_init(void)
signal_init();
// finish mspgack-rpc initialization
channel_init();
- server_init();
terminal_init();
}
@@ -241,9 +242,8 @@ int main(int argc, char **argv)
char_u *cwd = NULL; // current workding dir on startup
time_init();
- /* Many variables are in "params" so that we can pass them to invoked
- * functions without a lot of arguments. "argc" and "argv" are also
- * copied, so that they can be changed. */
+ // Many variables are in `params` so that we can pass them around easily.
+ // `argc` and `argv` are also copied, so that they can be changed.
init_params(&params, argc, argv);
init_startuptime(&params);
@@ -254,11 +254,10 @@ int main(int argc, char **argv)
check_and_set_isatty(&params);
event_init();
- /*
- * Process the command line arguments. File names are put in the global
- * argument list "global_alist".
- */
+ // Process the command line arguments. File names are put in the global
+ // argument list "global_alist".
command_line_scan(&params);
+ server_init(params.listen_addr);
if (GARGCOUNT > 0) {
fname = get_fname(&params, cwd);
@@ -819,6 +818,9 @@ static void command_line_scan(mparm_T *parmp)
if (!channel_from_stdio(true, CALLBACK_READER_INIT, &err)) {
abort();
}
+ } else if (STRNICMP(argv[0] + argv_idx, "listen", 6) == 0) {
+ want_argument = true;
+ argv_idx += 6;
} else if (STRNICMP(argv[0] + argv_idx, "literal", 7) == 0) {
#if !defined(UNIX)
parmp->literal = TRUE;
@@ -864,10 +866,6 @@ static void command_line_scan(mparm_T *parmp)
case 'f': /* "-f" GUI: run in foreground. */
break;
- case 'g': /* "-g" start GUI */
- main_start_gui();
- break;
-
case 'F': { // "-F" start in Farsi mode: rl + fkmap set.
p_fkmap = true;
set_option_value("rl", 1L, NULL, 0);
@@ -906,18 +904,8 @@ static void command_line_scan(mparm_T *parmp)
parmp->no_swap_file = TRUE;
break;
- case 'p': /* "-p[N]" open N tab pages */
-#ifdef TARGET_API_MAC_OSX
- /* For some reason on MacOS X, an argument like:
- -psn_0_10223617 is passed in when invoke from Finder
- or with the 'open' command */
- if (argv[0][argv_idx] == 's') {
- argv_idx = -1; /* bypass full -psn */
- main_start_gui();
- break;
- }
-#endif
- /* default is 0: open window for each file */
+ case 'p': // "-p[N]" open N tab pages
+ // default is 0: open window for each file
parmp->window_count = get_number_arg(argv[0], &argv_idx, 0);
parmp->window_layout = WIN_TABS;
break;
@@ -1030,15 +1018,12 @@ static void command_line_scan(mparm_T *parmp)
mainerr(err_opt_unknown, argv[0]);
}
- /*
- * Handle option arguments with argument.
- */
+ // Handle option arguments with argument.
if (want_argument) {
- /*
- * Check for garbage immediately after the option letter.
- */
- if (argv[0][argv_idx] != NUL)
+ // Check for garbage immediately after the option letter.
+ if (argv[0][argv_idx] != NUL) {
mainerr(err_opt_garbage, argv[0]);
+ }
--argc;
if (argc < 1 && c != 'S') /* -S has an optional argument */
@@ -1077,13 +1062,17 @@ static void command_line_scan(mparm_T *parmp)
break;
case '-':
- if (argv[-1][2] == 'c') {
- /* "--cmd {command}" execute command */
- if (parmp->n_pre_commands >= MAX_ARG_CMDS)
+ if (strequal(argv[-1], "--cmd")) {
+ // "--cmd {command}" execute command
+ if (parmp->n_pre_commands >= MAX_ARG_CMDS) {
mainerr(err_extra_cmd, NULL);
+ }
parmp->pre_commands[parmp->n_pre_commands++] = argv[0];
+ } else if (strequal(argv[-1], "--listen")) {
+ // "--listen {address}"
+ parmp->listen_addr = argv[0];
}
- /* "--startuptime <file>" already handled */
+ // "--startuptime <file>" already handled
break;
case 'q': /* "-q {errorfile}" QuickFix mode */
@@ -1224,11 +1213,10 @@ static void init_params(mparm_T *paramp, int argc, char **argv)
paramp->want_full_screen = true;
paramp->use_debug_break_level = -1;
paramp->window_count = -1;
+ paramp->listen_addr = NULL;
}
-/*
- * Initialize global startuptime file if "--startuptime" passed as an argument.
- */
+/// Initialize global startuptime file if "--startuptime" passed as an argument.
static void init_startuptime(mparm_T *paramp)
{
for (int i = 1; i < paramp->argc; i++) {
@@ -1834,17 +1822,6 @@ static void source_startup_scripts(const mparm_T *const parmp)
TIME_MSG("sourcing vimrc file(s)");
}
-/*
- * Setup to start using the GUI. Exit with an error when not available.
- */
-static void main_start_gui(void)
-{
- mch_errmsg(_(e_nogvim));
- mch_errmsg("\n");
- mch_exit(2);
-}
-
-
/// Get an environment variable, and execute it as Ex commands.
///
/// @param env environment variable to execute
@@ -1968,6 +1945,7 @@ static void usage(void)
mch_msg(_(" --api-info Write msgpack-encoded API metadata to stdout\n"));
mch_msg(_(" --embed Use stdin/stdout as a msgpack-rpc channel\n"));
mch_msg(_(" --headless Don't start a user interface\n"));
+ mch_msg(_(" --listen <address> Start RPC server at this address\n"));
#if !defined(UNIX)
mch_msg(_(" --literal Don't expand wildcards\n"));
#endif
diff --git a/src/nvim/map.h b/src/nvim/map.h
index 047aa163ce..ac1239a548 100644
--- a/src/nvim/map.h
+++ b/src/nvim/map.h
@@ -8,6 +8,11 @@
#include "nvim/api/private/dispatch.h"
#include "nvim/bufhl_defs.h"
+#if defined(__NetBSD__)
+# undef uint64_t
+# define uint64_t uint64_t
+#endif
+
#define MAP_DECLS(T, U) \
KHASH_DECLARE(T##_##U##_map, T, U) \
\
diff --git a/src/nvim/message.c b/src/nvim/message.c
index 12e5b844be..04528629c7 100644
--- a/src/nvim/message.c
+++ b/src/nvim/message.c
@@ -1875,13 +1875,29 @@ bool message_filtered(char_u *msg)
return cmdmod.filter_force ? match : !match;
}
+/// including horizontal separator
+int msg_scrollsize(void)
+{
+ return msg_scrolled + p_ch + 1;
+}
+
/*
* Scroll the screen up one line for displaying the next message line.
*/
static void msg_scroll_up(void)
{
- /* scrolling up always works */
- screen_del_lines(0, 0, 1, (int)Rows, NULL);
+ if (dy_flags & DY_MSGSEP) {
+ if (msg_scrolled == 0) {
+ screen_fill(Rows-p_ch-1, Rows-p_ch, 0, (int)Columns,
+ fill_msgsep, fill_msgsep, hl_attr(HLF_MSGSEP));
+ }
+ int nscroll = MIN(msg_scrollsize()+1, Rows);
+ ui_call_set_scroll_region(Rows-nscroll, Rows-1, 0, Columns-1);
+ screen_del_lines(Rows-nscroll, 0, 1, nscroll, NULL);
+ ui_reset_scroll_region();
+ } else {
+ screen_del_lines(0, 0, 1, (int)Rows, NULL);
+ }
}
/*
diff --git a/src/nvim/msgpack_rpc/server.c b/src/nvim/msgpack_rpc/server.c
index 9bf122f4db..e5d80aea1d 100644
--- a/src/nvim/msgpack_rpc/server.c
+++ b/src/nvim/msgpack_rpc/server.c
@@ -32,26 +32,27 @@ static garray_T watchers = GA_EMPTY_INIT_VALUE;
#endif
/// Initializes the module
-bool server_init(void)
+bool server_init(const char *listen_addr)
{
ga_init(&watchers, sizeof(SocketWatcher *), 1);
- bool must_free = false;
- const char *listen_address = os_getenv(LISTEN_ADDRESS_ENV_VAR);
- if (listen_address == NULL) {
- must_free = true;
- listen_address = server_address_new();
- }
+ // $NVIM_LISTEN_ADDRESS
+ const char *env_addr = os_getenv(LISTEN_ADDRESS_ENV_VAR);
+ int rv = listen_addr == NULL ? 1 : server_start(listen_addr);
- if (!listen_address) {
- return false;
+ if (0 != rv) {
+ rv = env_addr == NULL ? 1 : server_start(env_addr);
+ if (0 != rv) {
+ listen_addr = server_address_new();
+ if (listen_addr == NULL) {
+ return false;
+ }
+ rv = server_start(listen_addr);
+ xfree((char *)listen_addr);
+ }
}
- bool ok = (server_start(listen_address) == 0);
- if (must_free) {
- xfree((char *) listen_address);
- }
- return ok;
+ return rv == 0;
}
/// Teardown a single server
@@ -120,8 +121,8 @@ bool server_owns_pipe_address(const char *path)
/// @param endpoint Address of the server. Either a 'ip:[port]' string or an
/// arbitrary identifier (trimmed to 256 bytes) for the Unix
/// socket or named pipe.
-/// @returns 0 on success, 1 on a regular error, and negative errno
-/// on failure to bind or listen.
+/// @returns 0: success, 1: validation error, 2: already listening,
+/// -errno: failed to bind or listen.
int server_start(const char *endpoint)
{
if (endpoint == NULL || endpoint[0] == '\0') {
@@ -145,7 +146,7 @@ int server_start(const char *endpoint)
uv_freeaddrinfo(watcher->uv.tcp.addrinfo);
}
socket_watcher_close(watcher, free_server);
- return 1;
+ return 2;
}
}
@@ -177,7 +178,7 @@ int server_start(const char *endpoint)
/// Stops listening on the address specified by `endpoint`.
///
/// @param endpoint Address of the server.
-void server_stop(char *endpoint)
+bool server_stop(char *endpoint)
{
SocketWatcher *watcher;
bool watcher_found = false;
@@ -196,8 +197,8 @@ void server_stop(char *endpoint)
}
if (!watcher_found) {
- ELOG("Not listening on %s", addr);
- return;
+ WLOG("Not listening on %s", addr);
+ return false;
}
// Unset $NVIM_LISTEN_ADDRESS if it is the stopped address.
@@ -219,6 +220,8 @@ void server_stop(char *endpoint)
if (STRCMP(addr, get_vim_var_str(VV_SEND_SERVER)) == 0) {
set_vservername(&watchers);
}
+
+ return true;
}
/// Returns an allocated array of server addresses.
diff --git a/src/nvim/option.c b/src/nvim/option.c
index d6903c8db7..c43ba2fc4f 100644
--- a/src/nvim/option.c
+++ b/src/nvim/option.c
@@ -13,7 +13,8 @@
// add some code to didset_window_options().
// - For a buffer option, add some code to buf_copy_options().
// - For a buffer string option, add code to check_buf_options().
-// - If it's a numeric option, add any necessary bounds checks to do_set().
+// - If it's a numeric option, add any necessary bounds checks to
+// set_num_option().
// - If it's a list of flags, add some code in do_set(), search for WW_ALL.
// - When adding an option with expansion (P_EXPAND), but with a different
// default for Vi and Vim (no P_VI_DEF), add some code at VIMEXP.
@@ -1467,8 +1468,7 @@ do_set (
goto skip;
}
} else if (*arg == '-' || ascii_isdigit(*arg)) {
- // Allow negative (for 'undolevels'), octal and
- // hex numbers.
+ // Allow negative, octal and hex numbers.
vim_str2nr(arg, NULL, &i, STR2NR_ALL, &value, NULL, 0);
if (arg[i] != NUL && !ascii_iswhite(arg[i])) {
errmsg = e_invarg;
@@ -3411,6 +3411,7 @@ static char_u *set_chars_option(char_u **varp)
{ &fill_vert, "vert" , 9474 }, // │
{ &fill_fold, "fold" , 183 }, // ·
{ &fill_diff, "diff" , '-' },
+ { &fill_msgsep, "msgsep", ' ' },
};
static struct charstab lcstab[] = {
{ &lcs_eol, "eol", NUL },
@@ -4089,238 +4090,259 @@ static char *set_num_option(int opt_idx, char_u *varp, long value,
return (char *)e_secure;
}
- *pp = value;
- /* Remember where the option was set. */
- set_option_scriptID_idx(opt_idx, opt_flags, current_SID);
-
- if (curbuf->b_p_sw < 0) {
- errmsg = e_positive;
- curbuf->b_p_sw = curbuf->b_p_ts;
+ // Many number options assume their value is in the signed int range.
+ if (value < INT_MIN || value > INT_MAX) {
+ return (char *)e_invarg;
}
- /*
- * Number options that need some action when changed
- */
- if (pp == &p_wh || pp == &p_hh) {
- if (p_wh < 1) {
+ // Options that need some validation.
+ if (pp == &p_wh) {
+ if (value < 1) {
errmsg = e_positive;
- p_wh = 1;
- }
- if (p_wmh > p_wh) {
+ } else if (p_wmh > value) {
errmsg = e_winheight;
- p_wh = p_wmh;
}
- if (p_hh < 0) {
+ } else if (pp == &p_hh) {
+ if (value < 0) {
errmsg = e_positive;
- p_hh = 0;
}
-
- /* Change window height NOW */
- if (!ONE_WINDOW) {
- if (pp == &p_wh && curwin->w_height < p_wh)
- win_setheight((int)p_wh);
- if (pp == &p_hh && curbuf->b_help && curwin->w_height < p_hh)
- win_setheight((int)p_hh);
- }
- }
- /* 'winminheight' */
- else if (pp == &p_wmh) {
- if (p_wmh < 0) {
+ } else if (pp == &p_wmh) {
+ if (value < 0) {
errmsg = e_positive;
- p_wmh = 0;
- }
- if (p_wmh > p_wh) {
+ } else if (value > p_wh) {
errmsg = e_winheight;
- p_wmh = p_wh;
}
- win_setminheight();
} else if (pp == &p_wiw) {
- if (p_wiw < 1) {
+ if (value < 1) {
errmsg = e_positive;
- p_wiw = 1;
+ } else if (p_wmw > value) {
+ errmsg = e_winwidth;
}
- if (p_wmw > p_wiw) {
+ } else if (pp == &p_wmw) {
+ if (value < 0) {
+ errmsg = e_positive;
+ } else if (value > p_wiw) {
errmsg = e_winwidth;
- p_wiw = p_wmw;
}
-
- /* Change window width NOW */
- if (!ONE_WINDOW && curwin->w_width < p_wiw)
- win_setwidth((int)p_wiw);
- }
- /* 'winminwidth' */
- else if (pp == &p_wmw) {
- if (p_wmw < 0) {
+ } else if (pp == &p_mco) {
+ if (value > MAX_MCO) {
+ errmsg = e_invarg;
+ } else if (value < 0) {
errmsg = e_positive;
- p_wmw = 0;
}
- if (p_wmw > p_wiw) {
- errmsg = e_winwidth;
- p_wmw = p_wiw;
+ } else if (pp == &p_titlelen) {
+ if (value < 0) {
+ errmsg = e_positive;
}
- win_setminheight();
- } else if (pp == &p_ls) {
- /* (re)set last window status line */
- last_status(false);
- }
- /* (re)set tab page line */
- else if (pp == &p_stal) {
- shell_new_rows(); /* recompute window positions and heights */
- }
- /* 'foldlevel' */
- else if (pp == &curwin->w_p_fdl) {
- if (curwin->w_p_fdl < 0)
- curwin->w_p_fdl = 0;
- newFoldLevel();
- }
- /* 'foldminlines' */
- else if (pp == &curwin->w_p_fml) {
- foldUpdateAll(curwin);
- }
- /* 'foldnestmax' */
- else if (pp == &curwin->w_p_fdn) {
- if (foldmethodIsSyntax(curwin) || foldmethodIsIndent(curwin))
- foldUpdateAll(curwin);
- }
- /* 'foldcolumn' */
- else if (pp == &curwin->w_p_fdc) {
- if (curwin->w_p_fdc < 0) {
+ } else if (pp == &p_uc) {
+ if (value < 0) {
errmsg = e_positive;
- curwin->w_p_fdc = 0;
- } else if (curwin->w_p_fdc > 12) {
- errmsg = e_invarg;
- curwin->w_p_fdc = 12;
}
- // 'shiftwidth' or 'tabstop'
- } else if (pp == &curbuf->b_p_sw || pp == (long *)&curbuf->b_p_ts) {
- if (foldmethodIsIndent(curwin)) {
- foldUpdateAll(curwin);
+ } else if (pp == &p_ch) {
+ if (value < 1) {
+ errmsg = e_positive;
}
- // When 'shiftwidth' changes, or it's zero and 'tabstop' changes:
- // parse 'cinoptions'.
- if (pp == &curbuf->b_p_sw || curbuf->b_p_sw == 0) {
- parse_cino(curbuf);
+ } else if (pp == &p_tm) {
+ if (value < 0) {
+ errmsg = e_positive;
}
- }
- /* 'maxcombine' */
- else if (pp == &p_mco) {
- if (p_mco > MAX_MCO)
- p_mco = MAX_MCO;
- else if (p_mco < 0)
- p_mco = 0;
- screenclear(); /* will re-allocate the screen */
- } else if (pp == &curbuf->b_p_iminsert) {
- if (curbuf->b_p_iminsert < 0 || curbuf->b_p_iminsert > B_IMODE_LAST) {
+ } else if (pp == &p_hi) {
+ if (value < 0) {
+ errmsg = e_positive;
+ } else if (value > 10000) {
errmsg = e_invarg;
- curbuf->b_p_iminsert = B_IMODE_NONE;
}
- p_iminsert = curbuf->b_p_iminsert;
- showmode();
- /* Show/unshow value of 'keymap' in status lines. */
- status_redraw_curbuf();
- } else if (pp == &p_window) {
- if (p_window < 1)
- p_window = 1;
- else if (p_window >= Rows)
- p_window = Rows - 1;
- } else if (pp == &curbuf->b_p_imsearch) {
- if (curbuf->b_p_imsearch < -1 || curbuf->b_p_imsearch > B_IMODE_LAST) {
+ } else if (pp == &p_re) {
+ if (value < 0 || value > 2) {
errmsg = e_invarg;
- curbuf->b_p_imsearch = B_IMODE_NONE;
}
- p_imsearch = curbuf->b_p_imsearch;
- } else if (pp == &p_channel || pp == &curbuf->b_p_channel) {
- errmsg = e_invarg;
- *pp = old_value;
- }
- /* if 'titlelen' has changed, redraw the title */
- else if (pp == &p_titlelen) {
- if (p_titlelen < 0) {
+ } else if (pp == &p_report) {
+ if (value < 0) {
errmsg = e_positive;
- p_titlelen = 85;
}
- if (starting != NO_SCREEN && old_value != p_titlelen)
- need_maketitle = TRUE;
- }
- /* if p_ch changed value, change the command line height */
- else if (pp == &p_ch) {
- if (p_ch < 1) {
+ } else if (pp == &p_titlelen) {
+ if (value < 0) {
errmsg = e_positive;
- p_ch = 1;
}
- if (p_ch > Rows - min_rows() + 1)
- p_ch = Rows - min_rows() + 1;
-
- /* Only compute the new window layout when startup has been
- * completed. Otherwise the frame sizes may be wrong. */
- if (p_ch != old_value && full_screen
- )
- command_height();
- }
- /* when 'updatecount' changes from zero to non-zero, open swap files */
- else if (pp == &p_uc) {
- if (p_uc < 0) {
+ } else if (pp == &p_so) {
+ if (value < 0 && full_screen) {
+ errmsg = e_scroll;
+ }
+ } else if (pp == &p_siso) {
+ if (value < 0 && full_screen) {
errmsg = e_positive;
- p_uc = 100;
}
- if (p_uc && !old_value)
- ml_open_files();
- } else if (pp == &curwin->w_p_cole) {
- if (curwin->w_p_cole < 0) {
+ } else if (pp == &p_cwh) {
+ if (value < 1) {
+ errmsg = e_positive;
+ }
+ } else if (pp == &p_ut) {
+ if (value < 0) {
+ errmsg = e_positive;
+ }
+ } else if (pp == &p_ss) {
+ if (value < 0) {
+ errmsg = e_positive;
+ }
+ } else if (pp == &curwin->w_p_fdl
+ || pp == (long *)GLOBAL_WO(&curwin->w_p_fdl)) {
+ if (value < 0) {
+ errmsg = e_positive;
+ }
+ } else if (pp == &curwin->w_p_fdc
+ || pp == (long *)GLOBAL_WO(&curwin->w_p_fdc)) {
+ if (value < 0) {
errmsg = e_positive;
- curwin->w_p_cole = 0;
- } else if (curwin->w_p_cole > 3) {
+ } else if (value > 12) {
errmsg = e_invarg;
- curwin->w_p_cole = 3;
- }
- }
- /* sync undo before 'undolevels' changes */
- else if (pp == &p_ul) {
- /* use the old value, otherwise u_sync() may not work properly */
- p_ul = old_value;
- u_sync(TRUE);
- p_ul = value;
- } else if (pp == &curbuf->b_p_ul) {
- /* use the old value, otherwise u_sync() may not work properly */
- curbuf->b_p_ul = old_value;
- u_sync(TRUE);
- curbuf->b_p_ul = value;
- }
- /* 'numberwidth' must be positive */
- else if (pp == &curwin->w_p_nuw) {
- if (curwin->w_p_nuw < 1) {
+ }
+ } else if (pp == &curwin->w_p_cole
+ || pp == (long *)GLOBAL_WO(&curwin->w_p_cole)) {
+ if (value < 0) {
errmsg = e_positive;
- curwin->w_p_nuw = 1;
+ } else if (value > 3) {
+ errmsg = e_invarg;
}
- if (curwin->w_p_nuw > 10) {
+ } else if (pp == &curwin->w_p_nuw
+ || pp == (long *)GLOBAL_WO(&curwin->w_p_nuw)) {
+ if (value < 1) {
+ errmsg = e_positive;
+ } else if (value > 10) {
errmsg = e_invarg;
- curwin->w_p_nuw = 10;
}
- curwin->w_nrwidth_line_count = 0;
- } else if (pp == &curbuf->b_p_tw) {
- if (curbuf->b_p_tw < 0) {
+ } else if (pp == &curbuf->b_p_iminsert || pp == &p_iminsert) {
+ if (value < 0 || value > B_IMODE_LAST) {
+ errmsg = e_invarg;
+ }
+ } else if (pp == &curbuf->b_p_imsearch || pp == &p_imsearch) {
+ if (value < -1 || value > B_IMODE_LAST) {
+ errmsg = e_invarg;
+ }
+ } else if (pp == &curbuf->b_p_channel || pp == &p_channel) {
+ errmsg = e_invarg;
+ } else if (pp == &curbuf->b_p_scbk || pp == &p_scbk) {
+ if (value < -1 || value > SB_MAX
+ || (value != -1 && opt_flags == OPT_LOCAL && !curbuf->terminal)) {
+ errmsg = e_invarg;
+ }
+ } else if (pp == &curbuf->b_p_sw || pp == &p_sw) {
+ if (value < 0) {
+ errmsg = e_positive;
+ }
+ } else if (pp == &curbuf->b_p_ts || pp == &p_ts) {
+ if (value < 1) {
+ errmsg = e_positive;
+ }
+ } else if (pp == &curbuf->b_p_tw || pp == &p_tw) {
+ if (value < 0) {
errmsg = e_positive;
- curbuf->b_p_tw = 0;
}
+ }
+ // Don't change the value and return early if validation failed.
+ if (errmsg != NULL) {
+ return (char *)errmsg;
+ }
+
+ *pp = value;
+ // Remember where the option was set.
+ set_option_scriptID_idx(opt_idx, opt_flags, current_SID);
+
+ // For these options we want to fix some invalid values.
+ if (pp == &p_window) {
+ if (p_window < 1) {
+ p_window = Rows - 1;
+ } else if (p_window >= Rows) {
+ p_window = Rows - 1;
+ }
+ } else if (pp == &p_ch) {
+ if (p_ch > Rows - min_rows() + 1) {
+ p_ch = Rows - min_rows() + 1;
+ }
+ }
+
+ // Number options that need some action when changed
+ if (pp == &p_wh) {
+ if (!ONE_WINDOW && curwin->w_height < p_wh) {
+ win_setheight((int)p_wh);
+ }
+ } else if (pp == &p_hh) {
+ if (!ONE_WINDOW && curbuf->b_help && curwin->w_height < p_hh) {
+ win_setheight((int)p_hh);
+ }
+ } else if (pp == &p_wmh) {
+ win_setminheight();
+ } else if (pp == &p_wiw) {
+ if (!ONE_WINDOW && curwin->w_width < p_wiw) {
+ win_setwidth((int)p_wiw);
+ }
+ } else if (pp == &p_ls) {
+ last_status(false); // (re)set last window status line.
+ } else if (pp == &p_stal) {
+ // (re)set tab page line
+ shell_new_rows(); // recompute window positions and heights
+ } else if (pp == &curwin->w_p_fdl) {
+ newFoldLevel();
+ } else if (pp == &curwin->w_p_fml) {
+ foldUpdateAll(curwin);
+ } else if (pp == &curwin->w_p_fdn) {
+ if (foldmethodIsSyntax(curwin) || foldmethodIsIndent(curwin)) {
+ foldUpdateAll(curwin);
+ }
+ } else if (pp == &curbuf->b_p_sw || pp == &curbuf->b_p_ts) {
+ // 'shiftwidth' or 'tabstop'
+ if (foldmethodIsIndent(curwin)) {
+ foldUpdateAll(curwin);
+ }
+ // When 'shiftwidth' changes, or it's zero and 'tabstop' changes:
+ // parse 'cinoptions'.
+ if (pp == &curbuf->b_p_sw || curbuf->b_p_sw == 0) {
+ parse_cino(curbuf);
+ }
+ } else if (pp == &p_mco) {
+ screenclear(); // will re-allocate the screen
+ } else if (pp == &curbuf->b_p_iminsert) {
+ showmode();
+ // Show/unshow value of 'keymap' in status lines.
+ status_redraw_curbuf();
+ } else if (pp == &p_titlelen) {
+ // if 'titlelen' has changed, redraw the title
+ if (starting != NO_SCREEN && old_value != p_titlelen) {
+ need_maketitle = true;
+ }
+ } else if (pp == &p_ch) {
+ // if p_ch changed value, change the command line height
+ // Only compute the new window layout when startup has been
+ // completed. Otherwise the frame sizes may be wrong.
+ if (p_ch != old_value && full_screen) {
+ command_height();
+ }
+ } else if (pp == &p_uc) {
+ // when 'updatecount' changes from zero to non-zero, open swap files
+ if (p_uc && !old_value) {
+ ml_open_files();
+ }
+ } else if (pp == &p_ul || pp == &curbuf->b_p_ul) {
+ // sync undo before 'undolevels' changes
+ // use the old value, otherwise u_sync() may not work properly
+ *pp = old_value;
+ u_sync(true);
+ *pp = value;
+ } else if (pp == &curbuf->b_p_tw) {
FOR_ALL_TAB_WINDOWS(tp, wp) {
check_colorcolumn(wp);
}
} else if (pp == &curbuf->b_p_scbk || pp == &p_scbk) {
- // 'scrollback'
- if (*pp < -1 || *pp > SB_MAX
- || (*pp != -1 && opt_flags == OPT_LOCAL && !curbuf->terminal)) {
- errmsg = e_invarg;
- *pp = old_value;
- } else if (curbuf->terminal) {
+ if (curbuf->terminal) {
// Force the scrollback to take effect.
terminal_resize(curbuf->terminal, UINT16_MAX, UINT16_MAX);
}
+ } else if (pp == &curwin->w_p_nuw) {
+ curwin->w_nrwidth_line_count = 0;
}
- /*
- * Check the bounds for numeric options here
- */
+
+ // Check the (new) bounds for Rows and Columns here.
if (Rows < min_rows() && full_screen) {
if (errbuf != NULL) {
vim_snprintf((char *)errbuf, errbuflen,
@@ -4340,19 +4362,17 @@ static char *set_num_option(int opt_idx, char_u *varp, long value,
limit_screen_size();
- /*
- * If the screen (shell) height has been changed, assume it is the
- * physical screenheight.
- */
+ // If the screen (shell) height has been changed, assume it is the
+ // physical screenheight.
if (old_Rows != Rows || old_Columns != Columns) {
- /* Changing the screen size is not allowed while updating the screen. */
+ // Changing the screen size is not allowed while updating the screen.
if (updating_screen) {
*pp = old_value;
} else if (full_screen) {
screen_resize((int)Columns, (int)Rows);
} else {
- /* Postpone the resizing; check the size and cmdline position for
- * messages. */
+ // Postpone the resizing; check the size and cmdline position for
+ // messages.
check_shellsize();
if (cmdline_row > Rows - p_ch && Rows > p_ch) {
assert(p_ch >= 0 && Rows - p_ch <= INT_MAX);
@@ -4364,14 +4384,6 @@ static char *set_num_option(int opt_idx, char_u *varp, long value,
}
}
- if (curbuf->b_p_ts <= 0) {
- errmsg = e_positive;
- curbuf->b_p_ts = 8;
- }
- if (p_tm < 0) {
- errmsg = e_positive;
- p_tm = 0;
- }
if ((curwin->w_p_scr <= 0
|| (curwin->w_p_scr > curwin->w_height
&& curwin->w_height > 0))
@@ -4388,21 +4400,6 @@ static char *set_num_option(int opt_idx, char_u *varp, long value,
else /* curwin->w_p_scr > curwin->w_height */
curwin->w_p_scr = curwin->w_height;
}
- if (p_hi < 0) {
- errmsg = e_positive;
- p_hi = 0;
- } else if (p_hi > 10000) {
- errmsg = e_invarg;
- p_hi = 10000;
- }
- if (p_re < 0 || p_re > 2) {
- errmsg = e_invarg;
- p_re = 0;
- }
- if (p_report < 0) {
- errmsg = e_positive;
- p_report = 1;
- }
if ((p_sj < -100 || p_sj >= Rows) && full_screen) {
if (Rows != old_Rows) /* Rows changed, just adjust p_sj */
p_sj = Rows / 2;
@@ -4411,30 +4408,11 @@ static char *set_num_option(int opt_idx, char_u *varp, long value,
p_sj = 1;
}
}
- if (p_so < 0 && full_screen) {
- errmsg = e_scroll;
- p_so = 0;
- }
- if (p_siso < 0 && full_screen) {
- errmsg = e_positive;
- p_siso = 0;
- }
- if (p_cwh < 1) {
- errmsg = e_positive;
- p_cwh = 1;
- }
- if (p_ut < 0) {
- errmsg = e_positive;
- p_ut = 2000;
- }
- if (p_ss < 0) {
- errmsg = e_positive;
- p_ss = 0;
- }
- /* May set global value for local option. */
- if ((opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0)
+ // May set global value for local option.
+ if ((opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0) {
*(long *)get_varp_scope(&(options[opt_idx]), OPT_GLOBAL) = *pp;
+ }
if (pp == &curbuf->b_p_scbk && !curbuf->terminal) {
// Normal buffer: reset local 'scrollback' after updating the global value.
diff --git a/src/nvim/option_defs.h b/src/nvim/option_defs.h
index e2e98f251e..66a49fd6e0 100644
--- a/src/nvim/option_defs.h
+++ b/src/nvim/option_defs.h
@@ -394,11 +394,13 @@ EXTERN char_u *p_dir; /* 'directory' */
EXTERN char_u *p_dy; /* 'display' */
EXTERN unsigned dy_flags;
#ifdef IN_OPTION_C
-static char *(p_dy_values[]) = { "lastline", "truncate", "uhex", NULL };
+static char *(p_dy_values[]) = { "lastline", "truncate", "uhex", "msgsep",
+ NULL };
#endif
#define DY_LASTLINE 0x001
#define DY_TRUNCATE 0x002
#define DY_UHEX 0x004
+#define DY_MSGSEP 0x008
EXTERN int p_ed; // 'edcompatible'
EXTERN int p_emoji; // 'emoji'
EXTERN char_u *p_ead; // 'eadirection'
diff --git a/src/nvim/options.lua b/src/nvim/options.lua
index d653147943..80484d0ad2 100644
--- a/src/nvim/options.lua
+++ b/src/nvim/options.lua
@@ -642,7 +642,7 @@ return {
vim=true,
redraw={'all_windows'},
varname='p_dy',
- defaults={if_true={vi="", vim="lastline"}}
+ defaults={if_true={vi="", vim="lastline,msgsep"}}
},
{
full_name='eadirection', abbreviation='ead',
diff --git a/src/nvim/os/process.c b/src/nvim/os/process.c
index e23ba8a4ee..a67e7487eb 100644
--- a/src/nvim/os/process.c
+++ b/src/nvim/os/process.c
@@ -12,12 +12,16 @@
# include <tlhelp32.h> // for CreateToolhelp32Snapshot
#endif
-#if defined(__FreeBSD__) // XXX: OpenBSD, NetBSD ?
+#if defined(__FreeBSD__) // XXX: OpenBSD ?
# include <string.h>
# include <sys/types.h>
# include <sys/user.h>
#endif
+#if defined(__NetBSD__) || defined(__OpenBSD__)
+# include <sys/param.h>
+#endif
+
#if defined(__APPLE__) || defined(BSD)
# include <sys/sysctl.h>
# include <pwd.h>
@@ -155,7 +159,13 @@ int os_proc_children(int ppid, int **proc_list, size_t *proc_count)
# define KP_PID(o) o.p_pid
# define KP_PPID(o) o.p_ppid
# endif
+# ifdef __NetBSD__
+ static int name[] = {
+ CTL_KERN, KERN_PROC2, KERN_PROC_ALL, 0, (int)(sizeof(struct kinfo_proc2)), 0
+ };
+# else
static int name[] = { CTL_KERN, KERN_PROC, KERN_PROC_ALL, 0 };
+# endif
// Get total process count.
size_t len = 0;
@@ -165,7 +175,11 @@ int os_proc_children(int ppid, int **proc_list, size_t *proc_count)
}
// Get ALL processes.
+# ifdef __NetBSD__
+ struct kinfo_proc2 *p_list = xmalloc(len);
+# else
struct kinfo_proc *p_list = xmalloc(len);
+# endif
rv = sysctl(name, ARRAY_SIZE(name) - 1, p_list, &len, NULL, 0);
if (rv) {
xfree(p_list);
diff --git a/src/nvim/os/shell.c b/src/nvim/os/shell.c
index f650a51fe7..04f59d7522 100644
--- a/src/nvim/os/shell.c
+++ b/src/nvim/os/shell.c
@@ -136,7 +136,7 @@ int os_call_shell(char_u *cmd, ShellOpts opts, char_u *extra_args)
xfree(input.data);
if (output) {
- (void)write_output(output, nread, true, true);
+ (void)write_output(output, nread, true);
xfree(output);
}
@@ -388,10 +388,10 @@ static bool out_data_decide_throttle(size_t size)
pulse_msg[1] = (tick == 0 || 1 == tick) ? ' ' : '.';
pulse_msg[2] = (tick == 0 || 1 == tick || 2 == tick) ? ' ' : '.';
if (visit == 1) {
- screen_del_lines(0, 0, 1, (int)Rows, NULL);
+ msg_putchar('\n');
}
- int lastrow = (int)Rows - 1;
- screen_puts_len((char_u *)pulse_msg, ARRAY_SIZE(pulse_msg), lastrow, 0, 0);
+ msg_putchar('\r'); // put cursor at start of line
+ msg_puts(pulse_msg);
ui_flush();
return true;
}
@@ -609,28 +609,20 @@ static void read_input(DynamicBuffer *buf)
}
}
-static size_t write_output(char *output, size_t remaining, bool to_buffer,
- bool eof)
+static size_t write_output(char *output, size_t remaining, bool eof)
{
if (!output) {
return 0;
}
- char replacement_NUL = to_buffer ? NL : 1;
char *start = output;
size_t off = 0;
- int lastrow = (int)Rows - 1;
while (off < remaining) {
if (output[off] == NL) {
// Insert the line
- if (to_buffer) {
- output[off] = NUL;
- ml_append(curwin->w_cursor.lnum++, (char_u *)output, (int)off + 1,
- false);
- } else {
- screen_del_lines(0, 0, 1, (int)Rows, NULL);
- screen_puts_len((char_u *)output, (int)off, lastrow, 0, 0);
- }
+ output[off] = NUL;
+ ml_append(curwin->w_cursor.lnum++, (char_u *)output, (int)off + 1,
+ false);
size_t skip = off + 1;
output += skip;
remaining -= skip;
@@ -640,24 +632,19 @@ static size_t write_output(char *output, size_t remaining, bool to_buffer,
if (output[off] == NUL) {
// Translate NUL to NL
- output[off] = replacement_NUL;
+ output[off] = NL;
}
off++;
}
if (eof) {
if (remaining) {
- if (to_buffer) {
- // append unfinished line
- ml_append(curwin->w_cursor.lnum++, (char_u *)output, 0, false);
- // remember that the NL was missing
- curbuf->b_no_eol_lnum = curwin->w_cursor.lnum;
- } else {
- screen_del_lines(0, 0, 1, (int)Rows, NULL);
- screen_puts_len((char_u *)output, (int)remaining, lastrow, 0, 0);
- }
+ // append unfinished line
+ ml_append(curwin->w_cursor.lnum++, (char_u *)output, 0, false);
+ // remember that the NL was missing
+ curbuf->b_no_eol_lnum = curwin->w_cursor.lnum;
output += remaining;
- } else if (to_buffer) {
+ } else {
curbuf->b_no_eol_lnum = 0;
}
}
diff --git a/src/nvim/os/stdpaths.c b/src/nvim/os/stdpaths.c
index a41fb7c621..866a005228 100644
--- a/src/nvim/os/stdpaths.c
+++ b/src/nvim/os/stdpaths.c
@@ -88,7 +88,7 @@ char *stdpaths_get_xdg_var(const XDGVarType idx)
///
/// In WIN32 get_xdg_home(kXDGDataHome) returns `{xdg_directory}/nvim-data` to
/// avoid storing configuration and data files in the same path.
-static char *get_xdg_home(const XDGVarType idx)
+char *get_xdg_home(const XDGVarType idx)
FUNC_ATTR_WARN_UNUSED_RESULT
{
char *dir = stdpaths_get_xdg_var(idx);
diff --git a/src/nvim/po/CMakeLists.txt b/src/nvim/po/CMakeLists.txt
index 121f22129a..94cc63baea 100644
--- a/src/nvim/po/CMakeLists.txt
+++ b/src/nvim/po/CMakeLists.txt
@@ -2,10 +2,8 @@ find_package(Gettext)
find_program(XGETTEXT_PRG xgettext)
find_program(ICONV_PRG iconv)
-if(HAVE_WORKING_LIBINTL AND GETTEXT_FOUND AND XGETTEXT_PRG AND ICONV_PRG)
- set(ENV{OLD_PO_FILE_INPUT} yes)
- set(ENV{OLD_PO_FILE_OUTPUT} yes)
-
+option(LANGUAGES "Localizations to build")
+if(NOT LANGUAGES)
set(LANGUAGES
af
ca
@@ -31,6 +29,12 @@ if(HAVE_WORKING_LIBINTL AND GETTEXT_FOUND AND XGETTEXT_PRG AND ICONV_PRG)
vi
zh_CN.UTF-8
zh_TW.UTF-8)
+endif()
+
+if(HAVE_WORKING_LIBINTL AND GETTEXT_FOUND AND XGETTEXT_PRG AND ICONV_PRG)
+ set(ENV{OLD_PO_FILE_INPUT} yes)
+ set(ENV{OLD_PO_FILE_OUTPUT} yes)
+
set(NVIM_RELATIVE_SOURCES)
foreach(SRC ${NVIM_SOURCES} ${NVIM_HEADERS})
@@ -135,22 +139,30 @@ if(HAVE_WORKING_LIBINTL AND GETTEXT_FOUND AND XGETTEXT_PRG AND ICONV_PRG)
endmacro()
# Create some translations from others.
- BuildPoIconv(ja utf-8 euc-jp)
- BuildMo(ja.euc-jp)
+ if(";${LANGUAGES};" MATCHES ";ja;")
+ BuildPoIconv(ja utf-8 euc-jp)
+ BuildMo(ja.euc-jp)
+ endif()
- BuildPoIconv(cs ISO-8859-2 cp1250)
- BuildMo(cs.cp1250)
+ if(";${LANGUAGES};" MATCHES ";cs;")
+ BuildPoIconv(cs ISO-8859-2 cp1250)
+ BuildMo(cs.cp1250)
+ endif()
- BuildPoIconv(sk ISO-8859-2 cp1250)
- BuildMo(sk.cp1250)
+ if(";${LANGUAGES};" MATCHES ";sk;")
+ BuildPoIconv(sk ISO-8859-2 cp1250)
+ BuildMo(sk.cp1250)
+ endif()
add_custom_target(update-po-nb
COMMAND ${CMAKE_COMMAND} -E copy
${CMAKE_CURRENT_SOURCE_DIR}/no.po ${CMAKE_CURRENT_SOURCE_DIR}/nb.po
DEPENDS no.po)
list(APPEND UPDATE_PO_TARGETS update-po-nb)
- CheckPo(nb)
- BuildMo(nb)
+ if(";${LANGUAGES};" MATCHES ";no;")
+ CheckPo(nb)
+ BuildMo(nb)
+ endif()
foreach(LANGUAGE ${LANGUAGES})
set(poFile "${CMAKE_CURRENT_SOURCE_DIR}/${LANGUAGE}.po")
diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c
index 2d8c353f92..46124e0672 100644
--- a/src/nvim/quickfix.c
+++ b/src/nvim/quickfix.c
@@ -3029,7 +3029,7 @@ static void qf_fill_buffer(qf_info_T *qi, buf_T *buf, qfline_T *old_last)
/*
* Return TRUE if "buf" is the quickfix buffer.
*/
-int bt_quickfix(buf_T *buf)
+int bt_quickfix(const buf_T *const buf)
{
return buf != NULL && buf->b_p_bt[0] == 'q';
}
diff --git a/src/nvim/screen.c b/src/nvim/screen.c
index 22de08041a..731bb2658a 100644
--- a/src/nvim/screen.c
+++ b/src/nvim/screen.c
@@ -300,13 +300,25 @@ void update_screen(int type)
* if the screen was scrolled up when displaying a message, scroll it down
*/
if (msg_scrolled) {
- clear_cmdline = TRUE;
- if (msg_scrolled > Rows - 5) /* clearing is faster */
+ clear_cmdline = true;
+ if (dy_flags & DY_MSGSEP) {
+ FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
+ int valid = Rows - msg_scrollsize();
+ if (wp->w_winrow + wp->w_height > valid) {
+ wp->w_redr_type = NOT_VALID;
+ wp->w_lines_valid = 0;
+ }
+ if (wp->w_winrow + wp->w_height + wp->w_status_height > valid) {
+ wp->w_redr_status = true;
+ }
+ }
+ } else if (msg_scrolled > Rows - 5) { // clearing is faster
type = CLEAR;
- else if (type != CLEAR) {
- check_for_delay(FALSE);
- if (screen_ins_lines(0, 0, msg_scrolled, (int)Rows, NULL) == FAIL)
+ } else if (type != CLEAR) {
+ check_for_delay(false);
+ if (screen_ins_lines(0, 0, msg_scrolled, (int)Rows, NULL) == FAIL) {
type = CLEAR;
+ }
FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
if (wp->w_winrow < msg_scrolled) {
if (wp->w_winrow + wp->w_height > msg_scrolled
@@ -2032,7 +2044,7 @@ static void fold_line(win_T *wp, long fold_count, foldinfo_T *foldinfo, linenr_T
}
screen_line(row + wp->w_winrow, wp->w_wincol, wp->w_width,
- wp->w_width, false, wp);
+ wp->w_width, false, wp, 0);
/*
* Update w_cline_height and w_cline_folded if the cursor line was
@@ -2453,10 +2465,6 @@ win_line (
line_attr = win_hl_attr(wp, HLF_QFL);
}
- if (wp->w_hl_attr_normal != 0) {
- line_attr = hl_combine_attr(wp->w_hl_attr_normal, line_attr);
- }
-
if (line_attr != 0) {
area_highlighting = true;
}
@@ -2914,7 +2922,8 @@ win_line (
&& lnum == wp->w_cursor.lnum && vcol >= (long)wp->w_virtcol
&& filler_todo <= 0
) {
- screen_line(screen_row, wp->w_wincol, col, -wp->w_width, wp->w_p_rl, wp);
+ screen_line(screen_row, wp->w_wincol, col, -wp->w_width, wp->w_p_rl, wp,
+ wp->w_hl_attr_normal);
// Pretend we have finished updating the window. Except when
// 'cursorcolumn' is set.
if (wp->w_p_cuc) {
@@ -4007,7 +4016,8 @@ win_line (
col++;
}
}
- screen_line(screen_row, wp->w_wincol, col, wp->w_width, wp->w_p_rl, wp);
+ screen_line(screen_row, wp->w_wincol, col, wp->w_width, wp->w_p_rl, wp,
+ wp->w_hl_attr_normal);
row++;
/*
@@ -4230,7 +4240,7 @@ win_line (
|| (n_extra != 0 && (c_extra != NUL || *p_extra != NUL)))
) {
screen_line(screen_row, wp->w_wincol, col - boguscols,
- wp->w_width, wp->w_p_rl, wp);
+ wp->w_width, wp->w_p_rl, wp, wp->w_hl_attr_normal);
boguscols = 0;
++row;
++screen_row;
@@ -4400,7 +4410,7 @@ static int char_needs_redraw(int off_from, int off_to, int cols)
* When FALSE and "clear_width" > 0, clear columns "endcol" to "clear_width"
*/
static void screen_line(int row, int coloff, int endcol,
- int clear_width, int rlflag, win_T *wp)
+ int clear_width, int rlflag, win_T *wp, int bg_attr)
{
unsigned off_from;
unsigned off_to;
@@ -4433,15 +4443,16 @@ static void screen_line(int row, int coloff, int endcol,
/* Clear rest first, because it's left of the text. */
if (clear_width > 0) {
while (col <= endcol && ScreenLines[off_to] == ' '
- && ScreenAttrs[off_to] == 0
+ && ScreenAttrs[off_to] == bg_attr
&& (!enc_utf8 || ScreenLinesUC[off_to] == 0)
) {
++off_to;
++col;
}
- if (col <= endcol)
- screen_fill(row, row + 1, col + coloff,
- endcol + coloff + 1, ' ', ' ', 0);
+ if (col <= endcol) {
+ screen_fill(row, row + 1, col + coloff, endcol + coloff + 1, ' ', ' ',
+ bg_attr);
+ }
}
col = endcol + 1;
off_to = LineOffset[row] + col + coloff;
@@ -4449,6 +4460,13 @@ static void screen_line(int row, int coloff, int endcol,
endcol = (clear_width > 0 ? clear_width : -clear_width);
}
+ if (bg_attr) {
+ for (int c = col; c < endcol; c++) {
+ ScreenAttrs[off_from+c] = hl_combine_attr(bg_attr,
+ ScreenAttrs[off_from+c]);
+ }
+ }
+
redraw_next = char_needs_redraw(off_from, off_to, endcol - col);
while (col < endcol) {
@@ -4547,15 +4565,15 @@ static void screen_line(int row, int coloff, int endcol,
/* blank out the rest of the line */
while (col < clear_width && ScreenLines[off_to] == ' '
- && ScreenAttrs[off_to] == 0
+ && ScreenAttrs[off_to] == bg_attr
&& (!enc_utf8 || ScreenLinesUC[off_to] == 0)
) {
++off_to;
++col;
}
if (col < clear_width) {
- screen_fill(row, row + 1, col + coloff, clear_width + coloff,
- ' ', ' ', 0);
+ screen_fill(row, row + 1, col + coloff, clear_width + coloff, ' ', ' ',
+ bg_attr);
off_to += clear_width - col;
col = clear_width;
}
diff --git a/src/nvim/shada.c b/src/nvim/shada.c
index 605d9c30a6..15ac28e1bf 100644
--- a/src/nvim/shada.c
+++ b/src/nvim/shada.c
@@ -16,12 +16,14 @@
#include "nvim/os/os.h"
#include "nvim/os/time.h"
#include "nvim/vim.h"
+#include "nvim/pos.h"
#include "nvim/ascii.h"
#include "nvim/shada.h"
#include "nvim/message.h"
#include "nvim/globals.h"
#include "nvim/memory.h"
#include "nvim/mark.h"
+#include "nvim/macros.h"
#include "nvim/ops.h"
#include "nvim/garray.h"
#include "nvim/option.h"
@@ -375,7 +377,8 @@ KHASH_MAP_INIT_STR(file_marks, FileMarks)
/// Before actually writing most of the data is read to this structure.
typedef struct {
HistoryMergerState hms[HIST_COUNT]; ///< Structures for history merging.
- PossiblyFreedShadaEntry global_marks[NGLOBALMARKS]; ///< All global marks.
+ PossiblyFreedShadaEntry global_marks[NMARKS]; ///< Named global marks.
+ PossiblyFreedShadaEntry numbered_marks[EXTRA_MARKS]; ///< Numbered marks.
PossiblyFreedShadaEntry registers[NUM_SAVED_REGISTERS]; ///< All registers.
PossiblyFreedShadaEntry jumps[JUMPLISTSIZE]; ///< All dumped jumps.
size_t jumps_size; ///< Number of jumps occupied.
@@ -2020,6 +2023,113 @@ shada_parse_msgpack_extra_bytes:
return ret;
}
+/// Format shada entry for debugging purposes
+///
+/// @param[in] entry ShaDa entry to format.
+///
+/// @return string representing ShaDa entry in a static buffer.
+static const char *shada_format_entry(const ShadaEntry entry)
+ FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_UNUSED FUNC_ATTR_NONNULL_RET
+{
+ static char ret[1024];
+ ret[0] = 0;
+ vim_snprintf(S_LEN(ret), "[ ] ts=%" PRIu64 " ");
+ // ^ Space for `can_free_entry`
+ switch (entry.type) {
+ case kSDItemMissing: {
+ vim_snprintf_add(S_LEN(ret), "Missing");
+ break;
+ }
+ case kSDItemHeader: {
+ vim_snprintf_add(S_LEN(ret), "Header { TODO }");
+ break;
+ }
+ case kSDItemBufferList: {
+ vim_snprintf_add(S_LEN(ret), "BufferList { TODO }");
+ break;
+ }
+ case kSDItemUnknown: {
+ vim_snprintf_add(S_LEN(ret), "Unknown { TODO }");
+ break;
+ }
+ case kSDItemSearchPattern: {
+ vim_snprintf_add(S_LEN(ret), "SearchPattern { TODO }");
+ break;
+ }
+ case kSDItemSubString: {
+ vim_snprintf_add(S_LEN(ret), "SubString { TODO }");
+ break;
+ }
+ case kSDItemHistoryEntry: {
+ vim_snprintf_add(S_LEN(ret), "HistoryEntry { TODO }");
+ break;
+ }
+ case kSDItemRegister: {
+ vim_snprintf_add(S_LEN(ret), "Register { TODO }");
+ break;
+ }
+ case kSDItemVariable: {
+ vim_snprintf_add(S_LEN(ret), "Variable { TODO }");
+ break;
+ }
+#define FORMAT_MARK_ENTRY(entry_name, name_fmt, name_fmt_arg) \
+ do { \
+ typval_T ad_tv = { \
+ .v_type = VAR_DICT, \
+ .vval.v_dict = entry.data.filemark.additional_data \
+ }; \
+ size_t ad_len; \
+ char *const ad = encode_tv2string(&ad_tv, &ad_len); \
+ vim_snprintf_add( \
+ S_LEN(ret), \
+ entry_name " {" name_fmt " file=[%zu]\"%.512s\", " \
+ "pos={l=%" PRIdLINENR ",c=%" PRIdCOLNR ",a=%" PRIdCOLNR "}, " \
+ "ad={%p:[%zu]%.64s} }", \
+ name_fmt_arg, \
+ strlen(entry.data.filemark.fname), \
+ entry.data.filemark.fname, \
+ entry.data.filemark.mark.lnum, \
+ entry.data.filemark.mark.col, \
+ entry.data.filemark.mark.coladd, \
+ entry.data.filemark.additional_data, \
+ ad_len, \
+ ad); \
+ } while (0)
+ case kSDItemGlobalMark: {
+ FORMAT_MARK_ENTRY("GlobalMark", " name='%c',", entry.data.filemark.name);
+ break;
+ }
+ case kSDItemChange: {
+ FORMAT_MARK_ENTRY("Change", "%s", "");
+ break;
+ }
+ case kSDItemLocalMark: {
+ FORMAT_MARK_ENTRY("LocalMark", " name='%c',", entry.data.filemark.name);
+ break;
+ }
+ case kSDItemJump: {
+ FORMAT_MARK_ENTRY("Jump", "%s", "");
+ break;
+ }
+#undef FORMAT_MARK_ENTRY
+ }
+ return ret;
+}
+
+/// Format possibly freed shada entry for debugging purposes
+///
+/// @param[in] entry ShaDa entry to format.
+///
+/// @return string representing ShaDa entry in a static buffer.
+static const char *shada_format_pfreed_entry(
+ const PossiblyFreedShadaEntry pfs_entry)
+ FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_UNUSED FUNC_ATTR_NONNULL_RET
+{
+ char *ret = (char *)shada_format_entry(pfs_entry.data);
+ ret[1] = (pfs_entry.can_free_entry ? 'T' : 'F');
+ return ret;
+}
+
/// Read and merge in ShaDa file, used when writing
///
/// @param[in] sd_reader Structure containing file reader definition.
@@ -2071,9 +2181,12 @@ static inline ShaDaWriteResult shada_read_when_writing(
shada_free_shada_entry(&wms_entry->data); \
} \
} \
- wms_entry->can_free_entry = true; \
- wms_entry->data = (entry); \
+ *wms_entry = pfs_entry; \
} while (0)
+ const PossiblyFreedShadaEntry pfs_entry = {
+ .can_free_entry = true,
+ .data = entry,
+ };
switch (entry.type) {
case kSDItemMissing: {
break;
@@ -2125,13 +2238,49 @@ static inline ShaDaWriteResult shada_read_when_writing(
break;
}
case kSDItemGlobalMark: {
- const int idx = mark_global_index(entry.data.filemark.name);
- if (idx < 0) {
- ret = shada_pack_entry(packer, entry, 0);
- shada_free_shada_entry(&entry);
- break;
+ if (ascii_isdigit(entry.data.filemark.name)) {
+ bool processed_mark = false;
+ // Completely ignore numbered mark names, make a list sorted by
+ // timestamp.
+ for (size_t i = ARRAY_SIZE(wms->numbered_marks); i > 0; i--) {
+ ShadaEntry wms_entry = wms->numbered_marks[i - 1].data;
+ if (wms_entry.type != kSDItemGlobalMark) {
+ continue;
+ }
+ // Ignore duplicates.
+ if (wms_entry.timestamp == entry.timestamp
+ && (wms_entry.data.filemark.additional_data == NULL
+ && entry.data.filemark.additional_data == NULL)
+ && marks_equal(wms_entry.data.filemark.mark,
+ entry.data.filemark.mark)
+ && strcmp(wms_entry.data.filemark.fname,
+ entry.data.filemark.fname) == 0) {
+ shada_free_shada_entry(&entry);
+ processed_mark = true;
+ break;
+ }
+ if (wms_entry.timestamp >= entry.timestamp) {
+ processed_mark = true;
+ if (i < ARRAY_SIZE(wms->numbered_marks)) {
+ replace_numbered_mark(wms, i, pfs_entry);
+ } else {
+ shada_free_shada_entry(&entry);
+ }
+ break;
+ }
+ }
+ if (!processed_mark) {
+ replace_numbered_mark(wms, 0, pfs_entry);
+ }
+ } else {
+ const int idx = mark_global_index(entry.data.filemark.name);
+ if (idx < 0) {
+ ret = shada_pack_entry(packer, entry, 0);
+ shada_free_shada_entry(&entry);
+ break;
+ }
+ COMPARE_WITH_ENTRY(&wms->global_marks[idx], entry);
}
- COMPARE_WITH_ENTRY(&wms->global_marks[idx], entry);
break;
}
case kSDItemChange:
@@ -2175,8 +2324,7 @@ static inline ShaDaWriteResult shada_read_when_writing(
shada_free_shada_entry(&wms_entry->data);
}
}
- wms_entry->can_free_entry = true;
- wms_entry->data = entry;
+ *wms_entry = pfs_entry;
}
} else {
#define FREE_POSSIBLY_FREED_SHADA_ENTRY(entry) \
@@ -2216,6 +2364,20 @@ static inline ShaDaWriteResult shada_read_when_writing(
return ret;
}
+/// Check whether buffer should be ignored
+///
+/// @param[in] buf buf_T* to check.
+/// @param[in] removable_bufs Cache of buffers ignored due to their location.
+///
+/// @return true or false.
+static inline bool ignore_buf(const buf_T *const buf,
+ khash_t(bufset) *const removable_bufs)
+ FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_ALWAYS_INLINE
+{
+ return (buf->b_ffname == NULL || !buf->b_p_bl || bt_quickfix(buf) \
+ || in_bufset(removable_bufs, buf));
+}
+
/// Get list of buffers to write to the shada file
///
/// @param[in] removable_bufs Buffers which are ignored
@@ -2227,11 +2389,9 @@ static inline ShadaEntry shada_get_buflist(
{
int max_bufs = get_shada_parameter('%');
size_t buf_count = 0;
-#define IGNORE_BUF(buf)\
- (buf->b_ffname == NULL || !buf->b_p_bl || bt_quickfix(buf) \
- || in_bufset(removable_bufs, buf)) // NOLINT(whitespace/indent)
FOR_ALL_BUFFERS(buf) {
- if (!IGNORE_BUF(buf) && (max_bufs < 0 || buf_count < (size_t)max_bufs)) {
+ if (!ignore_buf(buf, removable_bufs)
+ && (max_bufs < 0 || buf_count < (size_t)max_bufs)) {
buf_count++;
}
}
@@ -2249,7 +2409,7 @@ static inline ShadaEntry shada_get_buflist(
};
size_t i = 0;
FOR_ALL_BUFFERS(buf) {
- if (IGNORE_BUF(buf)) {
+ if (ignore_buf(buf, removable_bufs)) {
continue;
}
if (i >= buf_count) {
@@ -2263,7 +2423,6 @@ static inline ShadaEntry shada_get_buflist(
i++;
}
-#undef IGNORE_BUF
return buflist_entry;
}
@@ -2365,6 +2524,34 @@ static inline void shada_initialize_registers(WriteMergerState *const wms,
} while (reg_iter != NULL);
}
+/// Replace numbered mark in WriteMergerState
+///
+/// Frees the last mark, moves (including adjusting mark names) marks from idx
+/// to the last-but-one one and saves the new mark at given index.
+///
+/// @param[out] wms Merger state to adjust.
+/// @param[in] idx Index at which new mark should be placed.
+/// @param[in] entry New mark.
+static inline void replace_numbered_mark(WriteMergerState *const wms,
+ const size_t idx,
+ const PossiblyFreedShadaEntry entry)
+ FUNC_ATTR_NONNULL_ALL FUNC_ATTR_ALWAYS_INLINE
+{
+ if (ARRAY_LAST_ENTRY(wms->numbered_marks).can_free_entry) {
+ shada_free_shada_entry(&ARRAY_LAST_ENTRY(wms->numbered_marks).data);
+ }
+ for (size_t i = idx; i < ARRAY_SIZE(wms->numbered_marks) - 1; i++) {
+ if (wms->numbered_marks[i].data.type == kSDItemGlobalMark) {
+ wms->numbered_marks[i].data.data.filemark.name = (char)('0' + (int)i + 1);
+ }
+ }
+ memmove(wms->numbered_marks + idx + 1, wms->numbered_marks + idx,
+ sizeof(wms->numbered_marks[0])
+ * (ARRAY_SIZE(wms->numbered_marks) - 1 - idx));
+ wms->numbered_marks[idx] = entry;
+ wms->numbered_marks[idx].data.data.filemark.name = (char)('0' + (int)idx);
+}
+
/// Write ShaDa file
///
/// @param[in] sd_writer Structure containing file writer definition.
@@ -2597,6 +2784,7 @@ static ShaDaWriteResult shada_write(ShaDaWriteDef *const sd_writer,
// Initialize global marks
if (dump_global_marks) {
const void *global_mark_iter = NULL;
+ size_t digit_mark_idx = 0;
do {
char name = NUL;
xfmark_T fm;
@@ -2619,7 +2807,7 @@ static ShaDaWriteResult shada_write(ShaDaWriteDef *const sd_writer,
}
fname = (const char *) buf->b_ffname;
}
- wms->global_marks[mark_global_index(name)] = (PossiblyFreedShadaEntry) {
+ const PossiblyFreedShadaEntry pf_entry = {
.can_free_entry = false,
.data = {
.type = kSDItemGlobalMark,
@@ -2629,11 +2817,16 @@ static ShaDaWriteResult shada_write(ShaDaWriteDef *const sd_writer,
.mark = fm.fmark.mark,
.name = name,
.additional_data = fm.fmark.additional_data,
- .fname = (char *) fname,
+ .fname = (char *)fname,
}
}
},
};
+ if (ascii_isdigit(name)) {
+ replace_numbered_mark(wms, digit_mark_idx++, pf_entry);
+ } else {
+ wms->global_marks[mark_global_index(name)] = pf_entry;
+ }
} while (global_mark_iter != NULL);
}
@@ -2715,6 +2908,26 @@ static ShaDaWriteResult shada_write(ShaDaWriteDef *const sd_writer,
}
}
+ // Update numbered marks: '0' should be replaced with the current position,
+ // '9' should be removed and all other marks shifted.
+ if (!ignore_buf(curbuf, &removable_bufs) && curwin->w_cursor.lnum != 0) {
+ replace_numbered_mark(wms, 0, (PossiblyFreedShadaEntry) {
+ .can_free_entry = false,
+ .data = {
+ .type = kSDItemGlobalMark,
+ .timestamp = os_time(),
+ .data = {
+ .filemark = {
+ .mark = curwin->w_cursor,
+ .name = '0',
+ .additional_data = NULL,
+ .fname = (char *)curbuf->b_ffname,
+ }
+ }
+ },
+ });
+ }
+
// Write the rest
#define PACK_WMS_ARRAY(wms_array) \
do { \
@@ -2729,6 +2942,7 @@ static ShaDaWriteResult shada_write(ShaDaWriteDef *const sd_writer,
} \
} while (0)
PACK_WMS_ARRAY(wms->global_marks);
+ PACK_WMS_ARRAY(wms->numbered_marks);
PACK_WMS_ARRAY(wms->registers);
for (size_t i = 0; i < wms->jumps_size; i++) {
if (shada_pack_pfreed_entry(packer, wms->jumps[i], max_kbyte)
@@ -2823,6 +3037,7 @@ shada_write_exit:
return ret;
}
+#undef IGNORE_BUF
#undef PACK_STATIC_STR
/// Write ShaDa file to a given location
diff --git a/src/nvim/syntax.c b/src/nvim/syntax.c
index 8ec393e568..2613c09c19 100644
--- a/src/nvim/syntax.c
+++ b/src/nvim/syntax.c
@@ -5999,6 +5999,7 @@ static const char *highlight_init_both[] = {
"default link QuickFixLine Search",
"default link Substitute Search",
"default link Whitespace NonText",
+ "default link MsgSeparator StatusLine",
NULL
};
diff --git a/src/nvim/testdir/Makefile b/src/nvim/testdir/Makefile
index a31e1843fc..4bfcbf8e79 100644
--- a/src/nvim/testdir/Makefile
+++ b/src/nvim/testdir/Makefile
@@ -20,13 +20,13 @@ SCRIPTS_DEFAULT = \
test40.out \
test42.out \
test48.out \
- test49.out \
test52.out \
test64.out \
ifneq ($(OS),Windows_NT)
SCRIPTS_DEFAULTS := $(SCRIPTS_DEFAULT) \
test17.out \
+ test49.out \
endif
diff --git a/src/nvim/testdir/runtest.vim b/src/nvim/testdir/runtest.vim
index 6a7b44a76f..5c98455909 100644
--- a/src/nvim/testdir/runtest.vim
+++ b/src/nvim/testdir/runtest.vim
@@ -61,7 +61,7 @@ set nomore
lang mess C
" Always use forward slashes.
-set shellslash
+" set shellslash
" Prepare for calling test_garbagecollect_now().
let v:testing = 1
@@ -237,6 +237,7 @@ let s:flaky = [
\ 'Test_oneshot()',
\ 'Test_out_cb()',
\ 'Test_paused()',
+ \ 'Test_quoteplus()',
\ 'Test_reltime()',
\ 'Test_terminal_composing_unicode()',
\ 'Test_terminal_redir_file()',
diff --git a/src/nvim/testdir/setup.vim b/src/nvim/testdir/setup.vim
index 7d6dd0c7ce..aac9fefef4 100644
--- a/src/nvim/testdir/setup.vim
+++ b/src/nvim/testdir/setup.vim
@@ -17,3 +17,11 @@ let &packpath = &rtp
" Make sure $HOME does not get read or written.
let $HOME = '/does/not/exist'
+
+" Use default shell on Windows to avoid segfault, caused by TUI
+if has('win32')
+ let $SHELL = ''
+ let $TERM = ''
+ let &shell = empty($COMSPEC) ? exepath('cmd.exe') : $COMSPEC
+ set shellcmdflag=/s/c shellxquote=\" shellredir=>%s\ 2>&1
+endif
diff --git a/src/nvim/testdir/test_cmdline.vim b/src/nvim/testdir/test_cmdline.vim
index 673246e1fb..be68e9ff9d 100644
--- a/src/nvim/testdir/test_cmdline.vim
+++ b/src/nvim/testdir/test_cmdline.vim
@@ -154,7 +154,7 @@ func Test_getcompletion()
call assert_equal([], l)
let l = getcompletion('', 'dir')
- call assert_true(index(l, 'sautest/') >= 0)
+ call assert_true(index(l, expand('sautest/')) >= 0)
let l = getcompletion('NoMatch', 'dir')
call assert_equal([], l)
@@ -246,7 +246,7 @@ func Test_getcompletion()
" Command line completion tests
let l = getcompletion('cd ', 'cmdline')
- call assert_true(index(l, 'sautest/') >= 0)
+ call assert_true(index(l, expand('sautest/')) >= 0)
let l = getcompletion('cd NoMatch', 'cmdline')
call assert_equal([], l)
let l = getcompletion('let v:n', 'cmdline')
@@ -288,7 +288,7 @@ func Test_expand_star_star()
call mkdir('a/b', 'p')
call writefile(['asdfasdf'], 'a/b/fileXname')
call feedkeys(":find **/fileXname\<Tab>\<CR>", 'xt')
- call assert_equal('find a/b/fileXname', getreg(':'))
+ call assert_equal('find '.expand('a/b/fileXname'), getreg(':'))
bwipe!
call delete('a', 'rf')
endfunc
diff --git a/src/nvim/testdir/test_find_complete.vim b/src/nvim/testdir/test_find_complete.vim
index 4732109ed0..1019246404 100644
--- a/src/nvim/testdir/test_find_complete.vim
+++ b/src/nvim/testdir/test_find_complete.vim
@@ -3,6 +3,8 @@
" Do all the tests in a separate window to avoid E211 when we recursively
" delete the Xfind directory during cleanup
func Test_find_complete()
+ let shellslash = &shellslash
+ set shellslash
set belloff=all
" On windows a stale "Xfind" directory may exist, remove it so that
@@ -154,4 +156,5 @@ func Test_find_complete()
exe 'cd ' . cwd
call delete('Xfind', 'rf')
set path&
+ let &shellslash = shellslash
endfunc
diff --git a/src/nvim/testdir/test_help_tagjump.vim b/src/nvim/testdir/test_help_tagjump.vim
index 06c48d8e76..4d4a902031 100644
--- a/src/nvim/testdir/test_help_tagjump.vim
+++ b/src/nvim/testdir/test_help_tagjump.vim
@@ -30,7 +30,7 @@ func Test_help_tagjump()
help sp?it
call assert_equal("help", &filetype)
- call assert_true(getline('.') =~ '\*:split\*')
+ call assert_true(getline('.') =~ '\*'.(has('win32') ? 'split()' : ':split').'\*')
helpclose
help :?
diff --git a/src/nvim/testdir/test_makeencoding.vim b/src/nvim/testdir/test_makeencoding.vim
index a3d5538a47..6e4c7af821 100644
--- a/src/nvim/testdir/test_makeencoding.vim
+++ b/src/nvim/testdir/test_makeencoding.vim
@@ -13,12 +13,19 @@ endif
let s:script = 'test_makeencoding.py'
-let s:message_tbl = {
+if has('iconv')
+ let s:message_tbl = {
\ 'utf-8': 'ÀÈÌÒÙ こんにちは 你好',
\ 'latin1': 'ÀÈÌÒÙ',
\ 'cp932': 'こんにちは',
\ 'cp936': '你好',
\}
+else
+ let s:message_tbl = {
+ \ 'utf-8': 'ÀÈÌÒÙ こんにちは 你好',
+ \ 'latin1': 'ÀÈÌÒÙ',
+ \}
+endif
" Tests for :cgetfile and :lgetfile.
diff --git a/src/nvim/testdir/test_options.vim b/src/nvim/testdir/test_options.vim
index a15d15213a..f8c3161b40 100644
--- a/src/nvim/testdir/test_options.vim
+++ b/src/nvim/testdir/test_options.vim
@@ -158,6 +158,8 @@ func Test_set_completion()
call assert_equal('"set fileencodings:ucs-bom,utf-8,default,latin1', @:)
" Expand directories.
+ let shellslash = &shellslash
+ set shellslash
call feedkeys(":set cdpath=./\<C-A>\<C-B>\"\<CR>", 'tx')
call assert_match('./samples/ ', @:)
call assert_notmatch('./small.vim ', @:)
@@ -168,6 +170,7 @@ func Test_set_completion()
call feedkeys(":set tags=./\\\\ dif\<C-A>\<C-B>\"\<CR>", 'tx')
call assert_equal('"set tags=./\\ diff diffexpr diffopt', @:)
+ let &shellslash = shellslash
endfunc
func Test_set_errors()
diff --git a/src/nvim/testdir/test_quickfix.vim b/src/nvim/testdir/test_quickfix.vim
index dd177fd633..85f93cf3da 100644
--- a/src/nvim/testdir/test_quickfix.vim
+++ b/src/nvim/testdir/test_quickfix.vim
@@ -850,17 +850,17 @@ func s:dir_stack_tests(cchar)
let qf = g:Xgetlist()
- call assert_equal('dir1/a/habits2.txt', bufname(qf[1].bufnr))
+ call assert_equal(expand('dir1/a/habits2.txt'), bufname(qf[1].bufnr))
call assert_equal(1, qf[1].lnum)
- call assert_equal('dir1/a/b/habits3.txt', bufname(qf[3].bufnr))
+ call assert_equal(expand('dir1/a/b/habits3.txt'), bufname(qf[3].bufnr))
call assert_equal(2, qf[3].lnum)
- call assert_equal('dir1/a/habits2.txt', bufname(qf[4].bufnr))
+ call assert_equal(expand('dir1/a/habits2.txt'), bufname(qf[4].bufnr))
call assert_equal(7, qf[4].lnum)
- call assert_equal('dir1/c/habits4.txt', bufname(qf[6].bufnr))
+ call assert_equal(expand('dir1/c/habits4.txt'), bufname(qf[6].bufnr))
call assert_equal(3, qf[6].lnum)
call assert_equal('habits1.txt', bufname(qf[9].bufnr))
call assert_equal(4, qf[9].lnum)
- call assert_equal('dir2/habits5.txt', bufname(qf[11].bufnr))
+ call assert_equal(expand('dir2/habits5.txt'), bufname(qf[11].bufnr))
call assert_equal(5, qf[11].lnum)
let &efm=save_efm
@@ -1065,7 +1065,7 @@ func Test_efm2()
call assert_equal(8, len(l))
call assert_equal(89, l[4].lnum)
call assert_equal(1, l[4].valid)
- call assert_equal('unittests/dbfacadeTest.py', bufname(l[4].bufnr))
+ call assert_equal(expand('unittests/dbfacadeTest.py'), bufname(l[4].bufnr))
" The following sequence of commands used to crash Vim
set efm=%W%m
@@ -1609,11 +1609,11 @@ func Test_two_windows()
laddexpr 'one.txt:3:one one one'
let loc_one = getloclist(one_id)
- call assert_equal('Xone/a/one.txt', bufname(loc_one[1].bufnr))
+ call assert_equal(expand('Xone/a/one.txt'), bufname(loc_one[1].bufnr))
call assert_equal(3, loc_one[1].lnum)
let loc_two = getloclist(two_id)
- call assert_equal('Xtwo/a/two.txt', bufname(loc_two[1].bufnr))
+ call assert_equal(expand('Xtwo/a/two.txt'), bufname(loc_two[1].bufnr))
call assert_equal(5, loc_two[1].lnum)
call win_gotoid(one_id)
diff --git a/src/nvim/testdir/test_recover.vim b/src/nvim/testdir/test_recover.vim
index 46d884a97c..beecb4cd0d 100644
--- a/src/nvim/testdir/test_recover.vim
+++ b/src/nvim/testdir/test_recover.vim
@@ -6,11 +6,6 @@ func Test_recover_root_dir()
set dir=/
call assert_fails('recover', 'E305:')
close!
-
- if has('win32') || filewritable('/') == 2
- " can write in / directory on MS-Windows
- set dir=/notexist/
- endif
call assert_fails('split Xtest', 'E303:')
set dir&
endfunc
diff --git a/src/nvim/testdir/test_stat.vim b/src/nvim/testdir/test_stat.vim
index 1239fe9427..0a09130b0c 100644
--- a/src/nvim/testdir/test_stat.vim
+++ b/src/nvim/testdir/test_stat.vim
@@ -86,7 +86,7 @@ func Test_win32_symlink_dir()
let res = system('dir C:\Users /a')
if match(res, '\C<SYMLINKD> *All Users') >= 0
" Get the filetype of the symlink.
- call assert_equal('dir', getftype('C:\Users\All Users'))
+ call assert_equal('link', getftype('C:\Users\All Users'))
endif
endif
endfunc
diff --git a/src/nvim/testdir/test_system.vim b/src/nvim/testdir/test_system.vim
index ce9d110d82..d3c0594c03 100644
--- a/src/nvim/testdir/test_system.vim
+++ b/src/nvim/testdir/test_system.vim
@@ -5,14 +5,12 @@ function! Test_System()
return
endif
let out = system('echo 123')
- " On Windows we may get a trailing space.
- if out != "123 \n"
- call assert_equal("123\n", out)
- endif
+ call assert_equal("123\n", out)
let out = systemlist('echo 123')
- " On Windows we may get a trailing space and CR.
- if out != ["123 \r"]
+ if &shell =~# 'cmd.exe$'
+ call assert_equal(["123\r"], out)
+ else
call assert_equal(['123'], out)
endif
diff --git a/src/nvim/testdir/test_timers.vim b/src/nvim/testdir/test_timers.vim
index d377062780..81ac2b6171 100644
--- a/src/nvim/testdir/test_timers.vim
+++ b/src/nvim/testdir/test_timers.vim
@@ -119,7 +119,7 @@ func Test_paused()
let slept = WaitFor('g:val == 1')
call assert_equal(1, g:val)
if has('reltime')
- call assert_inrange(0, 60, slept)
+ call assert_inrange(0, 100, slept)
else
call assert_inrange(0, 10, slept)
endif
diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c
index bfebe0442d..72a25b0b59 100644
--- a/src/nvim/tui/tui.c
+++ b/src/nvim/tui/tui.c
@@ -450,7 +450,8 @@ static void update_attrs(UI *ui, HlAttrs attrs)
int attr = ui->rgb ? attrs.rgb_ae_attr : attrs.cterm_ae_attr;
bool bold = attr & HL_BOLD;
bool italic = attr & HL_ITALIC;
- bool reverse = attr & (HL_INVERSE | HL_STANDOUT);
+ bool reverse = attr & HL_INVERSE;
+ bool standout = attr & HL_STANDOUT;
bool underline = attr & (HL_UNDERLINE), undercurl = attr & (HL_UNDERCURL);
if (unibi_get_str(data->ut, unibi_set_attributes)) {
@@ -478,6 +479,9 @@ static void update_attrs(UI *ui, HlAttrs attrs)
if (underline || undercurl) {
unibi_out(ui, unibi_enter_underline_mode);
}
+ if (standout) {
+ unibi_out(ui, unibi_enter_standout_mode);
+ }
if (reverse) {
unibi_out(ui, unibi_enter_reverse_mode);
}
@@ -826,7 +830,7 @@ static void tui_cursor_goto(UI *ui, Integer row, Integer col)
CursorShape tui_cursor_decode_shape(const char *shape_str)
{
- CursorShape shape = 0;
+ CursorShape shape;
if (strequal(shape_str, "block")) {
shape = SHAPE_BLOCK;
} else if (strequal(shape_str, "vertical")) {
@@ -834,7 +838,8 @@ CursorShape tui_cursor_decode_shape(const char *shape_str)
} else if (strequal(shape_str, "horizontal")) {
shape = SHAPE_HOR;
} else {
- EMSG2(_(e_invarg2), shape_str);
+ WLOG("Unknown shape value '%s'", shape_str);
+ shape = SHAPE_BLOCK;
}
return shape;
}
@@ -920,7 +925,6 @@ static void tui_set_mode(UI *ui, ModeShape mode)
}
TUIData *data = ui->data;
cursorentry_T c = data->cursor_shapes[mode];
- int shape = c.shape;
if (c.id != 0 && ui->rgb) {
int attr = syn_id2attr(c.id);
@@ -931,11 +935,12 @@ static void tui_set_mode(UI *ui, ModeShape mode)
}
}
- switch (shape) {
+ int shape;
+ switch (c.shape) {
+ default: abort(); break;
case SHAPE_BLOCK: shape = 1; break;
case SHAPE_HOR: shape = 3; break;
case SHAPE_VER: shape = 5; break;
- default: WLOG("Unknown shape value %d", shape); break;
}
UNIBI_SET_NUM_VAR(data->params[0], shape + (int)(c.blinkon == 0));
unibi_out_ext(ui, data->unibi_ext.set_cursor_style);
diff --git a/src/nvim/ui.c b/src/nvim/ui.c
index c70a02d960..42366fdb76 100644
--- a/src/nvim/ui.c
+++ b/src/nvim/ui.c
@@ -186,6 +186,10 @@ Dictionary hlattrs2dict(const HlAttrs *aep, bool use_rgb)
PUT(hl, "bold", BOOLEAN_OBJ(true));
}
+ if (mask & HL_STANDOUT) {
+ PUT(hl, "standout", BOOLEAN_OBJ(true));
+ }
+
if (mask & HL_UNDERLINE) {
PUT(hl, "underline", BOOLEAN_OBJ(true));
}
@@ -198,7 +202,7 @@ Dictionary hlattrs2dict(const HlAttrs *aep, bool use_rgb)
PUT(hl, "italic", BOOLEAN_OBJ(true));
}
- if (mask & (HL_INVERSE | HL_STANDOUT)) {
+ if (mask & HL_INVERSE) {
PUT(hl, "reverse", BOOLEAN_OBJ(true));
}
diff --git a/src/nvim/viml/parser/expressions.c b/src/nvim/viml/parser/expressions.c
index 4196ecb9d2..ee59dc8c96 100644
--- a/src/nvim/viml/parser/expressions.c
+++ b/src/nvim/viml/parser/expressions.c
@@ -779,7 +779,8 @@ const char *viml_pexpr_repr_token(const ParserState *const pstate,
eltkn_opt_scope_tab[token.data.opt.scope],
(int)token.data.opt.len, token.data.opt.name)
TKNARGS(kExprLexPlainIdentifier, "(scope=%s,autoload=%i)",
- intchar2str(token.data.var.scope), (int)token.data.var.autoload)
+ intchar2str((int)token.data.var.scope),
+ (int)token.data.var.autoload)
TKNARGS(kExprLexNumber, "(is_float=%i,base=%i,val=%lg)",
(int)token.data.num.is_float,
(int)token.data.num.base,
diff --git a/test/functional/api/highlight_spec.lua b/test/functional/api/highlight_spec.lua
index 2297a0760f..fed53a3dfd 100644
--- a/test/functional/api/highlight_spec.lua
+++ b/test/functional/api/highlight_spec.lua
@@ -99,5 +99,14 @@ describe('highlight api',function()
eq(false, err)
eq('Invalid highlight name: ',
string.match(emsg, 'Invalid.*'))
+
+ -- Test "standout" attribute. #8054
+ eq({ underline = true, },
+ meths.get_hl_by_name('cursorline', 0));
+ command('hi CursorLine cterm=standout,underline term=standout,underline gui=standout,underline')
+ command('set cursorline')
+ eq({ underline = true, standout = true, },
+ meths.get_hl_by_name('cursorline', 0));
+
end)
end)
diff --git a/test/functional/api/ui_spec.lua b/test/functional/api/ui_spec.lua
new file mode 100644
index 0000000000..b028a50b02
--- /dev/null
+++ b/test/functional/api/ui_spec.lua
@@ -0,0 +1,37 @@
+local helpers = require('test.functional.helpers')(after_each)
+local Screen = require('test.functional.ui.screen')
+local clear = helpers.clear
+local eq = helpers.eq
+local eval = helpers.eval
+local expect_err = helpers.expect_err
+local meths = helpers.meths
+local request = helpers.request
+
+describe('nvim_ui_attach()', function()
+ before_each(function()
+ clear()
+ end)
+ it('handles very large width/height #2180', function()
+ local screen = Screen.new(999, 999)
+ screen:attach()
+ eq(999, eval('&lines'))
+ eq(999, eval('&columns'))
+ end)
+ it('invalid option returns error', function()
+ expect_err('No such UI option: foo',
+ meths.ui_attach, 80, 24, { foo={'foo'} })
+ end)
+ it('validates channel arg', function()
+ expect_err('UI not attached to channel: 1',
+ request, 'nvim_ui_try_resize', 40, 10)
+ expect_err('UI not attached to channel: 1',
+ request, 'nvim_ui_set_option', 'rgb', true)
+ expect_err('UI not attached to channel: 1',
+ request, 'nvim_ui_detach')
+
+ local screen = Screen.new()
+ screen:attach({rgb=false})
+ expect_err('UI already attached to channel: 1',
+ request, 'nvim_ui_attach', 40, 10, { rgb=false })
+ end)
+end)
diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua
index bd56161a54..718294d941 100644
--- a/test/functional/api/vim_spec.lua
+++ b/test/functional/api/vim_spec.lua
@@ -73,6 +73,8 @@ describe('api', function()
it('captures command output', function()
eq('this is\nspinal tap',
nvim('command_output', [[echo "this is\nspinal tap"]]))
+ eq('no line ending!',
+ nvim('command_output', [[echon "no line ending!"]]))
end)
it('captures empty command output', function()
@@ -579,7 +581,8 @@ describe('api', function()
screen:set_default_attr_ids({
[0] = {bold=true, foreground=Screen.colors.Blue},
[1] = {foreground = Screen.colors.White, background = Screen.colors.Red},
- [2] = {bold = true, foreground = Screen.colors.SeaGreen}
+ [2] = {bold = true, foreground = Screen.colors.SeaGreen},
+ [3] = {bold = true, reverse = true},
})
end)
@@ -600,11 +603,11 @@ describe('api', function()
it('shows return prompt when more than &cmdheight lines', function()
nvim_async('err_write', 'something happened\nvery bad\n')
screen:expect([[
+ |
{0:~ }|
{0:~ }|
{0:~ }|
- {0:~ }|
- {0:~ }|
+ {3: }|
{1:something happened} |
{1:very bad} |
{2:Press ENTER or type command to continue}^ |
@@ -614,9 +617,9 @@ describe('api', function()
it('shows return prompt after all lines are shown', function()
nvim_async('err_write', 'FAILURE\nERROR\nEXCEPTION\nTRACEBACK\n')
screen:expect([[
+ |
{0:~ }|
- {0:~ }|
- {0:~ }|
+ {3: }|
{1:FAILURE} |
{1:ERROR} |
{1:EXCEPTION} |
@@ -644,11 +647,11 @@ describe('api', function()
-- shows up to &cmdheight lines
nvim_async('err_write', 'more fail\ntoo fail\n')
screen:expect([[
+ |
{0:~ }|
{0:~ }|
{0:~ }|
- {0:~ }|
- {0:~ }|
+ {3: }|
{1:more fail} |
{1:too fail} |
{2:Press ENTER or type command to continue}^ |
diff --git a/test/functional/autocmd/cmdline_spec.lua b/test/functional/autocmd/cmdline_spec.lua
index 8ea086fb46..3f0504d02f 100644
--- a/test/functional/autocmd/cmdline_spec.lua
+++ b/test/functional/autocmd/cmdline_spec.lua
@@ -59,24 +59,25 @@ describe('cmdline autocommands', function()
[1] = {bold = true, foreground = Screen.colors.Blue1},
[2] = {foreground = Screen.colors.Grey100, background = Screen.colors.Red},
[3] = {bold = true, foreground = Screen.colors.SeaGreen4},
+ [4] = {bold = true, reverse = true},
})
command("autocmd CmdlineEnter * echoerr 'FAIL'")
command("autocmd CmdlineLeave * echoerr 'very error'")
feed(':')
screen:expect([[
+ |
{1:~ }|
{1:~ }|
{1:~ }|
- {1:~ }|
- {1:~ }|
+ {4: }|
: |
{2:E5500: autocmd has thrown an exception: Vim(echoerr):FAIL} |
:^ |
]])
feed("put ='lorem ipsum'<cr>")
screen:expect([[
- {1:~ }|
- {1:~ }|
+ |
+ {4: }|
: |
{2:E5500: autocmd has thrown an exception: Vim(echoerr):FAIL} |
:put ='lorem ipsum' |
diff --git a/test/functional/clipboard/clipboard_provider_spec.lua b/test/functional/clipboard/clipboard_provider_spec.lua
index a3ea3b568f..a40c080a6d 100644
--- a/test/functional/clipboard/clipboard_provider_spec.lua
+++ b/test/functional/clipboard/clipboard_provider_spec.lua
@@ -83,7 +83,14 @@ local function basic_register_test(noblock)
end
describe('clipboard', function()
- before_each(clear)
+ local screen
+
+ before_each(function()
+ clear()
+ screen = Screen.new(72, 4)
+ screen:attach()
+ command("set display-=msgsep")
+ end)
it('unnamed register works without provider', function()
eq('"', eval('v:register'))
@@ -92,8 +99,6 @@ describe('clipboard', function()
it('`:redir @+>` with invalid g:clipboard shows exactly one error #7184',
function()
- local screen = Screen.new(72, 4)
- screen:attach()
command("let g:clipboard = 'bogus'")
feed_command('redir @+> | :silent echo system("cat CONTRIBUTING.md") | redir END')
screen:expect([[
@@ -106,8 +111,6 @@ describe('clipboard', function()
it('`:redir @+>|bogus_cmd|redir END` + invalid g:clipboard must not recurse #7184',
function()
- local screen = Screen.new(72, 4)
- screen:attach()
command("let g:clipboard = 'bogus'")
feed_command('redir @+> | bogus_cmd | redir END')
screen:expect([[
@@ -123,8 +126,6 @@ describe('clipboard', function()
eq('', eval('provider#clipboard#Executable()'))
eq('clipboard: invalid g:clipboard', eval('provider#clipboard#Error()'))
- local screen = Screen.new(72, 4)
- screen:attach()
command("let g:clipboard = 'bogus'")
-- Explicit clipboard attempt, should show a hint message.
feed_command('let @+="foo"')
@@ -493,10 +494,10 @@ describe('clipboard', function()
feed_command("let g:test_clip['+'] = ['such', 'plus', 'stuff']")
feed_command("registers")
screen:expect([[
- ~ |
- ~ |
- ~ |
- ~ |
+ |
+ {0:~ }|
+ {0:~ }|
+ {4: }|
:registers |
{1:--- Registers ---} |
"* some{2:^J}star data{2:^J} |
@@ -504,10 +505,11 @@ describe('clipboard', function()
": let g:test_clip['+'] = ['such', 'plus', 'stuff'] |
{3:Press ENTER or type command to continue}^ |
]], {
+ [0] = {bold = true, foreground = Screen.colors.Blue},
[1] = {bold = true, foreground = Screen.colors.Fuchsia},
[2] = {foreground = Screen.colors.Blue},
- [3] = {bold = true, foreground = Screen.colors.SeaGreen}},
- {{bold = true, foreground = Screen.colors.Blue}})
+ [3] = {bold = true, foreground = Screen.colors.SeaGreen},
+ [4] = {bold = true, reverse = true}})
feed('<cr>') -- clear out of Press ENTER screen
end)
diff --git a/test/functional/core/job_spec.lua b/test/functional/core/job_spec.lua
index 45b739057f..e90339b0cd 100644
--- a/test/functional/core/job_spec.lua
+++ b/test/functional/core/job_spec.lua
@@ -685,6 +685,21 @@ describe('jobs', function()
ok(string.find(err, "E475: Invalid argument: job cannot have both 'pty' and 'rpc' options set") ~= nil)
end)
+ it('does not crash when repeatedly failing to start shell', function()
+ source([[
+ set shell=nosuchshell
+ func! DoIt()
+ call jobstart('true')
+ call jobstart('true')
+ endfunc
+ ]])
+ -- The crash only triggered if both jobs are cleaned up on the same event
+ -- loop tick. This is also prevented by try-block, so feed must be used.
+ feed_command("call DoIt()")
+ feed('<cr>') -- press RETURN
+ eq(2,eval('1+1'))
+ end)
+
it('jobstop() kills entire process tree #6530', function()
-- XXX: Using `nvim` isn't a good test, it reaps its children on exit.
-- local c = 'call jobstart([v:progpath, "-u", "NONE", "-i", "NONE", "--headless"])'
diff --git a/test/functional/eval/execute_spec.lua b/test/functional/eval/execute_spec.lua
index 183884a51e..925e311c7d 100644
--- a/test/functional/eval/execute_spec.lua
+++ b/test/functional/eval/execute_spec.lua
@@ -106,16 +106,22 @@ describe('execute()', function()
end)
it('does not corrupt the command display #5422', function()
- local screen = Screen.new(70, 5)
+ local screen = Screen.new(70, 7)
screen:attach()
feed(':echo execute("hi ErrorMsg")<CR>')
screen:expect([[
- ~ |
- ~ |
+ |
+ {1:~ }|
+ {1:~ }|
+ {2: }|
:echo execute("hi ErrorMsg") |
ErrorMsg xxx ctermfg=15 ctermbg=1 guifg=White guibg=Red |
- Press ENTER or type command to continue^ |
- ]])
+ {3:Press ENTER or type command to continue}^ |
+ ]], {
+ [1] = {bold = true, foreground = Screen.colors.Blue1},
+ [2] = {bold = true, reverse = true},
+ [3] = {bold = true, foreground = Screen.colors.SeaGreen4},
+ })
feed('<CR>')
end)
diff --git a/test/functional/eval/input_spec.lua b/test/functional/eval/input_spec.lua
index 1e6b107c60..777f49462d 100644
--- a/test/functional/eval/input_spec.lua
+++ b/test/functional/eval/input_spec.lua
@@ -58,6 +58,7 @@ before_each(function()
RBP2={background=Screen.colors.Yellow},
RBP3={background=Screen.colors.Green},
RBP4={background=Screen.colors.Blue},
+ SEP={bold = true, reverse = true},
})
end)
@@ -65,9 +66,9 @@ describe('input()', function()
it('works with multiline prompts', function()
feed([[:call input("Test\nFoo")<CR>]])
screen:expect([[
+ |
{EOB:~ }|
- {EOB:~ }|
- {EOB:~ }|
+ {SEP: }|
Test |
Foo^ |
]])
@@ -75,9 +76,9 @@ describe('input()', function()
it('works with multiline prompts and :echohl', function()
feed([[:echohl Test | call input("Test\nFoo")<CR>]])
screen:expect([[
+ |
{EOB:~ }|
- {EOB:~ }|
- {EOB:~ }|
+ {SEP: }|
{T:Test} |
{T:Foo}^ |
]])
@@ -242,17 +243,17 @@ describe('input()', function()
it('is not hidden by :silent', function()
feed([[:silent call input('Foo: ')<CR>]])
screen:expect([[
+ |
{EOB:~ }|
- {EOB:~ }|
- {EOB:~ }|
+ {SEP: }|
Foo: ^ |
|
]])
feed('Bar')
screen:expect([[
+ |
{EOB:~ }|
- {EOB:~ }|
- {EOB:~ }|
+ {SEP: }|
Foo: Bar^ |
|
]])
@@ -263,9 +264,9 @@ describe('inputdialog()', function()
it('works with multiline prompts', function()
feed([[:call inputdialog("Test\nFoo")<CR>]])
screen:expect([[
+ |
{EOB:~ }|
- {EOB:~ }|
- {EOB:~ }|
+ {SEP: }|
Test |
Foo^ |
]])
@@ -273,9 +274,9 @@ describe('inputdialog()', function()
it('works with multiline prompts and :echohl', function()
feed([[:echohl Test | call inputdialog("Test\nFoo")<CR>]])
screen:expect([[
+ |
{EOB:~ }|
- {EOB:~ }|
- {EOB:~ }|
+ {SEP: }|
{T:Test} |
{T:Foo}^ |
]])
diff --git a/test/functional/eval/server_spec.lua b/test/functional/eval/server_spec.lua
index 393616838e..4e4aed864b 100644
--- a/test/functional/eval/server_spec.lua
+++ b/test/functional/eval/server_spec.lua
@@ -1,31 +1,40 @@
-
local helpers = require('test.functional.helpers')(after_each)
local eq, neq, eval = helpers.eq, helpers.neq, helpers.eval
local command = helpers.command
local clear, funcs, meths = helpers.clear, helpers.funcs, helpers.meths
-local os_name = helpers.os_name
+local iswin = helpers.iswin
+local ok = helpers.ok
+local matches = helpers.matches
local function clear_serverlist()
- for _, server in pairs(funcs.serverlist()) do
- funcs.serverstop(server)
- end
+ for _, server in pairs(funcs.serverlist()) do
+ funcs.serverstop(server)
+ end
end
-describe('serverstart(), serverstop()', function()
+describe('server', function()
before_each(clear)
- it('sets $NVIM_LISTEN_ADDRESS on first invocation', function()
+ it('serverstart() sets $NVIM_LISTEN_ADDRESS on first invocation', function()
-- Unset $NVIM_LISTEN_ADDRESS
command('let $NVIM_LISTEN_ADDRESS = ""')
local s = eval('serverstart()')
assert(s ~= nil and s:len() > 0, "serverstart() returned empty")
eq(s, eval('$NVIM_LISTEN_ADDRESS'))
- command("call serverstop('"..s.."')")
+ eq(1, eval("serverstop('"..s.."')"))
eq('', eval('$NVIM_LISTEN_ADDRESS'))
end)
- it('sets v:servername _only_ on nvim startup unless all servers are stopped',
+ it('sets new v:servername if $NVIM_LISTEN_ADDRESS is invalid', function()
+ clear({env={NVIM_LISTEN_ADDRESS='.'}})
+ eq('.', eval('$NVIM_LISTEN_ADDRESS'))
+ local servers = funcs.serverlist()
+ eq(1, #servers)
+ ok(string.len(servers[1]) > 4) -- Like /tmp/nvim…/… or \\.\pipe\…
+ end)
+
+ it('sets v:servername at startup or if all servers were stopped',
function()
local initial_server = meths.get_vvar('servername')
assert(initial_server ~= nil and initial_server:len() > 0,
@@ -38,24 +47,23 @@ describe('serverstart(), serverstop()', function()
neq(initial_server, s)
-- serverstop() does _not_ modify v:servername...
- funcs.serverstop(s)
+ eq(1, funcs.serverstop(s))
eq(initial_server, meths.get_vvar('servername'))
-- ...unless we stop _all_ servers.
- funcs.serverstop(funcs.serverlist()[1])
+ eq(1, funcs.serverstop(funcs.serverlist()[1]))
eq('', meths.get_vvar('servername'))
-- v:servername will take the next available server.
- local servername = (os_name() == 'windows'
- and [[\\.\pipe\Xtest-functional-server-pipe]]
- or 'Xtest-functional-server-socket')
+ local servername = (iswin() and [[\\.\pipe\Xtest-functional-server-pipe]]
+ or 'Xtest-functional-server-socket')
funcs.serverstart(servername)
eq(servername, meths.get_vvar('servername'))
end)
- it('serverstop() ignores invalid input', function()
- command("call serverstop('')")
- command("call serverstop('bogus-socket-name')")
+ it('serverstop() returns false for invalid input', function()
+ eq(0, eval("serverstop('')"))
+ eq(0, eval("serverstop('bogus-socket-name')"))
end)
it('parses endpoints correctly', function()
@@ -96,17 +104,13 @@ describe('serverstart(), serverstop()', function()
funcs.serverstart('127.0.0.1:65536') -- invalid port
eq({}, funcs.serverlist())
end)
-end)
-
-describe('serverlist()', function()
- before_each(clear)
- it('returns the list of servers', function()
+ it('serverlist() returns the list of servers', function()
-- There should already be at least one server.
local n = eval('len(serverlist())')
- -- Add a few
- local servs = (os_name() == 'windows'
+ -- Add some servers.
+ local servs = (iswin()
and { [[\\.\pipe\Xtest-pipe0934]], [[\\.\pipe\Xtest-pipe4324]] }
or { [[Xtest-pipe0934]], [[Xtest-pipe4324]] })
for _, s in ipairs(servs) do
@@ -120,9 +124,31 @@ describe('serverlist()', function()
-- The new servers should be at the end of the list.
for i = 1, #servs do
eq(servs[i], new_servs[i + n])
- command("call serverstop('"..servs[i].."')")
+ eq(1, eval("serverstop('"..servs[i].."')"))
end
-- After serverstop() the servers should NOT be in the list.
eq(n, eval('len(serverlist())'))
end)
end)
+
+describe('startup --listen', function()
+ it('validates', function()
+ clear()
+
+ local cmd = { unpack(helpers.nvim_argv) }
+ table.insert(cmd, '--listen')
+ matches('nvim.*: Argument missing after: "%-%-listen"', funcs.system(cmd))
+
+ cmd = { unpack(helpers.nvim_argv) }
+ table.insert(cmd, '--listen2')
+ matches('nvim.*: Garbage after option argument: "%-%-listen2"', funcs.system(cmd))
+ end)
+
+ it('sets v:servername, overrides $NVIM_LISTEN_ADDRESS', function()
+ local addr = (iswin() and [[\\.\pipe\Xtest-listen-pipe]]
+ or 'Xtest-listen-pipe')
+ clear({ env={ NVIM_LISTEN_ADDRESS='Xtest-env-pipe' },
+ args={ '--listen', addr } })
+ eq(addr, meths.get_vvar('servername'))
+ end)
+end)
diff --git a/test/functional/eval/system_spec.lua b/test/functional/eval/system_spec.lua
index 201426c40b..23cea4c038 100644
--- a/test/functional/eval/system_spec.lua
+++ b/test/functional/eval/system_spec.lua
@@ -255,10 +255,8 @@ describe('system()', function()
end
end)
it('to backgrounded command does not crash', function()
- -- cmd.exe doesn't background a command with &
- if iswin() then return end
-- This is indeterminate, just exercise the codepath. May get E5677.
- feed_command('call system("echo -n echoed &")')
+ feed_command('call system(has("win32") ? "start /b /wait cmd /c echo echoed" : "echo -n echoed &")')
local v_errnum = string.match(eval("v:errmsg"), "^E%d*:")
if v_errnum then
eq("E5677:", v_errnum)
@@ -272,10 +270,8 @@ describe('system()', function()
eq("input", eval('system("cat -", "input")'))
end)
it('to backgrounded command does not crash', function()
- -- cmd.exe doesn't background a command with &
- if iswin() then return end
-- This is indeterminate, just exercise the codepath. May get E5677.
- feed_command('call system("cat - &", "input")')
+ feed_command('call system(has("win32") ? "start /b /wait more" : "cat - &", "input")')
local v_errnum = string.match(eval("v:errmsg"), "^E%d*:")
if v_errnum then
eq("E5677:", v_errnum)
diff --git a/test/functional/ex_cmds/cmd_map_spec.lua b/test/functional/ex_cmds/cmd_map_spec.lua
index 5b7f0942b1..77d025dcc7 100644
--- a/test/functional/ex_cmds/cmd_map_spec.lua
+++ b/test/functional/ex_cmds/cmd_map_spec.lua
@@ -27,6 +27,7 @@ describe('mappings with <Cmd>', function()
[4] = {bold = true},
[5] = {background = Screen.colors.LightGrey},
[6] = {foreground = Screen.colors.Blue1},
+ [7] = {bold = true, reverse = true},
})
screen:attach()
@@ -342,11 +343,11 @@ describe('mappings with <Cmd>', function()
-- error doesn't interrupt visual mode
feed('ggvw<F6>')
screen:expect([[
+ {5:some }short lines |
+ of test text |
{1:~ }|
{1:~ }|
- {1:~ }|
- {1:~ }|
- {1:~ }|
+ {7: }|
{2:Error detected while processing :} |
{2:E605: Exception not caught: very error} |
{3:Press ENTER or type command to continue}^ |
@@ -425,11 +426,11 @@ describe('mappings with <Cmd>', function()
-- error doesn't interrupt temporary visual mode
feed('<esc>ggvw<c-g><F6>')
screen:expect([[
+ {5:some }short lines |
+ of test text |
{1:~ }|
{1:~ }|
- {1:~ }|
- {1:~ }|
- {1:~ }|
+ {7: }|
{2:Error detected while processing :} |
{2:E605: Exception not caught: very error} |
{3:Press ENTER or type command to continue}^ |
@@ -453,11 +454,11 @@ describe('mappings with <Cmd>', function()
-- error doesn't interrupt select mode
feed('<esc>ggvw<c-g><F1>')
screen:expect([[
+ {5:some }short lines |
+ of test text |
{1:~ }|
{1:~ }|
- {1:~ }|
- {1:~ }|
- {1:~ }|
+ {7: }|
{2:Error detected while processing :} |
{2:E605: Exception not caught: very error} |
{3:Press ENTER or type command to continue}^ |
@@ -527,11 +528,11 @@ describe('mappings with <Cmd>', function()
-- error aborts operator-pending, operator not performed
feed('d<F6>')
screen:expect([[
+ some short lines |
+ of test text |
{1:~ }|
{1:~ }|
- {1:~ }|
- {1:~ }|
- {1:~ }|
+ {7: }|
{2:Error detected while processing :} |
{2:E605: Exception not caught: very error} |
{3:Press ENTER or type command to continue}^ |
@@ -571,11 +572,11 @@ describe('mappings with <Cmd>', function()
feed('<F6>')
screen:expect([[
+ indeed some short little lines |
+ of test text |
{1:~ }|
{1:~ }|
- {1:~ }|
- {1:~ }|
- {1:~ }|
+ {7: }|
{2:Error detected while processing :} |
{2:E605: Exception not caught: very error} |
{3:Press ENTER or type command to continue}^ |
@@ -675,10 +676,10 @@ describe('mappings with <Cmd>', function()
feed(':echo 2<F6>')
screen:expect([[
+ some short lines |
+ of test text |
{1:~ }|
- {1:~ }|
- {1:~ }|
- {1:~ }|
+ {7: }|
:echo 2 |
{2:Error detected while processing :} |
{2:E605: Exception not caught: very error} |
@@ -689,9 +690,9 @@ describe('mappings with <Cmd>', function()
eq('c', eval('mode(1)'))
feed('+2<cr>')
screen:expect([[
- {1:~ }|
- {1:~ }|
- {1:~ }|
+ some short lines |
+ of test text |
+ {7: }|
:echo 2 |
{2:Error detected while processing :} |
{2:E605: Exception not caught: very error} |
diff --git a/test/functional/ex_cmds/oldfiles_spec.lua b/test/functional/ex_cmds/oldfiles_spec.lua
index 4002855c24..448326cdfb 100644
--- a/test/functional/ex_cmds/oldfiles_spec.lua
+++ b/test/functional/ex_cmds/oldfiles_spec.lua
@@ -29,6 +29,7 @@ describe(':oldfiles', function()
it('shows most recently used files', function()
local screen = Screen.new(100, 5)
screen:attach()
+ feed_command("set display-=msgsep")
feed_command('edit testfile1')
feed_command('edit testfile2')
feed_command('wshada')
diff --git a/test/functional/helpers.lua b/test/functional/helpers.lua
index f2f5a6220c..03c6f3bbaa 100644
--- a/test/functional/helpers.lua
+++ b/test/functional/helpers.lua
@@ -14,8 +14,10 @@ local check_cores = global_helpers.check_cores
local check_logs = global_helpers.check_logs
local neq = global_helpers.neq
local eq = global_helpers.eq
+local expect_err = global_helpers.expect_err
local ok = global_helpers.ok
local map = global_helpers.map
+local matches = global_helpers.matches
local filter = global_helpers.filter
local dedent = global_helpers.dedent
local table_flatten = global_helpers.table_flatten
@@ -736,6 +738,7 @@ local module = {
exc_exec = exc_exec,
expect = expect,
expect_any = expect_any,
+ expect_err = expect_err,
expect_msg_seq = expect_msg_seq,
expect_twostreams = expect_twostreams,
feed = feed,
@@ -747,6 +750,7 @@ local module = {
insert = insert,
iswin = iswin,
map = map,
+ matches = matches,
merge_args = merge_args,
meth_pcall = meth_pcall,
meths = meths,
diff --git a/test/functional/insert/insert_spec.lua b/test/functional/insert/insert_spec.lua
new file mode 100644
index 0000000000..427954f5a6
--- /dev/null
+++ b/test/functional/insert/insert_spec.lua
@@ -0,0 +1,41 @@
+local helpers = require('test.functional.helpers')(after_each)
+local clear, feed, insert = helpers.clear, helpers.feed, helpers.insert
+local command = helpers.command
+local eq = helpers.eq
+local expect = helpers.expect
+local funcs = helpers.funcs
+
+describe('insert-mode', function()
+ before_each(function()
+ clear()
+ end)
+
+ it('CTRL-@', function()
+ -- Inserts last-inserted text, leaves insert-mode.
+ insert('hello')
+ feed('i<C-@>x')
+ expect('hellhello')
+
+ -- C-Space is the same as C-@.
+ -- CTRL-SPC inserts last-inserted text, leaves insert-mode.
+ feed('i<C-Space>x')
+ expect('hellhellhello')
+
+ -- CTRL-A inserts last inserted text
+ feed('i<C-A>x')
+ expect('hellhellhellhelloxo')
+ end)
+
+ it('ALT/META #8213', function()
+ -- Mapped ALT-chord behaves as mapped.
+ command('inoremap <M-l> meta-l')
+ command('inoremap <A-j> alt-j')
+ feed('i<M-l> xxx <A-j><M-h>a<A-h>')
+ expect('meta-l xxx alt-j')
+ eq({ 0, 1, 14, 0, }, funcs.getpos('.'))
+ -- Unmapped ALT-chord behaves as ESC+c.
+ command('iunmap <M-l>')
+ feed('0i<M-l>')
+ eq({ 0, 1, 2, 0, }, funcs.getpos('.'))
+ end)
+end)
diff --git a/test/functional/insert/last_inserted_spec.lua b/test/functional/insert/last_inserted_spec.lua
deleted file mode 100644
index dce23a3790..0000000000
--- a/test/functional/insert/last_inserted_spec.lua
+++ /dev/null
@@ -1,22 +0,0 @@
-local helpers = require('test.functional.helpers')(after_each)
-local clear, feed, insert = helpers.clear, helpers.feed, helpers.insert
-local expect = helpers.expect
-
-clear()
-
-describe('insert-mode', function()
- it('CTRL-@ inserts last-inserted text, leaves insert-mode', function()
- insert('hello')
- feed('i<C-@>x')
- expect('hellhello')
- end)
- -- C-Space is the same as C-@
- it('CTRL-SPC inserts last-inserted text, leaves insert-mode', function()
- feed('i<C-Space>x')
- expect('hellhellhello')
- end)
- it('CTRL-A inserts last inserted text', function()
- feed('i<C-A>x')
- expect('hellhellhellhelloxo')
- end)
-end)
diff --git a/test/functional/legacy/077_mf_hash_grow_spec.lua b/test/functional/legacy/077_mf_hash_grow_spec.lua
index c692127213..4719a3ecbf 100644
--- a/test/functional/legacy/077_mf_hash_grow_spec.lua
+++ b/test/functional/legacy/077_mf_hash_grow_spec.lua
@@ -18,7 +18,8 @@ describe('mf_hash_grow()', function()
setup(clear)
-- Check to see if cksum exists, otherwise skip the test
- if os.execute('which cksum 2>&1 > /dev/null') ~= 0 then
+ local null = helpers.iswin() and 'nul' or '/dev/null'
+ if os.execute('cksum --help >' .. null .. ' 2>&1') ~= 0 then
pending('was not tested because cksum was not found', function() end)
else
it('is working', function()
diff --git a/test/functional/lua/overrides_spec.lua b/test/functional/lua/overrides_spec.lua
index 8ca5fe57ba..007d40874f 100644
--- a/test/functional/lua/overrides_spec.lua
+++ b/test/functional/lua/overrides_spec.lua
@@ -87,6 +87,7 @@ describe('debug.debug', function()
E = {foreground = Screen.colors.Grey100, background = Screen.colors.Red},
cr = {bold = true, foreground = Screen.colors.SeaGreen4},
})
+ command("set display-=msgsep")
end)
it('works', function()
command([[lua
diff --git a/test/functional/options/defaults_spec.lua b/test/functional/options/defaults_spec.lua
index 9e29baba2d..f452cafd22 100644
--- a/test/functional/options/defaults_spec.lua
+++ b/test/functional/options/defaults_spec.lua
@@ -5,12 +5,15 @@ local Screen = require('test.functional.ui.screen')
local meths = helpers.meths
local command = helpers.command
local clear = helpers.clear
+local exc_exec = helpers.exc_exec
local eval = helpers.eval
local eq = helpers.eq
+local funcs = helpers.funcs
local insert = helpers.insert
local neq = helpers.neq
local mkdir = helpers.mkdir
local rmdir = helpers.rmdir
+local alter_slashes = helpers.alter_slashes
describe('startup defaults', function()
describe(':filetype', function()
@@ -422,3 +425,276 @@ describe('XDG-based defaults', function()
end)
end)
end)
+
+
+describe('stdpath()', function()
+ context('returns a String', function()
+ describe('with "config"' , function ()
+ it('knows XDG_CONFIG_HOME', function()
+ clear({env={
+ XDG_CONFIG_HOME=alter_slashes('/home/docwhat/.config'),
+ }})
+ eq(alter_slashes('/home/docwhat/.config/nvim'), funcs.stdpath('config'))
+ end)
+
+ it('handles changes during runtime', function()
+ clear({env={
+ XDG_CONFIG_HOME=alter_slashes('/home/original'),
+ }})
+ eq(alter_slashes('/home/original/nvim'), funcs.stdpath('config'))
+ command("let $XDG_CONFIG_HOME='"..alter_slashes('/home/new').."'")
+ eq(alter_slashes('/home/new/nvim'), funcs.stdpath('config'))
+ end)
+
+ it("doesn't expand $VARIABLES", function()
+ clear({env={
+ XDG_CONFIG_HOME='$VARIABLES',
+ VARIABLES='this-should-not-happen',
+ }})
+ eq(alter_slashes('$VARIABLES/nvim'), funcs.stdpath('config'))
+ end)
+
+ it("doesn't expand ~/", function()
+ clear({env={
+ XDG_CONFIG_HOME=alter_slashes('~/frobnitz'),
+ }})
+ eq(alter_slashes('~/frobnitz/nvim'), funcs.stdpath('config'))
+ end)
+ end)
+
+ describe('with "data"' , function ()
+ local appended_dir
+ setup(function()
+ -- Windows appends 'nvim-data' instead of just 'nvim' to
+ -- prevent collisions due to XDG_CONFIG_HOME and XDG_DATA_HOME
+ -- being the same.
+ if helpers.iswin() then
+ appended_dir = '/nvim-data'
+ else
+ appended_dir = '/nvim'
+ end
+ end)
+
+ it('knows XDG_DATA_HOME', function()
+ clear({env={
+ XDG_DATA_HOME=alter_slashes('/home/docwhat/.local'),
+ }})
+ eq(alter_slashes('/home/docwhat/.local' .. appended_dir), funcs.stdpath('data'))
+ end)
+
+ it('handles changes during runtime', function()
+ clear({env={
+ XDG_DATA_HOME=alter_slashes('/home/original'),
+ }})
+ eq(alter_slashes('/home/original' .. appended_dir), funcs.stdpath('data'))
+ command("let $XDG_DATA_HOME='"..alter_slashes('/home/new').."'")
+ eq(alter_slashes('/home/new' .. appended_dir), funcs.stdpath('data'))
+ end)
+
+ it("doesn't expand $VARIABLES", function()
+ clear({env={
+ XDG_DATA_HOME='$VARIABLES',
+ VARIABLES='this-should-not-happen',
+ }})
+ eq(alter_slashes('$VARIABLES' .. appended_dir), funcs.stdpath('data'))
+ end)
+
+ it("doesn't expand ~/", function()
+ clear({env={
+ XDG_DATA_HOME=alter_slashes('~/frobnitz'),
+ }})
+ eq(alter_slashes('~/frobnitz' .. appended_dir), funcs.stdpath('data'))
+ end)
+ end)
+
+ describe('with "cache"' , function ()
+ it('knows XDG_CACHE_HOME', function()
+ clear({env={
+ XDG_CACHE_HOME=alter_slashes('/home/docwhat/.cache'),
+ }})
+ eq(alter_slashes('/home/docwhat/.cache/nvim'), funcs.stdpath('cache'))
+ end)
+
+ it('handles changes during runtime', function()
+ clear({env={
+ XDG_CACHE_HOME=alter_slashes('/home/original'),
+ }})
+ eq(alter_slashes('/home/original/nvim'), funcs.stdpath('cache'))
+ command("let $XDG_CACHE_HOME='"..alter_slashes('/home/new').."'")
+ eq(alter_slashes('/home/new/nvim'), funcs.stdpath('cache'))
+ end)
+
+ it("doesn't expand $VARIABLES", function()
+ clear({env={
+ XDG_CACHE_HOME='$VARIABLES',
+ VARIABLES='this-should-not-happen',
+ }})
+ eq(alter_slashes('$VARIABLES/nvim'), funcs.stdpath('cache'))
+ end)
+
+ it("doesn't expand ~/", function()
+ clear({env={
+ XDG_CACHE_HOME=alter_slashes('~/frobnitz'),
+ }})
+ eq(alter_slashes('~/frobnitz/nvim'), funcs.stdpath('cache'))
+ end)
+ end)
+ end)
+
+ context('returns a List', function()
+ -- Some OS specific variables the system would have set.
+ local function base_env()
+ if helpers.iswin() then
+ return {
+ HOME='C:\\Users\\docwhat', -- technically, is not a usual PATH
+ HOMEDRIVE='C:',
+ HOMEPATH='\\Users\\docwhat',
+ LOCALAPPDATA='C:\\Users\\docwhat\\AppData\\Local',
+ TEMP='C:\\Users\\docwhat\\AppData\\Local\\Temp',
+ TMPDIR='C:\\Users\\docwhat\\AppData\\Local\\Temp',
+ TMP='C:\\Users\\docwhat\\AppData\\Local\\Temp',
+ }
+ else
+ return {
+ HOME='/home/docwhat',
+ HOMEDRIVE='HOMEDRIVE-should-be-ignored',
+ HOMEPATH='HOMEPATH-should-be-ignored',
+ LOCALAPPDATA='LOCALAPPDATA-should-be-ignored',
+ TEMP='TEMP-should-be-ignored',
+ TMPDIR='TMPDIR-should-be-ignored',
+ TMP='TMP-should-be-ignored',
+ }
+ end
+ end
+
+ local function set_paths_via_system(var_name, paths)
+ local env = base_env()
+ env[var_name] = table.concat(paths, ':')
+ clear({env=env})
+ end
+
+ local function set_paths_at_runtime(var_name, paths)
+ clear({env=base_env()})
+ meths.set_var('env_val', table.concat(paths, ':'))
+ command(('let $%s=g:env_val'):format(var_name))
+ end
+
+ local function behaves_like_dir_list_env(msg, stdpath_arg, env_var_name, paths, expected_paths)
+ describe(msg, function()
+ it('set via system', function()
+ set_paths_via_system(env_var_name, paths)
+ eq(expected_paths, funcs.stdpath(stdpath_arg))
+ end)
+
+ it('set at runtime', function()
+ set_paths_at_runtime(env_var_name, paths)
+ eq(expected_paths, funcs.stdpath(stdpath_arg))
+ end)
+ end)
+ end
+
+ describe('with "config_dirs"' , function ()
+ behaves_like_dir_list_env(
+ 'handles XDG_CONFIG_DIRS with one path',
+ 'config_dirs', 'XDG_CONFIG_DIRS',
+ {
+ alter_slashes('/home/docwhat/.config')
+ },
+ {
+ alter_slashes('/home/docwhat/.config/nvim')
+ })
+
+ behaves_like_dir_list_env(
+ 'handles XDG_CONFIG_DIRS with two paths',
+ 'config_dirs', 'XDG_CONFIG_DIRS',
+ {
+ alter_slashes('/home/docwhat/.config'),
+ alter_slashes('/etc/config')
+ },
+ {
+ alter_slashes('/home/docwhat/.config/nvim'),
+ alter_slashes('/etc/config/nvim')
+ })
+
+ behaves_like_dir_list_env(
+ "doesn't expand $VAR and $IBLES",
+ 'config_dirs', 'XDG_CONFIG_DIRS',
+ { '$HOME', '$TMP' },
+ {
+ alter_slashes('$HOME/nvim'),
+ alter_slashes('$TMP/nvim')
+ })
+
+
+ behaves_like_dir_list_env(
+ "doesn't expand ~/",
+ 'config_dirs', 'XDG_CONFIG_DIRS',
+ {
+ alter_slashes('~/.oldconfig'),
+ alter_slashes('~/.olderconfig')
+ },
+ {
+ alter_slashes('~/.oldconfig/nvim'),
+ alter_slashes('~/.olderconfig/nvim')
+ })
+ end)
+
+ describe('with "data_dirs"' , function ()
+ behaves_like_dir_list_env(
+ 'knows XDG_DATA_DIRS with one path',
+ 'data_dirs', 'XDG_DATA_DIRS',
+ {
+ alter_slashes('/home/docwhat/.data')
+ },
+ {
+ alter_slashes('/home/docwhat/.data/nvim')
+ })
+
+ behaves_like_dir_list_env(
+ 'knows XDG_DATA_DIRS with two paths',
+ 'data_dirs', 'XDG_DATA_DIRS',
+ {
+ alter_slashes('/home/docwhat/.data'),
+ alter_slashes('/etc/local')
+ },
+ {
+ alter_slashes('/home/docwhat/.data/nvim'),
+ alter_slashes('/etc/local/nvim'),
+ })
+
+ behaves_like_dir_list_env(
+ "doesn't expand $VAR and $IBLES",
+ 'data_dirs', 'XDG_DATA_DIRS',
+ { '$HOME', '$TMP' },
+ {
+ alter_slashes('$HOME/nvim'),
+ alter_slashes('$TMP/nvim')
+ })
+
+ behaves_like_dir_list_env(
+ "doesn't expand ~/",
+ 'data_dirs', 'XDG_DATA_DIRS',
+ {
+ alter_slashes('~/.oldconfig'),
+ alter_slashes('~/.olderconfig')
+ },
+ {
+ alter_slashes('~/.oldconfig/nvim'),
+ alter_slashes('~/.olderconfig/nvim'),
+ })
+ end)
+ end)
+
+ describe('errors', function()
+ it('on unknown strings', function()
+ eq('Vim(call):E6100: "capybara" is not a valid stdpath', exc_exec('call stdpath("capybara")'))
+ eq('Vim(call):E6100: "" is not a valid stdpath', exc_exec('call stdpath("")'))
+ eq('Vim(call):E6100: "23" is not a valid stdpath', exc_exec('call stdpath(23)'))
+ end)
+
+ it('on non-strings', function()
+ eq('Vim(call):E731: using Dictionary as a String', exc_exec('call stdpath({"eris": 23})'))
+ eq('Vim(call):E730: using List as a String', exc_exec('call stdpath([23])'))
+ end)
+ end)
+end)
diff --git a/test/functional/options/num_options_spec.lua b/test/functional/options/num_options_spec.lua
new file mode 100644
index 0000000000..ed17ffdd3c
--- /dev/null
+++ b/test/functional/options/num_options_spec.lua
@@ -0,0 +1,97 @@
+-- Tests for :setlocal and :setglobal
+
+local helpers = require('test.functional.helpers')(after_each)
+local clear, feed_command, eval, eq, meths =
+ helpers.clear, helpers.feed_command, helpers.eval, helpers.eq, helpers.meths
+
+local function should_fail(opt, value, errmsg)
+ feed_command('setglobal ' .. opt .. '=' .. value)
+ eq(errmsg, eval("v:errmsg"):match("E%d*"))
+ feed_command('let v:errmsg = ""')
+ feed_command('setlocal ' .. opt .. '=' .. value)
+ eq(errmsg, eval("v:errmsg"):match("E%d*"))
+ feed_command('let v:errmsg = ""')
+ local status, err = pcall(meths.set_option, opt, value)
+ eq(status, false)
+ eq(errmsg, err:match("E%d*"))
+ eq('', eval("v:errmsg"))
+end
+
+local function should_succeed(opt, value)
+ feed_command('setglobal ' .. opt .. '=' .. value)
+ feed_command('setlocal ' .. opt .. '=' .. value)
+ meths.set_option(opt, value)
+ eq(value, meths.get_option(opt))
+ eq('', eval("v:errmsg"))
+end
+
+describe(':setlocal', function()
+ before_each(clear)
+
+ it('setlocal sets only local value', function()
+ eq(0, meths.get_option('iminsert'))
+ feed_command('setlocal iminsert=1')
+ eq(0, meths.get_option('iminsert'))
+ eq(0, meths.get_option('imsearch'))
+ feed_command('setlocal imsearch=1')
+ eq(0, meths.get_option('imsearch'))
+ end)
+end)
+
+describe(':set validation', function()
+ before_each(clear)
+
+ it('setlocal and setglobal validate values', function()
+ should_fail('shiftwidth', -10, 'E487')
+ should_succeed('shiftwidth', 0)
+ should_fail('tabstop', -10, 'E487')
+ should_fail('winheight', -10, 'E487')
+ should_fail('winheight', 0, 'E487')
+ should_fail('winminheight', -1, 'E487')
+ should_succeed('winminheight', 0)
+ should_fail('winwidth', 0, 'E487')
+ should_fail('helpheight', -1, 'E487')
+ should_fail('maxcombine', 7, 'E474')
+ should_fail('iminsert', 3, 'E474')
+ should_fail('imsearch', 3, 'E474')
+ should_fail('titlelen', -1, 'E487')
+ should_fail('cmdheight', 0, 'E487')
+ should_fail('updatecount', -1, 'E487')
+ should_fail('textwidth', -1, 'E487')
+ should_fail('tabstop', 0, 'E487')
+ should_fail('timeoutlen', -1, 'E487')
+ should_fail('history', 1000000, 'E474')
+ should_fail('regexpengine', -1, 'E474')
+ should_fail('regexpengine', 3, 'E474')
+ should_succeed('regexpengine', 2)
+ should_fail('report', -1, 'E487')
+ should_succeed('report', 0)
+ should_fail('scrolloff', -1, 'E49')
+ should_fail('sidescrolloff', -1, 'E487')
+ should_fail('sidescroll', -1, 'E487')
+ should_fail('cmdwinheight', 0, 'E487')
+ should_fail('updatetime', -1, 'E487')
+
+ should_fail('foldlevel', -5, 'E487')
+ should_fail('foldcolumn', 13, 'E474')
+ should_fail('conceallevel', 4, 'E474')
+ should_fail('numberwidth', 11, 'E474')
+ should_fail('numberwidth', 0, 'E487')
+
+ -- If smaller than 1 this one is set to 'lines'-1
+ feed_command('setglobal window=-10')
+ meths.set_option('window', -10)
+ eq(23, meths.get_option('window'))
+ eq('', eval("v:errmsg"))
+ end)
+
+ it('set wmh/wh wmw/wiw checks', function()
+ feed_command('set winheight=2')
+ feed_command('set winminheight=3')
+ eq('E591', eval("v:errmsg"):match("E%d*"))
+
+ feed_command('set winwidth=2')
+ feed_command('set winminwidth=3')
+ eq('E592', eval("v:errmsg"):match("E%d*"))
+ end)
+end)
diff --git a/test/functional/shada/merging_spec.lua b/test/functional/shada/merging_spec.lua
index 7a15c8908b..a628baff53 100644
--- a/test/functional/shada/merging_spec.lua
+++ b/test/functional/shada/merging_spec.lua
@@ -525,6 +525,85 @@ describe('ShaDa marks support code', function()
eq('-', funcs.fnamemodify(curbufmeths.get_name(), ':t'))
end)
+ it('can merge with file with mark 9 as the only numeric mark', function()
+ wshada('\007\001\014\130\161f\196\006' .. mock_file_path .. '-\161n9')
+ eq(0, exc_exec(sdrcmd()))
+ nvim_command('normal! `9oabc')
+ eq('-', funcs.fnamemodify(curbufmeths.get_name(), ':t'))
+ eq(0, exc_exec('wshada ' .. shada_fname))
+ local found = {}
+ for _, v in ipairs(read_shada_file(shada_fname)) do
+ if v.type == 7 and v.value.f == mock_file_path .. '-' then
+ local name = ('%c'):format(v.value.n)
+ found[name] = (found[name] or 0) + 1
+ end
+ end
+ eq({['0']=1, ['1']=1}, found)
+ end)
+
+ it('removes duplicates while merging', function()
+ wshada('\007\001\014\130\161f\196\006' .. mock_file_path .. '-\161n9'
+ .. '\007\001\014\130\161f\196\006' .. mock_file_path .. '-\161n9')
+ eq(0, exc_exec(sdrcmd()))
+ eq(0, exc_exec('wshada ' .. shada_fname))
+ local found = 0
+ for _, v in ipairs(read_shada_file(shada_fname)) do
+ if v.type == 7 and v.value.f == mock_file_path .. '-' then
+ print(require('test.helpers').format_luav(v))
+ found = found + 1
+ end
+ end
+ eq(1, found)
+ end)
+
+ it('does not leak when no append is performed due to too many marks',
+ function()
+ wshada('\007\002\018\131\162mX\195\161f\196\006' .. mock_file_path .. 'a\161n0'
+ .. '\007\002\018\131\162mX\195\161f\196\006' .. mock_file_path .. 'b\161n1'
+ .. '\007\002\018\131\162mX\195\161f\196\006' .. mock_file_path .. 'c\161n2'
+ .. '\007\002\018\131\162mX\195\161f\196\006' .. mock_file_path .. 'd\161n3'
+ .. '\007\002\018\131\162mX\195\161f\196\006' .. mock_file_path .. 'e\161n4'
+ .. '\007\002\018\131\162mX\195\161f\196\006' .. mock_file_path .. 'f\161n5'
+ .. '\007\002\018\131\162mX\195\161f\196\006' .. mock_file_path .. 'g\161n6'
+ .. '\007\002\018\131\162mX\195\161f\196\006' .. mock_file_path .. 'h\161n7'
+ .. '\007\002\018\131\162mX\195\161f\196\006' .. mock_file_path .. 'i\161n8'
+ .. '\007\002\018\131\162mX\195\161f\196\006' .. mock_file_path .. 'j\161n9'
+ .. '\007\001\018\131\162mX\195\161f\196\006' .. mock_file_path .. 'k\161n9')
+ eq(0, exc_exec(sdrcmd()))
+ eq(0, exc_exec('wshada ' .. shada_fname))
+ local found = {}
+ for _, v in ipairs(read_shada_file(shada_fname)) do
+ if v.type == 7 and v.value.f:sub(1, #mock_file_path) == mock_file_path then
+ found[#found + 1] = v.value.f:sub(#v.value.f)
+ end
+ end
+ eq({'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'}, found)
+ end)
+
+ it('does not leak when last mark in file removes some of the earlier ones',
+ function()
+ wshada('\007\002\018\131\162mX\195\161f\196\006' .. mock_file_path .. 'a\161n0'
+ .. '\007\002\018\131\162mX\195\161f\196\006' .. mock_file_path .. 'b\161n1'
+ .. '\007\002\018\131\162mX\195\161f\196\006' .. mock_file_path .. 'c\161n2'
+ .. '\007\002\018\131\162mX\195\161f\196\006' .. mock_file_path .. 'd\161n3'
+ .. '\007\002\018\131\162mX\195\161f\196\006' .. mock_file_path .. 'e\161n4'
+ .. '\007\002\018\131\162mX\195\161f\196\006' .. mock_file_path .. 'f\161n5'
+ .. '\007\002\018\131\162mX\195\161f\196\006' .. mock_file_path .. 'g\161n6'
+ .. '\007\002\018\131\162mX\195\161f\196\006' .. mock_file_path .. 'h\161n7'
+ .. '\007\002\018\131\162mX\195\161f\196\006' .. mock_file_path .. 'i\161n8'
+ .. '\007\002\018\131\162mX\195\161f\196\006' .. mock_file_path .. 'j\161n9'
+ .. '\007\003\018\131\162mX\195\161f\196\006' .. mock_file_path .. 'k\161n9')
+ eq(0, exc_exec(sdrcmd()))
+ eq(0, exc_exec('wshada ' .. shada_fname))
+ local found = {}
+ for _, v in ipairs(read_shada_file(shada_fname)) do
+ if v.type == 7 and v.value.f:sub(1, #mock_file_path) == mock_file_path then
+ found[#found + 1] = v.value.f:sub(#v.value.f)
+ end
+ end
+ eq({'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'k'}, found)
+ end)
+
it('uses last A mark with gt timestamp from file when reading with !',
function()
wshada('\007\001\018\131\162mX\195\161f\196\006' .. mock_file_path .. '-\161nA')
@@ -563,13 +642,14 @@ describe('ShaDa marks support code', function()
nvim_command('normal! `A')
eq('-', funcs.fnamemodify(curbufmeths.get_name(), ':t'))
eq(0, exc_exec('wshada ' .. shada_fname))
- local found = 0
+ local found = {}
for _, v in ipairs(read_shada_file(shada_fname)) do
- if v.type == 7 and v.value.f == '' .. mock_file_path .. '-' then
- found = found + 1
+ if v.type == 7 and v.value.f == mock_file_path .. '-' then
+ local name = ('%c'):format(v.value.n)
+ found[name] = (found[name] or 0) + 1
end
end
- eq(1, found)
+ eq({['0']=1, A=1}, found)
end)
it('uses last A mark with eq timestamp from instance when writing',
@@ -580,30 +660,33 @@ describe('ShaDa marks support code', function()
nvim_command('normal! `A')
eq('-', funcs.fnamemodify(curbufmeths.get_name(), ':t'))
eq(0, exc_exec('wshada ' .. shada_fname))
- local found = 0
+ local found = {}
for _, v in ipairs(read_shada_file(shada_fname)) do
if v.type == 7 and v.value.f == mock_file_path .. '-' then
- found = found + 1
+ local name = ('%c'):format(v.value.n)
+ found[name] = (found[name] or 0) + 1
end
end
- eq(1, found)
+ eq({['0']=1, A=1}, found)
end)
- it('uses last A mark with gt timestamp from file when writing',
- function()
+ it('uses last A mark with gt timestamp from file when writing', function()
wshada('\007\001\018\131\162mX\195\161f\196\006' .. mock_file_path .. '-\161nA')
eq(0, exc_exec(sdrcmd()))
wshada('\007\002\018\131\162mX\195\161f\196\006' .. mock_file_path .. '?\161nA')
nvim_command('normal! `A')
eq('-', funcs.fnamemodify(curbufmeths.get_name(), ':t'))
eq(0, exc_exec('wshada ' .. shada_fname))
- local found = 0
+ local found = {}
for _, v in ipairs(read_shada_file(shada_fname)) do
- if v.type == 7 and v.value.f == '' .. mock_file_path .. '?' then
- found = found + 1
+ if v.type == 7 then
+ local name = ('%c'):format(v.value.n)
+ local t = found[name] or {}
+ t[v.value.f] = (t[v.value.f] or 0) + 1
+ found[name] = t
end
end
- eq(1, found)
+ eq({['0']={[mock_file_path .. '-']=1}, A={[mock_file_path .. '?']=1}}, found)
end)
it('uses last a mark with gt timestamp from instance when reading',
diff --git a/test/functional/shada/shada_spec.lua b/test/functional/shada/shada_spec.lua
index ca44026852..720855860a 100644
--- a/test/functional/shada/shada_spec.lua
+++ b/test/functional/shada/shada_spec.lua
@@ -181,13 +181,13 @@ describe('ShaDa support code', function()
nvim_command('set shada+=%')
nvim_command('wshada! ' .. shada_fname)
local readme_fname = funcs.resolve(paths.test_source_path) .. '/README.md'
- eq({[7]=1, [8]=2, [9]=1, [10]=4, [11]=1}, find_file(readme_fname))
+ eq({[7]=2, [8]=2, [9]=1, [10]=4, [11]=1}, find_file(readme_fname))
nvim_command('set shada+=r~')
nvim_command('wshada! ' .. shada_fname)
eq({}, find_file(readme_fname))
nvim_command('set shada-=r~')
nvim_command('wshada! ' .. shada_fname)
- eq({[7]=1, [8]=2, [9]=1, [10]=4, [11]=1}, find_file(readme_fname))
+ eq({[7]=2, [8]=2, [9]=1, [10]=4, [11]=1}, find_file(readme_fname))
nvim_command('set shada+=r' .. funcs.escape(
funcs.escape(paths.test_source_path, '$~'), ' "\\,'))
nvim_command('wshada! ' .. shada_fname)
@@ -206,7 +206,7 @@ describe('ShaDa support code', function()
nvim_command('undo')
nvim_command('set shada+=%')
nvim_command('wshada! ' .. shada_fname)
- eq({[7]=1, [8]=2, [9]=1, [10]=4, [11]=2}, find_file(fname))
+ eq({[7]=2, [8]=2, [9]=1, [10]=4, [11]=2}, find_file(fname))
nvim_command('set shada+=r' .. pwd .. '/АБВ')
nvim_command('wshada! ' .. shada_fname)
eq({}, find_file(fname))
diff --git a/test/functional/terminal/tui_spec.lua b/test/functional/terminal/tui_spec.lua
index 171745eb57..2f9abfd3f6 100644
--- a/test/functional/terminal/tui_spec.lua
+++ b/test/functional/terminal/tui_spec.lua
@@ -115,16 +115,12 @@ describe('tui', function()
]])
end)
- it('does not mangle unmapped ALT-key chord', function()
- -- Vim represents ALT/META by setting the "high bit" of the modified key;
- -- we do _not_. #3982
- --
- -- Example: for input ALT+j:
- -- * Vim (Nvim prior to #3982) sets high-bit, inserts "ê".
- -- * Nvim (after #3982) inserts "j".
- feed_data('i\027j')
+ it('interprets ESC+key as ALT chord', function()
+ -- Vim represents ALT/META by setting the "high bit" of the modified key:
+ -- ALT+j inserts "ê". Nvim does not (#3982).
+ feed_data('i\022\027j')
screen:expect([[
- j{1: } |
+ <M-j>{1: } |
{4:~ }|
{4:~ }|
{4:~ }|
diff --git a/test/functional/ui/cmdline_highlight_spec.lua b/test/functional/ui/cmdline_highlight_spec.lua
index ffb6a26aef..3c316d1cfa 100644
--- a/test/functional/ui/cmdline_highlight_spec.lua
+++ b/test/functional/ui/cmdline_highlight_spec.lua
@@ -24,6 +24,7 @@ before_each(function()
clear()
screen = Screen.new(40, 8)
screen:attach()
+ command("set display-=msgsep")
source([[
highlight RBP1 guibg=Red
highlight RBP2 guibg=Yellow
@@ -737,6 +738,22 @@ describe('Command-line coloring', function()
feed('<CR><CR>')
eq('', meths.get_var('out'))
end)
+ it('does not crash when callback has caught not-a-editor-command exception',
+ function()
+ source([[
+ function CaughtExc(cmdline) abort
+ try
+ gibberish
+ catch
+ " Do nothing
+ endtry
+ return []
+ endfunction
+ ]])
+ set_color_cb('CaughtExc')
+ start_prompt('1')
+ eq(1, meths.eval('1'))
+ end)
end)
describe('Ex commands coloring support', function()
it('works', function()
diff --git a/test/functional/ui/cursor_spec.lua b/test/functional/ui/cursor_spec.lua
index b47210a777..812c095add 100644
--- a/test/functional/ui/cursor_spec.lua
+++ b/test/functional/ui/cursor_spec.lua
@@ -194,8 +194,8 @@ describe('ui/cursor', function()
if m.blinkoff then m.blinkoff = 400 end
if m.blinkwait then m.blinkwait = 700 end
end
- if m.hl_id then m.hl_id = 48 end
- if m.id_lm then m.id_lm = 49 end
+ if m.hl_id then m.hl_id = 49 end
+ if m.id_lm then m.id_lm = 50 end
end
-- Assert the new expectation.
diff --git a/test/functional/ui/highlight_spec.lua b/test/functional/ui/highlight_spec.lua
index 6f1b31964b..ab3b1c3cac 100644
--- a/test/functional/ui/highlight_spec.lua
+++ b/test/functional/ui/highlight_spec.lua
@@ -94,6 +94,7 @@ describe('highlight defaults', function()
clear()
screen = Screen.new()
screen:attach()
+ command("set display-=msgsep")
end)
after_each(function()
@@ -312,7 +313,7 @@ describe('highlight defaults', function()
end)
end)
-describe('guisp (special/undercurl)', function()
+describe('highlight', function()
local screen
before_each(function()
@@ -321,7 +322,31 @@ describe('guisp (special/undercurl)', function()
screen:attach()
end)
- it('can be set and is applied like foreground or background', function()
+ it('cterm=standout gui=standout', function()
+ screen:detach()
+ screen = Screen.new(20,5)
+ screen:attach()
+ screen:set_default_attr_ids({
+ [1] = {bold = true, foreground = Screen.colors.Blue1},
+ [2] = {standout = true, bold = true, underline = true,
+ background = Screen.colors.Gray90, foreground = Screen.colors.Blue1},
+ [3] = {standout = true, underline = true,
+ background = Screen.colors.Gray90}
+ })
+ feed_command('hi CursorLine cterm=standout,underline gui=standout,underline')
+ feed_command('set cursorline')
+ feed_command('set listchars=space:.,eol:¬,tab:>-,extends:>,precedes:<,trail:* list')
+ feed('i\t abcd <cr>\t abcd <cr><esc>k')
+ screen:expect([[
+ {1:>-------.}abcd{1:*¬} |
+ {2:^>-------.}{3:abcd}{2:*¬}{3: }|
+ {1:¬} |
+ {1:~ }|
+ |
+ ]])
+ end)
+
+ it('guisp (special/undercurl)', function()
feed_command('syntax on')
feed_command('syn keyword TmpKeyword neovim')
feed_command('syn keyword TmpKeyword1 special')
@@ -650,6 +675,76 @@ describe("'listchars' highlight", function()
end)
end)
+describe("MsgSeparator highlight and msgsep fillchar", function()
+ before_each(clear)
+ it("works", function()
+ local screen = Screen.new(50,5)
+ screen:set_default_attr_ids({
+ [1] = {bold=true, foreground=Screen.colors.Blue},
+ [2] = {bold=true, reverse=true},
+ [3] = {bold = true, foreground = Screen.colors.SeaGreen4},
+ [4] = {background = Screen.colors.Cyan, bold = true, reverse = true},
+ [5] = {bold = true, background = Screen.colors.Magenta}
+ })
+ screen:attach()
+
+ -- defaults
+ feed_command("ls")
+ screen:expect([[
+ |
+ {2: }|
+ :ls |
+ 1 %a "[No Name]" line 1 |
+ {3:Press ENTER or type command to continue}^ |
+ ]])
+ feed('<cr>')
+
+ feed_command("set fillchars+=msgsep:-")
+ feed_command("ls")
+ screen:expect([[
+ |
+ {2:--------------------------------------------------}|
+ :ls |
+ 1 %a "[No Name]" line 1 |
+ {3:Press ENTER or type command to continue}^ |
+ ]])
+
+ -- linked to StatusLine per default
+ feed_command("hi StatusLine guibg=Cyan")
+ feed_command("ls")
+ screen:expect([[
+ |
+ {4:--------------------------------------------------}|
+ :ls |
+ 1 %a "[No Name]" line 1 |
+ {3:Press ENTER or type command to continue}^ |
+ ]])
+
+ -- but can be unlinked
+ feed_command("hi clear MsgSeparator")
+ feed_command("hi MsgSeparator guibg=Magenta gui=bold")
+ feed_command("ls")
+ screen:expect([[
+ |
+ {5:--------------------------------------------------}|
+ :ls |
+ 1 %a "[No Name]" line 1 |
+ {3:Press ENTER or type command to continue}^ |
+ ]])
+
+ -- when display doesn't contain msgsep, these options have no effect
+ feed_command("set display-=msgsep")
+ feed_command("ls")
+ screen:expect([[
+ {1:~ }|
+ {1:~ }|
+ :ls |
+ 1 %a "[No Name]" line 1 |
+ {3:Press ENTER or type command to continue}^ |
+ ]])
+ end)
+end)
+
describe("'winhighlight' highlight", function()
local screen
@@ -683,6 +778,9 @@ describe("'winhighlight' highlight", function()
[22] = {bold = true, foreground = Screen.colors.SeaGreen4},
[23] = {background = Screen.colors.LightMagenta},
[24] = {background = Screen.colors.WebGray},
+ [25] = {bold = true, foreground = Screen.colors.Green1},
+ [26] = {background = Screen.colors.Red},
+ [27] = {background = Screen.colors.DarkBlue, bold = true, foreground = Screen.colors.Green1},
})
command("hi Background1 guibg=DarkBlue")
command("hi Background2 guibg=DarkGreen")
@@ -952,6 +1050,39 @@ describe("'winhighlight' highlight", function()
]])
end)
+ it("background doesn't override syntax background", function()
+ command('syntax on')
+ command('syntax keyword Foobar foobar')
+ command('syntax keyword Article the')
+ command('hi Foobar guibg=#FF0000')
+ command('hi Article guifg=#00FF00 gui=bold')
+ insert('the foobar was foobar')
+ screen:expect([[
+ {25:the} {26:foobar} was {26:fooba}|
+ {26:^r} |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ |
+ ]])
+
+ -- winhl=Normal:Group with background doesn't override syntax background,
+ -- but does combine with syntax foreground.
+ command('set winhl=Normal:Background1')
+ screen:expect([[
+ {27:the}{1: }{26:foobar}{1: was }{26:fooba}|
+ {26:^r}{1: }|
+ {2:~ }|
+ {2:~ }|
+ {2:~ }|
+ {2:~ }|
+ {2:~ }|
+ |
+ ]])
+ end)
+
it('can override NonText, Conceal and EndOfBuffer', function()
curbufmeths.set_lines(0,-1,true, {"raa\000"})
command('call matchaddpos("Conceal", [[1,2]], 0, -1, {"conceal": "#"})')
diff --git a/test/functional/ui/inccommand_spec.lua b/test/functional/ui/inccommand_spec.lua
index 8b0cb82365..27e4066d9f 100644
--- a/test/functional/ui/inccommand_spec.lua
+++ b/test/functional/ui/inccommand_spec.lua
@@ -63,6 +63,7 @@ local function common_setup(screen, inccommand, text)
command("syntax on")
command("set nohlsearch")
command("hi Substitute guifg=red guibg=yellow")
+ command("set display-=msgsep")
screen:attach()
screen:set_default_attr_ids({
[1] = {foreground = Screen.colors.Fuchsia},
diff --git a/test/functional/ui/input_spec.lua b/test/functional/ui/input_spec.lua
index 8e62a37ef1..3dd9a2506e 100644
--- a/test/functional/ui/input_spec.lua
+++ b/test/functional/ui/input_spec.lua
@@ -1,6 +1,7 @@
local helpers = require('test.functional.helpers')(after_each)
local clear, feed_command, nvim = helpers.clear, helpers.feed_command, helpers.nvim
local feed, next_msg, eq = helpers.feed, helpers.next_msg, helpers.eq
+local command = helpers.command
local expect = helpers.expect
local write_file = helpers.write_file
local Screen = require('test.functional.ui.screen')
@@ -127,6 +128,10 @@ describe('input utf sequences that contain CSI/K_SPECIAL', function()
end)
describe('input non-printable chars', function()
+ after_each(function()
+ os.remove('Xtest-overwrite')
+ end)
+
it("doesn't crash when echoing them back", function()
write_file("Xtest-overwrite", [[foobar]])
clear()
@@ -137,6 +142,7 @@ describe('input non-printable chars', function()
[3] = {bold = true, foreground = Screen.colors.SeaGreen4}
})
screen:attach()
+ command("set display-=msgsep")
feed_command("e Xtest-overwrite")
screen:expect([[
diff --git a/test/functional/ui/mouse_spec.lua b/test/functional/ui/mouse_spec.lua
index 05d5a6409a..debd324977 100644
--- a/test/functional/ui/mouse_spec.lua
+++ b/test/functional/ui/mouse_spec.lua
@@ -26,6 +26,7 @@ describe('ui/mouse/input', function()
[4] = {reverse = true},
[5] = {bold = true, reverse = true},
})
+ command("set display-=msgsep")
feed('itesting<cr>mouse<cr>support and selection<esc>')
screen:expect([[
testing |
diff --git a/test/functional/ui/output_spec.lua b/test/functional/ui/output_spec.lua
index 4246020fab..02ca566bd8 100644
--- a/test/functional/ui/output_spec.lua
+++ b/test/functional/ui/output_spec.lua
@@ -40,10 +40,10 @@ describe("shell command :!", function()
-- to avoid triggering a UI flush.
child_session.feed_data(":!printf foo; sleep 200\n")
screen:expect([[
+ |
{4:~ }|
{4:~ }|
- {4:~ }|
- {4:~ }|
+ {5: }|
:!printf foo; sleep 200 |
foo |
{3:-- TERMINAL --} |
@@ -99,6 +99,7 @@ describe("shell command :!", function()
end
local screen = Screen.new(50, 4)
screen:attach()
+ command("set display-=msgsep")
-- Print TAB chars. #2958
feed([[:!printf '1\t2\t3'<CR>]])
screen:expect([[
@@ -153,6 +154,7 @@ describe("shell command :!", function()
[1] = {bold = true, foreground = Screen.colors.Blue1},
[2] = {foreground = Screen.colors.Blue1},
[3] = {bold = true, foreground = Screen.colors.SeaGreen4},
+ [4] = {bold = true, reverse = true},
})
screen:attach()
end)
@@ -170,10 +172,10 @@ describe("shell command :!", function()
or [[:!ls bang_filter_spec ]])
feed([[\l]])
screen:expect([[
+ |
{1:~ }|
{1:~ }|
- {1:~ }|
- {1:~ }|
+ {4: }|
]]..result..[[ |
f1 |
f2 |
@@ -187,9 +189,9 @@ describe("shell command :!", function()
feed_command('!cat test/functional/fixtures/shell_data.txt')
screen.bell = false
screen:expect([[
+ |
{1:~ }|
- {1:~ }|
- {1:~ }|
+ {4: }|
:!cat test/functional/fixtures/shell_data.txt |
{2:^@^A^B^C^D^E^F^H} |
{2:^N^O^P^Q^R^S^T^U^V^W^X^Y^Z^[^\^]^^^_} |
@@ -213,8 +215,8 @@ describe("shell command :!", function()
feed_command(cmd)
-- Note: only the first example of split composed char works
screen:expect([[
- {1:~ }|
- {1:~ }|
+ |
+ {4: }|
:]]..cmd..[[ |
å |
ref: å̲ |
diff --git a/test/functional/ui/screen_basic_spec.lua b/test/functional/ui/screen_basic_spec.lua
index bbdf576641..7fafd6b352 100644
--- a/test/functional/ui/screen_basic_spec.lua
+++ b/test/functional/ui/screen_basic_spec.lua
@@ -76,11 +76,26 @@ describe('Screen', function()
local function check()
eq(true, screen.suspended)
end
+
+ command('let g:ev = []')
+ command('autocmd VimResume * :call add(g:ev, "r")')
+ command('autocmd VimSuspend * :call add(g:ev, "s")')
+
+ eq(false, screen.suspended)
command('suspend')
+ eq({ 's', 'r' }, eval('g:ev'))
+
screen:expect(check)
screen.suspended = false
+
feed('<c-z>')
+ eq({ 's', 'r', 's', 'r' }, eval('g:ev'))
+
screen:expect(check)
+ screen.suspended = false
+
+ command('suspend')
+ eq({ 's', 'r', 's', 'r', 's', 'r' }, eval('g:ev'))
end)
end)
@@ -355,7 +370,8 @@ describe('Screen', function()
]])
end)
- it('execute command with multi-line output', function()
+ it('execute command with multi-line output without msgsep', function()
+ command("set display-=msgsep")
feed(':ls<cr>')
screen:expect([[
{0:~ }|
@@ -375,6 +391,28 @@ describe('Screen', function()
]])
feed('<cr>') -- skip the "Press ENTER..." state or tests will hang
end)
+
+ it('execute command with multi-line output and with msgsep', function()
+ command("set display+=msgsep")
+ feed(':ls<cr>')
+ screen:expect([[
+ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {1: }|
+ :ls |
+ 1 %a "[No Name]" line 1 |
+ {7:Press ENTER or type command to continue}^ |
+ ]])
+ feed('<cr>') -- skip the "Press ENTER..." state or tests will hang
+ end)
end)
describe('scrolling and clearing', function()
@@ -573,6 +611,7 @@ describe('Screen', function()
command('nnoremap <F1> :echo "TEST"<CR>')
feed(':ls<CR>')
screen:expect([[
+ |
{0:~ }|
{0:~ }|
{0:~ }|
@@ -582,8 +621,7 @@ describe('Screen', function()
{0:~ }|
{0:~ }|
{0:~ }|
- {0:~ }|
- {0:~ }|
+ {1: }|
:ls |
1 %a "[No Name]" line 1 |
{7:Press ENTER or type command to continue}^ |
@@ -608,21 +646,3 @@ describe('Screen', function()
end)
end)
end)
-
-describe('nvim_ui_attach()', function()
- before_each(function()
- clear()
- end)
- it('handles very large width/height #2180', function()
- local screen = Screen.new(999, 999)
- screen:attach()
- eq(999, eval('&lines'))
- eq(999, eval('&columns'))
- end)
- it('invalid option returns error', function()
- local screen = Screen.new()
- local status, rv = pcall(function() screen:attach({foo={'foo'}}) end)
- eq(false, status)
- eq('No such ui option', rv:match("No such .*"))
- end)
-end)
diff --git a/test/helpers.lua b/test/helpers.lua
index 91ceed4df1..e0645d083f 100644
--- a/test/helpers.lua
+++ b/test/helpers.lua
@@ -16,6 +16,19 @@ end
local function ok(res)
return assert.is_true(res)
end
+local function matches(pat, actual)
+ if nil ~= string.match(actual, pat) then
+ return true
+ end
+ error(string.format('Pattern does not match.\nPattern:\n%s\nActual:\n%s', pat, actual))
+end
+-- Expect an error matching pattern `pat`.
+local function expect_err(pat, ...)
+ local fn = select(1, ...)
+ local fn_args = {...}
+ table.remove(fn_args, 1)
+ assert.error_matches(function() return fn(unpack(fn_args)) end, pat)
+end
-- initial_path: directory to recurse into
-- re: include pattern (string)
@@ -469,6 +482,8 @@ format_luav = function(v, indent, opts)
end
elseif type(v) == 'nil' then
ret = 'nil'
+ elseif type(v) == 'boolean' then
+ ret = (v and 'true' or 'false')
else
print(type(v))
-- Not implemented yet
@@ -561,6 +576,7 @@ return {
deepcopy = deepcopy,
dictdiff = dictdiff,
eq = eq,
+ expect_err = expect_err,
filter = filter,
fixtbl = fixtbl,
fixtbl_rec = fixtbl_rec,
@@ -570,6 +586,7 @@ return {
hasenv = hasenv,
intchar2lua = intchar2lua,
map = map,
+ matches = matches,
mergedicts_copy = mergedicts_copy,
neq = neq,
ok = ok,
diff --git a/third-party/CMakeLists.txt b/third-party/CMakeLists.txt
index d082e8d883..30503e3c4a 100644
--- a/third-party/CMakeLists.txt
+++ b/third-party/CMakeLists.txt
@@ -124,13 +124,8 @@ set(LUAROCKS_SHA256 ea1881d6954f2a98c34f93674571c8f0cbdbc28dedb3fa3cb56b6a91886d
set(UNIBILIUM_URL https://github.com/mauke/unibilium/archive/v2.0.0.tar.gz)
set(UNIBILIUM_SHA256 78997d38d4c8177c60d3d0c1aa8c53fd0806eb21825b7b335b1768d7116bc1c1)
-if(WIN32)
-set(LIBTERMKEY_URL https://github.com/equalsraf/libtermkey/archive/tb-windows.zip)
-set(LIBTERMKEY_SHA256 c81e33e38662b151a49847ff4feef4f8c4b2a66f3e159a28b575cbc9bcd8ffea)
-else()
set(LIBTERMKEY_URL http://www.leonerd.org.uk/code/libtermkey/libtermkey-0.20.tar.gz)
set(LIBTERMKEY_SHA256 6c0d87c94ab9915e76ecd313baec08dedf3bd56de83743d9aa923a081935d2f5)
-endif()
set(LIBVTERM_URL https://github.com/neovim/libvterm/archive/a9c7c6fd20fa35e0ad3e0e98901ca12dfca9c25c.tar.gz)
set(LIBVTERM_SHA256 1a4272be91d9614dc183a503786df83b6584e4afaab7feaaa5409f841afbd796)
diff --git a/third-party/cmake/BuildGperf.cmake b/third-party/cmake/BuildGperf.cmake
index fd11aa1998..fa8b35f383 100644
--- a/third-party/cmake/BuildGperf.cmake
+++ b/third-party/cmake/BuildGperf.cmake
@@ -40,7 +40,7 @@ if(UNIX OR (MINGW AND CMAKE_CROSSCOMPILING))
BuildGperf(
CONFIGURE_COMMAND ${DEPS_BUILD_DIR}/src/gperf/configure
- --prefix=${HOSTDEPS_INSTALL_DIR}
+ --prefix=${HOSTDEPS_INSTALL_DIR} MAKE=${MAKE_PRG}
INSTALL_COMMAND ${MAKE_PRG} install)
elseif(MSVC OR MINGW)
@@ -61,4 +61,3 @@ elseif(MSVC OR MINGW)
else()
message(FATAL_ERROR "Trying to build gperf in an unsupported system ${CMAKE_SYSTEM_NAME}/${CMAKE_C_COMPILER_ID}")
endif()
-
diff --git a/third-party/cmake/BuildLibtermkey.cmake b/third-party/cmake/BuildLibtermkey.cmake
index b5cd0c4ca6..8147c47e1e 100644
--- a/third-party/cmake/BuildLibtermkey.cmake
+++ b/third-party/cmake/BuildLibtermkey.cmake
@@ -11,14 +11,22 @@ ExternalProject_Add(libtermkey
-DTARGET=libtermkey
-DUSE_EXISTING_SRC_DIR=${USE_EXISTING_SRC_DIR}
-P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/DownloadAndExtractFile.cmake
- CONFIGURE_COMMAND ${CMAKE_COMMAND} ${DEPS_BUILD_DIR}/src/libtermkey
- -DCMAKE_INSTALL_PREFIX=${DEPS_INSTALL_DIR}
- # Pass toolchain
- -DCMAKE_TOOLCHAIN_FILE=${TOOLCHAIN}
- -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}
- # Hack to avoid -rdynamic in Mingw
- -DCMAKE_SHARED_LIBRARY_LINK_C_FLAGS=""
- -DCMAKE_GENERATOR=${CMAKE_GENERATOR}
+ PATCH_COMMAND ${GIT_EXECUTABLE} -C ${DEPS_BUILD_DIR}/src/libtermkey init
+ COMMAND ${GIT_EXECUTABLE} -C ${DEPS_BUILD_DIR}/src/libtermkey apply --ignore-whitespace
+ ${CMAKE_CURRENT_SOURCE_DIR}/patches/libtermkey-Add-support-for-Windows.patch
+ CONFIGURE_COMMAND ${CMAKE_COMMAND} -E copy
+ ${CMAKE_CURRENT_SOURCE_DIR}/cmake/libtermkeyCMakeLists.txt
+ ${DEPS_BUILD_DIR}/src/libtermkey/CMakeLists.txt
+ COMMAND ${CMAKE_COMMAND} ${DEPS_BUILD_DIR}/src/libtermkey
+ -DCMAKE_INSTALL_PREFIX=${DEPS_INSTALL_DIR}
+ # Pass toolchain
+ -DCMAKE_TOOLCHAIN_FILE=${TOOLCHAIN}
+ -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}
+ # Hack to avoid -rdynamic in Mingw
+ -DCMAKE_SHARED_LIBRARY_LINK_C_FLAGS=""
+ -DCMAKE_GENERATOR=${CMAKE_GENERATOR}
+ -DUNIBILIUM_INCLUDE_DIRS=${DEPS_INSTALL_DIR}/include
+ -DUNIBILIUM_LIBRARIES=${DEPS_LIB_DIR}/${CMAKE_STATIC_LIBRARY_PREFIX}unibilium${CMAKE_STATIC_LIBRARY_SUFFIX}
BUILD_COMMAND ${CMAKE_COMMAND} --build . --config ${CMAKE_BUILD_TYPE}
INSTALL_COMMAND ${CMAKE_COMMAND} --build . --target install --config ${CMAKE_BUILD_TYPE})
else()
diff --git a/third-party/cmake/BuildLibuv.cmake b/third-party/cmake/BuildLibuv.cmake
index f6a9660d1c..8ac7624be6 100644
--- a/third-party/cmake/BuildLibuv.cmake
+++ b/third-party/cmake/BuildLibuv.cmake
@@ -43,7 +43,7 @@ set(UNIX_CFGCMD sh ${DEPS_BUILD_DIR}/src/libuv/autogen.sh &&
if(UNIX)
BuildLibuv(
- CONFIGURE_COMMAND ${UNIX_CFGCMD}
+ CONFIGURE_COMMAND ${UNIX_CFGCMD} MAKE=${MAKE_PRG}
INSTALL_COMMAND ${MAKE_PRG} V=1 install)
elseif(MINGW AND CMAKE_CROSSCOMPILING)
diff --git a/third-party/cmake/BuildLuajit.cmake b/third-party/cmake/BuildLuajit.cmake
index e65a81bba5..2fda221b12 100644
--- a/third-party/cmake/BuildLuajit.cmake
+++ b/third-party/cmake/BuildLuajit.cmake
@@ -35,10 +35,16 @@ function(BuildLuajit)
INSTALL_COMMAND "${_luajit_INSTALL_COMMAND}")
endfunction()
+if(CMAKE_SYSTEM_NAME MATCHES "OpenBSD")
+ set(AMD64_ABI "LDFLAGS=-lpthread -lc++abi")
+else()
+ set(AMD64_ABI "")
+endif()
set(INSTALLCMD_UNIX ${MAKE_PRG} CFLAGS=-fPIC
CFLAGS+=-DLUAJIT_DISABLE_JIT
CFLAGS+=-DLUA_USE_APICHECK
CFLAGS+=-DLUA_USE_ASSERT
+ ${AMD64_ABI}
CCDEBUG+=-g
Q=
install)
diff --git a/third-party/cmake/BuildLuv.cmake b/third-party/cmake/BuildLuv.cmake
index 2a786dd8f3..339264746c 100644
--- a/third-party/cmake/BuildLuv.cmake
+++ b/third-party/cmake/BuildLuv.cmake
@@ -37,9 +37,17 @@ set(LUV_SRC_DIR ${DEPS_BUILD_DIR}/src/luv)
set(LUV_INCLUDE_FLAGS
"-I${DEPS_INSTALL_DIR}/include -I${DEPS_INSTALL_DIR}/include/luajit-2.0")
+# Replace luv default rockspec with the alternate one under the "rockspecs"
+# directory
set(LUV_PATCH_COMMAND
- ${CMAKE_COMMAND} -DLUV_SRC_DIR=${LUV_SRC_DIR}
- -P ${PROJECT_SOURCE_DIR}/cmake/PatchLuv.cmake)
+ ${CMAKE_COMMAND} -E copy_directory ${LUV_SRC_DIR}/rockspecs ${LUV_SRC_DIR})
+if(MINGW)
+ set(LUV_PATCH_COMMAND
+ ${LUV_PATCH_COMMAND}
+ COMMAND ${GIT_EXECUTABLE} -C ${LUV_SRC_DIR} init
+ COMMAND ${GIT_EXECUTABLE} -C ${LUV_SRC_DIR} apply --ignore-whitespace
+ ${CMAKE_CURRENT_SOURCE_DIR}/patches/luv-Add-missing-definitions-for-MinGW.patch)
+endif()
set(LUV_CONFIGURE_COMMAND_COMMON
${CMAKE_COMMAND} ${LUV_SRC_DIR}
@@ -78,7 +86,12 @@ else()
"-DCMAKE_C_FLAGS:STRING=${CMAKE_C_COMPILER_ARG1} ${LUV_INCLUDE_FLAGS} -fPIC")
endif()
-set(LUV_BUILD_COMMAND ${CMAKE_COMMAND} --build .)
+if(CMAKE_GENERATOR MATCHES "Unix Makefiles" AND
+ (CMAKE_SYSTEM_NAME MATCHES ".*BSD" OR CMAKE_SYSTEM_NAME MATCHES "DragonFly"))
+ set(LUV_BUILD_COMMAND ${CMAKE_COMMAND} "-DCMAKE_MAKE_PROGRAM=gmake" --build .)
+else()
+ set(LUV_BUILD_COMMAND ${CMAKE_COMMAND} --build .)
+endif()
set(LUV_INSTALL_COMMAND ${CMAKE_COMMAND} --build . --target install)
BuildLuv(PATCH_COMMAND ${LUV_PATCH_COMMAND}
diff --git a/third-party/cmake/PatchLuv.cmake b/third-party/cmake/PatchLuv.cmake
deleted file mode 100644
index 96595a2f30..0000000000
--- a/third-party/cmake/PatchLuv.cmake
+++ /dev/null
@@ -1,29 +0,0 @@
-# replace luv default rockspec with the alternate one under the "rockspecs"
-# directory
-file(GLOB LUV_ROCKSPEC RELATIVE ${LUV_SRC_DIR} ${LUV_SRC_DIR}/*.rockspec)
-file(RENAME ${LUV_SRC_DIR}/rockspecs/${LUV_ROCKSPEC} ${LUV_SRC_DIR}/${LUV_ROCKSPEC})
-
-# Some versions of mingw are missing defines required by luv dns module, add
-# them now
-set(LUV_SRC_DNS_C_DEFS
-"#ifndef AI_NUMERICSERV
-# define AI_NUMERICSERV 0x0008
-#endif
-#ifndef AI_ALL
-# define AI_ALL 0x00000100
-#endif
-#ifndef AI_ADDRCONFIG
-# define AI_ADDRCONFIG 0x00000400
-#endif
-#ifndef AI_V4MAPPED
-# define AI_V4MAPPED 0x00000800
-#endif")
-
-file(READ ${LUV_SRC_DIR}/src/dns.c LUV_SRC_DNS_C)
-string(REPLACE
- "\n#include <netdb.h>"
- "\n#include <netdb.h>\n#else\n${LUV_SRC_DNS_C_DEFS}"
- LUV_SRC_DNS_C_PATCHED
- "${LUV_SRC_DNS_C}")
-file(WRITE ${LUV_SRC_DIR}/src/dns.c "${LUV_SRC_DNS_C_PATCHED}")
-
diff --git a/third-party/cmake/libtermkeyCMakeLists.txt b/third-party/cmake/libtermkeyCMakeLists.txt
new file mode 100644
index 0000000000..cb57631c1c
--- /dev/null
+++ b/third-party/cmake/libtermkeyCMakeLists.txt
@@ -0,0 +1,34 @@
+cmake_minimum_required(VERSION 2.8.7)
+project(libtermkey)
+
+add_definitions(-D _CRT_SECURE_NO_WARNINGS)
+add_definitions(-DHAVE_UNIBILIUM)
+if(NOT MSVC)
+ add_definitions(-std=c99)
+endif()
+
+include_directories(${PROJECT_BINARY_DIR}/t)
+include_directories(SYSTEM ${UNIBILIUM_INCLUDE_DIRS})
+
+add_library(termkey termkey.c driver-csi.c driver-ti.c)
+set_target_properties(termkey PROPERTIES
+ PUBLIC_HEADER ${PROJECT_SOURCE_DIR}/termkey.h)
+target_link_libraries(termkey ${UNIBILIUM_LIBRARIES})
+
+include(GNUInstallDirs)
+install(TARGETS termkey
+ ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
+ PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
+
+enable_testing()
+file(GLOB TESTSOURCES "t/[0-9]*.c")
+foreach(f ${TESTSOURCES})
+ get_filename_component(t ${f} NAME_WE)
+ if(${t} STREQUAL 05read)
+ continue()
+ endif()
+
+ add_executable("test_${t}" ${f} t/taplib.c)
+ target_link_libraries("test_${t}" termkey)
+ add_test("${t}" "test_${t}")
+endforeach()
diff --git a/third-party/patches/libtermkey-Add-support-for-Windows.patch b/third-party/patches/libtermkey-Add-support-for-Windows.patch
new file mode 100644
index 0000000000..b839e94d05
--- /dev/null
+++ b/third-party/patches/libtermkey-Add-support-for-Windows.patch
@@ -0,0 +1,170 @@
+From fbe91a958816d85fa93665eb8f7a7a8e05eb9650 Mon Sep 17 00:00:00 2001
+From: Rui Abreu Ferreira <raf-ep@gmx.com>
+Date: Tue, 5 Apr 2016 00:12:41 +0100
+Subject: [PATCH] Add support for Windows
+
+Ported termkey for windows.
+
+- The TERMKEY_FLAG_NOTERMIOS is ignore in Windows, since there is no termios.
+- The termkey_waitkey() function is not implemented in windows, since there
+ is no poll() alternative.
+- The CMake recipe only supports unibilium, not curses.
+---
+ driver-ti.c | 8 +++++++-
+ termkey-internal.h | 11 ++++++++++-
+ termkey.c | 22 ++++++++++++++++++----
+ 3 files changed, 35 insertions(+), 6 deletions(-)
+
+diff --git a/driver-ti.c b/driver-ti.c
+index e673ab7..f5f8052 100644
+--- a/driver-ti.c
++++ b/driver-ti.c
+@@ -17,7 +17,9 @@
+ #include <ctype.h>
+ #include <stdio.h>
+ #include <string.h>
+-#include <unistd.h>
++#ifndef _WIN32
++# include <unistd.h>
++#endif
+ #include <sys/types.h>
+ #include <sys/stat.h>
+
+@@ -338,8 +340,10 @@ static int start_driver(TermKey *tk, void *info)
+ if(fstat(tk->fd, &statbuf) == -1)
+ return 0;
+
++#ifndef _WIN32
+ if(S_ISFIFO(statbuf.st_mode))
+ return 1;
++#endif
+
+ // Can't call putp or tputs because they suck and don't give us fd control
+ len = strlen(start_string);
+@@ -367,8 +371,10 @@ static int stop_driver(TermKey *tk, void *info)
+ if(fstat(tk->fd, &statbuf) == -1)
+ return 0;
+
++#ifndef _WIN32
+ if(S_ISFIFO(statbuf.st_mode))
+ return 1;
++#endif
+
+ /* The terminfo database will contain keys in application cursor key mode.
+ * We may need to enable that mode
+diff --git a/termkey-internal.h b/termkey-internal.h
+index 52829b3..b796729 100644
+--- a/termkey-internal.h
++++ b/termkey-internal.h
+@@ -4,7 +4,14 @@
+ #include "termkey.h"
+
+ #include <stdint.h>
+-#include <termios.h>
++#ifndef _WIN32
++# include <termios.h>
++#endif
++
++#ifdef _MSC_VER
++#include <BaseTsd.h>
++typedef SSIZE_T ssize_t;
++#endif
+
+ struct TermKeyDriver
+ {
+@@ -41,8 +48,10 @@ struct TermKey {
+ size_t hightide; /* Position beyond buffstart at which peekkey() should next start
+ * normally 0, but see also termkey_interpret_csi */
+
++#ifndef _WIN32
+ struct termios restore_termios;
+ char restore_termios_valid;
++#endif
+
+ TermKey_Terminfo_Getstr_Hook *ti_getstr_hook;
+ void *ti_getstr_hook_data;
+diff --git a/termkey.c b/termkey.c
+index 2f01f3a..145b99f 100644
+--- a/termkey.c
++++ b/termkey.c
+@@ -3,14 +3,20 @@
+
+ #include <ctype.h>
+ #include <errno.h>
+-#include <poll.h>
+-#include <unistd.h>
++#ifndef _WIN32
++# include <poll.h>
++# include <unistd.h>
++# include <strings.h>
++#endif
+ #include <string.h>
+-#include <strings.h>
+
+ #include <stdio.h>
+
+-#define strcaseeq(a,b) (strcasecmp(a,b) == 0)
++#ifdef _MSC_VER
++# define strcaseeq(a,b) (_stricmp(a,b) == 0)
++#else
++# define strcaseeq(a,b) (strcasecmp(a,b) == 0)
++#endif
+
+ void termkey_check_version(int major, int minor)
+ {
+@@ -282,7 +288,9 @@ static TermKey *termkey_alloc(void)
+ tk->buffsize = 256; /* bytes */
+ tk->hightide = 0;
+
++#ifndef _WIN32
+ tk->restore_termios_valid = 0;
++#endif
+
+ tk->ti_getstr_hook = NULL;
+ tk->ti_getstr_hook_data = NULL;
+@@ -483,6 +491,7 @@ int termkey_start(TermKey *tk)
+ if(tk->is_started)
+ return 1;
+
++#ifndef _WIN32
+ if(tk->fd != -1 && !(tk->flags & TERMKEY_FLAG_NOTERMIOS)) {
+ struct termios termios;
+ if(tcgetattr(tk->fd, &termios) == 0) {
+@@ -517,6 +526,7 @@ int termkey_start(TermKey *tk)
+ tcsetattr(tk->fd, TCSANOW, &termios);
+ }
+ }
++#endif
+
+ struct TermKeyDriverNode *p;
+ for(p = tk->drivers; p; p = p->next)
+@@ -542,8 +552,10 @@ int termkey_stop(TermKey *tk)
+ if(p->driver->stop_driver)
+ (*p->driver->stop_driver)(tk, p->info);
+
++#ifndef _WIN32
+ if(tk->restore_termios_valid)
+ tcsetattr(tk->fd, TCSANOW, &tk->restore_termios);
++#endif
+
+ tk->is_started = 0;
+
+@@ -1046,6 +1058,7 @@ TermKeyResult termkey_getkey_force(TermKey *tk, TermKeyKey *key)
+ return ret;
+ }
+
++#ifndef _WIN32
+ TermKeyResult termkey_waitkey(TermKey *tk, TermKeyKey *key)
+ {
+ if(tk->fd == -1) {
+@@ -1105,6 +1118,7 @@ retry:
+
+ /* UNREACHABLE */
+ }
++#endif
+
+ TermKeyResult termkey_advisereadable(TermKey *tk)
+ {
+--
+2.16.1.windows.4
+
diff --git a/third-party/patches/libvterm-Remove-VLAs-for-MSVC.patch b/third-party/patches/libvterm-Remove-VLAs-for-MSVC.patch
index 3fb18351be..e999c0fa9b 100644
--- a/third-party/patches/libvterm-Remove-VLAs-for-MSVC.patch
+++ b/third-party/patches/libvterm-Remove-VLAs-for-MSVC.patch
@@ -23,7 +23,7 @@ index 84299df..f9aabb3 100644
// We'll have at most len codepoints
- uint32_t codepoints[len];
-+ uint32_t* codepoints = _alloca(len);
++ uint32_t* codepoints = _alloca(len * sizeof(uint32_t));
int npoints = 0;
size_t eaten = 0;
@@ -32,7 +32,7 @@ index 84299df..f9aabb3 100644
int width = 0;
- uint32_t chars[glyph_ends - glyph_starts + 1];
-+ uint32_t* chars = _alloca(glyph_ends - glyph_starts + 1);
++ uint32_t* chars = _alloca((glyph_ends - glyph_starts + 1) * sizeof(uint32_t));
for( ; i < glyph_ends; i++) {
chars[i - glyph_starts] = codepoints[i];
diff --git a/third-party/patches/luv-Add-missing-definitions-for-MinGW.patch b/third-party/patches/luv-Add-missing-definitions-for-MinGW.patch
new file mode 100644
index 0000000000..8954ae21c3
--- /dev/null
+++ b/third-party/patches/luv-Add-missing-definitions-for-MinGW.patch
@@ -0,0 +1,24 @@
+diff --git a/src/dns.c b/src/dns.c
+index 8634157..5f36625 100644
+--- a/src/dns.c
++++ b/src/dns.c
+@@ -20,6 +20,19 @@
+ #include <sys/types.h>
+ #include <sys/socket.h>
+ #include <netdb.h>
++#elif __MINGW32__
++# ifndef AI_NUMERICSERV
++# define AI_NUMERICSERV 0x0008
++# endif
++# ifndef AI_ALL
++# define AI_ALL 0x00000100
++# endif
++# ifndef AI_ADDRCONFIG
++# define AI_ADDRCONFIG 0x00000400
++# endif
++# ifndef AI_V4MAPPED
++# define AI_V4MAPPED 0x00000800
++# endif
+ #endif
+
+ static void luv_pushaddrinfo(lua_State* L, struct addrinfo* res) {