aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZyX <kp-pav@yandex.ru>2017-10-15 21:16:27 +0300
committerZyX <kp-pav@yandex.ru>2017-10-15 21:16:27 +0300
commit76f0466536757fdc7306f92061017b8d51f0ef09 (patch)
treeaa6334c6afa44ed55c8b60ff869c59744efad993
parent3aa2c0d63ae488e302a89fdcdd650404cb2670fd (diff)
parent3e502fd7d67f01f8f8e3006da255d3fba40ee961 (diff)
downloadrneovim-76f0466536757fdc7306f92061017b8d51f0ef09.tar.gz
rneovim-76f0466536757fdc7306f92061017b8d51f0ef09.tar.bz2
rneovim-76f0466536757fdc7306f92061017b8d51f0ef09.zip
Merge branch 'master' into expression-parser
-rw-r--r--.editorconfig4
-rw-r--r--.gitignore1
-rw-r--r--BSDmakefile4
-rw-r--r--CMakeLists.txt20
-rw-r--r--README.md29
-rw-r--r--appveyor.yml2
-rwxr-xr-xci/before_install.sh16
-rwxr-xr-xci/install.sh4
-rw-r--r--cmake/FindLibIntl.cmake1
-rw-r--r--runtime/CMakeLists.txt1
-rw-r--r--runtime/autoload/health.vim24
-rw-r--r--runtime/autoload/health/nvim.vim6
-rw-r--r--runtime/autoload/health/provider.vim43
-rw-r--r--runtime/autoload/provider.vim6
-rw-r--r--runtime/autoload/provider/clipboard.vim32
-rw-r--r--runtime/autoload/remote/define.vim3
-rw-r--r--runtime/doc/api.txt16
-rw-r--r--runtime/doc/editing.txt2
-rw-r--r--runtime/doc/eval.txt39
-rw-r--r--runtime/doc/message.txt6
-rw-r--r--runtime/doc/options.txt31
-rw-r--r--runtime/doc/pi_health.txt8
-rw-r--r--runtime/doc/syntax.txt7
-rw-r--r--runtime/doc/term.txt21
-rw-r--r--runtime/doc/various.txt1
-rw-r--r--runtime/doc/vim_diff.txt36
-rw-r--r--runtime/syntax/vim.vim31
-rw-r--r--runtime/tutor/en/vim-01-beginner.tutor326
-rw-r--r--runtime/tutor/en/vim-01-beginner.tutor.json8
-rwxr-xr-xscripts/vim-patch.sh2
-rw-r--r--src/nvim/CMakeLists.txt5
-rw-r--r--src/nvim/api/ui.c35
-rw-r--r--src/nvim/api/vim.c79
-rw-r--r--src/nvim/aucmd.c41
-rw-r--r--src/nvim/aucmd.h9
-rw-r--r--src/nvim/buffer.c2
-rw-r--r--src/nvim/charset.c2
-rw-r--r--src/nvim/diff.c19
-rw-r--r--src/nvim/edit.c12
-rw-r--r--src/nvim/eval.c83
-rw-r--r--src/nvim/event/loop.c27
-rw-r--r--src/nvim/event/loop.h22
-rw-r--r--src/nvim/event/process.c3
-rw-r--r--src/nvim/event/rstream.c2
-rw-r--r--src/nvim/event/stream.c2
-rw-r--r--src/nvim/event/wstream.c1
-rw-r--r--src/nvim/ex_cmds.c76
-rw-r--r--src/nvim/ex_cmds2.c97
-rw-r--r--src/nvim/ex_docmd.c78
-rw-r--r--src/nvim/ex_getln.c14
-rw-r--r--src/nvim/getchar.c39
-rw-r--r--src/nvim/gettext.h1
-rw-r--r--src/nvim/globals.h8
-rw-r--r--src/nvim/indent_c.c115
-rw-r--r--src/nvim/keymap.c299
-rw-r--r--src/nvim/keymap.h2
-rw-r--r--src/nvim/log.c42
-rw-r--r--src/nvim/log.h22
-rw-r--r--src/nvim/main.c116
-rw-r--r--src/nvim/move.c13
-rw-r--r--src/nvim/msgpack_rpc/channel.c86
-rw-r--r--src/nvim/msgpack_rpc/helpers.c9
-rw-r--r--src/nvim/normal.c21
-rw-r--r--src/nvim/ops.c97
-rw-r--r--src/nvim/option.c14
-rw-r--r--src/nvim/options.lua2
-rw-r--r--src/nvim/path.c10
-rw-r--r--src/nvim/regexp.c77
-rw-r--r--src/nvim/screen.c78
-rw-r--r--src/nvim/search.c12
-rw-r--r--src/nvim/state.c13
-rw-r--r--src/nvim/syntax.c313
-rw-r--r--src/nvim/syntax_defs.h10
-rw-r--r--src/nvim/terminal.c119
-rw-r--r--src/nvim/testdir/Makefile2
-rw-r--r--src/nvim/testdir/test_cmdline.vim31
-rw-r--r--src/nvim/testdir/test_diffmode.vim37
-rw-r--r--src/nvim/testdir/test_help_tagjump.vim57
-rw-r--r--src/nvim/testdir/test_mksession.vim155
-rw-r--r--src/nvim/testdir/test_mksession_utf8.vim104
-rw-r--r--src/nvim/testdir/test_options.vim16
-rw-r--r--src/nvim/testdir/test_popup.vim37
-rw-r--r--src/nvim/testdir/test_startup.vim58
-rw-r--r--src/nvim/testdir/test_syntax.vim84
-rw-r--r--src/nvim/testdir/test_visual.vim20
-rw-r--r--src/nvim/tui/input.c13
-rw-r--r--src/nvim/tui/terminfo.c4
-rw-r--r--src/nvim/tui/tui.c172
-rw-r--r--src/nvim/ugrid.c4
-rw-r--r--src/nvim/ugrid.h2
-rw-r--r--src/nvim/ui.c128
-rw-r--r--src/nvim/ui.h3
-rw-r--r--src/nvim/version.c236
-rw-r--r--src/nvim/window.c20
-rw-r--r--test/.luacheckrc2
-rw-r--r--test/functional/api/highlight_spec.lua103
-rw-r--r--test/functional/api/server_requests_spec.lua30
-rw-r--r--test/functional/api/vim_spec.lua74
-rw-r--r--test/functional/autocmd/termclose_spec.lua4
-rw-r--r--test/functional/clipboard/clipboard_provider_spec.lua113
-rw-r--r--test/functional/core/job_spec.lua4
-rw-r--r--test/functional/core/path_spec.lua56
-rw-r--r--test/functional/eval/input_spec.lua19
-rw-r--r--test/functional/fixtures/autoload/provider/clipboard.vim8
-rw-r--r--test/functional/legacy/003_cindent_spec.lua76
-rw-r--r--test/functional/legacy/005_bufleave_delete_buffer_spec.lua1
-rw-r--r--test/functional/legacy/006_argument_list_spec.lua6
-rw-r--r--test/functional/legacy/007_ball_buffer_list_spec.lua4
-rw-r--r--test/functional/legacy/011_autocommands_spec.lua2
-rw-r--r--test/functional/legacy/015_alignment_spec.lua3
-rw-r--r--test/functional/legacy/019_smarttab_expandtab_spec.lua1
-rw-r--r--test/functional/legacy/029_join_spec.lua2
-rw-r--r--test/functional/legacy/033_lisp_indent_spec.lua5
-rw-r--r--test/functional/legacy/038_virtual_replace_spec.lua1
-rw-r--r--test/functional/legacy/039_visual_block_mode_commands_spec.lua2
-rw-r--r--test/functional/legacy/051_highlight_spec.lua1
-rw-r--r--test/functional/legacy/055_list_and_dict_types_spec.lua1
-rw-r--r--test/functional/legacy/060_exists_and_has_functions_spec.lua26
-rw-r--r--test/functional/legacy/066_visual_block_tab_spec.lua4
-rw-r--r--test/functional/legacy/068_text_formatting_spec.lua1
-rw-r--r--test/functional/legacy/069_multibyte_formatting_spec.lua14
-rw-r--r--test/functional/legacy/078_swapfile_recover_spec.lua16
-rw-r--r--test/functional/legacy/081_coptions_movement_spec.lua1
-rw-r--r--test/functional/legacy/082_string_comparison_spec.lua4
-rw-r--r--test/functional/legacy/084_curswant_spec.lua1
-rw-r--r--test/functional/legacy/088_conceal_tabs_spec.lua1
-rw-r--r--test/functional/legacy/089_number_relnumber_findfile_spec.lua18
-rw-r--r--test/functional/legacy/092_mksession_cursor_cols_utf8_spec.lua1
-rw-r--r--test/functional/legacy/093_mksession_cursor_cols_latin1_spec.lua1
-rw-r--r--test/functional/legacy/094_visual_mode_operators_spec.lua1
-rw-r--r--test/functional/legacy/103_visual_mode_reset_spec.lua4
-rw-r--r--test/functional/legacy/106_errorformat_spec.lua4
-rw-r--r--test/functional/legacy/108_backtrace_debug_commands_spec.lua40
-rw-r--r--test/functional/legacy/assert_spec.lua2
-rw-r--r--test/functional/legacy/breakindent_spec.lua3
-rw-r--r--test/functional/legacy/command_count_spec.lua9
-rw-r--r--test/functional/legacy/erasebackword_spec.lua1
-rw-r--r--test/functional/legacy/increment_spec.lua2
-rw-r--r--test/functional/legacy/listchars_spec.lua2
-rw-r--r--test/functional/legacy/listlbr_spec.lua27
-rw-r--r--test/functional/legacy/listlbr_utf8_spec.lua40
-rw-r--r--test/functional/legacy/marks_spec.lua1
-rw-r--r--test/functional/legacy/options_spec.lua2
-rw-r--r--test/functional/legacy/packadd_spec.lua44
-rw-r--r--test/functional/legacy/tagcase_spec.lua6
-rw-r--r--test/functional/legacy/utf8_spec.lua1
-rw-r--r--test/functional/plugin/health_spec.lua43
-rw-r--r--test/functional/shada/compatibility_spec.lua29
-rw-r--r--test/functional/shada/merging_spec.lua187
-rw-r--r--test/functional/terminal/ex_terminal_spec.lua38
-rw-r--r--test/functional/terminal/tui_spec.lua83
-rw-r--r--test/functional/ui/highlight_spec.lua6
-rw-r--r--test/functional/ui/inccommand_spec.lua52
-rw-r--r--test/functional/ui/screen_basic_spec.lua6
-rw-r--r--test/unit/path_spec.lua14
155 files changed, 3672 insertions, 1621 deletions
diff --git a/.editorconfig b/.editorconfig
index b08a27f2a2..ac902ecec5 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -7,6 +7,10 @@ end_of_line = lf
insert_final_newline = true
charset = utf_8
+[runtime/doc/*.txt]
+indent_style = tab
+indent_size = 8
+
[Makefile]
indent_style = tab
tab_width = 4
diff --git a/.gitignore b/.gitignore
index 3a8994a5f6..61b96c158f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,6 @@
# Build/deps dir
/build/
+/cmake-build-debug/
/dist/
/.deps/
/tmp/
diff --git a/BSDmakefile b/BSDmakefile
new file mode 100644
index 0000000000..93b7dc7f3d
--- /dev/null
+++ b/BSDmakefile
@@ -0,0 +1,4 @@
+.DONE:
+ @echo "Please use GNU Make (gmake) to build neovim"
+.DEFAULT:
+ @echo "Please use GNU Make (gmake) to build neovim"
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 17e14bcbd0..df29774d45 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -254,7 +254,10 @@ if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS "4.8.5")
# Array-bounds testing is broken in some GCC versions before 4.8.5.
# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56273
- add_definitions(-Wno-array-bounds)
+ check_c_compiler_flag(-Wno-array-bounds HAS_NO_ARRAY_BOUNDS_FLAG)
+ if(HAS_NO_ARRAY_BOUNDS_FLAG)
+ add_definitions(-Wno-array-bounds)
+ endif()
endif()
endif()
@@ -344,6 +347,21 @@ if(FEAT_TUI)
find_package(Unibilium REQUIRED)
include_directories(SYSTEM ${UNIBILIUM_INCLUDE_DIRS})
+ list(APPEND CMAKE_REQUIRED_INCLUDES "${UNIBILIUM_INCLUDE_DIRS}")
+ list(APPEND CMAKE_REQUIRED_LIBRARIES "${UNIBILIUM_LIBRARIES}")
+ check_c_source_compiles("
+ #include <unibilium.h>
+
+ int
+ main(void)
+ {
+ return unibi_num_from_var(unibi_var_from_num(0));
+ }
+ " UNIBI_HAS_VAR_FROM)
+ if(UNIBI_HAS_VAR_FROM)
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DNVIM_UNIBI_HAS_VAR_FROM")
+ endif()
+
find_package(LibTermkey REQUIRED)
include_directories(SYSTEM ${LIBTERMKEY_INCLUDE_DIRS})
endif()
diff --git a/README.md b/README.md
index 0442ee61de..4016c9b3c2 100644
--- a/README.md
+++ b/README.md
@@ -48,17 +48,24 @@ and [more](https://github.com/neovim/neovim/wiki/Installing-Neovim)!
Project layout
--------------
- ├─ ci/ Build server scripts
- ├─ cmake/ Build scripts
- ├─ runtime/ User plugins/docs
- ├─ src/ Source code
- ├─ third-party/ CMake subproject to build dependencies
- └─ test/ Test code
-
-- `third-party/` is activated if `USE_BUNDLED_DEPS` is undefined or the
- `USE_BUNDLED` CMake option is true.
-- [Source README](src/nvim/README.md)
-- [Test README](test/README.md)
+ ├─ ci/ build automation
+ ├─ cmake/ build scripts
+ ├─ runtime/ user plugins/docs
+ ├─ src/ application source code (see src/nvim/README.md)
+ │ ├─ api/ API subsystem
+ │ ├─ eval/ VimL subsystem
+ │ ├─ event/ event-loop subsystem
+ │ ├─ generators/ code generation (pre-compilation)
+ │ ├─ lib/ generic data structures
+ │ ├─ lua/ lua subsystem
+ │ ├─ msgpack_rpc/ RPC subsystem
+ │ ├─ os/ low-level platform code
+ │ └─ tui/ built-in UI
+ ├─ third-party/ cmake subproject to build dependencies
+ └─ test/ tests (see test/README.md)
+
+- To disable `third-party/` specify `USE_BUNDLED_DEPS=NO` or `USE_BUNDLED=NO`
+ (CMake option).
Features
--------
diff --git a/appveyor.yml b/appveyor.yml
index ecea6c5fa3..2d6135c7a2 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -1,4 +1,6 @@
version: '{build}'
+environment:
+ APPVEYOR_CACHE_ENTRY_ZIP_ARGS: "-t7z -m0=lzma -mx=9"
configuration:
- MINGW_64
- MINGW_32
diff --git a/ci/before_install.sh b/ci/before_install.sh
index 5b36adaef2..f84ad935bc 100755
--- a/ci/before_install.sh
+++ b/ci/before_install.sh
@@ -11,6 +11,18 @@ if [[ "${TRAVIS_OS_NAME}" == osx ]]; then
brew update
fi
+echo 'python info:'
+(
+ 2>&1 python --version || true
+ 2>&1 python2 --version || true
+ 2>&1 python3 --version || true
+ 2>&1 pip --version || true
+ 2>&1 pip2 --version || true
+ 2>&1 pip3 --version || true
+ echo 'pyenv versions:'
+ 2>&1 pyenv versions || true
+) | sed 's/^/ /'
+
echo "Upgrade Python 2 pip."
pip2.7 -q install --user --upgrade pip
@@ -21,5 +33,7 @@ if [[ "${TRAVIS_OS_NAME}" == osx ]]; then
pip3 -q install --user --upgrade pip
else
echo "Upgrade Python 3 pip."
- pip3 -q install --user --upgrade pip
+ # Allow failure. pyenv pip3 on travis is broken:
+ # https://github.com/travis-ci/travis-ci/issues/8363
+ pip3 -q install --user --upgrade pip || true
fi
diff --git a/ci/install.sh b/ci/install.sh
index 4ee99e1e44..c8a0c8825d 100755
--- a/ci/install.sh
+++ b/ci/install.sh
@@ -17,7 +17,9 @@ echo "Install neovim module and coveralls for Python 2."
CC=cc pip2.7 -q install --user --upgrade neovim cpp-coveralls
echo "Install neovim module for Python 3."
-CC=cc pip3 -q install --user --upgrade neovim
+# Allow failure. pyenv pip3 on travis is broken:
+# https://github.com/travis-ci/travis-ci/issues/8363
+CC=cc pip3 -q install --user --upgrade neovim || true
echo "Install neovim RubyGem."
gem install --no-document --version ">= 0.2.0" neovim
diff --git a/cmake/FindLibIntl.cmake b/cmake/FindLibIntl.cmake
index 75926200c1..ab4632cf45 100644
--- a/cmake/FindLibIntl.cmake
+++ b/cmake/FindLibIntl.cmake
@@ -46,6 +46,7 @@ check_c_source_compiles("
int main(int argc, char** argv) {
gettext(\"foo\");
+ ngettext(\"foo\", \"bar\", 1);
bindtextdomain(\"foo\", \"bar\");
bind_textdomain_codeset(\"foo\", \"bar\");
textdomain(\"foo\");
diff --git a/runtime/CMakeLists.txt b/runtime/CMakeLists.txt
index a9efc90b87..f81d8541b5 100644
--- a/runtime/CMakeLists.txt
+++ b/runtime/CMakeLists.txt
@@ -71,6 +71,7 @@ foreach(DF ${DOCFILES})
endforeach()
add_custom_target(helptags
+ COMMAND ${CMAKE_COMMAND} -E remove_directory ${GENERATED_RUNTIME_DIR}/doc
COMMAND ${CMAKE_COMMAND} -E copy_directory
${PROJECT_SOURCE_DIR}/runtime/doc ${GENERATED_RUNTIME_DIR}/doc
COMMAND "${PROJECT_BINARY_DIR}/bin/nvim"
diff --git a/runtime/autoload/health.vim b/runtime/autoload/health.vim
index f875c8b797..d0ad7729ab 100644
--- a/runtime/autoload/health.vim
+++ b/runtime/autoload/health.vim
@@ -1,15 +1,15 @@
function! s:enhance_syntax() abort
syntax case match
- syntax keyword healthError ERROR
+ syntax keyword healthError ERROR[:]
\ containedin=markdownCodeBlock,mkdListItemLine
highlight link healthError Error
- syntax keyword healthWarning WARNING
+ syntax keyword healthWarning WARNING[:]
\ containedin=markdownCodeBlock,mkdListItemLine
highlight link healthWarning WarningMsg
- syntax keyword healthSuccess SUCCESS
+ syntax keyword healthSuccess OK[:]
\ containedin=markdownCodeBlock,mkdListItemLine
highlight healthSuccess guibg=#5fff00 guifg=#080808 ctermbg=82 ctermfg=232
@@ -90,27 +90,27 @@ endfunction
" Changes ':h clipboard' to ':help |clipboard|'.
function! s:help_to_link(s) abort
- return substitute(a:s, '\v:h%[elp] ([^|][^"\r\n]+)', ':help |\1|', 'g')
+ return substitute(a:s, '\v:h%[elp] ([^|][^"\r\n ]+)', ':help |\1|', 'g')
endfunction
" Format a message for a specific report item
function! s:format_report_message(status, msg, ...) abort " {{{
let output = ' - ' . a:status . ': ' . s:indent_after_line1(a:msg, 4)
- let suggestions = []
+ let advice = []
" Optional parameters
if a:0 > 0
- let suggestions = type(a:1) == type("") ? [a:1] : a:1
- if type(suggestions) != type([])
- echoerr "Expected String or List"
+ let advice = type(a:1) == type("") ? [a:1] : a:1
+ if type(advice) != type([])
+ throw "Expected String or List"
endif
endif
" Report each suggestion
- if len(suggestions) > 0
- let output .= "\n - SUGGESTIONS:"
+ if len(advice) > 0
+ let output .= "\n - ADVICE:"
endif
- for suggestion in suggestions
+ for suggestion in advice
let output .= "\n - " . s:indent_after_line1(suggestion, 10)
endfor
@@ -124,7 +124,7 @@ endfunction " }}}
" Reports a successful healthcheck.
function! health#report_ok(msg) abort " {{{
- echo s:format_report_message('SUCCESS', a:msg)
+ echo s:format_report_message('OK', a:msg)
endfunction " }}}
" Reports a health warning.
diff --git a/runtime/autoload/health/nvim.vim b/runtime/autoload/health/nvim.vim
index 3834cbd054..6c6a5e8543 100644
--- a/runtime/autoload/health/nvim.vim
+++ b/runtime/autoload/health/nvim.vim
@@ -10,6 +10,12 @@ function! s:check_config() abort
\ [ "Use the 'guicursor' option to configure cursor shape. :help 'guicursor'",
\ 'https://github.com/neovim/neovim/wiki/Following-HEAD#20170402' ])
endif
+ if &paste
+ let ok = v:false
+ call health#report_error("'paste' is enabled. This option is only for pasting text.\nIt should not be set in your config.",
+ \ [ 'Remove `set paste` from your init.vim, if applicable.',
+ \ 'Check `:verbose set paste?` to see if a plugin or script set the option.', ])
+ endif
if ok
call health#report_ok('no issues found')
diff --git a/runtime/autoload/health/provider.vim b/runtime/autoload/health/provider.vim
index ec20615f69..0eaa678459 100644
--- a/runtime/autoload/health/provider.vim
+++ b/runtime/autoload/health/provider.vim
@@ -121,14 +121,14 @@ function! s:check_clipboard() abort
call health#report_start('Clipboard (optional)')
let clipboard_tool = provider#clipboard#Executable()
- if empty(clipboard_tool)
+ if exists('g:clipboard') && empty(clipboard_tool)
+ call health#report_error(
+ \ provider#clipboard#Error(),
+ \ ["Use the example in :help g:clipboard as a template, or don't set g:clipboard at all."])
+ elseif empty(clipboard_tool)
call health#report_warn(
- \ 'No clipboard tool found. Clipboard registers will not work.',
+ \ 'No clipboard tool found. Clipboard registers (`"+` and `"*`) will not work.',
\ [':help clipboard'])
- elseif exists('g:clipboard') && (type({}) != type(g:clipboard)
- \ || !has_key(g:clipboard, 'copy') || !has_key(g:clipboard, 'paste'))
- call health#report_error(
- \ 'g:clipboard exists but is malformed. It must be a dictionary with the keys documented at :help g:clipboard')
else
call health#report_ok('Clipboard tool found: '. clipboard_tool)
endif
@@ -239,7 +239,7 @@ function! s:check_python(version) abort
let pyname = 'python'.(a:version == 2 ? '' : '3')
let pyenv = resolve(exepath('pyenv'))
- let pyenv_root = exists('$PYENV_ROOT') ? resolve($PYENV_ROOT) : 'n'
+ let pyenv_root = exists('$PYENV_ROOT') ? resolve($PYENV_ROOT) : ''
let venv = exists('$VIRTUAL_ENV') ? resolve($VIRTUAL_ENV) : ''
let host_prog_var = pyname.'_host_prog'
let loaded_var = 'g:loaded_'.pyname.'_provider'
@@ -251,6 +251,19 @@ function! s:check_python(version) abort
return
endif
+ if !empty(pyenv)
+ if empty(pyenv_root)
+ call health#report_warn(
+ \ 'pyenv was found, but $PYENV_ROOT is not set.',
+ \ ['Did you follow the final install instructions?',
+ \ 'If you use a shell "framework" like Prezto or Oh My Zsh, try without.',
+ \ 'Try a different shell (bash).']
+ \ )
+ else
+ call health#report_ok(printf('pyenv found: "%s"', pyenv))
+ endif
+ endif
+
if exists('g:'.host_prog_var)
call health#report_info(printf('Using: g:%s = "%s"', host_prog_var, get(g:, host_prog_var)))
endif
@@ -282,15 +295,6 @@ function! s:check_python(version) abort
endif
if !empty(pyenv)
- if empty(pyenv_root)
- call health#report_warn(
- \ 'pyenv was found, but $PYENV_ROOT is not set.',
- \ ['Did you follow the final install instructions?']
- \ )
- else
- call health#report_ok(printf('pyenv found: "%s"', pyenv))
- endif
-
let python_bin = s:trim(s:system([pyenv, 'which', pyname], '', 1))
if empty(python_bin)
@@ -320,9 +324,8 @@ function! s:check_python(version) abort
if python_bin =~# '\<shims\>'
call health#report_warn(printf('`%s` appears to be a pyenv shim.', python_bin), [
- \ 'The `pyenv` executable is not in $PATH,',
- \ 'Your pyenv installation is broken. You should set '
- \ . '`g:'.host_prog_var.'` to avoid surprises.',
+ \ '`pyenv` is not in $PATH, your pyenv installation is broken. '
+ \ .'Set `g:'.host_prog_var.'` to avoid surprises.',
\ ])
endif
endif
@@ -335,7 +338,7 @@ function! s:check_python(version) abort
call health#report_warn('pyenv is not set up optimally.', [
\ printf('Create a virtualenv specifically '
\ . 'for Neovim using pyenv, and set `g:%s`. This will avoid '
- \ . 'the need to install Neovim''s Python module in each '
+ \ . 'the need to install the Neovim Python module in each '
\ . 'version/virtualenv.', host_prog_var)
\ ])
elseif !empty(venv) && exists('g:'.host_prog_var)
diff --git a/runtime/autoload/provider.vim b/runtime/autoload/provider.vim
index a4d5241b57..e6514f5ba8 100644
--- a/runtime/autoload/provider.vim
+++ b/runtime/autoload/provider.vim
@@ -2,7 +2,7 @@
let s:stderr = {}
-function! provider#stderr_collector(chan_id, data, event) dict
+function! provider#stderr_collector(chan_id, data, event)
let stderr = get(s:stderr, a:chan_id, [''])
let stderr[-1] .= a:data[0]
call extend(stderr, a:data[1:])
@@ -10,7 +10,9 @@ function! provider#stderr_collector(chan_id, data, event) dict
endfunction
function! provider#clear_stderr(chan_id)
- silent! call delete(s:stderr, a:chan_id)
+ if has_key(s:stderr, a:chan_id)
+ call remove(s:stderr, a:chan_id)
+ endif
endfunction
function! provider#get_stderr(chan_id)
diff --git a/runtime/autoload/provider/clipboard.vim b/runtime/autoload/provider/clipboard.vim
index 8eb694e9fa..6454a01c2a 100644
--- a/runtime/autoload/provider/clipboard.vim
+++ b/runtime/autoload/provider/clipboard.vim
@@ -3,6 +3,7 @@
" available.
let s:copy = {}
let s:paste = {}
+let s:clipboard = {}
" When caching is enabled, store the jobid of the xclip/xsel process keeping
" ownership of the selection, so we know how long the cache is valid.
@@ -23,7 +24,7 @@ function! s:selection.on_exit(jobid, data, event) abort
call provider#clear_stderr(a:jobid)
endfunction
-let s:selections = { '*': s:selection, '+': copy(s:selection)}
+let s:selections = { '*': s:selection, '+': copy(s:selection) }
function! s:try_cmd(cmd, ...) abort
let argv = split(a:cmd, " ")
@@ -31,7 +32,7 @@ function! s:try_cmd(cmd, ...) abort
if v:shell_error
if !exists('s:did_error_try_cmd')
echohl WarningMsg
- echomsg "clipboard: error: ".(len(out) ? out[0] : '')
+ echomsg "clipboard: error: ".(len(out) ? out[0] : v:shell_error)
echohl None
let s:did_error_try_cmd = 1
endif
@@ -55,9 +56,15 @@ endfunction
function! provider#clipboard#Executable() abort
if exists('g:clipboard')
+ if type({}) isnot# type(g:clipboard)
+ \ || type({}) isnot# type(get(g:clipboard, 'copy', v:null))
+ \ || type({}) isnot# type(get(g:clipboard, 'paste', v:null))
+ let s:err = 'clipboard: invalid g:clipboard'
+ return ''
+ endif
let s:copy = get(g:clipboard, 'copy', { '+': v:null, '*': v:null })
let s:paste = get(g:clipboard, 'paste', { '+': v:null, '*': v:null })
- let s:cache_enabled = get(g:clipboard, 'cache_enabled', 1)
+ let s:cache_enabled = get(g:clipboard, 'cache_enabled', 0)
return get(g:clipboard, 'name', 'g:clipboard')
elseif has('mac') && executable('pbcopy')
let s:copy['+'] = 'pbcopy'
@@ -104,16 +111,17 @@ function! provider#clipboard#Executable() abort
return 'tmux'
endif
- let s:err = 'clipboard: No clipboard tool available. :help clipboard'
+ let s:err = 'clipboard: No clipboard tool. :help clipboard'
return ''
endfunction
if empty(provider#clipboard#Executable())
+ " provider#clipboard#Call() *must not* be defined if the provider is broken.
+ " Otherwise eval_has_provider() thinks the clipboard provider is
+ " functioning, and eval_call_provider() will happily call it.
finish
endif
-let s:clipboard = {}
-
function! s:clipboard.get(reg) abort
if s:selections[a:reg].owner > 0
return s:selections[a:reg].data
@@ -154,9 +162,19 @@ function! s:clipboard.set(lines, regtype, reg) abort
echohl WarningMsg
echomsg 'clipboard: failed to execute: '.(s:copy[a:reg])
echohl None
+ return 0
endif
+ return 1
endfunction
function! provider#clipboard#Call(method, args) abort
- return call(s:clipboard[a:method],a:args,s:clipboard)
+ if get(s:, 'here', v:false) " Clipboard provider must not recurse. #7184
+ return 0
+ endif
+ let s:here = v:true
+ try
+ return call(s:clipboard[a:method],a:args,s:clipboard)
+ finally
+ let s:here = v:false
+ endtry
endfunction
diff --git a/runtime/autoload/remote/define.vim b/runtime/autoload/remote/define.vim
index b04a5d2280..b5c976c823 100644
--- a/runtime/autoload/remote/define.vim
+++ b/runtime/autoload/remote/define.vim
@@ -89,7 +89,8 @@ endfunction
function! remote#define#AutocmdOnHost(host, method, sync, name, opts)
let group = s:GetNextAutocmdGroup()
- let forward = '"doau '.group.' '.a:name.' ".'.'expand("<amatch>")'
+ let forward = '"doau '.group.' '.a:name.' ".'
+ \ . 'fnameescape(expand("<amatch>"))'
let a:opts.group = group
let bootstrap_def = s:GetAutocmdPrefix(a:name, a:opts)
\ .' call remote#define#AutocmdBootstrap("'.a:host.'"'
diff --git a/runtime/doc/api.txt b/runtime/doc/api.txt
index 7c6b8a3c1a..e12cd1cfa9 100644
--- a/runtime/doc/api.txt
+++ b/runtime/doc/api.txt
@@ -171,8 +171,8 @@ nvim_replace_termcodes({str}, {from_part}, {do_lt}, {special})
Parameters:~
{str} String to be converted.
{from_part} Legacy Vim parameter. Usually true.
- {do_lt} Also translate <lt>. Does nothing if
- `special` is false.
+ {do_lt} Also translate <lt>. Ignored if `special` is
+ false.
{special} Replace |keycodes|, e.g. <CR> becomes a "\n"
char.
@@ -309,20 +309,24 @@ nvim_set_option({name}, {value}) *nvim_set_option()*
{value} New option value
nvim_out_write({str}) *nvim_out_write()*
- Writes a message to vim output buffer
+ Writes a message to the Vim output buffer. Does not append
+ "\n", the message is buffered (won't display) until a linefeed
+ is written.
Parameters:~
{str} Message
nvim_err_write({str}) *nvim_err_write()*
- Writes a message to vim error buffer
+ Writes a message to the Vim error buffer. Does not append
+ "\n", the message is buffered (won't display) until a linefeed
+ is written.
Parameters:~
{str} Message
nvim_err_writeln({str}) *nvim_err_writeln()*
- Writes a message to vim error buffer. Appends a linefeed to
- ensure all contents are written.
+ Writes a message to the Vim error buffer. Appends "\n", so the
+ buffer is flushed (and displayed).
Parameters:~
{str} Message
diff --git a/runtime/doc/editing.txt b/runtime/doc/editing.txt
index 9fe815ea9c..8974a5c64e 100644
--- a/runtime/doc/editing.txt
+++ b/runtime/doc/editing.txt
@@ -1271,7 +1271,7 @@ Commands for changing the working directory can be suffixed with a bang "!"
*:lcd-*
:lcd[!] - Change to the previous current directory (before the
- previous ":tcd {path}" command).
+ previous ":lcd {path}" command).
*:pw* *:pwd* *E187*
:pw[d] Print the current directory name.
diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt
index 29e254b0b3..b37b0e8836 100644
--- a/runtime/doc/eval.txt
+++ b/runtime/doc/eval.txt
@@ -1522,14 +1522,16 @@ v:errors Errors found by assert functions, such as |assert_true()|.
*v:event* *event-variable*
v:event Dictionary of event data for the current |autocommand|. Valid
- only during the autocommand lifetime: storing or passing
- `v:event` is invalid. Copy it instead: >
+ only during the event lifetime; storing or passing v:event is
+ invalid! Copy it instead: >
au TextYankPost * let g:foo = deepcopy(v:event)
< Keys vary by event; see the documentation for the specific
- event, e.g. |TextYankPost|.
+ event, e.g. |DirChanged| or |TextYankPost|.
KEY DESCRIPTION ~
- operator The current |operator|. Also set for
- Ex commands (unlike |v:operator|). For
+ cwd Current working directory
+ scope Event-specific scope name.
+ operator Current |operator|. Also set for Ex
+ commands (unlike |v:operator|). For
example if |TextYankPost| is triggered
by the |:yank| Ex command then
`v:event['operator']` is "y".
@@ -4726,7 +4728,8 @@ input({opts})
"-complete=" argument. Refer to |:command-completion| for
more information. Example: >
let fname = input("File: ", "", "file")
-< *E5400* *E5402*
+
+< *input()-highlight* *E5400* *E5402*
The optional `highlight` key allows specifying function which
will be used for highlighting user input. This function
receives user input as its only argument and must return
@@ -4744,6 +4747,30 @@ input({opts})
sections must be ordered so that next hl_start_col is greater
then or equal to previous hl_end_col.
+ Example (try some input with parentheses): >
+ highlight RBP1 guibg=Red ctermbg=red
+ highlight RBP2 guibg=Yellow ctermbg=yellow
+ highlight RBP3 guibg=Green ctermbg=green
+ highlight RBP4 guibg=Blue ctermbg=blue
+ let g:rainbow_levels = 4
+ function! RainbowParens(cmdline)
+ let ret = []
+ let i = 0
+ let lvl = 0
+ while i < len(a:cmdline)
+ if a:cmdline[i] is# '('
+ call add(ret, [i, i + 1, 'RBP' . ((lvl % g:rainbow_levels) + 1)])
+ let lvl += 1
+ elseif a:cmdline[i] is# ')'
+ let lvl -= 1
+ call add(ret, [i, i + 1, 'RBP' . ((lvl % g:rainbow_levels) + 1)])
+ endif
+ let i += 1
+ endwhile
+ return ret
+ endfunction
+ call input({'prompt':'>','highlight':'RainbowParens'})
+<
Highlight function is called at least once for each new
displayed input string, before command-line is redrawn. It is
expected that function is pure for the duration of one input()
diff --git a/runtime/doc/message.txt b/runtime/doc/message.txt
index c6c6f49026..58ababf229 100644
--- a/runtime/doc/message.txt
+++ b/runtime/doc/message.txt
@@ -449,12 +449,6 @@ changed. To avoid the message reset the 'warn' option.
Something inside Vim went wrong and resulted in a NULL pointer. If you know
how to reproduce this problem, please report it. |bugs|
- *E172* >
- Only one file name allowed
-
-The ":edit" command only accepts one file name. When you want to specify
-several files for editing use ":next" |:next|.
-
*E41* *E82* *E83* *E342* >
Out of memory!
Out of memory! (allocating {number} bytes)
diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt
index c6965648ef..d55eb7405c 100644
--- a/runtime/doc/options.txt
+++ b/runtime/doc/options.txt
@@ -6267,11 +6267,11 @@ A jump table for the options with a short description can be found at |Q_op|.
when part of a command has been typed.
*'title'* *'notitle'*
-'title' boolean (default off, on when title can be restored)
+'title' boolean (default off)
global
When on, the title of the window will be set to the value of
'titlestring' (if it is not empty), or to:
- filename [+=-] (path) - VIM
+ filename [+=-] (path) - NVIM
Where:
filename the name of the file being edited
- indicates the file cannot be modified, 'ma' off
@@ -6279,7 +6279,7 @@ A jump table for the options with a short description can be found at |Q_op|.
= indicates the file is read-only
=+ indicates the file is read-only and modified
(path) is the path of the file being edited
- - VIM the server name |v:servername| or "VIM"
+ - NVIM the server name |v:servername| or "NVIM"
*'titlelen'*
'titlelen' number (default 85)
@@ -6295,11 +6295,10 @@ A jump table for the options with a short description can be found at |Q_op|.
'titlelen' is also used for the 'titlestring' option.
*'titleold'*
-'titleold' string (default "Thanks for flying Vim")
+'titleold' string (default "")
global
- This option will be used for the window title when exiting Vim if the
- original title cannot be restored. Only happens if 'title' is on or
- 'titlestring' is not empty.
+ If not empty, this option will be used to set the window title when
+ exiting. Only if 'title' is enabled.
This option cannot be set from a |modeline| or in the |sandbox|, for
security reasons.
*'titlestring'*
@@ -6748,19 +6747,19 @@ A jump table for the options with a short description can be found at |Q_op|.
*'winhighlight'* *'winhl'*
'winhighlight' 'winhl' string (default empty)
local to window
- Window-local highlights. Comma-delimited list of |group-name| pairs
- "{hl-builtin}:{hl-group},..." where each {hl-builtin} is a group (from
- |highlight-groups|) to be overridden by {hl-group} in the window where
- this option was set. Only builting ui highlights are supported, not
- syntax highlighting. For that purpose, use |:ownsyntax|.
+ Window-local highlights. Comma-delimited list of highlight
+ |group-name| pairs "{hl-builtin}:{hl},..." where each {hl-builtin} is
+ a built-in |highlight-groups| item to be overridden by {hl} group in
+ the window. Only built-in |highlight-groups| are supported, not
+ syntax highlighting (use |:ownsyntax| for that).
- Most highlights occuring within the frame of a window are supported.
Highlights of vertical separators are determined by the window to the
left of the separator. The highlight of a tabpage in |tabline| is
- determined by the last focused window in the tabpage. Highlights of
+ determine by the last-focused window of the tabpage. Highlights of
the popupmenu are determined by the current window. Highlights in the
- message area are not overridable. Example for overriding the
- backgrond color: >
+ message area cannot be overridden.
+
+ Example: show a different color for non-current windows: >
set winhighlight=Normal:MyNormal,NormalNC:MyNormalNC
<
*'winfixheight'* *'wfh'* *'nowinfixheight'* *'nowfh'*
diff --git a/runtime/doc/pi_health.txt b/runtime/doc/pi_health.txt
index 8354c0470f..f77267288c 100644
--- a/runtime/doc/pi_health.txt
+++ b/runtime/doc/pi_health.txt
@@ -64,11 +64,11 @@ health#report_info({msg}) *health#report_info*
health#report_ok({msg}) *health#report_ok*
Displays a "success" message.
-health#report_warn({msg}, [{suggestions}]) *health#report_warn*
- Displays a warning. {suggestions} is an optional List of suggestions.
+health#report_warn({msg}, [{advice}]) *health#report_warn*
+ Displays a warning. {advice} is an optional List of suggestions.
-health#report_error({msg}, [{suggestions}]) *health#report_error*
- Displays an error. {suggestions} is an optional List of suggestions.
+health#report_error({msg}, [{advice}]) *health#report_error*
+ Displays an error. {advice} is an optional List of suggestions.
health#{plugin}#check() *health.user_checker*
This is the form of a healthcheck definition. Call the above functions
diff --git a/runtime/doc/syntax.txt b/runtime/doc/syntax.txt
index fd17e3b381..73841edb09 100644
--- a/runtime/doc/syntax.txt
+++ b/runtime/doc/syntax.txt
@@ -3270,11 +3270,10 @@ improve screen updating rates (see |:syn-sync| for more on this). >
The g:vimsyn_embed option allows users to select what, if any, types of
embedded script highlighting they wish to have. >
- g:vimsyn_embed == 0 : don't embed any scripts
- g:vimsyn_embed =~ 'P' : support embedded python
+ g:vimsyn_embed == 0 : disable (don't embed any scripts)
+ g:vimsyn_embed == 'lPr' : support embedded lua, python and ruby
<
-By default, g:vimsyn_embed is a string supporting interpreters that your vim
-itself supports.
+This option is disabled by default.
*g:vimsyn_folding*
Some folding is now supported with syntax/vim.vim: >
diff --git a/runtime/doc/term.txt b/runtime/doc/term.txt
index d99f9b7160..39eb0673c4 100644
--- a/runtime/doc/term.txt
+++ b/runtime/doc/term.txt
@@ -41,16 +41,17 @@ $TERM is also important because it is mirrored by SSH to the remote session,
unlike other common client-end environment variables ($COLORTERM,
$XTERM_VERSION, $VTE_VERSION, $KONSOLE_PROFILE_NAME, $TERM_PROGRAM, ...).
- For this terminal Set $TERM to |builtin-terms|?
-
- iTerm.app "iterm" or "iTerm.app" Y
- anything libvte based "vte" or "vte-256color" Y
- (e.g. GNOME Terminal) (aliases: "gnome", "gnome-256color")
- tmux "tmux" or "tmux-256color" Y
- screen "screen" or "screen-256color" Y
- PuTTY "putty" or "putty-256color" Y
- Terminal.app "nsterm" N
- Linux virtual terminal "linux" or "linux-256color" Y
+ For this terminal Set $TERM to |builtin-terms|
+ -------------------------------------------------------------------------
+ iTerm (original) iterm, iTerm.app N
+ iTerm2 (new capabilities) iterm2, iTerm2.app Y
+ anything libvte-based vte, vte-256color Y
+ (e.g. GNOME Terminal) (aliases: gnome, gnome-256color)
+ tmux tmux, tmux-256color Y
+ screen screen, screen-256color Y
+ PuTTY putty, putty-256color Y
+ Terminal.app nsterm N
+ Linux virtual terminal linux, linux-256color Y
*builtin-terms* *builtin_terms*
If a |terminfo| database is not available, or no entry for the terminal type is
diff --git a/runtime/doc/various.txt b/runtime/doc/various.txt
index f06c062ee3..223a0135b2 100644
--- a/runtime/doc/various.txt
+++ b/runtime/doc/various.txt
@@ -212,7 +212,6 @@ g8 Print the hex values of the bytes used in the
Equivalent to: >
:enew
:call termopen('{cmd}')
- :startinsert
<
See |termopen()|.
diff --git a/runtime/doc/vim_diff.txt b/runtime/doc/vim_diff.txt
index 2f031c0b1f..861fa65c3a 100644
--- a/runtime/doc/vim_diff.txt
+++ b/runtime/doc/vim_diff.txt
@@ -6,9 +6,8 @@
Differences between Nvim and Vim *vim-differences*
-Throughout the help files, differences between Nvim and Vim are indicated via
-the "{Nvim}" tag. This document is a complete and centralized list of all
-these differences.
+Nvim differs from Vim in many ways, big and small. This document is
+a complete and centralized reference of those differences.
Type <M-]> to see the table of contents.
@@ -72,12 +71,18 @@ Clipboard integration |provider-clipboard|
USER EXPERIENCE ~
-Working intuitively and consistently is a major goal of Nvim. Examples:
+Working intuitively and consistently is a major goal of Nvim.
-- Nvim does not have `-X`, a platform-specific option "sometimes" available in
- Vim (with potential surprises: http://stackoverflow.com/q/14635295). Nvim
- avoids features that cannot be provided on all platforms--instead that is
- delegated to external plugins/extensions.
+ *feature-compile*
+- Nvim always includes ALL features, in contrast to Vim (which ships with
+ various combinations of 100+ optional features). Think of it as a leaner
+ version of Vim's "HUGE" build. This reduces surface area for bugs, and
+ removes a common source of confusion and friction for users.
+
+- Nvim avoids features that cannot be provided on all platforms; instead that
+ is delegated to external plugins/extensions. E.g. the `-X` platform-specific
+ option is "sometimes" available in Vim (with potential surprises:
+ http://stackoverflow.com/q/14635295).
- Vim's internal test functions (test_autochdir(), test_settime(), etc.) are
not exposed (nor implemented); instead Nvim has a robust API.
@@ -268,13 +273,16 @@ Lua interface (|if_lua.txt|):
- Lua has direct access to Nvim |API| via `vim.api`.
- Lua package.path and package.cpath are automatically updated according to
'runtimepath': |lua-require|.
-- Currently, most legacy Vim features are missing.
-|input()| and |inputdialog()| gained support for each other’s features (return
-on cancel and completion respectively) via dictionary argument (replaces all
+|input()| and |inputdialog()| support for each other’s features (return on
+cancel and completion respectively) via dictionary argument (replaces all
other arguments if used).
-|input()| and |inputdialog()| now support user-defined cmdline highlighting.
+|input()| and |inputdialog()| support user-defined cmdline highlighting.
+
+Highlight groups:
+ |hl-ColorColumn|, |hl-CursorColumn|, |hl-CursorLine| are lower priority than
+ (overridden by) most other highlight groups.
==============================================================================
5. Missing legacy features *nvim-features-missing*
@@ -282,7 +290,7 @@ other arguments if used).
Some legacy Vim features are not implemented:
- |if_py|: vim.bindeval() and vim.Function() are not supported
-- |if_lua|: the `vim` object currently only supports `vim.api`
+- |if_lua|: the `vim` object is missing most legacy methods
- *if_perl*
- *if_mzscheme*
- *if_tcl*
@@ -290,7 +298,7 @@ Some legacy Vim features are not implemented:
==============================================================================
6. Removed features *nvim-features-removed*
-These features are in Vim, but have been intentionally removed from Nvim.
+These Vim features were intentionally removed from Nvim.
*'cp'* *'nocompatible'* *'nocp'* *'compatible'*
Nvim is always "non-compatible" with Vi.
diff --git a/runtime/syntax/vim.vim b/runtime/syntax/vim.vim
index 7025ee5369..26eea03a3c 100644
--- a/runtime/syntax/vim.vim
+++ b/runtime/syntax/vim.vim
@@ -3,8 +3,8 @@
" #############################################################################
" #############################################################################
" Note: Be careful when merging the upstream version of this file.
-" Much of this is generated by scripts/genvimvim.lua (result is installed
-" to: $VIMRUNTIME/syntax/vim/generated.vim)
+" Much of this is generated by scripts/genvimvim.lua
+" (installs to $VIMRUNTIME/syntax/vim/generated.vim)
" #############################################################################
" #############################################################################
@@ -128,6 +128,13 @@ if exists("g:vimsyntax_noerror")
let g:vimsyn_noerror= g:vimsyntax_noerror
endif
+" Variable options {{{2
+if exists("g:vim_maxlines")
+ let s:vimsyn_maxlines= g:vim_maxlines
+else
+ let s:vimsyn_maxlines= 60
+endif
+
" Numbers {{{2
" =======
syn match vimNumber "\<\d\+\%(\.\d\+\%([eE][+-]\=\d\+\)\=\)\=" skipwhite nextgroup=vimGlobal,vimSubst,vimCommand
@@ -601,7 +608,7 @@ syn region vimGlobal matchgroup=Statement start='\<v\%[global]!\=/' skip='\\.' e
" g:vimsyn_embed =~# 'r' : embed ruby
" g:vimsyn_embed =~# 't' : embed tcl
if !exists("g:vimsyn_embed")
- let g:vimsyn_embed= "lpPr"
+ let g:vimsyn_embed= 0
endif
" [-- lua --] {{{3
@@ -744,9 +751,10 @@ if !filereadable(s:mzschemepath)
endif
if g:vimsyn_embed =~# 'm' && filereadable(s:mzschemepath)
unlet! b:current_syntax
- let iskKeep= &isk
+ let s:iskKeep= &isk
exe "syn include @vimMzSchemeScript ".s:mzschemepath
- let &isk= iskKeep
+ let &isk= s:iskKeep
+ unlet s:iskKeep
VimFoldm syn region vimMzSchemeRegion matchgroup=vimScriptDelim start=+mz\%[scheme]\s*<<\s*\z(.*\)$+ end=+^\z1$+ contains=@vimMzSchemeScript
VimFoldm syn region vimMzSchemeRegion matchgroup=vimScriptDelim start=+mz\%[scheme]\s*<<\s*$+ end=+\.$+ contains=@vimMzSchemeScript
syn cluster vimFuncBodyList add=vimMzSchemeRegion
@@ -761,11 +769,7 @@ unlet s:mzschemepath
if exists("g:vimsyn_minlines")
exe "syn sync minlines=".g:vimsyn_minlines
endif
-if exists("g:vimsyn_maxlines")
- exe "syn sync maxlines=".g:vimsyn_maxlines
-else
- syn sync maxlines=60
-endif
+exe "syn sync maxlines=".s:vimsyn_maxlines
syn sync linecont "^\s\+\\"
syn sync match vimAugroupSyncA groupthere NONE "\<aug\%[roup]\>\s\+[eE][nN][dD]"
@@ -778,7 +782,7 @@ if !exists("skip_vim_syntax_inits")
hi def link vimBehaveError vimError
hi def link vimCollClassErr vimError
hi def link vimErrSetting vimError
- hi def link vimEmbedError vimError
+ hi def link vimEmbedError Normal
hi def link vimFTError vimError
hi def link vimFunctionError vimError
hi def link vimFunc vimError
@@ -935,6 +939,11 @@ if !exists("skip_vim_syntax_inits")
hi def link vimUserFunc Normal
hi def link vimVar Identifier
hi def link vimWarn WarningMsg
+
+ hi def link nvimAutoEvent vimAutoEvent
+ hi def link nvimHLGroup vimHLGroup
+ hi def link nvimMap vimMap
+ hi def link nvimUnmap vimUnmap
endif
" Current Syntax Variable: {{{2
diff --git a/runtime/tutor/en/vim-01-beginner.tutor b/runtime/tutor/en/vim-01-beginner.tutor
index fee7de21d2..6364b201d5 100644
--- a/runtime/tutor/en/vim-01-beginner.tutor
+++ b/runtime/tutor/en/vim-01-beginner.tutor
@@ -23,7 +23,7 @@ relevant help (hopefully), and pressing K over any word will try to do so too.
Sometimes you will be required to modify text like
this here
Once you have done the changes correctly, the ✗ sign at the left will change
-to ✓. I imagine you can already see how neat Vim can be ;)
+to ✓. I imagine you can already see how neat Vim can be. ;)
Other times, you'll be prompted to run a command (I'll explain this later):
~~~ cmd
:help <Enter>
@@ -36,30 +36,30 @@ or press a sequence of keys
Text within <'s and >'s (like `<Enter>`{normal}) describes a key to press instead of text
to type.
-Now, move to the next lesson (remember, use j).
+Now, move to the next lesson (remember, use the `j`{normal} key to scroll down).
## Lesson 1.1: MOVING THE CURSOR
** To move the cursor, press the `h`, `j`, `k`, `l` keys as indicated. **
- k Hint: The h key is at the left and moves left.
- ← h l → The l key is at the right and moves right.
- j The j key looks like a down arrow.
+ k Hint: The `h`{normal} key is at the left and moves left.
+ ← h l → The `l`{normal} key is at the right and moves right.
+ j The `j`{normal} key looks like a down arrow.
1. Move the cursor around the screen until you are comfortable.
- 2. Hold down the down key (j) until it repeats.
+ 2. Hold down the down key (`j`{normal}) until it repeats.
Now you know how to move to the next lesson.
3. Using the down key, move to Lesson 1.2.
NOTE: If you are ever unsure about something you typed, press <Esc> to place
- you in Normal mode. Then retype the command you wanted.
+ you in Normal mode. Then retype the command you wanted.
-NOTE: The cursor keys should also work. But using hjkl you will be able to
- move around much faster, once you get used to it. Really!
+NOTE: The cursor keys should also work. But using hjkl you will be able to
+ move around much faster, once you get used to it. Really!
# Lesson 1.2: EXITING VIM
@@ -81,7 +81,7 @@ NOTE: The cursor keys should also work. But using hjkl you will be able to
4. If you have these steps memorized and are confident, execute steps
1 through 3 to exit and re-enter the editor.
-NOTE: [:q!](:q) <Enter> discards any changes you made. In a few lessons you
+NOTE: [:q!](:q) <Enter> discards any changes you made. In a few lessons you
will learn how to save the changes to a file.
5. Move the cursor down to Lesson 1.3.
@@ -90,18 +90,18 @@ NOTE: [:q!](:q) <Enter> discards any changes you made. In a few lessons you
** Press `x`{normal} to delete the character under the cursor. **
-1. Move the cursor to the line below marked --->.
+ 1. Move the cursor to the line below marked --->.
-2. To fix the errors, move the cursor until it is on top of the
- character to be deleted.
+ 2. To fix the errors, move the cursor until it is on top of the
+ character to be deleted.
-3. Press [the x key](x) to delete the unwanted character.
+ 3. Press [the x key](x) to delete the unwanted character.
-4. Repeat steps 2 through 4 until the sentence is correct.
+ 4. Repeat steps 2 through 4 until the sentence is correct.
The ccow jumpedd ovverr thhe mooon.
-5. Now that the line is correct, go on to Lesson 1.4.
+ 5. Now that the line is correct, go on to Lesson 1.4.
NOTE: As you go through this tutor, do not try to memorize, learn by usage.
@@ -114,15 +114,15 @@ NOTE: As you go through this tutor, do not try to memorize, learn by usage.
2. To make the first line the same as the second, move the cursor on top
of the first character AFTER where the text is to be inserted.
- 3. Press i and type in the necessary additions.
+ 3. Press `i`{normal} and type in the necessary additions.
- 4. As each error is fixed press <Esc> to return to Normal mode.
+ 4. As each error is fixed press `<Esc>`{normal} to return to Normal mode.
Repeat steps 2 through 4 to correct the sentence.
There is text misng this .
There is some text missing from this line.
- 5. When you are comfortable inserting text move to lesson 1.5.
+ 5. When you are comfortable inserting text move to Lesson 1.5.
# Lesson 1.5: TEXT EDITING: APPENDING
@@ -131,9 +131,9 @@ There is some text missing from this line.
1. Move the cursor to the first line below marked --->.
It does not matter on what character the cursor is in that line.
- 2. Press [A](A) and type in the necessary additions.
+ 2. Press [A](A) and type in the necessary additions.
- 3. As the text has been appended press <Esc> to return to Normal mode.
+ 3. As the text has been appended press `<Esc>`{normal} to return to Normal mode.
4. Move the cursor to the second line marked ---> and repeat
steps 2 and 3 to correct this sentence.
@@ -143,7 +143,7 @@ There is some text missing from this line.
There is also some text miss
There is also some text missing here.
- 5. When you are comfortable appending text move to lesson 1.6.
+ 5. When you are comfortable appending text move to Lesson 1.6.
# Lesson 1.6: EDITING A FILE
@@ -151,7 +151,7 @@ There is also some text missing here.
!! NOTE: Before executing any of the steps below, read this entire lesson !!
- 1. Exit this tutor as you did in lesson 1.2: :q!
+ 1. Exit this tutor as you did in Lesson 1.2: `:q!`{vim}
Or, if you have access to another terminal, do the following there.
2. At the shell prompt type this command:
@@ -159,7 +159,7 @@ There is also some text missing here.
$ vim tutor
~~~
'vim' is the command to start the Vim editor, 'tutor' is the name of the
- file you wish to edit. Use a file that may be changed.
+ file you wish to edit. Use a file that may be changed.
3. Insert and delete text as you learned in the previous lessons.
@@ -186,14 +186,14 @@ There is also some text missing here.
$ vim FILENAME
~~~
- 3. To exit Vim type: <Esc> :q! <Enter> to trash all changes.
- OR type: <Esc> :wq <Enter> to save the changes.
+ 3. To exit Vim type: `<Esc>`{normal} `:q!`{vim} `<Enter>`{normal} to trash all changes.
+ OR type: `<Esc>`{normal} `:wq`{vim} `<Enter>`{normal} to save the changes.
- 4. To delete the character at the cursor type: `x`{normal}
+ 4. To delete the character at the cursor type: `x`{normal}
5. To insert or append text type:
- `i`{normal} type inserted text `<Esc>`{normal} insert before the cursor
- `A`{normal} type appended text `<Esc>`{normal} append after the line
+ `i`{normal} insert text `<Esc>`{normal} insert before the cursor.
+ `A`{normal} append text `<Esc>`{normal} append after the line.
NOTE: Pressing `<Esc>`{normal} will place you in Normal mode or will cancel
an unwanted and partially completed command.
@@ -210,7 +210,7 @@ Now continue with Lesson 2.
3. Move the cursor to the beginning of a word that needs to be deleted.
- 4. Type [d](d)[w](w) to make the word disappear.
+ 4. Type [d](d)[w](w) to make the word disappear.
There are a some words fun that don't belong paper in this sentence.
@@ -218,9 +218,9 @@ There are a some words fun that don't belong paper in this sentence.
# Lesson 2.2: MORE DELETION COMMANDS
-** Type `d$`{normal} to delete to the end of the line. **
+** Type `d$`{normal} to delete to the end of the line. **
- 1. Press <Esc> to make sure you are in Normal mode.
+ 1. Press `<Esc>`{normal} to make sure you are in Normal mode.
2. Move the cursor to the line below marked --->.
@@ -236,7 +236,7 @@ Somebody typed the end of this line twice. end of this line twice.
Many commands that change text are made from an [operator](operator) and a [motion](navigation).
-The format for a delete command with the [d](d) delete operator is as follows:
+The format for a delete command with the [d](d) delete operator is as follows:
d motion
@@ -249,7 +249,7 @@ The format for a delete command with the [d](d) delete operator is as follows:
[e](e) - to the end of the current word, INCLUDING the last character.
[$]($) - to the end of the line, INCLUDING the last character.
- Thus typing `de`{normal} will delete from the cursor to the end of the word.
+ Thus typing `de`{normal} will delete from the cursor to the end of the word.
NOTE: Pressing just the motion while in Normal mode without an operator will
move the cursor as specified.
@@ -260,11 +260,11 @@ NOTE: Pressing just the motion while in Normal mode without an operator will
1. Move the cursor to the start of the line marked ---> below.
- 2. Type `2w`{normal} to move the cursor two words forward.
+ 2. Type `2w`{normal} to move the cursor two words forward.
- 3. Type `3e`{normal} to move the cursor to the end of the third word forward.
+ 3. Type `3e`{normal} to move the cursor to the end of the third word forward.
- 4. Type `0`{normal} ([zero](0)) to move to the start of the line.
+ 4. Type `0`{normal} ([zero](0)) to move to the start of the line.
5. Repeat steps 2 and 3 with different numbers.
@@ -282,22 +282,22 @@ insert a count before the motion to delete more:
1. Move the cursor to the first UPPER CASE word in the line marked --->.
- 2. Type `d2w`{normal} to delete the two UPPER CASE words
+ 2. Type `d2w`{normal} to delete the two UPPER CASE words
3. Repeat steps 1 and 2 with a different count to delete the consecutive
UPPER CASE words with one command
-this ABC DE line FGHI JK LMN OP of words is Q RS TUV cleaned up.
+This ABC DE line FGHI JK LMN OP of words is Q RS TUV cleaned up.
# Lesson 2.6: OPERATING ON LINES
-** Type dd to delete a whole line. **
+** Type `dd`{normal} to delete a whole line. **
Due to the frequency of whole line deletion, the designers of Vi decided
it would be easier to simply type two d's to delete a line.
1. Move the cursor to the second line in the phrase below.
- 2. Type [dd](dd) to delete the line.
+ 2. Type [dd](dd) to delete the line.
3. Now move to the fourth line.
4. Type `2dd`{normal} to delete two lines.
@@ -311,20 +311,20 @@ this ABC DE line FGHI JK LMN OP of words is Q RS TUV cleaned up.
# Lesson 2.7: THE UNDO COMMAND
-** Press u to undo the last commands, U to fix a whole line. **
+** Press `u`{normal} to undo the last commands, `U`{normal} to fix a whole line. **
1. Move the cursor to the line below marked ---> and place it on the
first error.
- 2. Type `x`{normal} to delete the first unwanted character.
- 3. Now type `u`{normal} to undo the last command executed.
- 4. This time fix all the errors on the line using the `x`{normal} command.
- 5. Now type a capital `U`{normal} to return the line to its original state.
- 6. Now type `u`{normal} a few times to undo the U and preceding commands.
- 7. Now type `<Ctrl-r>`{normal} a few times to redo the commands (undo the undo's).
+ 2. Type `x`{normal} to delete the first unwanted character.
+ 3. Now type `u`{normal} to undo the last command executed.
+ 4. This time fix all the errors on the line using the `x`{normal} command.
+ 5. Now type a capital `U`{normal} to return the line to its original state.
+ 6. Now type `u`{normal} a few times to undo the `U`{normal} and preceding commands.
+ 7. Now type `<Ctrl-r>`{normal} a few times to redo the commands (undo the undo's).
Fiix the errors oon thhis line and reeplace them witth undo.
- 8. These are very useful commands. Now move on to the Lesson 2 Summary.
+ 8. These are very useful commands. Now move on to the Lesson 2 Summary.
# Lesson 2 SUMMARY
@@ -336,13 +336,13 @@ Fiix the errors oon thhis line and reeplace them witth undo.
5. The format for a change command is:
operator [number] motion
where:
- operator - is what to do, such as [d](d) for delete
+ operator - is what to do, such as [d](d) for delete
[number] - is an optional count to repeat the motion
motion - moves over the text to operate on, such as:
[w](w) (word),
[$]($) (to the end of line), etc.
- 6. To move to the start of the line use a zero: [0](0)
+ 6. To move to the start of the line use a zero: [0](0)
7. To undo previous actions, type: `u`{normal} (lowercase u)
To undo all the changes on a line, type: `U`{normal} (capital U)
@@ -350,15 +350,15 @@ Fiix the errors oon thhis line and reeplace them witth undo.
# Lesson 3.1: THE PUT COMMAND
-** Type p to put previously deleted text after the cursor. **
+** Type `p`{normal} to put previously deleted text after the cursor. **
1. Move the cursor to the first ---> line below.
- 2. Type `dd`{normal} to delete the line and store it in a Vim register.
+ 2. Type `dd`{normal} to delete the line and store it in a Vim register.
3. Move the cursor to the c) line, ABOVE where the deleted line should go.
- 4. Type `p`{normal} to put the line below the cursor.
+ 4. Type `p`{normal} to put the line below the cursor.
5. Repeat steps 2 through 4 to put all the lines in correct order.
@@ -388,11 +388,11 @@ NOTE: Remember that you should be learning by doing, not memorization.
# Lesson 3.3: THE CHANGE OPERATOR
-** To change until the end of a word, type `ce`{normal} **
+** To change until the end of a word, type `ce`{normal}. **
1. Move the cursor to the first line below marked --->.
- 2. Place the cursor on the "u" in "lubw".
+ 2. Place the cursor on the "u" in "lubw".
3. Type `ce`{normal} and the correct word (in this case, type "ine" ).
@@ -405,11 +405,11 @@ This line has a few words that need changing using the change operator.
Notice that [c](c)e deletes the word and places you in Insert mode.
-# Lesson 3.4: MORE CHANGES USING c
+# Lesson 3.4: MORE CHANGES USING `c`{normal}
** The change operator is used with the same motions as delete. **
- 1. The change operator works in the same way as delete. The format is:
+ 1. The change operator works in the same way as delete. The format is:
c [number] motion
@@ -422,13 +422,13 @@ Notice that [c](c)e deletes the word and places you in Insert mode.
5. Type `c$`{normal} and type the rest of the line like the second and press `<Esc>`{normal}.
The end of this line needs some help to make it like the second.
-The end of this line needs to be corrected using the c$ command.
+The end of this line needs to be corrected using the `c$`{normal} command.
-NOTE: You can use the Backspace key to correct mistakes while typing.
+NOTE: You can use the Backspace key to correct mistakes while typing.
# Lesson 3 SUMMARY
- 1. To put back text that has just been deleted, type [p](p). This puts the
+ 1. To put back text that has just been deleted, type [p](p). This puts the
deleted text AFTER the cursor (if a line was deleted it will go on the
line below the cursor).
@@ -436,8 +436,8 @@ NOTE: You can use the Backspace key to correct mistakes while typing.
character you want to have there.
3. The [change operator](c) allows you to change from the cursor to where the
- motion takes you. eg. Type `ce`{normal} to change from the cursor to the end of
- the word, `c$`{normal} to change to the end of a line.
+ motion takes you. Type `ce`{normal} to change from the cursor to the end of
+ the word, `c$`{normal} to change to the end of a line.
4. The format for change is:
@@ -448,21 +448,21 @@ Now go on to the next lesson.
# Lesson 4.1: CURSOR LOCATION AND FILE STATUS
** Type `<Ctrl-g>`{normal} to show your location in the file and the file status.
- Type `G`{normal} to move to a line in the file. **
+ Type `G`{normal} to move to a line in the file. **
NOTE: Read this entire lesson before executing any of the steps!!
- 1. Hold down the `<Ctrl>`{normal} key and press `g`{normal}. We call this `<Ctrl-g>`{normal}.
+ 1. Hold down the `<Ctrl>`{normal} key and press `g`{normal}. We call this `<Ctrl-g>`{normal}.
A message will appear at the bottom of the page with the filename and the
- position in the file. Remember the line number for Step 3.
+ position in the file. Remember the line number for Step 3.
-NOTE: You may see the cursor position in the lower right corner of the screen
- This happens when the ['ruler']('ruler') option is set (see :help 'ruler' )
+NOTE: You may see the cursor position in the lower right corner of the screen
+ This happens when the ['ruler']('ruler') option is set (see `:help 'ruler'`{vim} ).
- 2. Press [G](G) to move you to the bottom of the file.
- Type [gg](gg) to move you to the start of the file.
+ 2. Press [G](G) to move you to the bottom of the file.
+ Type [gg](gg) to move you to the start of the file.
- 3. Type the number of the line you were on and then `G`{normal} . This will
+ 3. Type the number of the line you were on and then `G`{normal}. This will
return you to the line you were on when you first pressed `<Ctrl-g>`{normal}.
4. If you feel confident to do this, execute steps 1 through 3.
@@ -471,20 +471,20 @@ NOTE: You may see the cursor position in the lower right corner of the screen
** Type `/`{normal} followed by a phrase to search for the phrase. **
- 1. In Normal mode type the `/`{normal} character. Notice that it and the cursor
- appear at the bottom of the screen as with the : command.
+ 1. In Normal mode type the `/`{normal} character. Notice that it and the cursor
+ appear at the bottom of the screen as with the `:`{normal} command.
- 2. Now type 'errroor' `<Enter>`{normal}. This is the word you want to search for.
+ 2. Now type 'errroor' `<Enter>`{normal}. This is the word you want to search for.
- 3. To search for the same phrase again, simply type [n](n) .
- To search for the same phrase in the opposite direction, type [N](N) .
+ 3. To search for the same phrase again, simply type [n](n).
+ To search for the same phrase in the opposite direction, type [N](N).
- 4. To search for a phrase in the backward direction, use [?](?) instead of / .
+ 4. To search for a phrase in the backward direction, use [?](?) instead of `/`{normal}.
- 5. To go back to where you came from press `<Ctrl-o>`{normal} (Keep Ctrl down while
- pressing the letter o). Repeat to go back further. `<Ctrl-i>`{normal} goes forward.
+ 5. To go back to where you came from press `<Ctrl-o>`{normal} (keep `<Ctrl>`{normal} pressed down while
+ pressing the letter `o`{normal}). Repeat to go back further. `<Ctrl-i>`{normal} goes forward.
-"errroor" is not the way to spell error; errroor is an error.
+"errroor" is not the way to spell error; errroor is an error.
NOTE: When the search reaches the end of the file it will continue at the
start, unless the ['wrapscan']('wrapscan') option has been reset.
@@ -495,7 +495,7 @@ NOTE: When the search reaches the end of the file it will continue at the
1. Place the cursor on any (, [, or { in the line below marked --->.
- 2. Now type the [%](%) character.
+ 2. Now type the [%](%) character.
3. The cursor will move to the matching parenthesis or bracket.
@@ -528,7 +528,7 @@ NOTE: This is very useful in debugging a program with unmatched parentheses!
Adding the g [flag](:s_flags) means to substitute globally in the line, change
all occurrences of "thee" in the line.
-thee best time to see thee flowers is in thee spring.
+Usually thee best time to see thee flowers is in thee spring.
4. To change every occurrence of a character string between two lines, type
~~~ cmd
@@ -589,20 +589,20 @@ thee best time to see thee flowers is in thee spring.
** Type `:!`{vim} followed by an external command to execute that command. **
1. Type the familiar command `:`{normal} to set the cursor at the bottom of the
- screen. This allows you to enter a command-line command.
+ screen. This allows you to enter a command-line command.
- 2. Now type the [!](!cmd) (exclamation point) character. This allows you to
+ 2. Now type the [!](!cmd) (exclamation point) character. This allows you to
execute any external shell command.
- 3. As an example type "ls" following the "!" and then hit `<Enter>`{normal}. This
+ 3. As an example type "ls" following the "!" and then hit `<Enter>`{normal}. This
will show you a listing of your directory, just as if you were at the
shell prompt.
-NOTE: It is possible to execute any external command this way, also with
- arguments.
+NOTE: It is possible to execute any external command this way, also with
+ arguments.
-NOTE: All : commands must be finished by hitting <Enter>
- From here on we will not always mention it.
+NOTE: All `:`{vim} commands must be finished by hitting `<Enter>`{normal}.
+ From here on we will not always mention it.
# Lesson 5.2: MORE ON WRITING FILES
@@ -622,7 +622,7 @@ NOTE: All : commands must be finished by hitting <Enter>
4. This saves the whole file (the Vim Tutor) under the name TEST.
To verify this, type `:!ls`{vim} again to see your directory.
-NOTE: If you were to exit Vim and start it again with vim TEST , the file
+NOTE: If you were to exit Vim and start it again with `nvim TEST`, the file
would be an exact copy of the tutor when you saved it.
5. Now remove the file by typing:
@@ -632,14 +632,14 @@ NOTE: If you were to exit Vim and start it again with vim TEST , the file
# Lesson 5.3: SELECTING TEXT TO WRITE
-** To save part of the file, type `v`{normal} motion `:w FILENAME`{vim} **
+** To save part of the file, type `v`{normal} motion `:w FILENAME`{vim}. **
1. Move the cursor to this line.
- 2. Press [v](v) and move the cursor to the fifth item below. Notice that the
+ 2. Press [v](v) and move the cursor to the fifth item below. Notice that the
text is highlighted.
- 3. Press the `:`{normal} character. At the bottom of the screen
+ 3. Press the `:`{normal} character. At the bottom of the screen
:'<,'>
@@ -649,27 +649,27 @@ NOTE: If you were to exit Vim and start it again with vim TEST , the file
`:w TEST`{vim}
- where TEST is a filename that does not exist yet. Verify that you see
+ where TEST is a filename that does not exist yet. Verify that you see
`:'<,'>w TEST`{vim}
before you press `<Enter>`{normal}.
- 5. Vim will write the selected lines to the file TEST. Use `:!ls`{vim} to see it.
- Do not remove it yet! We will use it in the next lesson.
+ 5. Vim will write the selected lines to the file TEST. Use `:!ls`{vim} to see it.
+ Do not remove it yet! We will use it in the next lesson.
-NOTE: Pressing [v](v) starts [Visual selection](visual-mode). You can move
- the cursor around to make the selection bigger or smaller. Then you can
- use an operator to do something with the text. For example, `d`{normal} deletes
- the text.
+NOTE: Pressing [v](v) starts [Visual selection](visual-mode). You can move
+ the cursor around to make the selection bigger or smaller. Then you can
+ use an operator to do something with the text. For example, `d`{normal} deletes
+ the text.
# Lesson 5.4: RETRIEVING AND MERGING FILES
-** To insert the contents of a file, type `:r FILENAME`{vim} **
+** To insert the contents of a file, type `:r FILENAME`{vim}. **
1. Place the cursor just above this line.
-NOTE: After executing Step 2 you will see text from Lesson 5.3. Then move
+NOTE: After executing Step 2 you will see text from Lesson 5.3. Then move
DOWN to see this lesson again.
2. Now retrieve your TEST file using the command
@@ -682,31 +682,31 @@ NOTE: After executing Step 2 you will see text from Lesson 5.3. Then move
3. To verify that a file was retrieved, cursor back and notice that there
are now two copies of Lesson 5.3, the original and the file version.
-NOTE: You can also read the output of an external command. For example,
+NOTE: You can also read the output of an external command. For example,
- `:r !ls`{vim}
+ `:r !ls`{vim}
- reads the output of the `ls` command and puts it below the cursor.
+ reads the output of the `ls` command and puts it below the cursor.
# Lesson 5 SUMMARY
- 1. [:!command](:!cmd) executes an external command.
+ 1. [:!command](:!cmd) executes an external command.
- Some useful examples are:
- `:!ls`{vim} - shows a directory listing
- `:!rm FILENAME`{vim} - removes file FILENAME
+ Some useful examples are:
+ `:!ls`{vim} - shows a directory listing
+ `:!rm FILENAME`{vim} - removes file FILENAME
- 2. [:w](:w) FILENAME writes the current Vim file to disk with
- name FILENAME.
+ 2. [:w](:w) FILENAME writes the current Vim file to disk with
+ name FILENAME.
- 3. [v](v) motion :w FILENAME saves the Visually selected lines in file
- FILENAME.
+ 3. [v](v) motion :w FILENAME saves the Visually selected lines in file
+ FILENAME.
- 4. [:r](:r) FILENAME retrieves disk file FILENAME and puts it
- below the cursor position.
+ 4. [:r](:r) FILENAME retrieves disk file FILENAME and puts it
+ below the cursor position.
- 5. [:r !dir](:r!) reads the output of the dir command and
- puts it below the cursor position.
+ 5. [:r !dir](:r!) reads the output of the dir command and
+ puts it below the cursor position.
# Lesson 6.1: THE OPEN COMMAND
@@ -719,10 +719,10 @@ NOTE: You can also read the output of an external command. For example,
3. Now type some text and press `<Esc>`{normal} to exit Insert mode.
-After typing o the cursor is placed on the open line in Insert mode.
+After typing `o`{normal} the cursor is placed on the open line in Insert mode.
4. To open up a line ABOVE the cursor, simply type a [capital O](O), rather
- than a lowercase `o`{normal}. Try this on the line below.
+ than a lowercase `o`{normal}. Try this on the line below.
Open up a line above this by typing O while the cursor is on this line.
@@ -734,9 +734,9 @@ Open up a line above this by typing O while the cursor is on this line.
2. Press `e`{normal} until the cursor is on the end of "li".
- 3. Type an `a`{normal} (lowercase) to [append](a) text AFTER the cursor.
+ 3. Type the lowercase letter `a`{normal} to [append](a) text AFTER the cursor.
- 4. Complete the word like the line below it. Press `<Esc>`{normal} to exit Insert
+ 4. Complete the word like the line below it. Press `<Esc>`{normal} to exit Insert
mode.
5. Use `e`{normal} to move to the next incomplete word and repeat steps 3 and 4.
@@ -744,20 +744,20 @@ Open up a line above this by typing O while the cursor is on this line.
This li will allow you to pract appendi text to a line.
This line will allow you to practice appending text to a line.
-NOTE: [a](a), [i](i) and [A](A) all go to the same Insert mode, the only difference is where
- the characters are inserted.
+NOTE: [a](a), [i](i) and [A](A) all go to the same Insert mode, the only difference is where
+ the characters are inserted.
# Lesson 6.3: ANOTHER WAY TO REPLACE
** Type a capital `R`{normal} to replace more than one character. **
- 1. Move the cursor to the first line below marked --->. Move the cursor to
+ 1. Move the cursor to the first line below marked --->. Move the cursor to
the beginning of the first "xxx".
2. Now press `R`{normal} ([capital R](R)) and type the number below it in the second line, so that it
replaces the "xxx".
- 3. Press `<Esc>`{normal} to leave [Replace mode](mode-replace). Notice that the rest of the line
+ 3. Press `<Esc>`{normal} to leave [Replace mode](mode-replace). Notice that the rest of the line
remains unmodified.
4. Repeat the steps to replace the remaining "xxx".
@@ -765,12 +765,12 @@ NOTE: [a](a), [i](i) and [A](A) all go to the same Insert mode, the only differ
Adding 123 to xxx gives you xxx.
Adding 123 to 456 gives you 579.
-NOTE: Replace mode is like Insert mode, but every typed character deletes an
- existing character.
+NOTE: Replace mode is like Insert mode, but every typed character deletes an
+ existing character.
# Lesson 6.4: COPY AND PASTE TEXT
-** Use the `y`{normal} operator to copy text and `p`{normal} to paste it **
+** Use the `y`{normal} operator to copy text and `p`{normal} to paste it. **
1. Go to the line marked with ---> below and place the cursor after "a)".
@@ -780,35 +780,37 @@ NOTE: Replace mode is like Insert mode, but every typed character deletes an
4. Move the cursor to the end of the next line: `j$`{normal}
- 5. Type `p`{normal} to [put](put) (paste) the text. Then type: "a second"`<Esc>`{normal}.
+ 5. Type `p`{normal} to [put](put) (paste) the text.
+
+ 6. Press `a`{normal} and then type "second". Press `<Esc>`{normal} to leave Insert mode.
- 6. Use Visual mode to select " item.", yank it with `y`{normal}, move to the end of
+ 7. Use Visual mode to select " item.", yank it with `y`{normal}, move to the end of
the next line with `j$`{normal} and put the text there with `p`{normal}.
-a) this is the first item.
- b)
+a) This is the first item.
+ b)
- NOTE: you can also use `y`{normal} as an operator; `yw`{normal} yanks one word.
+NOTE: you can also use `y`{normal} as an operator; `yw`{normal} yanks one word.
# Lesson 6.5: SET OPTION
-** Set an option so a search or substitute ignores case **
+** Set an option so a search or substitute ignores case. **
- 1. Search for 'ignore' by entering: `/ignore`
+ 1. Search for 'ignore' by entering: `/ignore`
Repeat several times by pressing `n`{normal}.
2. Set the 'ic' (Ignore case) option by entering:
~~~ cmd
:set ic
~~~
- 3. Now search for 'ignore' again by pressing n
+ 3. Now search for 'ignore' again by pressing `n`{normal}.
Notice that Ignore and IGNORE are now also found.
4. Set the 'hlsearch' and 'incsearch' options:
~~~ cmd
:set hls is
~~~
- 5. Now type the search command again and see what happens: /ignore <Enter>
+ 5. Now type the search command again and see what happens: /ignore <Enter>
6. To disable ignoring case enter:
~~~ cmd
@@ -818,12 +820,12 @@ a) this is the first item.
~~~ cmd
:set invic
~~~
-NOTE: To remove the highlighting of matches enter:
+NOTE: To remove the highlighting of matches enter:
~~~ cmd
:nohlsearch
~~~
-NOTE: If you want to ignore case for just one search command, use [\c](/\c)
- in the phrase: /ignore\c <Enter>
+NOTE: If you want to ignore case for just one search command, use [\c](/\c)
+ in the phrase: /ignore\c <Enter>
# Lesson 6 SUMMARY
@@ -839,7 +841,7 @@ NOTE: If you want to ignore case for just one search command, use [\c](/\c)
5. Typing a capital `R`{normal} enters Replace mode until `<Esc>`{normal} is pressed.
- 6. Typing "[:set](:set) xxx" sets the option "xxx". Some options are:
+ 6. Typing "[:set](:set) xxx" sets the option "xxx". Some options are:
'ic' 'ignorecase' ignore upper/lower case when searching
'is' 'incsearch' show partial matches for a search phrase
@@ -858,9 +860,9 @@ NOTE: If you want to ignore case for just one search command, use [\c](/\c)
# Lesson 7.1: GETTING HELP
-** Use the on-line help system **
+** Use the on-line help system. **
-Vim has a comprehensive on-line help system. To get started, try one of
+Vim has a comprehensive on-line help system. To get started, try one of
these three:
- press the `<HELP>`{normal} key (if you have one)
- press the `<F1>`{normal} key (if you have one)
@@ -872,7 +874,7 @@ Type `<Ctrl-w><Ctrl-w>`{normal} to jump from one window to another.
Type `:q`{vim} to close the help window.
You can find help on just about any subject, by giving an argument to the
-":help" command. Try these (don't forget pressing <Enter>):
+":help" command. Try these (don't forget pressing <Enter>):
~~~ cmd
:help w
:help c_CTRL-D
@@ -881,13 +883,13 @@ You can find help on just about any subject, by giving an argument to the
~~~
# Lesson 7.2: CREATE A STARTUP SCRIPT
-** Enable Vim features **
+** Enable Vim features. **
Vim has many more features than Vi, but most of them are disabled by
-default. To start using more features you have to create a "vimrc" file.
+default. To start using more features you have to create a "vimrc" file.
- 1. Start editing the "vimrc" file. This depends on your system:
- `:e ~/.config/nvim/init.vim`{vim} for Unix-like systems
+ 1. Start editing the "vimrc" file. This depends on your system:
+ `:e ~/.config/nvim/init.vim`{vim} for Unix-like systems
2. Now read the example "vimrc" file contents:
`:r $VIMRUNTIME/vimrc_example.vim`{vim}
@@ -897,15 +899,15 @@ default. To start using more features you have to create a "vimrc" file.
The next time you start Vim it will use syntax highlighting.
You can add all your preferred settings to this "vimrc" file.
- For more information type :help vimrc-intro
+ For more information type `:help vimrc-intro`{vim}.
# Lesson 7.3: COMPLETION
-** Command line completion with `<Ctrl-d>`{normal} and `<Tab>`{normal} **
+** Command line completion with `<Ctrl-d>`{normal} and `<Tab>`{normal}. **
- 1. Look what files exist in the directory: `:!ls`{vim}
+ 1. Look what files exist in the directory: `:!ls`{vim}
- 2. Type the start of a command: `:e`{vim}
+ 2. Type the start of a command: `:e`{vim}
3. Press `<Ctrl-d>`{normal} and Vim will show a list of commands that start with "e".
@@ -913,20 +915,20 @@ default. To start using more features you have to create a "vimrc" file.
5. Now add a space and the start of an existing file name: `:edit FIL`{vim}
- 6. Press `<Tab>`{normal}. Vim will complete the name (if it is unique).
+ 6. Press `<Tab>`{normal}. Vim will complete the name (if it is unique).
-NOTE: Completion works for many commands. It is especially useful for `:help`{vim}.
+NOTE: Completion works for many commands. It is especially useful for `:help`{vim}.
# Lesson 7 SUMMARY
1. Type `:help`{vim}
or press `<F1>`{normal} or `<Help>`{normal} to open a help window.
- 2. Type `:help TOPIC`{vim} to find help on TOPIC.
+ 2. Type `:help TOPIC`{vim} to find help on TOPIC.
- 3. Type `<Ctrl-w><Ctrl-w>`{normal} to jump to another window
+ 3. Type `<Ctrl-w><Ctrl-w>`{normal} to jump to another window
- 4. Type `:q`{vim} to close the help window
+ 4. Type `:q`{vim} to close the help window
5. Create a vimrc startup script to keep your preferred settings.
@@ -937,24 +939,24 @@ NOTE: Completion works for many commands. It is especially useful for `:help`{v
This was intended to give a brief overview of the Vim editor, just enough to
allow you to use the editor fairly easily. It is far from complete as Vim has
-many many more commands. Consult the help often.
+many many more commands. Consult the help often.
There are many resources online to learn more about vim. Here's a bunch of them:
- *Learn Vim Progressively*: http://yannesposito.com/Scratch/en/blog/Learn-Vim-Progressively/
- *Learning Vim in 2014*: http://benmccormick.org/learning-vim-in-2014/
-- Vimcasts: http://vimcasts.org/
-- Vim Video-Tutorials by Derek Wyatt: http://derekwyatt.org/vim/tutorials/
+- *Vimcasts*: http://vimcasts.org/
+- *Vim Video-Tutorials by Derek Wyatt*: http://derekwyatt.org/vim/tutorials/
- *Learn Vimscript the Hard Way*: http://learnvimscriptthehardway.stevelosh.com/
- *7 Habits of Effective Text Editing*: http://www.moolenaar.net/habits.html
- *vim-galore*: https://github.com/mhinz/vim-galore
If you prefer a book, *Practical Vim* by Drew Neil is recommended often (the sequel, *Modern
-Vim*, includes material specific to nvim!).
+Vim*, includes material specific to nvim).
This tutorial was written by Michael C. Pierce and Robert K. Ware, Colorado
School of Mines using ideas supplied by Charles Smith, Colorado State
-University. E-mail: bware@mines.colorado.edu.
+University. E-mail: bware@mines.colorado.edu.
Modified for Vim by Bram Moolenaar.
Modified for vim-tutor-mode by Felipe Morales.
diff --git a/runtime/tutor/en/vim-01-beginner.tutor.json b/runtime/tutor/en/vim-01-beginner.tutor.json
index 3f55971a09..444bd7c4b7 100644
--- a/runtime/tutor/en/vim-01-beginner.tutor.json
+++ b/runtime/tutor/en/vim-01-beginner.tutor.json
@@ -11,7 +11,7 @@
"215": "There are some words that don't belong in this sentence.",
"231": "Somebody typed the end of this line twice.",
"271": -1,
- "290": "this line of words is cleaned up.",
+ "290": "This line of words is cleaned up.",
"304": -1,
"305": -1,
"306": -1,
@@ -32,14 +32,14 @@
"425": "The end of this line needs to be corrected using the c$ command.",
"487": -1,
"506": -1,
- "531": "the best time to see the flowers is in the spring.",
+ "531": "Usually the best time to see the flowers is in the spring.",
"722": -1,
"727": -1,
"744": "This line will allow you to practice appending text to a line.",
"745": "This line will allow you to practice appending text to a line.",
"765": "Adding 123 to 456 gives you 579.",
"766": "Adding 123 to 456 gives you 579.",
- "788": "a) this is the first item.",
- "789": " b) this is the second item."
+ "790": "a) This is the first item.",
+ "791": " b) This is the second item."
}
}
diff --git a/scripts/vim-patch.sh b/scripts/vim-patch.sh
index 5ebb6a38b3..4f6bb40488 100755
--- a/scripts/vim-patch.sh
+++ b/scripts/vim-patch.sh
@@ -133,7 +133,7 @@ preprocess_patch() {
# Remove *.proto, Make*, gui_*, some if_*
local na_src='proto\|Make*\|gui_*\|if_lua\|if_mzsch\|if_olepp\|if_ole\|if_perl\|if_py\|if_ruby\|if_tcl\|if_xcmdsrv'
- 2>/dev/null $nvim --cmd 'set dir=/tmp' +'g@^diff --git a/src/\S*\<\%('${na_src}'\)@norm! d/\v(^diff)|%$ ' +w +q "$file"
+ 2>/dev/null $nvim --cmd 'set dir=/tmp' +'g@^diff --git a/src/\S*\<\%(testdir/\)\@<!\%('${na_src}'\)@norm! d/\v(^diff)|%$ ' +w +q "$file"
# Remove channel.txt, netbeans.txt, os_*.txt, term.txt, todo.txt, version*.txt, tags
local na_doc='channel\.txt\|netbeans\.txt\|os_\w\+\.txt\|term\.txt\|todo\.txt\|version\d\.txt\|tags'
diff --git a/src/nvim/CMakeLists.txt b/src/nvim/CMakeLists.txt
index 77e4721853..e7b9deb152 100644
--- a/src/nvim/CMakeLists.txt
+++ b/src/nvim/CMakeLists.txt
@@ -10,6 +10,11 @@ if(USE_GCOV)
endif()
endif()
+if(WIN32)
+ # tell MinGW compiler to enable wmain
+ set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -municode")
+endif()
+
set(TOUCHES_DIR ${PROJECT_BINARY_DIR}/touches)
set(GENERATOR_DIR ${CMAKE_CURRENT_LIST_DIR}/generators)
set(GENERATED_DIR ${PROJECT_BINARY_DIR}/src/nvim/auto)
diff --git a/src/nvim/api/ui.c b/src/nvim/api/ui.c
index 573be23d8e..afbee09c1c 100644
--- a/src/nvim/api/ui.c
+++ b/src/nvim/api/ui.c
@@ -215,6 +215,7 @@ static void ui_set_option(UI *ui, String name, Object value, Error *error)
#undef UI_EXT_OPTION
}
+/// Pushes data into UI.UIData, to be consumed later by remote_ui_flush().
static void push_call(UI *ui, char *name, Array args)
{
Array call = ARRAY_DICT_INIT;
@@ -241,39 +242,7 @@ static void push_call(UI *ui, char *name, Array args)
static void remote_ui_highlight_set(UI *ui, HlAttrs attrs)
{
Array args = ARRAY_DICT_INIT;
- Dictionary hl = ARRAY_DICT_INIT;
-
- if (attrs.bold) {
- PUT(hl, "bold", BOOLEAN_OBJ(true));
- }
-
- if (attrs.underline) {
- PUT(hl, "underline", BOOLEAN_OBJ(true));
- }
-
- if (attrs.undercurl) {
- PUT(hl, "undercurl", BOOLEAN_OBJ(true));
- }
-
- if (attrs.italic) {
- PUT(hl, "italic", BOOLEAN_OBJ(true));
- }
-
- if (attrs.reverse) {
- PUT(hl, "reverse", BOOLEAN_OBJ(true));
- }
-
- if (attrs.foreground != -1) {
- PUT(hl, "foreground", INTEGER_OBJ(attrs.foreground));
- }
-
- if (attrs.background != -1) {
- PUT(hl, "background", INTEGER_OBJ(attrs.background));
- }
-
- if (attrs.special != -1) {
- PUT(hl, "special", INTEGER_OBJ(attrs.special));
- }
+ Dictionary hl = hlattrs2dict(attrs);
ADD(args, DICTIONARY_OBJ(hl));
push_call(ui, "highlight_set", args);
diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c
index 2bc31b2812..98f4410347 100644
--- a/src/nvim/api/vim.c
+++ b/src/nvim/api/vim.c
@@ -55,6 +55,47 @@ void nvim_command(String command, Error *err)
try_end(err);
}
+/// Gets a highlight definition by name.
+///
+/// @param name Highlight group name
+/// @param rgb Export RGB colors
+/// @param[out] err Error details, if any
+/// @return Highlight definition map
+/// @see nvim_get_hl_by_id
+Dictionary nvim_get_hl_by_name(String name, Boolean rgb, Error *err)
+ FUNC_API_SINCE(3)
+{
+ Dictionary result = ARRAY_DICT_INIT;
+ int id = syn_name2id((const char_u *)name.data);
+
+ if (id == 0) {
+ api_set_error(err, kErrorTypeException, "Invalid highlight name: %s",
+ name.data);
+ return result;
+ }
+ result = nvim_get_hl_by_id(id, rgb, err);
+ return result;
+}
+
+/// Gets a highlight definition by id. |hlID()|
+///
+/// @param hl_id Highlight id as returned by |hlID()|
+/// @param rgb Export RGB colors
+/// @param[out] err Error details, if any
+/// @return Highlight definition map
+/// @see nvim_get_hl_by_name
+Dictionary nvim_get_hl_by_id(Integer hl_id, Boolean rgb, Error *err)
+ FUNC_API_SINCE(3)
+{
+ Dictionary dic = ARRAY_DICT_INIT;
+ if (syn_get_final_id((int)hl_id) == 0) {
+ api_set_error(err, kErrorTypeException, "Invalid highlight id: %d", hl_id);
+ return dic;
+ }
+ int attrcode = syn_id2attr((int)hl_id);
+ return hl_get_attr_by_id(attrcode, rgb, err);
+}
+
/// Passes input keys to Nvim.
/// On VimL error: Does not fail, but updates v:errmsg.
///
@@ -255,12 +296,11 @@ free_vim_args:
return rv;
}
-/// Execute lua code. Parameters might be passed, they are available inside
-/// the chunk as `...`. The chunk can return a value.
+/// Execute lua code. Parameters (if any) are available as `...` inside the
+/// chunk. The chunk can return a value.
///
-/// To evaluate an expression, it must be prefixed with "return ". For
-/// instance, to call a lua function with arguments sent in and get its
-/// return value back, use the code "return my_function(...)".
+/// Only statements are executed. To evaluate an expression, prefix it
+/// with `return`: return my_function(...)
///
/// @param code lua code to execute
/// @param args Arguments to the code
@@ -423,29 +463,18 @@ void nvim_del_var(String name, Error *err)
dict_set_var(&globvardict, name, NIL, true, false, err);
}
-/// Sets a global variable
-///
/// @deprecated
-///
-/// @param name Variable name
-/// @param value Variable value
-/// @param[out] err Error details, if any
+/// @see nvim_set_var
/// @return Old value or nil if there was no previous value.
-///
-/// @warning It may return nil if there was no previous value
-/// or if previous value was `v:null`.
+/// @warning May return nil if there was no previous value
+/// OR if previous value was `v:null`.
Object vim_set_var(String name, Object value, Error *err)
{
return dict_set_var(&globvardict, name, value, false, true, err);
}
-/// Removes a global variable
-///
/// @deprecated
-///
-/// @param name Variable name
-/// @param[out] err Error details, if any
-/// @return Old value
+/// @see nvim_del_var
Object vim_del_var(String name, Error *err)
{
return dict_set_var(&globvardict, name, NIL, true, true, err);
@@ -484,7 +513,8 @@ void nvim_set_option(String name, Object value, Error *err)
set_option_to(NULL, SREQ_GLOBAL, name, value, err);
}
-/// Writes a message to vim output buffer
+/// Writes a message to the Vim output buffer. Does not append "\n", the
+/// message is buffered (won't display) until a linefeed is written.
///
/// @param str Message
void nvim_out_write(String str)
@@ -493,7 +523,8 @@ void nvim_out_write(String str)
write_msg(str, false);
}
-/// Writes a message to vim error buffer
+/// Writes a message to the Vim error buffer. Does not append "\n", the
+/// message is buffered (won't display) until a linefeed is written.
///
/// @param str Message
void nvim_err_write(String str)
@@ -502,8 +533,8 @@ void nvim_err_write(String str)
write_msg(str, true);
}
-/// Writes a message to vim error buffer. Appends a linefeed to ensure all
-/// contents are written.
+/// Writes a message to the Vim error buffer. Appends "\n", so the buffer is
+/// flushed (and displayed).
///
/// @param str Message
/// @see nvim_err_write()
diff --git a/src/nvim/aucmd.c b/src/nvim/aucmd.c
new file mode 100644
index 0000000000..fc421116ea
--- /dev/null
+++ b/src/nvim/aucmd.c
@@ -0,0 +1,41 @@
+// 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
+
+#include "nvim/os/os.h"
+#include "nvim/fileio.h"
+#include "nvim/vim.h"
+#include "nvim/main.h"
+#include "nvim/ui.h"
+
+#ifdef INCLUDE_GENERATED_DECLARATIONS
+# include "aucmd.c.generated.h"
+#endif
+
+static void focusgained_event(void **argv)
+{
+ bool *gainedp = argv[0];
+ do_autocmd_focusgained(*gainedp);
+ xfree(gainedp);
+}
+void aucmd_schedule_focusgained(bool gained)
+{
+ bool *gainedp = xmalloc(sizeof(*gainedp));
+ *gainedp = gained;
+ loop_schedule_deferred(&main_loop,
+ event_create(focusgained_event, 1, gainedp));
+}
+
+static void do_autocmd_focusgained(bool gained)
+ FUNC_ATTR_NONNULL_ALL
+{
+ static bool recursive = false;
+
+ if (recursive) {
+ return; // disallow recursion
+ }
+ recursive = true;
+ apply_autocmds((gained ? EVENT_FOCUSGAINED : EVENT_FOCUSLOST),
+ NULL, NULL, false, curbuf);
+ recursive = false;
+}
+
diff --git a/src/nvim/aucmd.h b/src/nvim/aucmd.h
new file mode 100644
index 0000000000..6570ba7a92
--- /dev/null
+++ b/src/nvim/aucmd.h
@@ -0,0 +1,9 @@
+#ifndef NVIM_AUCMD_H
+#define NVIM_AUCMD_H
+
+#ifdef INCLUDE_GENERATED_DECLARATIONS
+# include "aucmd.h.generated.h"
+#endif
+
+#endif // NVIM_AUCMD_H
+
diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c
index 724a8578ac..fc5bb90973 100644
--- a/src/nvim/buffer.c
+++ b/src/nvim/buffer.c
@@ -3069,8 +3069,8 @@ static bool ti_change(char_u *str, char_u **last)
/// Set current window title
void resettitle(void)
{
- ui_call_set_title(cstr_as_string((char *)lasttitle));
ui_call_set_icon(cstr_as_string((char *)lasticon));
+ ui_call_set_title(cstr_as_string((char *)lasttitle));
ui_flush();
}
diff --git a/src/nvim/charset.c b/src/nvim/charset.c
index 1147b78c9a..f824717fcd 100644
--- a/src/nvim/charset.c
+++ b/src/nvim/charset.c
@@ -762,7 +762,7 @@ bool vim_isIDc(int c)
}
/// Check that "c" is a keyword character:
-/// Letters and characters from 'iskeyword' option for current buffer.
+/// Letters and characters from 'iskeyword' option for the current buffer.
/// For multi-byte characters mb_get_class() is used (builtin rules).
///
/// @param c character to check
diff --git a/src/nvim/diff.c b/src/nvim/diff.c
index 17de4284ce..cc0f3b2629 100644
--- a/src/nvim/diff.c
+++ b/src/nvim/diff.c
@@ -135,6 +135,20 @@ void diff_buf_add(buf_T *buf)
EMSGN(_("E96: Cannot diff more than %" PRId64 " buffers"), DB_COUNT);
}
+///
+/// Remove all buffers to make diffs for.
+///
+static void diff_buf_clear(void)
+{
+ for (int i = 0; i < DB_COUNT; i++) {
+ if (curtab->tp_diffbuf[i] != NULL) {
+ curtab->tp_diffbuf[i] = NULL;
+ curtab->tp_diff_invalid = true;
+ diff_redraw(true);
+ }
+ }
+}
+
/// Find buffer "buf" in the list of diff buffers for the current tab page.
///
/// @param buf The buffer to find.
@@ -1175,6 +1189,11 @@ void ex_diffoff(exarg_T *eap)
diffwin |= wp->w_p_diff;
}
+ // Also remove hidden buffers from the list.
+ if (eap->forceit) {
+ diff_buf_clear();
+ }
+
// Remove "hor" from from 'scrollopt' if there are no diff windows left.
if (!diffwin && (vim_strchr(p_sbo, 'h') != NULL)) {
do_cmdline_cmd("set sbo-=hor");
diff --git a/src/nvim/edit.c b/src/nvim/edit.c
index e57598fc91..28722a4d10 100644
--- a/src/nvim/edit.c
+++ b/src/nvim/edit.c
@@ -974,14 +974,6 @@ static int insert_handle_key(InsertState *s)
multiqueue_process_events(main_loop.events);
break;
- case K_FOCUSGAINED: // Neovim has been given focus
- apply_autocmds(EVENT_FOCUSGAINED, NULL, NULL, false, curbuf);
- break;
-
- case K_FOCUSLOST: // Neovim has lost focus
- apply_autocmds(EVENT_FOCUSLOST, NULL, NULL, false, curbuf);
- break;
-
case K_HOME: // <Home>
case K_KHOME:
case K_S_HOME:
@@ -2406,6 +2398,7 @@ void set_completion(colnr_T startcol, list_T *list)
ins_compl_prep(' ');
}
ins_compl_clear();
+ ins_compl_free();
compl_direction = FORWARD;
if (startcol > curwin->w_cursor.col)
@@ -3166,8 +3159,7 @@ static bool ins_compl_prep(int c)
/* Ignore end of Select mode mapping and mouse scroll buttons. */
if (c == K_SELECT || c == K_MOUSEDOWN || c == K_MOUSEUP
- || c == K_MOUSELEFT || c == K_MOUSERIGHT || c == K_EVENT
- || c == K_FOCUSGAINED || c == K_FOCUSLOST) {
+ || c == K_MOUSELEFT || c == K_MOUSERIGHT || c == K_EVENT) {
return retval;
}
diff --git a/src/nvim/eval.c b/src/nvim/eval.c
index ac22d75a83..b2a0d9a767 100644
--- a/src/nvim/eval.c
+++ b/src/nvim/eval.c
@@ -6733,6 +6733,39 @@ static void prepare_assert_error(garray_T *gap)
}
}
+// Append "str" to "gap", escaping unprintable characters.
+// Changes NL to \n, CR to \r, etc.
+static void ga_concat_esc(garray_T *gap, char_u *str)
+{
+ char_u *p;
+ char_u buf[NUMBUFLEN];
+
+ if (str == NULL) {
+ ga_concat(gap, (char_u *)"NULL");
+ return;
+ }
+
+ for (p = str; *p != NUL; p++) {
+ switch (*p) {
+ case BS: ga_concat(gap, (char_u *)"\\b"); break;
+ case ESC: ga_concat(gap, (char_u *)"\\e"); break;
+ case FF: ga_concat(gap, (char_u *)"\\f"); break;
+ case NL: ga_concat(gap, (char_u *)"\\n"); break;
+ case TAB: ga_concat(gap, (char_u *)"\\t"); break;
+ case CAR: ga_concat(gap, (char_u *)"\\r"); break;
+ case '\\': ga_concat(gap, (char_u *)"\\\\"); break;
+ default:
+ if (*p < ' ') {
+ vim_snprintf((char *)buf, NUMBUFLEN, "\\x%02x", *p);
+ ga_concat(gap, buf);
+ } else {
+ ga_append(gap, *p);
+ }
+ break;
+ }
+ }
+}
+
// Fill "gap" with information about an assert error.
static void fill_assert_error(garray_T *gap, typval_T *opt_msg_tv,
char_u *exp_str, typval_T *exp_tv,
@@ -6747,28 +6780,30 @@ static void fill_assert_error(garray_T *gap, typval_T *opt_msg_tv,
} else {
if (atype == ASSERT_MATCH || atype == ASSERT_NOTMATCH) {
ga_concat(gap, (char_u *)"Pattern ");
+ } else if (atype == ASSERT_NOTEQUAL) {
+ ga_concat(gap, (char_u *)"Expected not equal to ");
} else {
ga_concat(gap, (char_u *)"Expected ");
}
if (exp_str == NULL) {
- tofree = (char_u *) encode_tv2string(exp_tv, NULL);
- ga_concat(gap, tofree);
+ tofree = (char_u *)encode_tv2string(exp_tv, NULL);
+ ga_concat_esc(gap, tofree);
xfree(tofree);
} else {
- ga_concat(gap, exp_str);
+ ga_concat_esc(gap, exp_str);
}
- tofree = (char_u *)encode_tv2string(got_tv, NULL);
- if (atype == ASSERT_MATCH) {
- ga_concat(gap, (char_u *)" does not match ");
- } else if (atype == ASSERT_NOTMATCH) {
- ga_concat(gap, (char_u *)" does match ");
- } else if (atype == ASSERT_NOTEQUAL) {
- ga_concat(gap, (char_u *)" differs from ");
- } else {
- ga_concat(gap, (char_u *)" but got ");
+ if (atype != ASSERT_NOTEQUAL) {
+ if (atype == ASSERT_MATCH) {
+ ga_concat(gap, (char_u *)" does not match ");
+ } else if (atype == ASSERT_NOTMATCH) {
+ ga_concat(gap, (char_u *)" does match ");
+ } else {
+ ga_concat(gap, (char_u *)" but got ");
+ }
+ tofree = (char_u *)encode_tv2string(got_tv, NULL);
+ ga_concat_esc(gap, tofree);
+ xfree(tofree);
}
- ga_concat(gap, tofree);
- xfree(tofree);
}
}
@@ -17493,7 +17528,7 @@ static void f_winsaveview(typval_T *argvars, typval_T *rettv, FunPtr fptr)
tv_dict_add_nr(dict, S_LEN("skipcol"), (varnumber_T)curwin->w_skipcol);
}
-/// Writes list of strings to file
+/// Write "list" of strings to file "fd".
///
/// @param fp File to write to.
/// @param[in] list List to write.
@@ -22775,7 +22810,7 @@ typval_T eval_call_provider(char *provider, char *method, list_T *arguments)
bool eval_has_provider(const char *name)
{
-#define check_provider(name) \
+#define CHECK_PROVIDER(name) \
if (has_##name == -1) { \
has_##name = !!find_func((char_u *)"provider#" #name "#Call"); \
if (!has_##name) { \
@@ -22791,17 +22826,17 @@ bool eval_has_provider(const char *name)
static int has_python3 = -1;
static int has_ruby = -1;
- if (!strcmp(name, "clipboard")) {
- check_provider(clipboard);
+ if (strequal(name, "clipboard")) {
+ CHECK_PROVIDER(clipboard);
return has_clipboard;
- } else if (!strcmp(name, "python3")) {
- check_provider(python3);
+ } else if (strequal(name, "python3")) {
+ CHECK_PROVIDER(python3);
return has_python3;
- } else if (!strcmp(name, "python")) {
- check_provider(python);
+ } else if (strequal(name, "python")) {
+ CHECK_PROVIDER(python);
return has_python;
- } else if (!strcmp(name, "ruby")) {
- check_provider(ruby);
+ } else if (strequal(name, "ruby")) {
+ CHECK_PROVIDER(ruby);
return has_ruby;
}
diff --git a/src/nvim/event/loop.c b/src/nvim/event/loop.c
index 25701a1621..5adf16c0f3 100644
--- a/src/nvim/event/loop.c
+++ b/src/nvim/event/loop.c
@@ -59,7 +59,14 @@ void loop_poll_events(Loop *loop, int ms)
multiqueue_process_events(loop->fast_events);
}
-// Schedule an event from another thread
+/// Schedules an event from another thread.
+///
+/// @note Event is queued into `fast_events`, which is processed outside of the
+/// primary `events` queue by loop_poll_events(). For `main_loop`, that
+/// means `fast_events` is NOT processed in an "editor mode"
+/// (VimState.execute), so redraw and other side-effects are likely to be
+/// skipped.
+/// @see loop_schedule_deferred
void loop_schedule(Loop *loop, Event event)
{
uv_mutex_lock(&loop->mutex);
@@ -68,6 +75,24 @@ void loop_schedule(Loop *loop, Event event)
uv_mutex_unlock(&loop->mutex);
}
+/// Schedules an event from another thread. Unlike loop_schedule(), the event
+/// is forwarded to `Loop.events`, instead of being processed immediately.
+///
+/// @see loop_schedule
+void loop_schedule_deferred(Loop *loop, Event event)
+{
+ Event *eventp = xmalloc(sizeof(*eventp));
+ *eventp = event;
+ loop_schedule(loop, event_create(loop_deferred_event, 2, loop, eventp));
+}
+static void loop_deferred_event(void **argv)
+{
+ Loop *loop = argv[0];
+ Event *eventp = argv[1];
+ multiqueue_put_event(loop->events, *eventp);
+ xfree(eventp);
+}
+
void loop_on_put(MultiQueue *queue, void *data)
{
Loop *loop = data;
diff --git a/src/nvim/event/loop.h b/src/nvim/event/loop.h
index e7d7bdd483..b0ddc59469 100644
--- a/src/nvim/event/loop.h
+++ b/src/nvim/event/loop.h
@@ -16,10 +16,28 @@ KLIST_INIT(WatcherPtr, WatcherPtr, _noop)
typedef struct loop {
uv_loop_t uv;
- MultiQueue *events, *fast_events, *thread_events;
+ MultiQueue *events;
+ MultiQueue *thread_events;
+ // Immediate events:
+ // "Events that should be processed after exiting uv_run() (to avoid
+ // recursion), but before returning from loop_poll_events()."
+ // 502aee690c980fcb3cfcb3f211dcfad06103db46
+ // Practical consequence: these events are processed by
+ // state_enter()..os_inchar()
+ // whereas "regular" (main_loop.events) events are processed by
+ // state_enter()..VimState.execute()
+ // But state_enter()..os_inchar() can be "too early" if you want the event
+ // to trigger UI updates and other user-activity-related side-effects.
+ MultiQueue *fast_events;
+
+ // used by process/job-control subsystem
klist_t(WatcherPtr) *children;
uv_signal_t children_watcher;
- uv_timer_t children_kill_timer, poll_timer;
+ uv_timer_t children_kill_timer;
+
+ // generic timer, used by loop_poll_events()
+ uv_timer_t poll_timer;
+
size_t children_stop_requests;
uv_async_t async;
uv_mutex_t mutex;
diff --git a/src/nvim/event/process.c b/src/nvim/event/process.c
index c936583841..8371d3cd48 100644
--- a/src/nvim/event/process.c
+++ b/src/nvim/event/process.c
@@ -233,8 +233,7 @@ void process_stop(Process *proc) FUNC_ATTR_NONNULL_ALL
switch (proc->type) {
case kProcessTypeUv:
// Close the process's stdin. If the process doesn't close its own
- // stdout/stderr, they will be closed when it exits(possibly due to being
- // terminated after a timeout)
+ // stdout/stderr, they will be closed when it exits (voluntarily or not).
process_close_in(proc);
ILOG("Sending SIGTERM to pid %d", proc->pid);
uv_kill(proc->pid, SIGTERM);
diff --git a/src/nvim/event/rstream.c b/src/nvim/event/rstream.c
index 854af474b2..2c4db08b30 100644
--- a/src/nvim/event/rstream.c
+++ b/src/nvim/event/rstream.c
@@ -118,7 +118,7 @@ static void read_cb(uv_stream_t *uvstream, ssize_t cnt, const uv_buf_t *buf)
// to `alloc_cb` will return the same unused pointer(`rbuffer_produced`
// won't be called)
&& cnt != 0) {
- DLOG("Closing Stream (%p): %s (%s)", stream,
+ DLOG("closing Stream: %p: %s (%s)", stream,
uv_err_name((int)cnt), os_strerror((int)cnt));
// Read error or EOF, either way stop the stream and invoke the callback
// with eof == true
diff --git a/src/nvim/event/stream.c b/src/nvim/event/stream.c
index 60ceff9b24..7c865bfe1e 100644
--- a/src/nvim/event/stream.c
+++ b/src/nvim/event/stream.c
@@ -7,6 +7,7 @@
#include <uv.h>
+#include "nvim/log.h"
#include "nvim/rbuffer.h"
#include "nvim/macros.h"
#include "nvim/event/stream.h"
@@ -81,6 +82,7 @@ void stream_close(Stream *stream, stream_close_cb on_stream_close, void *data)
FUNC_ATTR_NONNULL_ARG(1)
{
assert(!stream->closed);
+ DLOG("closing Stream: %p", stream);
stream->closed = true;
stream->close_cb = on_stream_close;
stream->close_cb_data = data;
diff --git a/src/nvim/event/wstream.c b/src/nvim/event/wstream.c
index f453e5898d..320006890d 100644
--- a/src/nvim/event/wstream.c
+++ b/src/nvim/event/wstream.c
@@ -8,6 +8,7 @@
#include <uv.h>
+#include "nvim/log.h"
#include "nvim/event/loop.h"
#include "nvim/event/wstream.h"
#include "nvim/vim.h"
diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c
index a555fb77e8..918e7a0c91 100644
--- a/src/nvim/ex_cmds.c
+++ b/src/nvim/ex_cmds.c
@@ -3332,10 +3332,12 @@ static buf_T *do_sub(exarg_T *eap, proftime_T timeout)
sub = regtilde(sub, p_magic);
// Check for a match on each line.
+ // If preview: limit to max('cmdwinheight', viewport).
linenr_T line2 = eap->line2;
for (linenr_T lnum = eap->line1;
- lnum <= line2 && !(got_quit || aborting())
- && (!preview || matched_lines.size <= (size_t)p_cwh);
+ lnum <= line2 && !got_quit && !aborting()
+ && (!preview || matched_lines.size < (size_t)p_cwh
+ || lnum <= curwin->w_botline);
lnum++) {
long nmatch = vim_regexec_multi(&regmatch, curwin, curbuf, lnum,
(colnr_T)0, NULL);
@@ -3500,6 +3502,10 @@ static buf_T *do_sub(exarg_T *eap, proftime_T timeout)
setmouse(); /* disable mouse in xterm */
curwin->w_cursor.col = regmatch.startpos[0].col;
+ if (curwin->w_p_crb) {
+ do_check_cursorbind();
+ }
+
/* When 'cpoptions' contains "u" don't sync undo when
* asking for confirmation. */
if (vim_strchr(p_cpo, CPO_UNDO) != NULL)
@@ -3659,6 +3665,42 @@ static buf_T *do_sub(exarg_T *eap, proftime_T timeout)
* use "\=col("."). */
curwin->w_cursor.col = regmatch.startpos[0].col;
+ // When the match included the "$" of the last line it may
+ // go beyond the last line of the buffer.
+ if (nmatch > curbuf->b_ml.ml_line_count - sub_firstlnum + 1) {
+ nmatch = curbuf->b_ml.ml_line_count - sub_firstlnum + 1;
+ skip_match = true;
+ }
+
+#define ADJUST_SUB_FIRSTLNUM() \
+ do { \
+ /* For a multi-line match, make a copy of the last matched */ \
+ /* line and continue in that one. */ \
+ if (nmatch > 1) { \
+ sub_firstlnum += nmatch - 1; \
+ xfree(sub_firstline); \
+ sub_firstline = vim_strsave(ml_get(sub_firstlnum)); \
+ /* When going beyond the last line, stop substituting. */ \
+ if (sub_firstlnum <= line2) { \
+ do_again = true; \
+ } else { \
+ subflags.do_all = false; \
+ } \
+ } \
+ if (skip_match) { \
+ /* Already hit end of the buffer, sub_firstlnum is one */ \
+ /* less than what it ought to be. */ \
+ xfree(sub_firstline); \
+ sub_firstline = vim_strsave((char_u *)""); \
+ copycol = 0; \
+ } \
+ } while (0)
+
+ if (preview && !has_second_delim) {
+ ADJUST_SUB_FIRSTLNUM();
+ goto skip;
+ }
+
// 3. Substitute the string. During 'inccommand' preview only do this if
// there is a replace pattern.
if (!preview || has_second_delim) {
@@ -3685,13 +3727,6 @@ static buf_T *do_sub(exarg_T *eap, proftime_T timeout)
goto skip;
}
- // When the match included the "$" of the last line it may
- // go beyond the last line of the buffer.
- if (nmatch > curbuf->b_ml.ml_line_count - sub_firstlnum + 1) {
- nmatch = curbuf->b_ml.ml_line_count - sub_firstlnum + 1;
- skip_match = true;
- }
-
// Need room for:
// - result so far in new_start (not for first sub in line)
// - original text up to match
@@ -3722,30 +3757,10 @@ static buf_T *do_sub(exarg_T *eap, proftime_T timeout)
// is beyond the end of the line after the substitution.
curwin->w_cursor.col = 0;
- // For a multi-line match, make a copy of the last matched
- // line and continue in that one.
- if (nmatch > 1) {
- sub_firstlnum += nmatch - 1;
- xfree(sub_firstline);
- sub_firstline = vim_strsave(ml_get(sub_firstlnum));
- // When going beyond the last line, stop substituting.
- if (sub_firstlnum <= line2) {
- do_again = true;
- } else {
- subflags.do_all = false;
- }
- }
-
// Remember next character to be copied.
copycol = regmatch.endpos[0].col;
- if (skip_match) {
- // Already hit end of the buffer, sub_firstlnum is one
- // less than what it ought to be.
- xfree(sub_firstline);
- sub_firstline = vim_strsave((char_u *)"");
- copycol = 0;
- }
+ ADJUST_SUB_FIRSTLNUM();
// Now the trick is to replace CTRL-M chars with a real line
// break. This would make it impossible to insert a CTRL-M in
@@ -4002,6 +4017,7 @@ skip:
kv_destroy(matched_lines);
return preview_buf;
+#undef ADJUST_SUB_FIRSTLNUM
} // NOLINT(readability/fn_size)
/*
diff --git a/src/nvim/ex_cmds2.c b/src/nvim/ex_cmds2.c
index 33fe30cd5a..371f7b3bce 100644
--- a/src/nvim/ex_cmds2.c
+++ b/src/nvim/ex_cmds2.c
@@ -2319,16 +2319,6 @@ static void source_callback(char_u *fname, void *cookie)
(void)do_source(fname, false, DOSO_NONE);
}
-/// Source the file "name" from all directories in 'runtimepath'.
-/// "name" can contain wildcards.
-/// When "flags" has DIP_ALL: source all files, otherwise only the first one.
-///
-/// return FAIL when no file could be sourced, OK otherwise.
-int source_runtime(char_u *name, int flags)
-{
- return do_in_runtimepath(name, flags, source_callback, NULL);
-}
-
/// Find the file "name" in all directories in "path" and invoke
/// "callback(fname, cookie)".
/// "name" can contain wildcards.
@@ -2434,21 +2424,21 @@ int do_in_path(char_u *path, char_u *name, int flags,
return did_one ? OK : FAIL;
}
-/// Find "name" in 'runtimepath'. When found, invoke the callback function for
+/// Find "name" in "path". When found, invoke the callback function for
/// it: callback(fname, "cookie")
/// When "flags" has DIP_ALL repeat for all matches, otherwise only the first
/// one is used.
/// Returns OK when at least one match found, FAIL otherwise.
-/// If "name" is NULL calls callback for each entry in runtimepath. Cookie is
+/// If "name" is NULL calls callback for each entry in "path". Cookie is
/// passed by reference in this case, setting it to NULL indicates that callback
/// has done its job.
-int do_in_runtimepath(char_u *name, int flags, DoInRuntimepathCB callback,
- void *cookie)
+int do_in_path_and_pp(char_u *path, char_u *name, int flags,
+ DoInRuntimepathCB callback, void *cookie)
{
int done = FAIL;
if ((flags & DIP_NORTP) == 0) {
- done = do_in_path(p_rtp, name, flags, callback, cookie);
+ done = do_in_path(path, name, flags, callback, cookie);
}
if ((done == FAIL || (flags & DIP_ALL)) && (flags & DIP_START)) {
@@ -2476,6 +2466,29 @@ int do_in_runtimepath(char_u *name, int flags, DoInRuntimepathCB callback,
return done;
}
+/// Just like do_in_path_and_pp(), using 'runtimepath' for "path".
+int do_in_runtimepath(char_u *name, int flags, DoInRuntimepathCB callback,
+ void *cookie)
+{
+ return do_in_path_and_pp(p_rtp, name, flags, callback, cookie);
+}
+
+/// Source the file "name" from all directories in 'runtimepath'.
+/// "name" can contain wildcards.
+/// When "flags" has DIP_ALL: source all files, otherwise only the first one.
+///
+/// return FAIL when no file could be sourced, OK otherwise.
+int source_runtime(char_u *name, int flags)
+{
+ return source_in_path(p_rtp, name, flags);
+}
+
+/// Just like source_runtime(), but use "path" instead of 'runtimepath'.
+int source_in_path(char_u *path, char_u *name, int flags)
+{
+ return do_in_path_and_pp(path, name, flags, source_callback, NULL);
+}
+
// Expand wildcards in "pat" and invoke do_source() for each match.
static void source_all_matches(char_u *pat)
{
@@ -2498,6 +2511,7 @@ static int APP_BOTH;
static void add_pack_plugin(char_u *fname, void *cookie)
{
char_u *p4, *p3, *p2, *p1, *p;
+ char_u *buf = NULL;
char *const ffname = fix_fname((char *)fname);
@@ -2525,26 +2539,30 @@ static void add_pack_plugin(char_u *fname, void *cookie)
// Find "ffname" in "p_rtp", ignoring '/' vs '\' differences
size_t fname_len = strlen(ffname);
const char *insp = (const char *)p_rtp;
- for (;;) {
- if (path_fnamencmp(insp, ffname, fname_len) == 0) {
- break;
+ buf = try_malloc(MAXPATHL);
+ if (buf == NULL) {
+ goto theend;
+ }
+ while (*insp != NUL) {
+ copy_option_part((char_u **)&insp, buf, MAXPATHL, ",");
+ add_pathsep((char *)buf);
+ char *const rtp_ffname = fix_fname((char *)buf);
+ if (rtp_ffname == NULL) {
+ goto theend;
}
- insp = strchr(insp, ',');
- if (insp == NULL) {
+ bool match = path_fnamencmp(rtp_ffname, ffname, fname_len) == 0;
+ xfree(rtp_ffname);
+ if (match) {
break;
}
- insp++;
}
- if (insp == NULL) {
+ if (*insp == NUL) {
// not found, append at the end
insp = (const char *)p_rtp + STRLEN(p_rtp);
} else {
// append after the matching directory.
- insp += strlen(ffname);
- while (*insp != NUL && *insp != ',') {
- insp++;
- }
+ insp--;
}
*p4 = c;
@@ -2614,26 +2632,35 @@ static void add_pack_plugin(char_u *fname, void *cookie)
}
theend:
+ xfree(buf);
xfree(ffname);
}
-static bool did_source_packages = false;
+/// Add all packages in the "start" directory to 'runtimepath'.
+void add_pack_start_dirs(void)
+{
+ do_in_path(p_pp, (char_u *)"pack/*/start/*", DIP_ALL + DIP_DIR, // NOLINT
+ add_pack_plugin, &APP_ADD_DIR);
+}
+
+/// Load plugins from all packages in the "start" directory.
+void load_start_packages(void)
+{
+ did_source_packages = true;
+ do_in_path(p_pp, (char_u *)"pack/*/start/*", DIP_ALL + DIP_DIR, // NOLINT
+ add_pack_plugin, &APP_LOAD);
+}
// ":packloadall"
// Find plugins in the package directories and source them.
-// "eap" is NULL when invoked during startup.
void ex_packloadall(exarg_T *eap)
{
- if (!did_source_packages || (eap != NULL && eap->forceit)) {
- did_source_packages = true;
-
+ if (!did_source_packages || eap->forceit) {
// First do a round to add all directories to 'runtimepath', then load
// the plugins. This allows for plugins to use an autoload directory
// of another plugin.
- do_in_path(p_pp, (char_u *)"pack/*/start/*", DIP_ALL + DIP_DIR, // NOLINT
- add_pack_plugin, &APP_ADD_DIR);
- do_in_path(p_pp, (char_u *)"pack/*/start/*", DIP_ALL + DIP_DIR, // NOLINT
- add_pack_plugin, &APP_LOAD);
+ add_pack_start_dirs();
+ load_start_packages();
}
}
diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c
index 6e7938046a..3130747e08 100644
--- a/src/nvim/ex_docmd.c
+++ b/src/nvim/ex_docmd.c
@@ -1668,8 +1668,8 @@ static char_u * do_one_cmd(char_u **cmdlinep,
if (*ea.cmd == ';') {
if (!ea.skip) {
curwin->w_cursor.lnum = ea.line2;
- // Don't leave the cursor on an illegal line (caused by ';')
- check_cursor_lnum();
+ // don't leave the cursor on an illegal line or column
+ check_cursor();
}
} else if (*ea.cmd != ',') {
break;
@@ -1813,7 +1813,7 @@ static char_u * do_one_cmd(char_u **cmdlinep,
if (text_locked() && !(ea.argt & CMDWIN)
&& !IS_USER_CMDIDX(ea.cmdidx)) {
// Command not allowed when editing the command line.
- errormsg = get_text_locked_msg();
+ errormsg = (char_u *)_(get_text_locked_msg());
goto doend;
}
/* Disallow editing another buffer when "curbuf_lock" is set.
@@ -8810,11 +8810,12 @@ makeopens (
&& buf->b_fname != NULL
&& buf->b_p_bl) {
if (fprintf(fd, "badd +%" PRId64 " ",
- buf->b_wininfo == NULL ?
- (int64_t)1L :
- (int64_t)buf->b_wininfo->wi_fpos.lnum) < 0
- || ses_fname(fd, buf, &ssop_flags) == FAIL)
+ buf->b_wininfo == NULL
+ ? (int64_t)1L
+ : (int64_t)buf->b_wininfo->wi_fpos.lnum) < 0
+ || ses_fname(fd, buf, &ssop_flags, true) == FAIL) {
return FAIL;
+ }
}
}
@@ -8885,11 +8886,13 @@ makeopens (
&& !bt_nofile(wp->w_buffer)
) {
if (fputs(need_tabnew ? "tabedit " : "edit ", fd) < 0
- || ses_fname(fd, wp->w_buffer, &ssop_flags) == FAIL)
+ || ses_fname(fd, wp->w_buffer, &ssop_flags, true) == FAIL) {
return FAIL;
- need_tabnew = FALSE;
- if (!wp->w_arg_idx_invalid)
+ }
+ need_tabnew = false;
+ if (!wp->w_arg_idx_invalid) {
edited_win = wp;
+ }
break;
}
}
@@ -8933,6 +8936,8 @@ makeopens (
// resized when moving between windows.
// Do this before restoring the view, so that the topline and the
// cursor can be set. This is done again below.
+ // winminheight and winminwidth need to be set to avoid an error if the
+ // user has set winheight or winwidth.
if (put_line(fd, "set winminheight=1 winminwidth=1 winheight=1 winwidth=1")
== FAIL) {
return FAIL;
@@ -9221,24 +9226,35 @@ put_view (
if (wp->w_buffer->b_ffname != NULL
&& (!bt_nofile(wp->w_buffer) || wp->w_buffer->terminal)
) {
- /*
- * Editing a file in this buffer: use ":edit file".
- * This may have side effects! (e.g., compressed or network file).
- */
- if (fputs("edit ", fd) < 0
- || ses_fname(fd, wp->w_buffer, flagp) == FAIL)
+ // Editing a file in this buffer: use ":edit file".
+ // This may have side effects! (e.g., compressed or network file).
+ //
+ // Note, if a buffer for that file already exists, use :badd to
+ // edit that buffer, to not lose folding information (:edit resets
+ // folds in other buffers)
+ if (fputs("if bufexists('", fd) < 0
+ || ses_fname(fd, wp->w_buffer, flagp, false) == FAIL
+ || fputs("') | buffer ", fd) < 0
+ || ses_fname(fd, wp->w_buffer, flagp, false) == FAIL
+ || fputs(" | else | edit ", fd) < 0
+ || ses_fname(fd, wp->w_buffer, flagp, false) == FAIL
+ || fputs(" | endif", fd) < 0
+ || put_eol(fd) == FAIL) {
return FAIL;
+ }
} else {
- /* No file in this buffer, just make it empty. */
- if (put_line(fd, "enew") == FAIL)
+ // No file in this buffer, just make it empty.
+ if (put_line(fd, "enew") == FAIL) {
return FAIL;
+ }
if (wp->w_buffer->b_ffname != NULL) {
- /* The buffer does have a name, but it's not a file name. */
+ // The buffer does have a name, but it's not a file name.
if (fputs("file ", fd) < 0
- || ses_fname(fd, wp->w_buffer, flagp) == FAIL)
+ || ses_fname(fd, wp->w_buffer, flagp, true) == FAIL) {
return FAIL;
+ }
}
- do_cursor = FALSE;
+ do_cursor = false;
}
}
@@ -9378,7 +9394,7 @@ ses_arglist (
(void)vim_FullName((char *)s, (char *)buf, MAXPATHL, FALSE);
s = buf;
}
- if (fputs("argadd ", fd) < 0 || ses_put_fname(fd, s, flagp) == FAIL
+ if (fputs("$argadd ", fd) < 0 || ses_put_fname(fd, s, flagp) == FAIL
|| put_eol(fd) == FAIL) {
xfree(buf);
return FAIL;
@@ -9389,12 +9405,10 @@ ses_arglist (
return OK;
}
-/*
- * Write a buffer name to the session file.
- * Also ends the line.
- * Returns FAIL if writing fails.
- */
-static int ses_fname(FILE *fd, buf_T *buf, unsigned *flagp)
+/// Write a buffer name to the session file.
+/// Also ends the line, if "add_eol" is true.
+/// Returns FAIL if writing fails.
+static int ses_fname(FILE *fd, buf_T *buf, unsigned *flagp, bool add_eol)
{
char_u *name;
@@ -9411,8 +9425,10 @@ static int ses_fname(FILE *fd, buf_T *buf, unsigned *flagp)
name = buf->b_sfname;
else
name = buf->b_ffname;
- if (ses_put_fname(fd, name, flagp) == FAIL || put_eol(fd) == FAIL)
+ if (ses_put_fname(fd, name, flagp) == FAIL
+ || (add_eol && put_eol(fd) == FAIL)) {
return FAIL;
+ }
return OK;
}
@@ -9835,7 +9851,7 @@ static void ex_terminal(exarg_T *eap)
if (*eap->arg != NUL) { // Run {cmd} in 'shell'.
char *name = (char *)vim_strsave_escaped(eap->arg, (char_u *)"\"\\");
snprintf(ex_cmd, sizeof(ex_cmd),
- ":enew%s | call termopen(\"%s\") | startinsert",
+ ":enew%s | call termopen(\"%s\")",
eap->forceit ? "!" : "", name);
xfree(name);
} else { // No {cmd}: run the job with tokenized 'shell'.
@@ -9857,7 +9873,7 @@ static void ex_terminal(exarg_T *eap)
shell_free_argv(argv);
snprintf(ex_cmd, sizeof(ex_cmd),
- ":enew%s | call termopen([%s]) | startinsert",
+ ":enew%s | call termopen([%s])",
eap->forceit ? "!" : "", shell_argv + 1);
}
diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c
index 5e216925df..54e5bcb9ff 100644
--- a/src/nvim/ex_getln.c
+++ b/src/nvim/ex_getln.c
@@ -1620,14 +1620,6 @@ static int command_line_handle_key(CommandLineState *s)
}
return command_line_not_changed(s);
- case K_FOCUSGAINED: // Neovim has been given focus
- apply_autocmds(EVENT_FOCUSGAINED, NULL, NULL, false, curbuf);
- return command_line_not_changed(s);
-
- case K_FOCUSLOST: // Neovim has lost focus
- apply_autocmds(EVENT_FOCUSLOST, NULL, NULL, false, curbuf);
- return command_line_not_changed(s);
-
default:
// Normal character with no special meaning. Just set mod_mask
// to 0x0 so that typing Shift-Space in the GUI doesn't enter
@@ -1871,9 +1863,13 @@ char *getcmdline_prompt(const char firstc, const char *const prompt,
ccline.input_fn = (firstc == '@');
ccline.highlight_callback = highlight_callback;
+ int msg_silent_saved = msg_silent;
+ msg_silent = 0;
+
char *const ret = (char *)getcmdline(firstc, 1L, 0);
restore_cmdline(&save_ccline);
+ msg_silent = msg_silent_saved;
// Restore msg_col, the prompt from input() may have changed it.
// But only if called recursively and the commandline is therefore being
// restored to an old one; if not, the input() prompt stays on the screen,
@@ -5722,6 +5718,7 @@ static int ex_window(void)
i = RedrawingDisabled;
RedrawingDisabled = 0;
+ int save_count = save_batch_count();
/*
* Call the main loop until <CR> or CTRL-C is typed.
@@ -5730,6 +5727,7 @@ static int ex_window(void)
normal_enter(true, false);
RedrawingDisabled = i;
+ restore_batch_count(save_count);
int save_KeyTyped = KeyTyped;
diff --git a/src/nvim/getchar.c b/src/nvim/getchar.c
index a22b716bb6..4f8a8528a0 100644
--- a/src/nvim/getchar.c
+++ b/src/nvim/getchar.c
@@ -92,17 +92,15 @@ static int typeahead_char = 0; /* typeahead char that's not flushed */
*/
static int block_redo = FALSE;
-/*
- * Make a hash value for a mapping.
- * "mode" is the lower 4 bits of the State for the mapping.
- * "c1" is the first character of the "lhs".
- * Returns a value between 0 and 255, index in maphash.
- * Put Normal/Visual mode mappings mostly separately from Insert/Cmdline mode.
- */
+// Make a hash value for a mapping.
+// "mode" is the lower 4 bits of the State for the mapping.
+// "c1" is the first character of the "lhs".
+// Returns a value between 0 and 255, index in maphash.
+// Put Normal/Visual mode mappings mostly separately from Insert/Cmdline mode.
#define MAP_HASH(mode, \
c1) (((mode) & \
(NORMAL + VISUAL + SELECTMODE + \
- OP_PENDING)) ? (c1) : ((c1) ^ 0x80))
+ OP_PENDING + TERM_FOCUS)) ? (c1) : ((c1) ^ 0x80))
// Each mapping is put in one of the MAX_MAPHASH hash lists,
// to speed up finding it.
@@ -870,20 +868,15 @@ int ins_typebuf(char_u *str, int noremap, int offset, int nottyped, bool silent)
addlen = (int)STRLEN(str);
- /*
- * Easy case: there is room in front of typebuf.tb_buf[typebuf.tb_off]
- */
if (offset == 0 && addlen <= typebuf.tb_off) {
+ // Easy case: there is room in front of typebuf.tb_buf[typebuf.tb_off]
typebuf.tb_off -= addlen;
memmove(typebuf.tb_buf + typebuf.tb_off, str, (size_t)addlen);
- }
- /*
- * Need to allocate a new buffer.
- * In typebuf.tb_buf there must always be room for 3 * MAXMAPLEN + 4
- * characters. We add some extra room to avoid having to allocate too
- * often.
- */
- else {
+ } else {
+ // Need to allocate a new buffer.
+ // In typebuf.tb_buf there must always be room for 3 * MAXMAPLEN + 4
+ // characters. We add some extra room to avoid having to allocate too
+ // often.
newoff = MAXMAPLEN + 4;
newlen = typebuf.tb_len + addlen + newoff + 4 * (MAXMAPLEN + 4);
if (newlen < 0) { /* string is getting too long */
@@ -1665,10 +1658,10 @@ static int vgetorpeek(int advance)
}
if (c != NUL && !got_int) {
if (advance) {
- /* KeyTyped = FALSE; When the command that stuffed something
- * was typed, behave like the stuffed command was typed.
- * needed for CTRL-W CTRl-] to open a fold, for example. */
- KeyStuffed = TRUE;
+ // KeyTyped = FALSE; When the command that stuffed something
+ // was typed, behave like the stuffed command was typed.
+ // needed for CTRL-W CTRL-] to open a fold, for example.
+ KeyStuffed = true;
}
if (typebuf.tb_no_abbr_cnt == 0)
typebuf.tb_no_abbr_cnt = 1; /* no abbreviations now */
diff --git a/src/nvim/gettext.h b/src/nvim/gettext.h
index aa0e97233e..60317b8484 100644
--- a/src/nvim/gettext.h
+++ b/src/nvim/gettext.h
@@ -13,6 +13,7 @@
#else
# define _(x) ((char *)(x))
# define N_(x) x
+# define ngettext(x, xs, n) ((n) == 1 ? (x) : (xs))
# define bindtextdomain(x, y) // empty
# define bind_textdomain_codeset(x, y) // empty
# define textdomain(x) // empty
diff --git a/src/nvim/globals.h b/src/nvim/globals.h
index 86fff46737..c5d26aa2ce 100644
--- a/src/nvim/globals.h
+++ b/src/nvim/globals.h
@@ -407,6 +407,9 @@ EXTERN int garbage_collect_at_exit INIT(= FALSE);
/* ID of script being sourced or was sourced to define the current function. */
EXTERN scid_T current_SID INIT(= 0);
+
+EXTERN bool did_source_packages INIT(= false);
+
// Scope information for the code that indirectly triggered the current
// provider function call
EXTERN struct caller_scope {
@@ -1120,8 +1123,9 @@ EXTERN char_u e_winheight[] INIT(= N_(
EXTERN char_u e_winwidth[] INIT(= N_(
"E592: 'winwidth' cannot be smaller than 'winminwidth'"));
EXTERN char_u e_write[] INIT(= N_("E80: Error while writing"));
-EXTERN char_u e_zerocount[] INIT(= N_("Zero count"));
-EXTERN char_u e_usingsid[] INIT(= N_("E81: Using <SID> not in a script context"));
+EXTERN char_u e_zerocount[] INIT(= N_("E939: Positive count required"));
+EXTERN char_u e_usingsid[] INIT(= N_(
+ "E81: Using <SID> not in a script context"));
EXTERN char_u e_intern2[] INIT(= N_("E685: Internal error: %s"));
EXTERN char_u e_maxmempat[] INIT(= N_(
"E363: pattern uses more memory than 'maxmempattern'"));
diff --git a/src/nvim/indent_c.c b/src/nvim/indent_c.c
index fd194a4080..279d45bb0a 100644
--- a/src/nvim/indent_c.c
+++ b/src/nvim/indent_c.c
@@ -515,34 +515,41 @@ int cin_isscopedecl(char_u *s)
/* Maximum number of lines to search back for a "namespace" line. */
#define FIND_NAMESPACE_LIM 20
-/*
- * Recognize a "namespace" scope declaration.
- */
-static int cin_is_cpp_namespace(char_u *s)
+// Recognize a "namespace" scope declaration.
+static bool cin_is_cpp_namespace(char_u *s)
{
- char_u *p;
- int has_name = FALSE;
+ char_u *p;
+ bool has_name = false;
+ bool has_name_start = false;
s = cin_skipcomment(s);
if (STRNCMP(s, "namespace", 9) == 0 && (s[9] == NUL || !vim_iswordc(s[9]))) {
p = cin_skipcomment(skipwhite(s + 9));
while (*p != NUL) {
if (ascii_iswhite(*p)) {
- has_name = TRUE; /* found end of a name */
+ has_name = true; // found end of a name
p = cin_skipcomment(skipwhite(p));
} else if (*p == '{') {
break;
} else if (vim_iswordc(*p)) {
- if (has_name)
- return FALSE; /* word character after skipping past name */
- ++p;
+ has_name_start = true;
+ if (has_name) {
+ return false; // word character after skipping past name
+ }
+ p++;
+ } else if (p[0] == ':' && p[1] == ':' && vim_iswordc(p[2])) {
+ if (!has_name_start || has_name) {
+ return false;
+ }
+ // C++ 17 nested namespace
+ p += 3;
} else {
- return FALSE;
+ return false;
}
}
- return TRUE;
+ return true;
}
- return FALSE;
+ return false;
}
/*
@@ -727,16 +734,20 @@ static int cin_ispreproc(char_u *s)
return FALSE;
}
-/*
- * Return TRUE if line "*pp" at "*lnump" is a preprocessor statement or a
- * continuation line of a preprocessor statement. Decrease "*lnump" to the
- * start and return the line in "*pp".
- */
-static int cin_ispreproc_cont(char_u **pp, linenr_T *lnump)
+/// Return TRUE if line "*pp" at "*lnump" is a preprocessor statement or a
+/// continuation line of a preprocessor statement. Decrease "*lnump" to the
+/// start and return the line in "*pp".
+/// Put the amount of indent in "*amount".
+static int cin_ispreproc_cont(char_u **pp, linenr_T *lnump, int *amount)
{
char_u *line = *pp;
linenr_T lnum = *lnump;
- int retval = FALSE;
+ int retval = false;
+ int candidate_amount = *amount;
+
+ if (*line != NUL && line[STRLEN(line) - 1] == '\\') {
+ candidate_amount = get_indent_lnum(lnum);
+ }
for (;; ) {
if (cin_ispreproc(line)) {
@@ -751,8 +762,12 @@ static int cin_ispreproc_cont(char_u **pp, linenr_T *lnump)
break;
}
- if (lnum != *lnump)
+ if (lnum != *lnump) {
*pp = ml_get(*lnump);
+ }
+ if (retval) {
+ *amount = candidate_amount;
+ }
return retval;
}
@@ -1987,10 +2002,12 @@ int get_c_indent(void)
amount = -1;
for (lnum = cur_curpos.lnum - 1; lnum > our_paren_pos.lnum; --lnum) {
l = skipwhite(ml_get(lnum));
- if (cin_nocode(l)) /* skip comment lines */
+ if (cin_nocode(l)) { // skip comment lines
continue;
- if (cin_ispreproc_cont(&l, &lnum))
- continue; /* ignore #define, #if, etc. */
+ }
+ if (cin_ispreproc_cont(&l, &lnum, &amount)) {
+ continue; // ignore #define, #if, etc.
+ }
curwin->w_cursor.lnum = lnum;
/* Skip a comment or raw string. XXX */
@@ -2346,15 +2363,14 @@ int get_c_indent(void)
* up with it.
*/
if (curwin->w_cursor.lnum <= ourscope) {
- /* we reached end of scope:
- * if looking for an enum or structure initialization
- * go further back:
- * if it is an initializer (enum xxx or xxx =), then
- * don't add ind_continuation, otherwise it is a variable
- * declaration:
- * int x,
- * here; <-- add ind_continuation
- */
+ // We reached end of scope:
+ // If looking for a enum or structure initialization
+ // go further back:
+ // If it is an initializer (enum xxx or xxx =), then
+ // don't add ind_continuation, otherwise it is a variable
+ // declaration:
+ // int x,
+ // here; <-- add ind_continuation
if (lookfor == LOOKFOR_ENUM_OR_INIT) {
if (curwin->w_cursor.lnum == 0
|| curwin->w_cursor.lnum
@@ -2382,11 +2398,12 @@ int get_c_indent(void)
continue;
}
- /*
- * Skip preprocessor directives and blank lines.
- */
- if (cin_ispreproc_cont(&l, &curwin->w_cursor.lnum))
+ //
+ // Skip preprocessor directives and blank lines.
+ //
+ if (cin_ispreproc_cont(&l, &curwin->w_cursor.lnum, &amount)) {
continue;
+ }
if (cin_nocode(l))
continue;
@@ -2490,9 +2507,10 @@ int get_c_indent(void)
continue;
}
- /* Skip preprocessor directives and blank lines. */
- if (cin_ispreproc_cont(&l, &curwin->w_cursor.lnum))
+ // Skip preprocessor directives and blank lines.
+ if (cin_ispreproc_cont(&l, &curwin->w_cursor.lnum, &amount)) {
continue;
+ }
/* Finally the actual check for "namespace". */
if (cin_is_cpp_namespace(l)) {
@@ -2655,9 +2673,10 @@ int get_c_indent(void)
* unlocked it)
*/
l = get_cursor_line_ptr();
- if (cin_ispreproc_cont(&l, &curwin->w_cursor.lnum)
- || cin_nocode(l))
+ if (cin_ispreproc_cont(&l, &curwin->w_cursor.lnum, &amount)
+ || cin_nocode(l)) {
continue;
+ }
/*
* Are we at the start of a cpp base class declaration or
@@ -3302,11 +3321,12 @@ term_again:
break;
}
- /*
- * Skip preprocessor directives and blank lines.
- */
- if (cin_ispreproc_cont(&l, &curwin->w_cursor.lnum))
+ //
+ // Skip preprocessor directives and blank lines.
+ //
+ if (cin_ispreproc_cont(&l, &curwin->w_cursor.lnum, &amount)) {
continue;
+ }
if (cin_nocode(l))
continue;
@@ -3398,9 +3418,10 @@ term_again:
while (curwin->w_cursor.lnum > 1) {
look = ml_get(--curwin->w_cursor.lnum);
- if (!(cin_nocode(look) || cin_ispreproc_cont(
- &look, &curwin->w_cursor.lnum)))
+ if (!(cin_nocode(look)
+ || cin_ispreproc_cont(&look, &curwin->w_cursor.lnum, &amount))) {
break;
+ }
}
if (curwin->w_cursor.lnum > 0
&& cin_ends_in(look, (char_u *)"}", NULL))
diff --git a/src/nvim/keymap.c b/src/nvim/keymap.c
index f344d65c8d..a44b663cc6 100644
--- a/src/nvim/keymap.c
+++ b/src/nvim/keymap.c
@@ -139,154 +139,153 @@ static char_u modifier_keys_table[] =
};
static const struct key_name_entry {
- int key; ///< Special key code or ASCII value.
- const char *name; ///< Name of the key
-} key_names_table[] = {
- {' ', "Space"},
- {TAB, "Tab"},
- {K_TAB, "Tab"},
- {NL, "NL"},
- {NL, "NewLine"}, // Alternative name
- {NL, "LineFeed"}, // Alternative name
- {NL, "LF"}, // Alternative name
- {CAR, "CR"},
- {CAR, "Return"}, // Alternative name
- {CAR, "Enter"}, // Alternative name
- {K_BS, "BS"},
- {K_BS, "BackSpace"}, // Alternative name
- {ESC, "Esc"},
- {CSI, "CSI"},
- {K_CSI, "xCSI"},
- {'|', "Bar"},
- {'\\', "Bslash"},
- {K_DEL, "Del"},
- {K_DEL, "Delete"}, // Alternative name
- {K_KDEL, "kDel"},
- {K_UP, "Up"},
- {K_DOWN, "Down"},
- {K_LEFT, "Left"},
- {K_RIGHT, "Right"},
- {K_XUP, "xUp"},
- {K_XDOWN, "xDown"},
- {K_XLEFT, "xLeft"},
- {K_XRIGHT, "xRight"},
-
- {K_F1, "F1"},
- {K_F2, "F2"},
- {K_F3, "F3"},
- {K_F4, "F4"},
- {K_F5, "F5"},
- {K_F6, "F6"},
- {K_F7, "F7"},
- {K_F8, "F8"},
- {K_F9, "F9"},
- {K_F10, "F10"},
-
- {K_F11, "F11"},
- {K_F12, "F12"},
- {K_F13, "F13"},
- {K_F14, "F14"},
- {K_F15, "F15"},
- {K_F16, "F16"},
- {K_F17, "F17"},
- {K_F18, "F18"},
- {K_F19, "F19"},
- {K_F20, "F20"},
-
- {K_F21, "F21"},
- {K_F22, "F22"},
- {K_F23, "F23"},
- {K_F24, "F24"},
- {K_F25, "F25"},
- {K_F26, "F26"},
- {K_F27, "F27"},
- {K_F28, "F28"},
- {K_F29, "F29"},
- {K_F30, "F30"},
-
- {K_F31, "F31"},
- {K_F32, "F32"},
- {K_F33, "F33"},
- {K_F34, "F34"},
- {K_F35, "F35"},
- {K_F36, "F36"},
- {K_F37, "F37"},
-
- {K_XF1, "xF1"},
- {K_XF2, "xF2"},
- {K_XF3, "xF3"},
- {K_XF4, "xF4"},
-
- {K_HELP, "Help"},
- {K_UNDO, "Undo"},
- {K_INS, "Insert"},
- {K_INS, "Ins"}, // Alternative name
- {K_KINS, "kInsert"},
- {K_HOME, "Home"},
- {K_KHOME, "kHome"},
- {K_XHOME, "xHome"},
- {K_ZHOME, "zHome"},
- {K_END, "End"},
- {K_KEND, "kEnd"},
- {K_XEND, "xEnd"},
- {K_ZEND, "zEnd"},
- {K_PAGEUP, "PageUp"},
- {K_PAGEDOWN, "PageDown"},
- {K_KPAGEUP, "kPageUp"},
- {K_KPAGEDOWN, "kPageDown"},
-
- {K_KPLUS, "kPlus"},
- {K_KMINUS, "kMinus"},
- {K_KDIVIDE, "kDivide"},
- {K_KMULTIPLY, "kMultiply"},
- {K_KENTER, "kEnter"},
- {K_KPOINT, "kPoint"},
-
- {K_K0, "k0"},
- {K_K1, "k1"},
- {K_K2, "k2"},
- {K_K3, "k3"},
- {K_K4, "k4"},
- {K_K5, "k5"},
- {K_K6, "k6"},
- {K_K7, "k7"},
- {K_K8, "k8"},
- {K_K9, "k9"},
-
- {'<', "lt"},
-
- {K_MOUSE, "Mouse"},
- {K_LEFTMOUSE, "LeftMouse"},
- {K_LEFTMOUSE_NM, "LeftMouseNM"},
- {K_LEFTDRAG, "LeftDrag"},
- {K_LEFTRELEASE, "LeftRelease"},
- {K_LEFTRELEASE_NM, "LeftReleaseNM"},
- {K_MIDDLEMOUSE, "MiddleMouse"},
- {K_MIDDLEDRAG, "MiddleDrag"},
- {K_MIDDLERELEASE, "MiddleRelease"},
- {K_RIGHTMOUSE, "RightMouse"},
- {K_RIGHTDRAG, "RightDrag"},
- {K_RIGHTRELEASE, "RightRelease"},
- {K_MOUSEDOWN, "ScrollWheelUp"},
- {K_MOUSEUP, "ScrollWheelDown"},
- {K_MOUSELEFT, "ScrollWheelRight"},
- {K_MOUSERIGHT, "ScrollWheelLeft"},
- {K_MOUSEDOWN, "MouseDown"}, // OBSOLETE: Use ScrollWheelXXX instead
- {K_MOUSEUP, "MouseUp"}, // Same
- {K_X1MOUSE, "X1Mouse"},
- {K_X1DRAG, "X1Drag"},
- {K_X1RELEASE, "X1Release"},
- {K_X2MOUSE, "X2Mouse"},
- {K_X2DRAG, "X2Drag"},
- {K_X2RELEASE, "X2Release"},
- {K_DROP, "Drop"},
- {K_ZERO, "Nul"},
- {K_SNR, "SNR"},
- {K_PLUG, "Plug"},
- {K_PASTE, "Paste"},
- {K_FOCUSGAINED, "FocusGained"},
- {K_FOCUSLOST, "FocusLost"},
- {0, NULL}
+ int key; // Special key code or ascii value
+ const char *name; // Name of key
+} key_names_table[] =
+{
+ { ' ', "Space" },
+ { TAB, "Tab" },
+ { K_TAB, "Tab" },
+ { NL, "NL" },
+ { NL, "NewLine" }, // Alternative name
+ { NL, "LineFeed" }, // Alternative name
+ { NL, "LF" }, // Alternative name
+ { CAR, "CR" },
+ { CAR, "Return" }, // Alternative name
+ { CAR, "Enter" }, // Alternative name
+ { K_BS, "BS" },
+ { K_BS, "BackSpace" }, // Alternative name
+ { ESC, "Esc" },
+ { CSI, "CSI" },
+ { K_CSI, "xCSI" },
+ { '|', "Bar" },
+ { '\\', "Bslash" },
+ { K_DEL, "Del" },
+ { K_DEL, "Delete" }, // Alternative name
+ { K_KDEL, "kDel" },
+ { K_UP, "Up" },
+ { K_DOWN, "Down" },
+ { K_LEFT, "Left" },
+ { K_RIGHT, "Right" },
+ { K_XUP, "xUp" },
+ { K_XDOWN, "xDown" },
+ { K_XLEFT, "xLeft" },
+ { K_XRIGHT, "xRight" },
+
+ { K_F1, "F1" },
+ { K_F2, "F2" },
+ { K_F3, "F3" },
+ { K_F4, "F4" },
+ { K_F5, "F5" },
+ { K_F6, "F6" },
+ { K_F7, "F7" },
+ { K_F8, "F8" },
+ { K_F9, "F9" },
+ { K_F10, "F10" },
+
+ { K_F11, "F11" },
+ { K_F12, "F12" },
+ { K_F13, "F13" },
+ { K_F14, "F14" },
+ { K_F15, "F15" },
+ { K_F16, "F16" },
+ { K_F17, "F17" },
+ { K_F18, "F18" },
+ { K_F19, "F19" },
+ { K_F20, "F20" },
+
+ { K_F21, "F21" },
+ { K_F22, "F22" },
+ { K_F23, "F23" },
+ { K_F24, "F24" },
+ { K_F25, "F25" },
+ { K_F26, "F26" },
+ { K_F27, "F27" },
+ { K_F28, "F28" },
+ { K_F29, "F29" },
+ { K_F30, "F30" },
+
+ { K_F31, "F31" },
+ { K_F32, "F32" },
+ { K_F33, "F33" },
+ { K_F34, "F34" },
+ { K_F35, "F35" },
+ { K_F36, "F36" },
+ { K_F37, "F37" },
+
+ { K_XF1, "xF1" },
+ { K_XF2, "xF2" },
+ { K_XF3, "xF3" },
+ { K_XF4, "xF4" },
+
+ { K_HELP, "Help" },
+ { K_UNDO, "Undo" },
+ { K_INS, "Insert" },
+ { K_INS, "Ins" }, // Alternative name
+ { K_KINS, "kInsert" },
+ { K_HOME, "Home" },
+ { K_KHOME, "kHome" },
+ { K_XHOME, "xHome" },
+ { K_ZHOME, "zHome" },
+ { K_END, "End" },
+ { K_KEND, "kEnd" },
+ { K_XEND, "xEnd" },
+ { K_ZEND, "zEnd" },
+ { K_PAGEUP, "PageUp" },
+ { K_PAGEDOWN, "PageDown" },
+ { K_KPAGEUP, "kPageUp" },
+ { K_KPAGEDOWN, "kPageDown" },
+
+ { K_KPLUS, "kPlus" },
+ { K_KMINUS, "kMinus" },
+ { K_KDIVIDE, "kDivide" },
+ { K_KMULTIPLY, "kMultiply" },
+ { K_KENTER, "kEnter" },
+ { K_KPOINT, "kPoint" },
+
+ { K_K0, "k0" },
+ { K_K1, "k1" },
+ { K_K2, "k2" },
+ { K_K3, "k3" },
+ { K_K4, "k4" },
+ { K_K5, "k5" },
+ { K_K6, "k6" },
+ { K_K7, "k7" },
+ { K_K8, "k8" },
+ { K_K9, "k9" },
+
+ { '<', "lt" },
+
+ { K_MOUSE, "Mouse" },
+ { K_LEFTMOUSE, "LeftMouse" },
+ { K_LEFTMOUSE_NM, "LeftMouseNM" },
+ { K_LEFTDRAG, "LeftDrag" },
+ { K_LEFTRELEASE, "LeftRelease" },
+ { K_LEFTRELEASE_NM, "LeftReleaseNM" },
+ { K_MIDDLEMOUSE, "MiddleMouse" },
+ { K_MIDDLEDRAG, "MiddleDrag" },
+ { K_MIDDLERELEASE, "MiddleRelease" },
+ { K_RIGHTMOUSE, "RightMouse" },
+ { K_RIGHTDRAG, "RightDrag" },
+ { K_RIGHTRELEASE, "RightRelease" },
+ { K_MOUSEDOWN, "ScrollWheelUp" },
+ { K_MOUSEUP, "ScrollWheelDown" },
+ { K_MOUSELEFT, "ScrollWheelRight" },
+ { K_MOUSERIGHT, "ScrollWheelLeft" },
+ { K_MOUSEDOWN, "MouseDown" }, // OBSOLETE: Use
+ { K_MOUSEUP, "MouseUp" }, // ScrollWheelXXX instead
+ { K_X1MOUSE, "X1Mouse" },
+ { K_X1DRAG, "X1Drag" },
+ { K_X1RELEASE, "X1Release" },
+ { K_X2MOUSE, "X2Mouse" },
+ { K_X2DRAG, "X2Drag" },
+ { K_X2RELEASE, "X2Release" },
+ { K_DROP, "Drop" },
+ { K_ZERO, "Nul" },
+ { K_SNR, "SNR" },
+ { K_PLUG, "Plug" },
+ { K_PASTE, "Paste" },
+ { 0, NULL }
};
static struct mousetable {
@@ -720,8 +719,8 @@ int get_special_key_code(const char_u *name)
for (int i = 0; key_names_table[i].name != NULL; i++) {
const char *const table_name = key_names_table[i].name;
int j;
- for (j = 0; vim_isIDc(name[j]) && table_name[j] != NUL; j++) {
- if (TOLOWER_ASC(table_name[j]) != TOLOWER_ASC(name[j])) {
+ for (j = 0; vim_isIDc(name[j]) && table_name[j] != NUL; j++)
+ if (TOLOWER_ASC(table_name[j]) != TOLOWER_ASC(name[j]))
break;
}
}
diff --git a/src/nvim/keymap.h b/src/nvim/keymap.h
index b8fed77a90..ee64854c98 100644
--- a/src/nvim/keymap.h
+++ b/src/nvim/keymap.h
@@ -428,8 +428,6 @@ enum key_extra {
#define K_CMDWIN TERMCAP2KEY(KS_EXTRA, KE_CMDWIN)
#define K_DROP TERMCAP2KEY(KS_EXTRA, KE_DROP)
-#define K_FOCUSGAINED TERMCAP2KEY(KS_EXTRA, KE_FOCUSGAINED)
-#define K_FOCUSLOST TERMCAP2KEY(KS_EXTRA, KE_FOCUSLOST)
#define K_EVENT TERMCAP2KEY(KS_EXTRA, KE_EVENT)
#define K_PASTE TERMCAP2KEY(KS_EXTRA, KE_PASTE)
diff --git a/src/nvim/log.c b/src/nvim/log.c
index 3baf0b2ebd..7bfe5c4089 100644
--- a/src/nvim/log.c
+++ b/src/nvim/log.c
@@ -95,8 +95,12 @@ void log_unlock(void)
uv_mutex_unlock(&mutex);
}
-bool do_log(int log_level, const char *func_name, int line_num, bool eol,
- const char* fmt, ...) FUNC_ATTR_UNUSED
+/// @param context description of a shared context or subsystem
+/// @param func_name function name, or NULL
+/// @param line_num source line number, or -1
+bool do_log(int log_level, const char *context, const char *func_name,
+ int line_num, bool eol, const char *fmt, ...)
+ FUNC_ATTR_UNUSED
{
if (log_level < MIN_LOG_LEVEL) {
return false;
@@ -112,8 +116,8 @@ bool do_log(int log_level, const char *func_name, int line_num, bool eol,
va_list args;
va_start(args, fmt);
- ret = v_do_log_to_file(log_file, log_level, func_name, line_num, eol,
- fmt, args);
+ ret = v_do_log_to_file(log_file, log_level, context, func_name, line_num,
+ eol, fmt, args);
va_end(args);
if (log_file != stderr && log_file != stdout) {
@@ -151,7 +155,7 @@ FILE *open_log_file(void)
static bool opening_log_file = false;
// check if it's a recursive call
if (opening_log_file) {
- do_log_to_file(stderr, ERROR_LOG_LEVEL, __func__, __LINE__, true,
+ do_log_to_file(stderr, ERROR_LOG_LEVEL, NULL, __func__, __LINE__, true,
"Cannot LOG() recursively.");
return stderr;
}
@@ -171,7 +175,7 @@ FILE *open_log_file(void)
// - LOG() is called before early_init()
// - Directory does not exist
// - File is not writable
- do_log_to_file(stderr, ERROR_LOG_LEVEL, __func__, __LINE__, true,
+ do_log_to_file(stderr, ERROR_LOG_LEVEL, NULL, __func__, __LINE__, true,
"Logging to stderr, failed to open $" LOG_FILE_ENV ": %s",
log_file_path);
return stderr;
@@ -201,7 +205,7 @@ void log_callstack_to_file(FILE *log_file, const char *const func_name,
// Now we have a command string like:
// addr2line -e /path/to/exe -f -p 0x123 0x456 ...
- do_log_to_file(log_file, DEBUG_LOG_LEVEL, func_name, line_num, true,
+ do_log_to_file(log_file, DEBUG_LOG_LEVEL, NULL, func_name, line_num, true,
"trace:");
FILE *fp = popen(cmdbuf, "r");
char linebuf[IOSIZE];
@@ -230,27 +234,28 @@ end:
}
#endif
-static bool do_log_to_file(FILE *log_file, int log_level,
+static bool do_log_to_file(FILE *log_file, int log_level, const char *context,
const char *func_name, int line_num, bool eol,
const char* fmt, ...)
{
va_list args;
va_start(args, fmt);
- bool ret = v_do_log_to_file(log_file, log_level, func_name, line_num, eol,
- fmt, args);
+ bool ret = v_do_log_to_file(log_file, log_level, context, func_name,
+ line_num, eol, fmt, args);
va_end(args);
return ret;
}
static bool v_do_log_to_file(FILE *log_file, int log_level,
- const char *func_name, int line_num, bool eol,
- const char* fmt, va_list args)
+ const char *context, const char *func_name,
+ int line_num, bool eol, const char *fmt,
+ va_list args)
{
static const char *log_levels[] = {
[DEBUG_LOG_LEVEL] = "DEBUG",
[INFO_LOG_LEVEL] = "INFO ",
- [WARNING_LOG_LEVEL] = "WARN ",
+ [WARN_LOG_LEVEL] = "WARN ",
[ERROR_LOG_LEVEL] = "ERROR",
};
assert(log_level >= DEBUG_LOG_LEVEL && log_level <= ERROR_LOG_LEVEL);
@@ -268,8 +273,15 @@ static bool v_do_log_to_file(FILE *log_file, int log_level,
// print the log message prefixed by the current timestamp and pid
int64_t pid = os_get_pid();
- if (fprintf(log_file, "%s %s %" PRId64 "/%s:%d: ", date_time,
- log_levels[log_level], pid, func_name, line_num) < 0) {
+ int rv = (line_num == -1 || func_name == NULL)
+ ? fprintf(log_file, "%s %s %" PRId64 " %s", date_time,
+ log_levels[log_level], pid,
+ (context == NULL ? "?:" : context))
+ : fprintf(log_file, "%s %s %" PRId64 " %s%s:%d: ", date_time,
+ log_levels[log_level], pid,
+ (context == NULL ? "" : context),
+ func_name, line_num);
+ if (rv < 0) {
return false;
}
if (vfprintf(log_file, fmt, args) < 0) {
diff --git a/src/nvim/log.h b/src/nvim/log.h
index 5064d9333b..f378b92039 100644
--- a/src/nvim/log.h
+++ b/src/nvim/log.h
@@ -6,7 +6,7 @@
#define DEBUG_LOG_LEVEL 0
#define INFO_LOG_LEVEL 1
-#define WARNING_LOG_LEVEL 2
+#define WARN_LOG_LEVEL 2
#define ERROR_LOG_LEVEL 3
#define DLOG(...)
@@ -22,42 +22,42 @@
# define MIN_LOG_LEVEL INFO_LOG_LEVEL
#endif
-#define LOG(level, ...) do_log((level), __func__, __LINE__, true, \
+#define LOG(level, ...) do_log((level), NULL, __func__, __LINE__, true, \
__VA_ARGS__)
#if MIN_LOG_LEVEL <= DEBUG_LOG_LEVEL
# undef DLOG
# undef DLOGN
-# define DLOG(...) do_log(DEBUG_LOG_LEVEL, __func__, __LINE__, true, \
+# define DLOG(...) do_log(DEBUG_LOG_LEVEL, NULL, __func__, __LINE__, true, \
__VA_ARGS__)
-# define DLOGN(...) do_log(DEBUG_LOG_LEVEL, __func__, __LINE__, false, \
+# define DLOGN(...) do_log(DEBUG_LOG_LEVEL, NULL, __func__, __LINE__, false, \
__VA_ARGS__)
#endif
#if MIN_LOG_LEVEL <= INFO_LOG_LEVEL
# undef ILOG
# undef ILOGN
-# define ILOG(...) do_log(INFO_LOG_LEVEL, __func__, __LINE__, true, \
+# define ILOG(...) do_log(INFO_LOG_LEVEL, NULL, __func__, __LINE__, true, \
__VA_ARGS__)
-# define ILOGN(...) do_log(INFO_LOG_LEVEL, __func__, __LINE__, false, \
+# define ILOGN(...) do_log(INFO_LOG_LEVEL, NULL, __func__, __LINE__, false, \
__VA_ARGS__)
#endif
-#if MIN_LOG_LEVEL <= WARNING_LOG_LEVEL
+#if MIN_LOG_LEVEL <= WARN_LOG_LEVEL
# undef WLOG
# undef WLOGN
-# define WLOG(...) do_log(WARNING_LOG_LEVEL, __func__, __LINE__, true, \
+# define WLOG(...) do_log(WARN_LOG_LEVEL, NULL, __func__, __LINE__, true, \
__VA_ARGS__)
-# define WLOGN(...) do_log(WARNING_LOG_LEVEL, __func__, __LINE__, false, \
+# define WLOGN(...) do_log(WARN_LOG_LEVEL, NULL, __func__, __LINE__, false, \
__VA_ARGS__)
#endif
#if MIN_LOG_LEVEL <= ERROR_LOG_LEVEL
# undef ELOG
# undef ELOGN
-# define ELOG(...) do_log(ERROR_LOG_LEVEL, __func__, __LINE__, true, \
+# define ELOG(...) do_log(ERROR_LOG_LEVEL, NULL, __func__, __LINE__, true, \
__VA_ARGS__)
-# define ELOGN(...) do_log(ERROR_LOG_LEVEL, __func__, __LINE__, false, \
+# define ELOGN(...) do_log(ERROR_LOG_LEVEL, NULL, __func__, __LINE__, false, \
__VA_ARGS__)
#endif
diff --git a/src/nvim/main.c b/src/nvim/main.c
index 3f828d7be9..ea7a58bda3 100644
--- a/src/nvim/main.c
+++ b/src/nvim/main.c
@@ -7,6 +7,11 @@
#include <string.h>
#include <stdbool.h>
+#ifdef WIN32
+# include <wchar.h>
+# include <winnls.h>
+#endif
+
#include <msgpack.h>
#include "nvim/ascii.h"
@@ -215,10 +220,22 @@ void early_init(void)
#ifdef MAKE_LIB
int nvim_main(int argc, char **argv)
+#elif defined(WIN32)
+int wmain(int argc, wchar_t **argv_w) // multibyte args on Windows. #7060
#else
int main(int argc, char **argv)
#endif
{
+#if defined(WIN32) && !defined(MAKE_LIB)
+ char *argv[argc];
+ for (int i = 0; i < argc; i++) {
+ char *buf = NULL;
+ utf16_to_utf8(argv_w[i], &buf);
+ assert(buf);
+ argv[i] = buf;
+ }
+#endif
+
argv0 = argv[0];
char_u *fname = NULL; // file name from command line
@@ -632,6 +649,11 @@ void getout(int exitval)
/* Position the cursor again, the autocommands may have moved it */
ui_cursor_goto((int)Rows - 1, 0);
+ // Apply 'titleold'.
+ if (p_title && *p_titleold != NUL) {
+ ui_call_set_title(cstr_as_string((char *)p_titleold));
+ }
+
#if defined(USE_ICONV) && defined(DYNAMIC_ICONV)
iconv_end();
#endif
@@ -1291,10 +1313,29 @@ static void set_window_layout(mparm_T *paramp)
static void load_plugins(void)
{
if (p_lpl) {
- source_runtime((char_u *)"plugin/**/*.vim", DIP_ALL | DIP_NOAFTER); // NOLINT
+ char_u *rtp_copy = NULL;
+
+ // First add all package directories to 'runtimepath', so that their
+ // autoload directories can be found. Only if not done already with a
+ // :packloadall command.
+ // Make a copy of 'runtimepath', so that source_runtime does not use the
+ // pack directories.
+ if (!did_source_packages) {
+ rtp_copy = vim_strsave(p_rtp);
+ add_pack_start_dirs();
+ }
+
+ source_in_path(rtp_copy == NULL ? p_rtp : rtp_copy,
+ (char_u *)"plugin/**/*.vim", // NOLINT
+ DIP_ALL | DIP_NOAFTER);
TIME_MSG("loading plugins");
+ xfree(rtp_copy);
- ex_packloadall(NULL);
+ // Only source "start" packages if not done already with a :packloadall
+ // command.
+ if (!did_source_packages) {
+ load_start_packages();
+ }
TIME_MSG("loading packages");
source_runtime((char_u *)"plugin/**/*.vim", DIP_ALL | DIP_AFTER);
@@ -1878,54 +1919,47 @@ static void usage(void)
signal_stop(); // kill us with CTRL-C here, if you like
mch_msg(_("Usage:\n"));
- mch_msg(_(" nvim [arguments] [file ...] Edit specified file(s)\n"));
- mch_msg(_(" nvim [arguments] - Read text from stdin\n"));
- mch_msg(_(" nvim [arguments] -t <tag> Edit file where tag is defined\n"));
- mch_msg(_(" nvim [arguments] -q [errorfile] Edit file with first error\n"));
- mch_msg(_("\nArguments:\n"));
+ mch_msg(_(" nvim [options] [file ...] Edit file(s)\n"));
+ mch_msg(_(" nvim [options] - Read text from stdin\n"));
+ mch_msg(_(" nvim [options] -t <tag> Edit file where tag is defined\n"));
+ mch_msg(_(" nvim [options] -q [errorfile] Edit file with first error\n"));
+ mch_msg(_("\nOptions:\n"));
mch_msg(_(" -- Only file names after this\n"));
-#if !defined(UNIX)
- mch_msg(_(" --literal Don't expand wildcards\n"));
-#endif
- mch_msg(_(" -e Ex mode\n"));
- mch_msg(_(" -E Improved Ex mode\n"));
- mch_msg(_(" -s Silent (batch) mode (only for ex mode)\n"));
+ mch_msg(_(" + Start at end of file\n"));
+ mch_msg(_(" --cmd <cmd> Execute <cmd> before any config\n"));
+ mch_msg(_(" +<cmd>, -c <cmd> Execute <cmd> after config and first file\n"));
+ mch_msg("\n");
+ mch_msg(_(" -b Binary mode\n"));
mch_msg(_(" -d Diff mode\n"));
- mch_msg(_(" -R Read-only mode\n"));
- mch_msg(_(" -Z Restricted mode\n"));
+ mch_msg(_(" -e, -E Ex mode, Improved Ex mode\n"));
+ mch_msg(_(" -es Silent (batch) mode\n"));
+ mch_msg(_(" -h, --help Print this help message\n"));
+ mch_msg(_(" -i <shada> Use this shada file\n"));
mch_msg(_(" -m Modifications (writing files) not allowed\n"));
mch_msg(_(" -M Modifications in text not allowed\n"));
- mch_msg(_(" -b Binary mode\n"));
- mch_msg(_(" -l Lisp mode\n"));
- mch_msg(_(" -A Arabic mode\n"));
- mch_msg(_(" -F Farsi mode\n"));
- mch_msg(_(" -H Hebrew mode\n"));
- mch_msg(_(" -V[N][file] Be verbose [level N][log messages to file]\n"));
- mch_msg(_(" -D Debugging mode\n"));
mch_msg(_(" -n No swap file, use memory only\n"));
- mch_msg(_(" -r, -L List swap files and exit\n"));
- mch_msg(_(" -r <file> Recover crashed session\n"));
- mch_msg(_(" -u <vimrc> Use <vimrc> instead of the default\n"));
- mch_msg(_(" -i <shada> Use <shada> instead of the default\n"));
- mch_msg(_(" --noplugin Don't load plugin scripts\n"));
- mch_msg(_(" -o[N] Open N windows (default: one for each file)\n"));
- mch_msg(_(" -O[N] Like -o but split vertically\n"));
- mch_msg(_(" -p[N] Open N tab pages (default: one for each file)\n"));
- mch_msg(_(" + Start at end of file\n"));
- mch_msg(_(" +<linenum> Start at line <linenum>\n"));
- mch_msg(_(" +/<pattern> Start at first occurrence of <pattern>\n"));
- mch_msg(_(" --cmd <command> Execute <command> before loading any vimrc\n"));
- mch_msg(_(" -c <command> Execute <command> after loading the first file\n"));
+ mch_msg(_(" -o[N] Open N windows (default: one per file)\n"));
+ mch_msg(_(" -O[N] Open N vertical windows (default: one per file)\n"));
+ mch_msg(_(" -p[N] Open N tab pages (default: one per file)\n"));
+ mch_msg(_(" -r, -L List swap files\n"));
+ mch_msg(_(" -r <file> Recover edit state for this file\n"));
+ mch_msg(_(" -R Read-only mode\n"));
mch_msg(_(" -S <session> Source <session> after loading the first file\n"));
mch_msg(_(" -s <scriptin> Read Normal mode commands from <scriptin>\n"));
- mch_msg(_(" -w <scriptout> Append all typed characters to <scriptout>\n"));
- mch_msg(_(" -W <scriptout> Write all typed characters to <scriptout>\n"));
- mch_msg(_(" --startuptime <file> Write startup timing messages to <file>\n"));
- mch_msg(_(" --api-info Dump API metadata serialized to msgpack and exit\n"));
+ mch_msg(_(" -u <config> Use this config file\n"));
+ mch_msg(_(" -v, --version Print version information\n"));
+ mch_msg(_(" -V[N][file] Verbose [level][file]\n"));
+ mch_msg(_(" -Z Restricted mode\n"));
+ mch_msg("\n");
+ mch_msg(_(" --api-info Write msgpack-encoded API metadata to stdout\n"));
mch_msg(_(" --embed Use stdin/stdout as a msgpack-rpc channel\n"));
mch_msg(_(" --headless Don't start a user interface\n"));
- mch_msg(_(" -v, --version Print version information and exit\n"));
- mch_msg(_(" -h, --help Print this help message and exit\n"));
+#if !defined(UNIX)
+ mch_msg(_(" --literal Don't expand wildcards\n"));
+#endif
+ mch_msg(_(" --noplugin Don't load plugins\n"));
+ mch_msg(_(" --startuptime <file> Write startup timing messages to <file>\n"));
+ mch_msg(_("\nSee \":help startup-options\" for all options.\n"));
}
diff --git a/src/nvim/move.c b/src/nvim/move.c
index 4d646f5a4b..9693132846 100644
--- a/src/nvim/move.c
+++ b/src/nvim/move.c
@@ -2164,16 +2164,21 @@ void do_check_cursorbind(void)
int restart_edit_save = restart_edit;
restart_edit = true;
check_cursor();
+ if (curwin->w_p_cul || curwin->w_p_cuc) {
+ validate_cursor();
+ }
restart_edit = restart_edit_save;
}
- /* Correct cursor for multi-byte character. */
- if (has_mbyte)
+ // Correct cursor for multi-byte character.
+ if (has_mbyte) {
mb_adjust_cursor();
+ }
redraw_later(VALID);
- /* Only scroll when 'scrollbind' hasn't done this. */
- if (!curwin->w_p_scb)
+ // Only scroll when 'scrollbind' hasn't done this.
+ if (!curwin->w_p_scb) {
update_topline();
+ }
curwin->w_redr_status = true;
}
}
diff --git a/src/nvim/msgpack_rpc/channel.c b/src/nvim/msgpack_rpc/channel.c
index 6fd1af1ba6..88232a55de 100644
--- a/src/nvim/msgpack_rpc/channel.c
+++ b/src/nvim/msgpack_rpc/channel.c
@@ -62,7 +62,7 @@ typedef struct {
ChannelType type;
msgpack_unpacker *unpacker;
union {
- Stream stream;
+ Stream stream; // bidirectional (socket)
Process *proc;
struct {
Stream in;
@@ -133,6 +133,9 @@ uint64_t channel_from_process(Process *proc, uint64_t id, char *source)
rstream_init(proc->out, 0);
rstream_start(proc->out, receive_msgpack, channel);
+ DLOG("ch %" PRIu64 " in-stream=%p out-stream=%p", channel->id, proc->in,
+ proc->out);
+
return channel->id;
}
@@ -150,6 +153,9 @@ void channel_from_connection(SocketWatcher *watcher)
wstream_init(&channel->data.stream, 0);
rstream_init(&channel->data.stream, CHANNEL_BUFFER_SIZE);
rstream_start(&channel->data.stream, receive_msgpack, channel);
+
+ DLOG("ch %" PRIu64 " in/out-stream=%p", channel->id,
+ &channel->data.stream);
}
/// @param source description of source function, rplugin name, TCP addr, etc
@@ -182,12 +188,11 @@ uint64_t channel_connect(bool tcp, const char *address, int timeout,
return channel->id;
}
-/// Sends event/arguments to channel
+/// Publishes an event to a channel.
///
-/// @param id The channel id. If 0, the event will be sent to all
-/// channels that have subscribed to the event type
-/// @param name The event name, an arbitrary string
-/// @param args Array with event arguments
+/// @param id Channel id. 0 means "broadcast to all subscribed channels"
+/// @param name Event name (application-defined)
+/// @param args Array of event arguments
/// @return True if the event was sent successfully, false otherwise.
bool channel_send_event(uint64_t id, const char *name, Array args)
{
@@ -209,7 +214,6 @@ bool channel_send_event(uint64_t id, const char *name, Array args)
send_event(channel, name, args);
}
} else {
- // TODO(tarruda): Implement event broadcasting in vimscript
broadcast_event(name, args);
}
@@ -344,6 +348,9 @@ void channel_from_stdio(void)
rstream_start(&channel->data.std.in, receive_msgpack, channel);
// write stream
wstream_init_fd(&main_loop, &channel->data.std.out, 1, 0);
+
+ DLOG("ch %" PRIu64 " in-stream=%p out-stream=%p", channel->id,
+ &channel->data.std.in, &channel->data.std.out);
}
/// Creates a loopback channel. This is used to avoid deadlock
@@ -363,6 +370,7 @@ void channel_process_exit(uint64_t id, int status)
decref(channel);
}
+// rstream.c:read_event() invokes this as stream->read_cb().
static void receive_msgpack(Stream *stream, RBuffer *rbuf, size_t c,
void *data, bool eof)
{
@@ -374,12 +382,24 @@ static void receive_msgpack(Stream *stream, RBuffer *rbuf, size_t c,
char buf[256];
snprintf(buf, sizeof(buf), "ch %" PRIu64 " was closed by the client",
channel->id);
- call_set_error(channel, buf, WARNING_LOG_LEVEL);
+ call_set_error(channel, buf, WARN_LOG_LEVEL);
+ goto end;
+ }
+
+ if ((chan_wstream(channel) != NULL && chan_wstream(channel)->closed)
+ || (chan_rstream(channel) != NULL && chan_rstream(channel)->closed)) {
+ char buf[256];
+ snprintf(buf, sizeof(buf),
+ "ch %" PRIu64 ": stream closed unexpectedly. "
+ "closing channel",
+ channel->id);
+ call_set_error(channel, buf, WARN_LOG_LEVEL);
goto end;
}
size_t count = rbuffer_size(rbuf);
- DLOG("parsing %u bytes of msgpack data from Stream(%p)", count, stream);
+ DLOG("ch %" PRIu64 ": parsing %u bytes from msgpack Stream: %p",
+ channel->id, count, stream);
// Feed the unpacker with data
msgpack_unpacker_reserve_buffer(channel->unpacker, count);
@@ -435,8 +455,8 @@ static void parse_msgpack(Channel *channel)
// causes for this error(search for 'goto _failed')
//
// A not so uncommon cause for this might be deserializing objects with
- // a high nesting level: msgpack will break when it's internal parse stack
- // size exceeds MSGPACK_EMBED_STACK_SIZE(defined as 32 by default)
+ // a high nesting level: msgpack will break when its internal parse stack
+ // size exceeds MSGPACK_EMBED_STACK_SIZE (defined as 32 by default)
send_error(channel, 0, "Invalid msgpack payload. "
"This error can also happen when deserializing "
"an object with high level of nesting");
@@ -534,6 +554,39 @@ static void on_request_event(void **argv)
api_clear_error(&error);
}
+/// Returns the Stream that a Channel writes to.
+static Stream *chan_wstream(Channel *chan)
+{
+ switch (chan->type) {
+ case kChannelTypeSocket:
+ return &chan->data.stream;
+ case kChannelTypeProc:
+ return chan->data.proc->in;
+ case kChannelTypeStdio:
+ return &chan->data.std.out;
+ case kChannelTypeInternal:
+ return NULL;
+ }
+ abort();
+}
+
+/// Returns the Stream that a Channel reads from.
+static Stream *chan_rstream(Channel *chan)
+{
+ switch (chan->type) {
+ case kChannelTypeSocket:
+ return &chan->data.stream;
+ case kChannelTypeProc:
+ return chan->data.proc->out;
+ case kChannelTypeStdio:
+ return &chan->data.std.in;
+ case kChannelTypeInternal:
+ return NULL;
+ }
+ abort();
+}
+
+
static bool channel_write(Channel *channel, WBuffer *buffer)
{
bool success = false;
@@ -545,13 +598,9 @@ static bool channel_write(Channel *channel, WBuffer *buffer)
switch (channel->type) {
case kChannelTypeSocket:
- success = wstream_write(&channel->data.stream, buffer);
- break;
case kChannelTypeProc:
- success = wstream_write(channel->data.proc->in, buffer);
- break;
case kChannelTypeStdio:
- success = wstream_write(&channel->data.std.out, buffer);
+ success = wstream_write(chan_wstream(channel), buffer);
break;
case kChannelTypeInternal:
incref(channel);
@@ -565,8 +614,8 @@ static bool channel_write(Channel *channel, WBuffer *buffer)
char buf[256];
snprintf(buf,
sizeof(buf),
- "Before returning from a RPC call, ch %" PRIu64 " was "
- "closed due to a failed write",
+ "ch %" PRIu64 ": stream write failed. "
+ "RPC canceled; closing channel",
channel->id);
call_set_error(channel, buf, ERROR_LOG_LEVEL);
}
@@ -817,6 +866,7 @@ static void call_set_error(Channel *channel, char *msg, int loglevel)
ChannelCallFrame *frame = kv_A(channel->call_stack, i);
frame->returned = true;
frame->errored = true;
+ api_free_object(frame->result);
frame->result = STRING_OBJ(cstr_to_string(msg));
}
diff --git a/src/nvim/msgpack_rpc/helpers.c b/src/nvim/msgpack_rpc/helpers.c
index 444c6cc256..fecae11d45 100644
--- a/src/nvim/msgpack_rpc/helpers.c
+++ b/src/nvim/msgpack_rpc/helpers.c
@@ -88,7 +88,12 @@ bool msgpack_rpc_to_object(const msgpack_object *const obj, Object *const arg)
{
bool ret = true;
kvec_t(MPToAPIObjectStackItem) stack = KV_INITIAL_VALUE;
- kv_push(stack, ((MPToAPIObjectStackItem) { obj, arg, false, 0 }));
+ kv_push(stack, ((MPToAPIObjectStackItem) {
+ .mobj = obj,
+ .aobj = arg,
+ .container = false,
+ .idx = 0,
+ }));
while (ret && kv_size(stack)) {
MPToAPIObjectStackItem cur = kv_last(stack);
if (!cur.container) {
@@ -361,7 +366,7 @@ typedef struct {
size_t idx;
} APIToMPObjectStackItem;
-/// Convert type used by Neovim API to msgpack
+/// Convert type used by Nvim API to msgpack type.
///
/// @param[in] result Object to convert.
/// @param[out] res Structure that defines where conversion results are saved.
diff --git a/src/nvim/normal.c b/src/nvim/normal.c
index c1676780d8..c40ed58550 100644
--- a/src/nvim/normal.c
+++ b/src/nvim/normal.c
@@ -13,6 +13,7 @@
#include <stdbool.h>
#include <stdlib.h>
+#include "nvim/log.h"
#include "nvim/vim.h"
#include "nvim/ascii.h"
#include "nvim/normal.h"
@@ -344,8 +345,6 @@ static const struct nv_cmd {
{ K_F8, farsi_f8, 0, 0 },
{ K_F9, farsi_f9, 0, 0 },
{ K_EVENT, nv_event, NV_KEEPREG, 0 },
- { K_FOCUSGAINED, nv_focusgained, NV_KEEPREG, 0 },
- { K_FOCUSLOST, nv_focuslost, NV_KEEPREG, 0 },
};
/* Number of commands in nv_cmds[]. */
@@ -1943,8 +1942,11 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank)
* the lines. */
auto_format(false, true);
- if (restart_edit == 0)
+ if (restart_edit == 0) {
restart_edit = restart_edit_save;
+ } else {
+ cap->retval |= CA_COMMAND_BUSY;
+ }
}
break;
@@ -7957,18 +7959,7 @@ static void nv_event(cmdarg_T *cap)
may_garbage_collect = false;
multiqueue_process_events(main_loop.events);
cap->retval |= CA_COMMAND_BUSY; // don't call edit() now
-}
-
-/// Trigger FocusGained event.
-static void nv_focusgained(cmdarg_T *cap)
-{
- apply_autocmds(EVENT_FOCUSGAINED, NULL, NULL, false, curbuf);
-}
-
-/// Trigger FocusLost event.
-static void nv_focuslost(cmdarg_T *cap)
-{
- apply_autocmds(EVENT_FOCUSLOST, NULL, NULL, false, curbuf);
+ finish_op = false;
}
/*
diff --git a/src/nvim/ops.c b/src/nvim/ops.c
index 5c6f4d0d07..e7bc20698b 100644
--- a/src/nvim/ops.c
+++ b/src/nvim/ops.c
@@ -55,12 +55,11 @@ static yankreg_T y_regs[NUM_REGISTERS];
static yankreg_T *y_previous = NULL; /* ptr to last written yankreg */
-static bool clipboard_didwarn_unnamed = false;
-
// for behavior between start_batch_changes() and end_batch_changes())
-static bool clipboard_delay_update = false; // delay clipboard update
static int batch_change_count = 0; // inside a script
+static bool clipboard_delay_update = false; // delay clipboard update
static bool clipboard_needs_update = false; // clipboard was updated
+static bool clipboard_didwarn = false;
/*
* structure used by block_prep, op_delete and op_yank for blockwise operators
@@ -2061,7 +2060,7 @@ void op_insert(oparg_T *oap, long count1)
}
t1 = oap->start;
- edit(NUL, false, (linenr_T)count1);
+ (void)edit(NUL, false, (linenr_T)count1);
// When a tab was inserted, and the characters in front of the tab
// have been converted to a tab as well, the column of the cursor
@@ -5524,7 +5523,7 @@ int get_default_register_name(void)
}
/// Determine if register `*name` should be used as a clipboard.
-/// In an unnammed operation, `*name` is `NUL` and will be adjusted to `'*'/'+'` if
+/// In an unnamed operation, `*name` is `NUL` and will be adjusted to */+ if
/// `clipboard=unnamed[plus]` is set.
///
/// @param name The name of register, or `NUL` if unnamed.
@@ -5535,33 +5534,41 @@ int get_default_register_name(void)
/// if the register isn't a clipboard or provider isn't available.
static yankreg_T *adjust_clipboard_name(int *name, bool quiet, bool writing)
{
- if (*name == '*' || *name == '+') {
- if(!eval_has_provider("clipboard")) {
- if (!quiet) {
- EMSG("clipboard: No provider. Try \":CheckHealth\" or "
- "\":h clipboard\".");
- }
- return NULL;
- }
- return &y_regs[*name == '*' ? STAR_REGISTER : PLUS_REGISTER];
- } else if ((*name == NUL) && (cb_flags & CB_UNNAMEDMASK)) {
- if(!eval_has_provider("clipboard")) {
- if (!quiet && !clipboard_didwarn_unnamed) {
- msg((char_u *)"clipboard: No provider. Try \":CheckHealth\" or "
- "\":h clipboard\".");
- clipboard_didwarn_unnamed = true;
- }
- return NULL;
+#define MSG_NO_CLIP "clipboard: No provider. " \
+ "Try \":CheckHealth\" or \":h clipboard\"."
+
+ yankreg_T *target = NULL;
+ bool explicit_cb_reg = (*name == '*' || *name == '+');
+ bool implicit_cb_reg = (*name == NUL) && (cb_flags & CB_UNNAMEDMASK);
+ if (!explicit_cb_reg && !implicit_cb_reg) {
+ goto end;
+ }
+
+ if (!eval_has_provider("clipboard")) {
+ if (batch_change_count == 1 && !quiet
+ && (!clipboard_didwarn || (explicit_cb_reg && !redirecting()))) {
+ clipboard_didwarn = true;
+ // Do NOT error (emsg()) here--if it interrupts :redir we get into
+ // a weird state, stuck in "redirect mode".
+ msg((char_u *)MSG_NO_CLIP);
}
+ // ... else, be silent (don't flood during :while, :redir, etc.).
+ goto end;
+ }
+
+ if (explicit_cb_reg) {
+ target = &y_regs[*name == '*' ? STAR_REGISTER : PLUS_REGISTER];
+ goto end;
+ } else { // unnamed register: "implicit" clipboard
if (writing && clipboard_delay_update) {
+ // For "set" (copy), defer the clipboard call.
clipboard_needs_update = true;
- return NULL;
+ goto end;
} else if (!writing && clipboard_needs_update) {
- // use the internal value
- return NULL;
+ // For "get" (paste), use the internal value.
+ goto end;
}
- yankreg_T *target;
if (cb_flags & CB_UNNAMEDPLUS) {
*name = (cb_flags & CB_UNNAMED && writing) ? '"': '+';
target = &y_regs[PLUS_REGISTER];
@@ -5569,10 +5576,11 @@ static yankreg_T *adjust_clipboard_name(int *name, bool quiet, bool writing)
*name = '*';
target = &y_regs[STAR_REGISTER];
}
- return target; // unnamed register
+ goto end;
}
- // don't do anything for other register names
- return NULL;
+
+end:
+ return target;
}
static bool get_clipboard(int name, yankreg_T **target, bool quiet)
@@ -5740,17 +5748,16 @@ static void set_clipboard(int name, yankreg_T *reg)
(void)eval_call_provider("clipboard", "set", args);
}
-/// Avoid clipboard (slow) during batch operations (i.e., a script).
+/// Avoid slow things (clipboard) during batch operations (while/for-loops).
void start_batch_changes(void)
{
if (++batch_change_count > 1) {
return;
}
clipboard_delay_update = true;
- clipboard_needs_update = false;
}
-/// Update the clipboard after batch changes finished.
+/// Counterpart to start_batch_changes().
void end_batch_changes(void)
{
if (--batch_change_count > 0) {
@@ -5759,11 +5766,37 @@ void end_batch_changes(void)
}
clipboard_delay_update = false;
if (clipboard_needs_update) {
+ // must be before, as set_clipboard will invoke
+ // start/end_batch_changes recursively
+ clipboard_needs_update = false;
+ // unnamed ("implicit" clipboard)
set_clipboard(NUL, y_previous);
+ }
+}
+
+int save_batch_count(void)
+{
+ int save_count = batch_change_count;
+ batch_change_count = 0;
+ clipboard_delay_update = false;
+ if (clipboard_needs_update) {
clipboard_needs_update = false;
+ // unnamed ("implicit" clipboard)
+ set_clipboard(NUL, y_previous);
}
+ return save_count;
}
+void restore_batch_count(int save_count)
+{
+ assert(batch_change_count == 0);
+ batch_change_count = save_count;
+ if (batch_change_count > 0) {
+ clipboard_delay_update = true;
+ }
+}
+
+
/// Check whether register is empty
static inline bool reg_empty(const yankreg_T *const reg)
FUNC_ATTR_PURE
diff --git a/src/nvim/option.c b/src/nvim/option.c
index 8ba10fd38a..13aadb71bb 100644
--- a/src/nvim/option.c
+++ b/src/nvim/option.c
@@ -1749,7 +1749,7 @@ do_set (
if (flags & P_FLAGLIST) {
// Remove flags that appear twice.
- for (s = newval; *s; s++) {
+ for (s = newval; *s;) {
// if options have P_FLAGLIST and P_ONECOMMA such as
// 'whichwrap'
if (flags & P_ONECOMMA) {
@@ -1757,15 +1757,16 @@ do_set (
&& vim_strchr(s + 2, *s) != NULL) {
// Remove the duplicated value and the next comma.
STRMOVE(s, s + 2);
- s -= 2;
+ continue;
}
} else {
if ((!(flags & P_COMMA) || *s != ',')
&& vim_strchr(s + 1, *s) != NULL) {
STRMOVE(s, s + 1);
- s--;
+ continue;
}
}
+ s++;
}
}
@@ -2996,9 +2997,10 @@ did_set_string_option (
if (s[-1] == 'k' || s[-1] == 's') {
/* skip optional filename after 'k' and 's' */
while (*s && *s != ',' && *s != ' ') {
- if (*s == '\\')
- ++s;
- ++s;
+ if (*s == '\\' && s[1] != NUL) {
+ s++;
+ }
+ s++;
}
} else {
if (errbuf != NULL) {
diff --git a/src/nvim/options.lua b/src/nvim/options.lua
index 103227f6b5..84ccb2e28d 100644
--- a/src/nvim/options.lua
+++ b/src/nvim/options.lua
@@ -2498,7 +2498,7 @@ return {
no_mkrc=true,
vi_def=true,
varname='p_titleold',
- defaults={if_true={vi=N_("Thanks for flying Vim")}}
+ defaults={if_true={vi=N_("")}}
},
{
full_name='titlestring',
diff --git a/src/nvim/path.c b/src/nvim/path.c
index f2339c8046..51adcfb135 100644
--- a/src/nvim/path.c
+++ b/src/nvim/path.c
@@ -1690,6 +1690,9 @@ int vim_FullName(const char *fname, char *buf, size_t len, bool force)
if (strlen(fname) > (len - 1)) {
xstrlcpy(buf, fname, len); // truncate
+#ifdef WIN32
+ slash_adjust(buf);
+#endif
return FAIL;
}
@@ -1702,6 +1705,9 @@ int vim_FullName(const char *fname, char *buf, size_t len, bool force)
if (rv == FAIL) {
xstrlcpy(buf, fname, len); // something failed; use the filename
}
+#ifdef WIN32
+ slash_adjust(buf);
+#endif
return rv;
}
@@ -2196,11 +2202,11 @@ static int path_get_absolute_path(const char_u *fname, char_u *buf,
// expand it if forced or not an absolute path
if (force || !path_is_absolute_path(fname)) {
- if ((p = vim_strrchr(fname, '/')) != NULL) {
+ if ((p = vim_strrchr(fname, PATHSEP)) != NULL) {
// relative to root
if (p == fname) {
// only one path component
- relative_directory[0] = '/';
+ relative_directory[0] = PATHSEP;
relative_directory[1] = NUL;
} else {
assert(p >= fname);
diff --git a/src/nvim/regexp.c b/src/nvim/regexp.c
index 847b2f273e..ae611a0005 100644
--- a/src/nvim/regexp.c
+++ b/src/nvim/regexp.c
@@ -3316,6 +3316,47 @@ bt_regexec_nl (
return (int)r;
}
+/// Wrapper around strchr which accounts for case-insensitive searches and
+/// non-ASCII characters.
+///
+/// This function is used a lot for simple searches, keep it fast!
+///
+/// @param s string to search
+/// @param c character to find in @a s
+///
+/// @return NULL if no match, otherwise pointer to the position in @a s
+static inline char_u *cstrchr(const char_u *const s, const int c)
+ FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL
+ FUNC_ATTR_ALWAYS_INLINE
+{
+ if (!rex.reg_ic) {
+ return vim_strchr(s, c);
+ }
+
+ // Use folded case for UTF-8, slow! For ASCII use libc strpbrk which is
+ // expected to be highly optimized.
+ if (c > 0x80) {
+ const int folded_c = utf_fold(c);
+ for (const char_u *p = s; *p != NUL; p += utfc_ptr2len(p)) {
+ if (utf_fold(utf_ptr2char(p)) == folded_c) {
+ return (char_u *)p;
+ }
+ }
+ return NULL;
+ }
+
+ int cc;
+ if (ASCII_ISUPPER(c)) {
+ cc = TOLOWER_ASC(c);
+ } else if (ASCII_ISLOWER(c)) {
+ cc = TOUPPER_ASC(c);
+ } else {
+ return vim_strchr(s, c);
+ }
+
+ char tofind[] = { (char)c, (char)cc, NUL };
+ return (char_u *)strpbrk((const char *)s, tofind);
+}
/// Matches a regexp against multiple lines.
/// "rmp->regprog" is a compiled regexp as returned by vim_regcomp().
@@ -6320,42 +6361,6 @@ static int cstrncmp(char_u *s1, char_u *s2, int *n)
return result;
}
-/*
- * cstrchr: This function is used a lot for simple searches, keep it fast!
- */
-static inline char_u *cstrchr(const char_u *const s, const int c)
- FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL
- FUNC_ATTR_ALWAYS_INLINE
-{
- if (!rex.reg_ic) {
- return vim_strchr(s, c);
- }
-
- // Use folded case for UTF-8, slow! For ASCII use libc strpbrk which is
- // expected to be highly optimized.
- if (c > 0x80) {
- const int folded_c = utf_fold(c);
- for (const char_u *p = s; *p != NUL; p += utfc_ptr2len(p)) {
- if (utf_fold(utf_ptr2char(p)) == folded_c) {
- return (char_u *)p;
- }
- }
- return NULL;
- }
-
- int cc;
- if (ASCII_ISUPPER(c)) {
- cc = TOLOWER_ASC(c);
- } else if (ASCII_ISLOWER(c)) {
- cc = TOUPPER_ASC(c);
- } else {
- return vim_strchr(s, c);
- }
-
- char tofind[] = { (char)c, (char)cc, NUL };
- return (char_u *)strpbrk((const char *)s, tofind);
-}
-
/***************************************************************
* regsub stuff *
***************************************************************/
diff --git a/src/nvim/screen.c b/src/nvim/screen.c
index 95973354bc..5659f30f64 100644
--- a/src/nvim/screen.c
+++ b/src/nvim/screen.c
@@ -2201,16 +2201,17 @@ win_line (
int change_end = -1; /* last col of changed area */
colnr_T trailcol = MAXCOL; /* start of trailing spaces */
int need_showbreak = false; // overlong line, skip first x chars
- int line_attr = 0; /* attribute for the whole line */
- matchitem_T *cur; /* points to the match list */
- match_T *shl; /* points to search_hl or a match */
- int shl_flag; /* flag to indicate whether search_hl
- has been processed or not */
- int prevcol_hl_flag; /* flag to indicate whether prevcol
- equals startcol of search_hl or one
- of the matches */
- int prev_c = 0; /* previous Arabic character */
- int prev_c1 = 0; /* first composing char for prev_c */
+ int line_attr = 0; // attribute for the whole line
+ int line_attr_low_priority = 0; // current line, lowest priority
+ matchitem_T *cur; // points to the match list
+ match_T *shl; // points to search_hl or a match
+ int shl_flag; // flag to indicate whether search_hl
+ // has been processed or not
+ int prevcol_hl_flag; // flag to indicate whether prevcol
+ // equals startcol of search_hl or one
+ // of the matches
+ int prev_c = 0; // previous Arabic character
+ int prev_c1 = 0; // first composing char for prev_c
int did_line_attr = 0;
bool search_attr_from_match = false; // if search_attr is from :match
@@ -2427,10 +2428,17 @@ win_line (
filler_lines = wp->w_topfill;
filler_todo = filler_lines;
- /* If this line has a sign with line highlighting set line_attr. */
+ // 'cursorline' highlighting for the current window. Not when Visual mode is
+ // active, because it's not clear what is selected then.
+ if (wp->w_p_cul && lnum == wp->w_cursor.lnum
+ && !(wp == curwin && VIsual_active)) {
+ line_attr_low_priority = win_hl_attr(wp, HLF_CUL);
+ }
+
v = buf_getsigntype(wp->w_buffer, lnum, SIGN_LINEHL);
- if (v != 0)
- line_attr = sign_get_attr((int)v, TRUE);
+ if (v != 0) {
+ line_attr = sign_get_attr((int)v, true);
+ }
// Highlight the current line in the quickfix window.
if (bt_quickfix(wp->w_buffer) && qf_current_entry(wp) == lnum) {
@@ -2441,7 +2449,7 @@ win_line (
line_attr = hl_combine_attr(wp->w_hl_attr_normal, line_attr);
}
- if (line_attr != 0) {
+ if (line_attr_low_priority || line_attr) {
area_highlighting = true;
}
@@ -2663,20 +2671,6 @@ win_line (
cur = cur->next;
}
- /* Cursor line highlighting for 'cursorline' in the current window. Not
- * when Visual mode is active, because it's not clear what is selected
- * then. */
- if (wp->w_p_cul && lnum == wp->w_cursor.lnum
- && !(wp == curwin && VIsual_active)) {
- if (line_attr != 0 && !(State & INSERT) && bt_quickfix(wp->w_buffer)
- && qf_current_entry(wp) == lnum) {
- line_attr = hl_combine_attr(win_hl_attr(wp, HLF_CUL), line_attr);
- } else {
- line_attr = win_hl_attr(wp, HLF_CUL);
- }
- area_highlighting = true;
- }
-
off = (unsigned)(current_ScreenLine - ScreenLines);
col = 0;
if (wp->w_p_rl) {
@@ -3594,15 +3588,15 @@ win_line (
&& lcs_eol_one > 0) {
// Display a '$' after the line or highlight an extra
// character if the line break is included.
- // For a diff line the highlighting continues after the
- // "$".
- if (diff_hlf == (hlf_T)0 && line_attr == 0) {
- /* In virtualedit, visual selections may extend
- * beyond end of line. */
+ // For a diff line the highlighting continues after the "$".
+ if (diff_hlf == (hlf_T)0
+ && line_attr == 0
+ && line_attr_low_priority == 0) {
+ // In virtualedit, visual selections may extend beyond end of line.
if (area_highlighting && virtual_active()
- && tocol != MAXCOL && vcol < tocol)
+ && tocol != MAXCOL && vcol < tocol) {
n_extra = 0;
- else {
+ } else {
p_extra = at_end_str;
n_extra = 1;
c_extra = NUL;
@@ -3661,7 +3655,7 @@ win_line (
(col < wp->w_width))) {
c = ' ';
ptr--; // put it back at the NUL
- } else if ((diff_hlf != (hlf_T)0 || line_attr != 0)
+ } else if ((diff_hlf != (hlf_T)0 || line_attr_low_priority || line_attr)
&& (wp->w_p_rl
? (col >= 0)
: (col - boguscols < wp->w_width))) {
@@ -3673,7 +3667,8 @@ win_line (
did_line_attr++;
// don't do search HL for the rest of the line
- if (line_attr != 0 && char_attr == search_attr && col > 0) {
+ if ((line_attr_low_priority || line_attr)
+ && char_attr == search_attr && col > 0) {
char_attr = line_attr;
}
if (diff_hlf == HLF_TXD) {
@@ -4035,13 +4030,16 @@ win_line (
if (wp->w_p_cuc && VCOL_HLC == (long)wp->w_virtcol
&& lnum != wp->w_cursor.lnum) {
vcol_save_attr = char_attr;
- char_attr = hl_combine_attr(char_attr, win_hl_attr(wp, HLF_CUC));
+ char_attr = hl_combine_attr(win_hl_attr(wp, HLF_CUC), char_attr);
} else if (draw_color_col && VCOL_HLC == *color_cols) {
vcol_save_attr = char_attr;
- char_attr = hl_combine_attr(char_attr, win_hl_attr(wp, HLF_MC));
+ char_attr = hl_combine_attr(win_hl_attr(wp, HLF_MC), char_attr);
}
}
+ // Apply `line_attr_low_priority` now, so that everthing can override it.
+ char_attr = hl_combine_attr(line_attr_low_priority, char_attr);
+
/*
* Store character to be displayed.
* Skip characters that are left of the screen for 'nowrap'.
@@ -5847,7 +5845,7 @@ static void screen_start_highlight(int attr)
ui_start_highlight(attr);
}
-void screen_stop_highlight(void)
+static void screen_stop_highlight(void)
{
ui_stop_highlight();
screen_attr = 0;
diff --git a/src/nvim/search.c b/src/nvim/search.c
index 1bf2317d2a..387614fd09 100644
--- a/src/nvim/search.c
+++ b/src/nvim/search.c
@@ -3557,11 +3557,15 @@ extend:
--start_lnum;
if (VIsual_active) {
- /* Problem: when doing "Vipipip" nothing happens in a single white
- * line, we get stuck there. Trap this here. */
- if (VIsual_mode == 'V' && start_lnum == curwin->w_cursor.lnum)
+ // Problem: when doing "Vipipip" nothing happens in a single white
+ // line, we get stuck there. Trap this here.
+ if (VIsual_mode == 'V' && start_lnum == curwin->w_cursor.lnum) {
goto extend;
- VIsual.lnum = start_lnum;
+ }
+ if (VIsual.lnum != start_lnum) {
+ VIsual.lnum = start_lnum;
+ VIsual.col = 0;
+ }
VIsual_mode = 'V';
redraw_curbuf_later(INVERTED); /* update the inversion */
showmode();
diff --git a/src/nvim/state.c b/src/nvim/state.c
index eb0b590a9b..4d9032b7a5 100644
--- a/src/nvim/state.c
+++ b/src/nvim/state.c
@@ -26,10 +26,11 @@ void state_enter(VimState *s)
int check_result = s->check ? s->check(s) : 1;
if (!check_result) {
- break;
+ break; // Terminate this state.
} else if (check_result == -1) {
- continue;
+ continue; // check() again.
}
+ // Execute this state.
int key;
@@ -48,11 +49,13 @@ getkey:
ui_flush();
// Call `os_inchar` directly to block for events or user input without
// consuming anything from `input_buffer`(os/input.c) or calling the
- // mapping engine. If an event was put into the queue, we send K_EVENT
- // directly.
+ // mapping engine.
(void)os_inchar(NULL, 0, -1, 0);
input_disable_events();
- key = !multiqueue_empty(main_loop.events) ? K_EVENT : safe_vgetc();
+ // If an event was put into the queue, we send K_EVENT directly.
+ key = !multiqueue_empty(main_loop.events)
+ ? K_EVENT
+ : safe_vgetc();
}
if (key == K_EVENT) {
diff --git a/src/nvim/syntax.c b/src/nvim/syntax.c
index f0171fa525..70bda42d83 100644
--- a/src/nvim/syntax.c
+++ b/src/nvim/syntax.c
@@ -42,6 +42,7 @@
#include "nvim/ui.h"
#include "nvim/os/os.h"
#include "nvim/os/time.h"
+#include "nvim/api/private/helpers.h"
static bool did_syntax_onoff = false;
@@ -81,7 +82,10 @@ struct hl_group {
// highlight groups for 'highlight' option
static garray_T highlight_ga = GA_EMPTY_INIT_VALUE;
-#define HL_TABLE() ((struct hl_group *)((highlight_ga.ga_data)))
+static inline struct hl_group * HL_TABLE(void)
+{
+ return ((struct hl_group *)((highlight_ga.ga_data)));
+}
#define MAX_HL_ID 20000 /* maximum value for a highlight ID. */
@@ -100,10 +104,8 @@ static int include_none = 0; /* when 1 include "nvim/None" */
static int include_default = 0; /* when 1 include "nvim/default" */
static int include_link = 0; /* when 2 include "nvim/link" and "clear" */
-/*
- * The "term", "cterm" and "gui" arguments can be any combination of the
- * following names, separated by commas (but no spaces!).
- */
+/// The "term", "cterm" and "gui" arguments can be any combination of the
+/// following names, separated by commas (but no spaces!).
static char *(hl_name_table[]) =
{"bold", "standout", "underline", "undercurl",
"italic", "reverse", "inverse", "NONE"};
@@ -1775,8 +1777,9 @@ syn_current_attr (
cur_si->si_trans_id = CUR_STATE(
current_state.ga_len - 2).si_trans_id;
}
- } else
+ } else {
cur_si->si_attr = syn_id2attr(syn_id);
+ }
cur_si->si_cont_list = NULL;
cur_si->si_next_list = next_list;
check_keepend();
@@ -5252,12 +5255,10 @@ get_id_list (
/*
* Handle full group name.
*/
- if (vim_strpbrk(name + 1, (char_u *)"\\.*^$~[") == NULL)
+ if (vim_strpbrk(name + 1, (char_u *)"\\.*^$~[") == NULL) {
id = syn_check_group(name + 1, (int)(end - p));
- else {
- /*
- * Handle match of regexp with group names.
- */
+ } else {
+ // Handle match of regexp with group names.
*name = '^';
STRCAT(name, "$");
regmatch.regprog = vim_regcomp(name, RE_MAGIC);
@@ -5567,8 +5568,10 @@ bool syntax_present(win_T *win)
static enum {
- EXP_SUBCMD, /* expand ":syn" sub-commands */
- EXP_CASE /* expand ":syn case" arguments */
+ EXP_SUBCMD, // expand ":syn" sub-commands
+ EXP_CASE, // expand ":syn case" arguments
+ EXP_SPELL, // expand ":syn spell" arguments
+ EXP_SYNC // expand ":syn sync" arguments
} expand_what;
/*
@@ -5612,6 +5615,10 @@ void set_context_in_syntax_cmd(expand_T *xp, const char *arg)
xp->xp_context = EXPAND_NOTHING;
} else if (STRNICMP(arg, "case", p - arg) == 0) {
expand_what = EXP_CASE;
+ } else if (STRNICMP(arg, "spell", p - arg) == 0) {
+ expand_what = EXP_SPELL;
+ } else if (STRNICMP(arg, "sync", p - arg) == 0) {
+ expand_what = EXP_SYNC;
} else if (STRNICMP(arg, "keyword", p - arg) == 0
|| STRNICMP(arg, "region", p - arg) == 0
|| STRNICMP(arg, "match", p - arg) == 0
@@ -5624,17 +5631,33 @@ void set_context_in_syntax_cmd(expand_T *xp, const char *arg)
}
}
-static char *(case_args[]) = {"match", "ignore", NULL};
-
/*
* Function given to ExpandGeneric() to obtain the list syntax names for
* expansion.
*/
char_u *get_syntax_name(expand_T *xp, int idx)
{
- if (expand_what == EXP_SUBCMD)
- return (char_u *)subcommands[idx].name;
- return (char_u *)case_args[idx];
+ switch (expand_what) {
+ case EXP_SUBCMD:
+ return (char_u *)subcommands[idx].name;
+ case EXP_CASE: {
+ static char *case_args[] = { "match", "ignore", NULL };
+ return (char_u *)case_args[idx];
+ }
+ case EXP_SPELL: {
+ static char *spell_args[] =
+ { "toplevel", "notoplevel", "default", NULL };
+ return (char_u *)spell_args[idx];
+ }
+ case EXP_SYNC: {
+ static char *sync_args[] =
+ { "ccomment", "clear", "fromstart",
+ "linebreaks=", "linecont", "lines=", "match",
+ "maxlines=", "minlines=", "region", NULL };
+ return (char_u *)sync_args[idx];
+ }
+ }
+ return NULL;
}
@@ -5845,9 +5868,12 @@ static void syntime_report(void)
}
}
- /* sort on total time */
- qsort(ga.ga_data, (size_t)ga.ga_len, sizeof(time_entry_T),
- syn_compare_syntime);
+ // Sort on total time. Skip if there are no items to avoid passing NULL
+ // pointer to qsort().
+ if (ga.ga_len > 1) {
+ qsort(ga.ga_data, (size_t)ga.ga_len, sizeof(time_entry_T),
+ syn_compare_syntime);
+ }
MSG_PUTS_TITLE(_(
" TOTAL COUNT MATCH SLOWEST AVERAGE NAME PATTERN"));
@@ -5958,6 +5984,7 @@ static char *highlight_init_light[] =
"Title ctermfg=DarkMagenta gui=bold guifg=Magenta",
"Visual guibg=LightGrey",
"WarningMsg ctermfg=DarkRed guifg=Red",
+ "Normal gui=NONE",
NULL
};
@@ -5991,23 +6018,25 @@ static char *highlight_init_dark[] =
"Title ctermfg=LightMagenta gui=bold guifg=Magenta",
"Visual guibg=DarkGrey",
"WarningMsg ctermfg=LightRed guifg=Red",
+ "Normal gui=NONE",
NULL
};
-void
-init_highlight (
- int both, /* include groups where 'bg' doesn't matter */
- int reset /* clear group first */
-)
+
+/// Load colors from a file if "g:colors_name" is set, otherwise load builtin
+/// colors
+///
+/// @param both include groups where 'bg' doesn't matter
+/// @param reset clear groups first
+void
+init_highlight(int both, int reset)
{
int i;
char **pp;
static int had_both = FALSE;
- /*
- * Try finding the color scheme file. Used when a color file was loaded
- * and 'background' or 't_Co' is changed.
- */
+ // Try finding the color scheme file. Used when a color file was loaded
+ // and 'background' or 't_Co' is changed.
char_u *p = get_var_value("g:colors_name");
if (p != NULL) {
// Value of g:colors_name could be freed in load_colors() and make
@@ -6026,33 +6055,34 @@ init_highlight (
if (both) {
had_both = TRUE;
pp = highlight_init_both;
- for (i = 0; pp[i] != NULL; ++i)
- do_highlight((char_u *)pp[i], reset, TRUE);
- } else if (!had_both)
- /* Don't do anything before the call with both == TRUE from main().
- * Not everything has been setup then, and that call will overrule
- * everything anyway. */
+ for (i = 0; pp[i] != NULL; i++) {
+ do_highlight((char_u *)pp[i], reset, true);
+ }
+ } else if (!had_both) {
+ // Don't do anything before the call with both == TRUE from main().
+ // Not everything has been setup then, and that call will overrule
+ // everything anyway.
return;
+ }
- if (*p_bg == 'l')
- pp = highlight_init_light;
- else
- pp = highlight_init_dark;
- for (i = 0; pp[i] != NULL; ++i)
- do_highlight((char_u *)pp[i], reset, TRUE);
+ pp = (*p_bg == 'l') ? highlight_init_light : highlight_init_dark;
+
+ for (i = 0; pp[i] != NULL; i++) {
+ do_highlight((char_u *)pp[i], reset, true);
+ }
/* Reverse looks ugly, but grey may not work for 8 colors. Thus let it
* depend on the number of colors available.
* With 8 colors brown is equal to yellow, need to use black for Search fg
* to avoid Statement highlighted text disappears.
* Clear the attributes, needed when changing the t_Co value. */
- if (t_colors > 8)
+ if (t_colors > 8) {
do_highlight(
(char_u *)(*p_bg == 'l'
? "Visual cterm=NONE ctermbg=LightGrey"
- : "Visual cterm=NONE ctermbg=DarkGrey"), FALSE,
- TRUE);
- else {
+ : "Visual cterm=NONE ctermbg=DarkGrey"), false,
+ true);
+ } else {
do_highlight((char_u *)"Visual cterm=reverse ctermbg=NONE",
FALSE, TRUE);
if (*p_bg == 'l')
@@ -6112,12 +6142,7 @@ int load_colors(char_u *name)
/// "forceit" and "init" both TRUE.
/// @param init TRUE when called for initializing
void
-do_highlight(
- char_u *line,
- int forceit,
- int init
-)
-{
+do_highlight(char_u *line, int forceit, int init) {
char_u *name_end;
char_u *linep;
char_u *key_start;
@@ -6134,15 +6159,16 @@ do_highlight(
int dolink = FALSE;
int error = FALSE;
int color;
- int is_normal_group = FALSE; /* "Normal" group */
+ bool is_normal_group = false; // "Normal" group
/*
* If no argument, list current highlighting.
*/
if (ends_excmd(*line)) {
- for (int i = 1; i <= highlight_ga.ga_len && !got_int; ++i)
- /* TODO: only call when the group has attributes set */
+ for (int i = 1; i <= highlight_ga.ga_len && !got_int; i++) {
+ // todo(vim): only call when the group has attributes set
highlight_list_one(i);
+ }
return;
}
@@ -6270,12 +6296,12 @@ do_highlight(
return;
idx = id - 1; /* index is ID minus one */
- /* Return if "default" was used and the group already has settings. */
- if (dodefault && hl_has_settings(idx, TRUE))
+ // Return if "default" was used and the group already has settings
+ if (dodefault && hl_has_settings(idx, true)) {
return;
+ }
- if (STRCMP(HL_TABLE()[idx].sg_name_u, "NORMAL") == 0)
- is_normal_group = TRUE;
+ is_normal_group = (STRCMP(HL_TABLE()[idx].sg_name_u, "NORMAL") == 0);
/* Clear the highlighting for ":hi clear {group}" and ":hi clear". */
if (doclear || (forceit && init)) {
@@ -6284,7 +6310,7 @@ do_highlight(
HL_TABLE()[idx].sg_set = 0;
}
- if (!doclear)
+ if (!doclear) {
while (!ends_excmd(*linep)) {
key_start = linep;
if (*linep == '=') {
@@ -6390,12 +6416,12 @@ do_highlight(
}
}
} else if (STRCMP(key, "FONT") == 0) {
- /* in non-GUI fonts are simply ignored */
- } else if (STRCMP(key,
- "CTERMFG") == 0 || STRCMP(key, "CTERMBG") == 0) {
+ // in non-GUI fonts are simply ignored
+ } else if (STRCMP(key, "CTERMFG") == 0 || STRCMP(key, "CTERMBG") == 0) {
if (!init || !(HL_TABLE()[idx].sg_set & SG_CTERM)) {
- if (!init)
+ if (!init) {
HL_TABLE()[idx].sg_set |= SG_CTERM;
+ }
/* When setting the foreground color, and previously the "bold"
* flag was set for a light color, reset it now */
@@ -6489,9 +6515,10 @@ do_highlight(
* colors (on some terminals, e.g. "linux") */
if (color & 8) {
HL_TABLE()[idx].sg_cterm |= HL_BOLD;
- HL_TABLE()[idx].sg_cterm_bold = TRUE;
- } else
+ HL_TABLE()[idx].sg_cterm_bold = true;
+ } else {
HL_TABLE()[idx].sg_cterm &= ~HL_BOLD;
+ }
}
color &= 7; // truncate to 8 colors
} else if (t_colors == 16 || t_colors == 88 || t_colors >= 256) {
@@ -6603,38 +6630,40 @@ do_highlight(
/*
* When highlighting has been given for a group, don't link it.
*/
- if (!init || !(HL_TABLE()[idx].sg_set & SG_LINK))
+ if (!init || !(HL_TABLE()[idx].sg_set & SG_LINK)) {
HL_TABLE()[idx].sg_link = 0;
+ }
/*
* Continue with next argument.
*/
linep = skipwhite(linep);
}
+ }
/*
* If there is an error, and it's a new entry, remove it from the table.
*/
- if (error && idx == highlight_ga.ga_len)
+ if (error && idx == highlight_ga.ga_len) {
syn_unadd_group();
- else {
+ } else {
if (is_normal_group) {
- HL_TABLE()[idx].sg_attr = 0;
// Need to update all groups, because they might be using "bg" and/or
// "fg", which have been changed now.
highlight_attr_set_all();
// If the normal group has changed, it is simpler to refresh every UI
ui_refresh();
- } else
+ } else {
set_hl_attr(idx);
+ }
HL_TABLE()[idx].sg_scriptID = current_SID;
redraw_all_later(NOT_VALID);
}
xfree(key);
xfree(arg);
- /* Only call highlight_changed() once, after sourcing a syntax file */
- need_highlight_changed = TRUE;
+ // Only call highlight_changed() once, after sourcing a syntax file
+ need_highlight_changed = true;
}
#if defined(EXITFREE)
@@ -6707,14 +6736,15 @@ static void highlight_clear(int idx)
}
-/*
- * Table with the specifications for an attribute number.
- * Note that this table is used by ALL buffers. This is required because the
- * GUI can redraw at any time for any buffer.
- */
+/// Table with the specifications for an attribute number.
+/// Note that this table is used by ALL buffers. This is required because the
+/// GUI can redraw at any time for any buffer.
static garray_T attr_table = GA_EMPTY_INIT_VALUE;
-#define ATTR_ENTRY(idx) ((attrentry_T *)attr_table.ga_data)[idx]
+static inline attrentry_T * ATTR_ENTRY(int idx)
+{
+ return &((attrentry_T *)attr_table.ga_data)[idx];
+}
/// Return the attr number for a set of colors and font.
@@ -6804,7 +6834,7 @@ int hl_combine_attr(int char_attr, int prim_attr)
{
attrentry_T *char_aep = NULL;
attrentry_T *spell_aep;
- attrentry_T new_en;
+ attrentry_T new_en = ATTRENTRY_INIT;
if (char_attr == 0) {
return prim_attr;
@@ -6820,8 +6850,6 @@ int hl_combine_attr(int char_attr, int prim_attr)
if (char_aep != NULL) {
// Copy all attributes from char_aep to the new entry
new_en = *char_aep;
- } else {
- memset(&new_en, 0, sizeof(new_en));
}
spell_aep = syn_cterm_attr2entry(prim_attr);
@@ -6852,17 +6880,25 @@ int hl_combine_attr(int char_attr, int prim_attr)
return get_attr_entry(&new_en);
}
+/// \note this function does not apply exclusively to cterm attr contrary
+/// to what its name implies
+/// \warn don't call it with attr 0 (i.e., the null attribute)
attrentry_T *syn_cterm_attr2entry(int attr)
{
attr -= ATTR_OFF;
- if (attr >= attr_table.ga_len) /* did ":syntax clear" */
+ if (attr >= attr_table.ga_len) {
+ // did ":syntax clear"
return NULL;
- return &(ATTR_ENTRY(attr));
+ }
+ return ATTR_ENTRY(attr);
}
+/// \addtogroup LIST_XXX
+/// @{
#define LIST_ATTR 1
#define LIST_STRING 2
#define LIST_INT 3
+/// @}
static void highlight_list_one(int id)
{
@@ -6901,7 +6937,13 @@ static void highlight_list_one(int id)
last_set_msg(sgp->sg_scriptID);
}
-static int highlight_list_arg(int id, int didh, int type, int iarg, char_u *sarg, char *name)
+/// Outputs a highlight when doing ":hi MyHighlight"
+///
+/// @param type one of \ref LIST_XXX
+/// @param iarg integer argument used if \p type == LIST_INT
+/// @param sarg string used if \p type == LIST_STRING
+static int highlight_list_arg(int id, int didh, int type, int iarg,
+ char_u *sarg, const char *name)
{
char_u buf[100];
char_u *ts;
@@ -7041,24 +7083,23 @@ const char *highlight_color(const int id, const char *const what,
return NULL;
}
-/*
- * Output the syntax list header.
- * Return TRUE when started a new line.
- */
-static int
-syn_list_header (
- int did_header, /* did header already */
- int outlen, /* length of string that comes */
- int id /* highlight group id */
-)
+/// Output the syntax list header.
+///
+/// @param did_header did header already
+/// @param outlen length of string that comes
+/// @param id highlight group id
+/// @return true when started a new line.
+static int
+syn_list_header(int did_header, int outlen, int id)
{
int endcol = 19;
int newline = TRUE;
if (!did_header) {
msg_putchar('\n');
- if (got_int)
- return TRUE;
+ if (got_int) {
+ return true;
+ }
msg_outtrans(HL_TABLE()[id - 1].sg_name);
endcol = 15;
} else if (msg_col + outlen + 1 >= Columns) {
@@ -7086,21 +7127,14 @@ syn_list_header (
return newline;
}
-/*
- * Set the attribute numbers for a highlight group.
- * Called after one of the attributes has changed.
- */
-static void
-set_hl_attr (
- int idx /* index in array */
-)
+/// Set the attribute numbers for a highlight group.
+/// Called after one of the attributes has changed.
+/// @param idx corrected highlight index
+static void set_hl_attr(int idx)
{
- attrentry_T at_en;
+ attrentry_T at_en = ATTRENTRY_INIT;
struct hl_group *sgp = HL_TABLE() + idx;
- /* The "Normal" group doesn't need an attribute number */
- if (sgp->sg_name_u != NULL && STRCMP(sgp->sg_name_u, "NORMAL") == 0)
- return;
at_en.cterm_ae_attr = sgp->sg_cterm;
at_en.cterm_fg_color = sgp->sg_cterm_fg;
@@ -7124,10 +7158,10 @@ set_hl_attr (
}
}
-/*
- * Lookup a highlight group name and return it's ID.
- * If it is not found, 0 is returned.
- */
+/// Lookup a highlight group name and return its ID.
+///
+/// @param highlight name e.g. 'Cursor', 'Normal'
+/// @return the highlight id, else 0 if \p name does not exist
int syn_name2id(const char_u *name)
{
int i;
@@ -7176,7 +7210,7 @@ int syn_namen2id(char_u *linep, int len)
return id;
}
-/// Find highlight group name in the table and return it's ID.
+/// Find highlight group name in the table and return its ID.
/// If it doesn't exist yet, a new entry is created.
///
/// @param pp Highlight group name
@@ -7195,11 +7229,11 @@ int syn_check_group(char_u *pp, int len)
return id;
}
-/*
- * Add new highlight group and return it's ID.
- * "name" must be an allocated string, it will be consumed.
- * Return 0 for failure.
- */
+/// Add new highlight group and return it's ID.
+///
+/// @param name must be an allocated string, it will be consumed.
+/// @return 0 for failure, else the allocated group id
+/// @see syn_check_group syn_unadd_group
static int syn_add_group(char_u *name)
{
char_u *p;
@@ -7237,25 +7271,26 @@ static int syn_add_group(char_u *name)
struct hl_group* hlgp = GA_APPEND_VIA_PTR(struct hl_group, &highlight_ga);
memset(hlgp, 0, sizeof(*hlgp));
hlgp->sg_name = name;
+ hlgp->sg_rgb_bg = -1;
+ hlgp->sg_rgb_fg = -1;
+ hlgp->sg_rgb_sp = -1;
hlgp->sg_name_u = vim_strsave_up(name);
return highlight_ga.ga_len; /* ID is index plus one */
}
-/*
- * When, just after calling syn_add_group(), an error is discovered, this
- * function deletes the new name.
- */
+/// When, just after calling syn_add_group(), an error is discovered, this
+/// function deletes the new name.
static void syn_unadd_group(void)
{
- --highlight_ga.ga_len;
+ highlight_ga.ga_len--;
xfree(HL_TABLE()[highlight_ga.ga_len].sg_name);
xfree(HL_TABLE()[highlight_ga.ga_len].sg_name_u);
}
-/*
- * Translate a group ID to highlight attributes.
- */
+
+/// Translate a group ID to highlight attributes.
+/// @see syn_cterm_attr2entry
int syn_id2attr(int hl_id)
{
struct hl_group *sgp;
@@ -8208,6 +8243,30 @@ RgbValue name_to_color(const uint8_t *name)
return -1;
}
+/// Gets highlight description for id `attr_id` as a map.
+Dictionary hl_get_attr_by_id(Integer attr_id, Boolean rgb, Error *err)
+{
+ HlAttrs attrs = HLATTRS_INIT;
+ Dictionary dic = ARRAY_DICT_INIT;
+
+ if (attr_id == 0) {
+ goto end;
+ }
+
+ attrentry_T *aep = syn_cterm_attr2entry((int)attr_id);
+ if (!aep) {
+ api_set_error(err, kErrorTypeException,
+ "Invalid attribute id: %d", attr_id);
+ return dic;
+ }
+
+ attrs = attrentry2hlattrs(aep, rgb);
+
+end:
+ return hlattrs2dict(attrs);
+}
+
+
/**************************************
* End of Highlighting stuff *
**************************************/
diff --git a/src/nvim/syntax_defs.h b/src/nvim/syntax_defs.h
index 9f309451b0..56fadbe7f6 100644
--- a/src/nvim/syntax_defs.h
+++ b/src/nvim/syntax_defs.h
@@ -73,4 +73,14 @@ typedef struct attr_entry {
int cterm_fg_color, cterm_bg_color;
} attrentry_T;
+#define ATTRENTRY_INIT { \
+ .rgb_ae_attr = 0, \
+ .cterm_ae_attr = 0, \
+ .rgb_fg_color = -1, \
+ .rgb_bg_color = -1, \
+ .rgb_sp_color = -1, \
+ .cterm_fg_color = 0, \
+ .cterm_bg_color = 0, \
+}
+
#endif // NVIM_SYNTAX_DEFS_H
diff --git a/src/nvim/terminal.c b/src/nvim/terminal.c
index deec930ebd..4a9acf2559 100644
--- a/src/nvim/terminal.c
+++ b/src/nvim/terminal.c
@@ -432,14 +432,6 @@ static int terminal_execute(VimState *state, int key)
TerminalState *s = (TerminalState *)state;
switch (key) {
- case K_FOCUSGAINED: // nvim has been given focus
- apply_autocmds(EVENT_FOCUSGAINED, NULL, NULL, false, curbuf);
- break;
-
- case K_FOCUSLOST: // nvim has lost focus
- apply_autocmds(EVENT_FOCUSLOST, NULL, NULL, false, curbuf);
- break;
-
// Temporary fix until paste events gets implemented
case K_PASTE:
break;
@@ -530,6 +522,12 @@ void terminal_send(Terminal *term, char *data, size_t size)
void terminal_send_key(Terminal *term, int c)
{
VTermModifier mod = VTERM_MOD_NONE;
+
+ // Convert K_ZERO back to ASCII
+ if (c == K_ZERO) {
+ c = Ctrl_AT;
+ }
+
VTermKey key = convert_key(c, &mod);
if (key) {
@@ -783,26 +781,60 @@ static int term_sb_pop(int cols, VTermScreenCell *cells, void *data)
// }}}
// input handling {{{
-static void convert_modifiers(VTermModifier *statep)
+static void convert_modifiers(int key, VTermModifier *statep)
{
if (mod_mask & MOD_MASK_SHIFT) { *statep |= VTERM_MOD_SHIFT; }
if (mod_mask & MOD_MASK_CTRL) { *statep |= VTERM_MOD_CTRL; }
if (mod_mask & MOD_MASK_ALT) { *statep |= VTERM_MOD_ALT; }
+
+ switch (key) {
+ case K_S_TAB:
+ case K_S_UP:
+ case K_S_DOWN:
+ case K_S_LEFT:
+ case K_S_RIGHT:
+ case K_S_F1:
+ case K_S_F2:
+ case K_S_F3:
+ case K_S_F4:
+ case K_S_F5:
+ case K_S_F6:
+ case K_S_F7:
+ case K_S_F8:
+ case K_S_F9:
+ case K_S_F10:
+ case K_S_F11:
+ case K_S_F12:
+ *statep |= VTERM_MOD_SHIFT;
+ break;
+
+ case K_C_LEFT:
+ case K_C_RIGHT:
+ *statep |= VTERM_MOD_CTRL;
+ break;
+ }
}
static VTermKey convert_key(int key, VTermModifier *statep)
{
- convert_modifiers(statep);
+ convert_modifiers(key, statep);
switch (key) {
case K_BS: return VTERM_KEY_BACKSPACE;
+ case K_S_TAB: // FALLTHROUGH
case TAB: return VTERM_KEY_TAB;
case Ctrl_M: return VTERM_KEY_ENTER;
case ESC: return VTERM_KEY_ESCAPE;
+ case K_S_UP: // FALLTHROUGH
case K_UP: return VTERM_KEY_UP;
+ case K_S_DOWN: // FALLTHROUGH
case K_DOWN: return VTERM_KEY_DOWN;
+ case K_S_LEFT: // FALLTHROUGH
+ case K_C_LEFT: // FALLTHROUGH
case K_LEFT: return VTERM_KEY_LEFT;
+ case K_S_RIGHT: // FALLTHROUGH
+ case K_C_RIGHT: // FALLTHROUGH
case K_RIGHT: return VTERM_KEY_RIGHT;
case K_INS: return VTERM_KEY_INS;
@@ -812,22 +844,22 @@ static VTermKey convert_key(int key, VTermModifier *statep)
case K_PAGEUP: return VTERM_KEY_PAGEUP;
case K_PAGEDOWN: return VTERM_KEY_PAGEDOWN;
- case K_K0:
+ case K_K0: // FALLTHROUGH
case K_KINS: return VTERM_KEY_KP_0;
- case K_K1:
+ case K_K1: // FALLTHROUGH
case K_KEND: return VTERM_KEY_KP_1;
case K_K2: return VTERM_KEY_KP_2;
- case K_K3:
+ case K_K3: // FALLTHROUGH
case K_KPAGEDOWN: return VTERM_KEY_KP_3;
case K_K4: return VTERM_KEY_KP_4;
case K_K5: return VTERM_KEY_KP_5;
case K_K6: return VTERM_KEY_KP_6;
- case K_K7:
+ case K_K7: // FALLTHROUGH
case K_KHOME: return VTERM_KEY_KP_7;
case K_K8: return VTERM_KEY_KP_8;
- case K_K9:
+ case K_K9: // FALLTHROUGH
case K_KPAGEUP: return VTERM_KEY_KP_9;
- case K_KDEL:
+ case K_KDEL: // FALLTHROUGH
case K_KPOINT: return VTERM_KEY_KP_PERIOD;
case K_KENTER: return VTERM_KEY_KP_ENTER;
case K_KPLUS: return VTERM_KEY_KP_PLUS;
@@ -835,6 +867,57 @@ static VTermKey convert_key(int key, VTermModifier *statep)
case K_KMULTIPLY: return VTERM_KEY_KP_MULT;
case K_KDIVIDE: return VTERM_KEY_KP_DIVIDE;
+ case K_S_F1: // FALLTHROUGH
+ case K_F1: return VTERM_KEY_FUNCTION(1);
+ case K_S_F2: // FALLTHROUGH
+ case K_F2: return VTERM_KEY_FUNCTION(2);
+ case K_S_F3: // FALLTHROUGH
+ case K_F3: return VTERM_KEY_FUNCTION(3);
+ case K_S_F4: // FALLTHROUGH
+ case K_F4: return VTERM_KEY_FUNCTION(4);
+ case K_S_F5: // FALLTHROUGH
+ case K_F5: return VTERM_KEY_FUNCTION(5);
+ case K_S_F6: // FALLTHROUGH
+ case K_F6: return VTERM_KEY_FUNCTION(6);
+ case K_S_F7: // FALLTHROUGH
+ case K_F7: return VTERM_KEY_FUNCTION(7);
+ case K_S_F8: // FALLTHROUGH
+ case K_F8: return VTERM_KEY_FUNCTION(8);
+ case K_S_F9: // FALLTHROUGH
+ case K_F9: return VTERM_KEY_FUNCTION(9);
+ case K_S_F10: // FALLTHROUGH
+ case K_F10: return VTERM_KEY_FUNCTION(10);
+ case K_S_F11: // FALLTHROUGH
+ case K_F11: return VTERM_KEY_FUNCTION(11);
+ case K_S_F12: // FALLTHROUGH
+ case K_F12: return VTERM_KEY_FUNCTION(12);
+
+ case K_F13: return VTERM_KEY_FUNCTION(13);
+ case K_F14: return VTERM_KEY_FUNCTION(14);
+ case K_F15: return VTERM_KEY_FUNCTION(15);
+ case K_F16: return VTERM_KEY_FUNCTION(16);
+ case K_F17: return VTERM_KEY_FUNCTION(17);
+ case K_F18: return VTERM_KEY_FUNCTION(18);
+ case K_F19: return VTERM_KEY_FUNCTION(19);
+ case K_F20: return VTERM_KEY_FUNCTION(20);
+ case K_F21: return VTERM_KEY_FUNCTION(21);
+ case K_F22: return VTERM_KEY_FUNCTION(22);
+ case K_F23: return VTERM_KEY_FUNCTION(23);
+ case K_F24: return VTERM_KEY_FUNCTION(24);
+ case K_F25: return VTERM_KEY_FUNCTION(25);
+ case K_F26: return VTERM_KEY_FUNCTION(26);
+ case K_F27: return VTERM_KEY_FUNCTION(27);
+ case K_F28: return VTERM_KEY_FUNCTION(28);
+ case K_F29: return VTERM_KEY_FUNCTION(29);
+ case K_F30: return VTERM_KEY_FUNCTION(30);
+ case K_F31: return VTERM_KEY_FUNCTION(31);
+ case K_F32: return VTERM_KEY_FUNCTION(32);
+ case K_F33: return VTERM_KEY_FUNCTION(33);
+ case K_F34: return VTERM_KEY_FUNCTION(34);
+ case K_F35: return VTERM_KEY_FUNCTION(35);
+ case K_F36: return VTERM_KEY_FUNCTION(36);
+ case K_F37: return VTERM_KEY_FUNCTION(37);
+
default: return VTERM_KEY_NONE;
}
}
@@ -1176,6 +1259,10 @@ static void redraw(bool restore_cursor)
update_screen(0);
}
+ if (need_maketitle) { // Update title in terminal-mode. #7248
+ maketitle();
+ }
+
if (restore_cursor) {
ui_cursor_goto(save_row, save_col);
} else if (term) {
diff --git a/src/nvim/testdir/Makefile b/src/nvim/testdir/Makefile
index 96de7224c5..38caa8815d 100644
--- a/src/nvim/testdir/Makefile
+++ b/src/nvim/testdir/Makefile
@@ -58,6 +58,8 @@ NEW_TESTS ?= \
test_match.res \
test_matchadd_conceal.res \
test_matchadd_conceal_utf8.res \
+ test_mksession.res \
+ test_mksession_utf8.res \
test_nested_function.res \
test_normal.res \
test_quickfix.res \
diff --git a/src/nvim/testdir/test_cmdline.vim b/src/nvim/testdir/test_cmdline.vim
index bab700284f..c0f04f4730 100644
--- a/src/nvim/testdir/test_cmdline.vim
+++ b/src/nvim/testdir/test_cmdline.vim
@@ -230,12 +230,41 @@ func Test_paste_in_cmdline()
call feedkeys("f;:aaa \<C-R>\<C-A> bbb\<C-B>\"\<CR>", 'tx')
call assert_equal('"aaa a;b-c*d bbb', @:)
+
+ call feedkeys(":\<C-\>etoupper(getline(1))\<CR>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"ASDF.X /TMP/SOME VERYLONGWORD A;B-C*D ', @:)
bwipe!
endfunc
-func Test_illegal_address()
+func Test_remove_char_in_cmdline()
+ call feedkeys(":abc def\<S-Left>\<Del>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"abc ef', @:)
+
+ call feedkeys(":abc def\<S-Left>\<BS>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"abcdef', @:)
+
+ call feedkeys(":abc def ghi\<S-Left>\<C-W>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"abc ghi', @:)
+
+ call feedkeys(":abc def\<S-Left>\<C-U>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"def', @:)
+endfunc
+
+func Test_illegal_address1()
new
2;'(
2;')
quit
endfunc
+
+func Test_illegal_address2()
+ call writefile(['c', 'x', ' x', '.', '1;y'], 'Xtest.vim')
+ new
+ source Xtest.vim
+ " Trigger calling validate_cursor()
+ diffsp Xtest.vim
+ quit!
+ bwipe!
+ call delete('Xtest.vim')
+endfunc
+
diff --git a/src/nvim/testdir/test_diffmode.vim b/src/nvim/testdir/test_diffmode.vim
index f40e06ff33..8ee82bd538 100644
--- a/src/nvim/testdir/test_diffmode.vim
+++ b/src/nvim/testdir/test_diffmode.vim
@@ -212,6 +212,7 @@ func Test_diffoff()
call setline(1, ['One', '', 'Two', 'Three'])
diffthis
redraw
+ call assert_notequal(normattr, screenattr(1, 1))
diffoff!
redraw
call assert_equal(normattr, screenattr(1, 1))
@@ -219,6 +220,42 @@ func Test_diffoff()
bwipe!
endfunc
+func Test_diffoff_hidden()
+ set diffopt=filler,foldcolumn:0
+ e! one
+ call setline(1, ['Two', 'Three'])
+ let normattr = screenattr(1, 1)
+ diffthis
+ botright vert new two
+ call setline(1, ['One', 'Four'])
+ diffthis
+ redraw
+ call assert_notequal(normattr, screenattr(1, 1))
+ set hidden
+ close
+ redraw
+ " diffing with hidden buffer two
+ call assert_notequal(normattr, screenattr(1, 1))
+ diffoff
+ redraw
+ call assert_equal(normattr, screenattr(1, 1))
+ diffthis
+ redraw
+ " still diffing with hidden buffer two
+ call assert_notequal(normattr, screenattr(1, 1))
+ diffoff!
+ redraw
+ call assert_equal(normattr, screenattr(1, 1))
+ diffthis
+ redraw
+ " no longer diffing with hidden buffer two
+ call assert_equal(normattr, screenattr(1, 1))
+
+ bwipe!
+ bwipe!
+ set hidden& diffopt&
+endfunc
+
func Test_setting_cursor()
new Xtest1
put =range(1,90)
diff --git a/src/nvim/testdir/test_help_tagjump.vim b/src/nvim/testdir/test_help_tagjump.vim
index 1ca0f722cf..65d99c644c 100644
--- a/src/nvim/testdir/test_help_tagjump.vim
+++ b/src/nvim/testdir/test_help_tagjump.vim
@@ -89,17 +89,8 @@ func s:doc_config_teardown()
endif
endfunc
-func s:get_cmd_compl_list(cmd)
- let list = []
- let str = ''
- for cnt in range(1, 999)
- call feedkeys(a:cmd . repeat("\<Tab>", cnt) . "'\<C-B>let str='\<CR>", 'tx')
- if str ==# a:cmd[1:]
- break
- endif
- call add(list, str)
- endfor
- return list
+func s:get_help_compl_list(cmd)
+ return getcompletion(a:cmd, 'help')
endfunc
func Test_help_complete()
@@ -111,49 +102,49 @@ func Test_help_complete()
if has('multi_lang')
set helplang=
endif
- let list = s:get_cmd_compl_list(":h test")
- call assert_equal(['h test-col', 'h test-char'], list)
+ let list = s:get_help_compl_list("test")
+ call assert_equal(['test-col', 'test-char'], list)
if has('multi_lang')
" 'helplang=ab' and help file lang is 'en'
set helplang=ab
- let list = s:get_cmd_compl_list(":h test")
- call assert_equal(['h test-col', 'h test-char'], list)
+ let list = s:get_help_compl_list("test")
+ call assert_equal(['test-col', 'test-char'], list)
" 'helplang=' and help file lang is 'en' and 'ab'
set rtp+=Xdir1/doc-ab
set helplang=
- let list = s:get_cmd_compl_list(":h test")
- call assert_equal(sort(['h test-col@en', 'h test-col@ab',
- \ 'h test-char@en', 'h test-char@ab']), sort(list))
+ let list = s:get_help_compl_list("test")
+ call assert_equal(sort(['test-col@en', 'test-col@ab',
+ \ 'test-char@en', 'test-char@ab']), sort(list))
" 'helplang=ab' and help file lang is 'en' and 'ab'
set helplang=ab
- let list = s:get_cmd_compl_list(":h test")
- call assert_equal(sort(['h test-col', 'h test-col@en',
- \ 'h test-char', 'h test-char@en']), sort(list))
+ let list = s:get_help_compl_list("test")
+ call assert_equal(sort(['test-col', 'test-col@en',
+ \ 'test-char', 'test-char@en']), sort(list))
" 'helplang=' and help file lang is 'en', 'ab' and 'ja'
set rtp+=Xdir1/doc-ja
set helplang=
- let list = s:get_cmd_compl_list(":h test")
- call assert_equal(sort(['h test-col@en', 'h test-col@ab',
- \ 'h test-col@ja', 'h test-char@en',
- \ 'h test-char@ab', 'h test-char@ja']), sort(list))
+ let list = s:get_help_compl_list("test")
+ call assert_equal(sort(['test-col@en', 'test-col@ab',
+ \ 'test-col@ja', 'test-char@en',
+ \ 'test-char@ab', 'test-char@ja']), sort(list))
" 'helplang=ab' and help file lang is 'en', 'ab' and 'ja'
set helplang=ab
- let list = s:get_cmd_compl_list(":h test")
- call assert_equal(sort(['h test-col', 'h test-col@en',
- \ 'h test-col@ja', 'h test-char',
- \ 'h test-char@en', 'h test-char@ja']), sort(list))
+ let list = s:get_help_compl_list("test")
+ call assert_equal(sort(['test-col', 'test-col@en',
+ \ 'test-col@ja', 'test-char',
+ \ 'test-char@en', 'test-char@ja']), sort(list))
" 'helplang=ab,ja' and help file lang is 'en', 'ab' and 'ja'
set helplang=ab,ja
- let list = s:get_cmd_compl_list(":h test")
- call assert_equal(sort(['h test-col', 'h test-col@ja',
- \ 'h test-col@en', 'h test-char',
- \ 'h test-char@ja', 'h test-char@en']), sort(list))
+ let list = s:get_help_compl_list("test")
+ call assert_equal(sort(['test-col', 'test-col@ja',
+ \ 'test-col@en', 'test-char',
+ \ 'test-char@ja', 'test-char@en']), sort(list))
endif
catch
call assert_exception('X')
diff --git a/src/nvim/testdir/test_mksession.vim b/src/nvim/testdir/test_mksession.vim
new file mode 100644
index 0000000000..4774cf4af5
--- /dev/null
+++ b/src/nvim/testdir/test_mksession.vim
@@ -0,0 +1,155 @@
+" Test for :mksession, :mkview and :loadview in latin1 encoding
+
+scriptencoding latin1
+
+if !has('multi_byte') || !has('mksession')
+ finish
+endif
+
+func Test_mksession()
+ tabnew
+ let wrap_save = &wrap
+ set sessionoptions=buffers splitbelow fileencoding=latin1
+ call setline(1, [
+ \ 'start:',
+ \ 'no multibyte chAracter',
+ \ ' one leaDing tab',
+ \ ' four leadinG spaces',
+ \ 'two consecutive tabs',
+ \ 'two tabs in one line',
+ \ 'one multibyteCharacter',
+ \ 'a two multiByte characters',
+ \ 'A three mulTibyte characters'
+ \ ])
+ let tmpfile = 'Xtemp'
+ exec 'w! ' . tmpfile
+ /^start:
+ set wrap
+ vsplit
+ norm! j16|
+ split
+ norm! j16|
+ split
+ norm! j16|
+ split
+ norm! j8|
+ split
+ norm! j8|
+ split
+ norm! j16|
+ split
+ norm! j16|
+ split
+ norm! j16|
+ wincmd l
+
+ set nowrap
+ /^start:
+ norm! j16|3zl
+ split
+ norm! j016|3zl
+ split
+ norm! j016|3zl
+ split
+ norm! j08|3zl
+ split
+ norm! j08|3zl
+ split
+ norm! j016|3zl
+ split
+ norm! j016|3zl
+ split
+ norm! j016|3zl
+ split
+ call wincol()
+ mksession! Xtest_mks.out
+ let li = filter(readfile('Xtest_mks.out'), 'v:val =~# "\\(^ *normal! 0\\|^ *exe ''normal!\\)"')
+ let expected = [
+ \ 'normal! 016|',
+ \ 'normal! 016|',
+ \ 'normal! 016|',
+ \ 'normal! 08|',
+ \ 'normal! 08|',
+ \ 'normal! 016|',
+ \ 'normal! 016|',
+ \ 'normal! 016|',
+ \ " exe 'normal! ' . s:c . '|zs' . 16 . '|'",
+ \ " normal! 016|",
+ \ " exe 'normal! ' . s:c . '|zs' . 16 . '|'",
+ \ " normal! 016|",
+ \ " exe 'normal! ' . s:c . '|zs' . 16 . '|'",
+ \ " normal! 016|",
+ \ " exe 'normal! ' . s:c . '|zs' . 8 . '|'",
+ \ " normal! 08|",
+ \ " exe 'normal! ' . s:c . '|zs' . 8 . '|'",
+ \ " normal! 08|",
+ \ " exe 'normal! ' . s:c . '|zs' . 16 . '|'",
+ \ " normal! 016|",
+ \ " exe 'normal! ' . s:c . '|zs' . 16 . '|'",
+ \ " normal! 016|",
+ \ " exe 'normal! ' . s:c . '|zs' . 16 . '|'",
+ \ " normal! 016|",
+ \ " exe 'normal! ' . s:c . '|zs' . 16 . '|'",
+ \ " normal! 016|"
+ \ ]
+ call assert_equal(expected, li)
+ tabclose!
+
+ call delete('Xtest_mks.out')
+ call delete(tmpfile)
+ let &wrap = wrap_save
+endfunc
+
+func Test_mksession_winheight()
+ new
+ set winheight=10 winminheight=2
+ mksession! Xtest_mks.out
+ source Xtest_mks.out
+
+ call delete('Xtest_mks.out')
+endfunc
+
+" Verify that arglist is stored correctly to the session file.
+func Test_mksession_arglist()
+ argdel *
+ next file1 file2 file3 file4
+ mksession! Xtest_mks.out
+ source Xtest_mks.out
+ call assert_equal(['file1', 'file2', 'file3', 'file4'], argv())
+
+ call delete('Xtest_mks.out')
+ argdel *
+endfunc
+
+
+func Test_mksession_one_buffer_two_windows()
+ edit Xtest1
+ new Xtest2
+ split
+ mksession! Xtest_mks.out
+ let lines = readfile('Xtest_mks.out')
+ let count1 = 0
+ let count2 = 0
+ let count2buf = 0
+ for line in lines
+ if line =~ 'edit \f*Xtest1$'
+ let count1 += 1
+ endif
+ if line =~ 'edit \f\{-}Xtest2'
+ let count2 += 1
+ endif
+ if line =~ 'buffer \f\{-}Xtest2'
+ let count2buf += 1
+ endif
+ endfor
+ call assert_equal(1, count1, 'Xtest1 count')
+ call assert_equal(2, count2, 'Xtest2 count')
+ call assert_equal(2, count2buf, 'Xtest2 buffer count')
+
+ close
+ bwipe!
+ call delete('Xtest_mks.out')
+endfunc
+
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_mksession_utf8.vim b/src/nvim/testdir/test_mksession_utf8.vim
new file mode 100644
index 0000000000..c05a1d3b6d
--- /dev/null
+++ b/src/nvim/testdir/test_mksession_utf8.vim
@@ -0,0 +1,104 @@
+" Test for :mksession, :mkview and :loadview in utf-8 encoding
+
+set encoding=utf-8
+scriptencoding utf-8
+
+if !has('multi_byte') || !has('mksession')
+ finish
+endif
+
+func Test_mksession_utf8()
+ tabnew
+ let wrap_save = &wrap
+ set sessionoptions=buffers splitbelow fileencoding=utf-8
+ call setline(1, [
+ \ 'start:',
+ \ 'no multibyte chAracter',
+ \ ' one leaDing tab',
+ \ ' four leadinG spaces',
+ \ 'two consecutive tabs',
+ \ 'two tabs in one line',
+ \ 'one … multibyteCharacter',
+ \ 'a “b” two multiByte characters',
+ \ '“c”1€ three mulTibyte characters'
+ \ ])
+ let tmpfile = tempname()
+ exec 'w! ' . tmpfile
+ /^start:
+ set wrap
+ vsplit
+ norm! j16|
+ split
+ norm! j16|
+ split
+ norm! j16|
+ split
+ norm! j8|
+ split
+ norm! j8|
+ split
+ norm! j16|
+ split
+ norm! j16|
+ split
+ norm! j16|
+ wincmd l
+
+ set nowrap
+ /^start:
+ norm! j16|3zl
+ split
+ norm! j016|3zl
+ split
+ norm! j016|3zl
+ split
+ norm! j08|3zl
+ split
+ norm! j08|3zl
+ split
+ norm! j016|3zl
+ split
+ norm! j016|3zl
+ split
+ norm! j016|3zl
+ split
+ call wincol()
+ mksession! test_mks.out
+ let li = filter(readfile('test_mks.out'), 'v:val =~# "\\(^ *normal! 0\\|^ *exe ''normal!\\)"')
+ let expected = [
+ \ 'normal! 016|',
+ \ 'normal! 016|',
+ \ 'normal! 016|',
+ \ 'normal! 08|',
+ \ 'normal! 08|',
+ \ 'normal! 016|',
+ \ 'normal! 016|',
+ \ 'normal! 016|',
+ \ " exe 'normal! ' . s:c . '|zs' . 16 . '|'",
+ \ " normal! 016|",
+ \ " exe 'normal! ' . s:c . '|zs' . 16 . '|'",
+ \ " normal! 016|",
+ \ " exe 'normal! ' . s:c . '|zs' . 16 . '|'",
+ \ " normal! 016|",
+ \ " exe 'normal! ' . s:c . '|zs' . 8 . '|'",
+ \ " normal! 08|",
+ \ " exe 'normal! ' . s:c . '|zs' . 8 . '|'",
+ \ " normal! 08|",
+ \ " exe 'normal! ' . s:c . '|zs' . 16 . '|'",
+ \ " normal! 016|",
+ \ " exe 'normal! ' . s:c . '|zs' . 16 . '|'",
+ \ " normal! 016|",
+ \ " exe 'normal! ' . s:c . '|zs' . 16 . '|'",
+ \ " normal! 016|",
+ \ " exe 'normal! ' . s:c . '|zs' . 16 . '|'",
+ \ " normal! 016|"
+ \ ]
+ call assert_equal(expected, li)
+ tabclose!
+
+ call delete('test_mks.out')
+ call delete(tmpfile)
+ let &wrap = wrap_save
+endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_options.vim b/src/nvim/testdir/test_options.vim
index 5ee0919e18..8a9d793a2e 100644
--- a/src/nvim/testdir/test_options.vim
+++ b/src/nvim/testdir/test_options.vim
@@ -13,6 +13,12 @@ function! Test_whichwrap()
set whichwrap+=h,l
call assert_equal('b,s,h,l', &whichwrap)
+ set whichwrap=h,h
+ call assert_equal('h', &whichwrap)
+
+ set whichwrap=h,h,h
+ call assert_equal('h', &whichwrap)
+
set whichwrap&
endfunction
@@ -97,3 +103,13 @@ func Test_keymap_valid()
call assert_fails(":set kmp=trunc\x00name", "E544:")
call assert_fails(":set kmp=trunc\x00name", "trunc")
endfunc
+
+func Test_complete()
+ " Trailing single backslash used to cause invalid memory access.
+ set complete=s\
+ new
+ call feedkeys("i\<C-N>\<Esc>", 'xt')
+ bwipe!
+ set complete&
+endfun
+
diff --git a/src/nvim/testdir/test_popup.vim b/src/nvim/testdir/test_popup.vim
index 519d855cd8..e1ba142d1c 100644
--- a/src/nvim/testdir/test_popup.vim
+++ b/src/nvim/testdir/test_popup.vim
@@ -7,10 +7,10 @@ func! ListMonths()
if g:setting != ''
exe ":set" g:setting
endif
- let mth=copy(g:months)
+ let mth = copy(g:months)
let entered = strcharpart(getline('.'),0,col('.'))
if !empty(entered)
- let mth=filter(mth, 'v:val=~"^".entered')
+ let mth = filter(mth, 'v:val=~"^".entered')
endif
call complete(1, mth)
return ''
@@ -468,7 +468,7 @@ endfunc
" auto-wrap text.
func Test_completion_ctrl_e_without_autowrap()
new
- let tw_save=&tw
+ let tw_save = &tw
set tw=78
let li = [
\ '" zzz',
@@ -478,7 +478,7 @@ func Test_completion_ctrl_e_without_autowrap()
call feedkeys("A\<C-X>\<C-N>\<C-E>\<Esc>", "tx")
call assert_equal(li, getline(1, '$'))
- let &tw=tw_save
+ let &tw = tw_save
q!
endfunc
@@ -541,4 +541,33 @@ func Test_completion_comment_formatting()
bwipe!
endfunc
+function! DummyCompleteSix()
+ call complete(1, ['Hello', 'World'])
+ return ''
+endfunction
+
+" complete() correctly clears the list of autocomplete candidates
+func Test_completion_clear_candidate_list()
+ new
+ %d
+ " select first entry from the completion popup
+ call feedkeys("a xxx\<C-N>\<C-R>=DummyCompleteSix()\<CR>", "tx")
+ call assert_equal('Hello', getline(1))
+ %d
+ " select second entry from the completion popup
+ call feedkeys("a xxx\<C-N>\<C-R>=DummyCompleteSix()\<CR>\<C-N>", "tx")
+ call assert_equal('World', getline(1))
+ %d
+ " select original text
+ call feedkeys("a xxx\<C-N>\<C-R>=DummyCompleteSix()\<CR>\<C-N>\<C-N>", "tx")
+ call assert_equal(' xxx', getline(1))
+ %d
+ " back at first entry from completion list
+ call feedkeys("a xxx\<C-N>\<C-R>=DummyCompleteSix()\<CR>\<C-N>\<C-N>\<C-N>", "tx")
+ call assert_equal('Hello', getline(1))
+
+ bw!
+endfunc
+
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_startup.vim b/src/nvim/testdir/test_startup.vim
index 64f7f31294..11e26d03aa 100644
--- a/src/nvim/testdir/test_startup.vim
+++ b/src/nvim/testdir/test_startup.vim
@@ -24,28 +24,34 @@ func Test_after_comes_later()
\ 'set guioptions+=M',
\ 'let $HOME = "/does/not/exist"',
\ 'set loadplugins',
- \ 'set rtp=Xhere,Xafter',
+ \ 'set rtp=Xhere,Xafter,Xanother',
\ 'set packpath=Xhere,Xafter',
\ 'set nomore',
+ \ 'let g:sequence = ""',
\ ]
let after = [
\ 'redir! > Xtestout',
\ 'scriptnames',
\ 'redir END',
+ \ 'redir! > Xsequence',
+ \ 'echo g:sequence',
+ \ 'redir END',
\ 'quit',
\ ]
call mkdir('Xhere/plugin', 'p')
- call writefile(['let done = 1'], 'Xhere/plugin/here.vim')
+ call writefile(['let g:sequence .= "here "'], 'Xhere/plugin/here.vim')
+ call mkdir('Xanother/plugin', 'p')
+ call writefile(['let g:sequence .= "another "'], 'Xanother/plugin/another.vim')
call mkdir('Xhere/pack/foo/start/foobar/plugin', 'p')
- call writefile(['let done = 1'], 'Xhere/pack/foo/start/foobar/plugin/foo.vim')
+ call writefile(['let g:sequence .= "pack "'], 'Xhere/pack/foo/start/foobar/plugin/foo.vim')
call mkdir('Xafter/plugin', 'p')
- call writefile(['let done = 1'], 'Xafter/plugin/later.vim')
+ call writefile(['let g:sequence .= "after "'], 'Xafter/plugin/later.vim')
if RunVim(before, after, '')
let lines = readfile('Xtestout')
- let expected = ['Xbefore.vim', 'here.vim', 'foo.vim', 'later.vim', 'Xafter.vim']
+ let expected = ['Xbefore.vim', 'here.vim', 'another.vim', 'foo.vim', 'later.vim', 'Xafter.vim']
let found = []
for line in lines
for one in expected
@@ -57,11 +63,47 @@ func Test_after_comes_later()
call assert_equal(expected, found)
endif
+ call assert_equal('here another pack after', substitute(join(readfile('Xsequence', 1), ''), '\s\+$', '', ''))
+
call delete('Xtestout')
+ call delete('Xsequence')
call delete('Xhere', 'rf')
+ call delete('Xanother', 'rf')
call delete('Xafter', 'rf')
endfunc
+func Test_pack_in_rtp_when_plugins_run()
+ if !has('packages')
+ return
+ endif
+ let before = [
+ \ 'set nocp viminfo+=nviminfo',
+ \ 'set guioptions+=M',
+ \ 'let $HOME = "/does/not/exist"',
+ \ 'set loadplugins',
+ \ 'set rtp=Xhere',
+ \ 'set packpath=Xhere',
+ \ 'set nomore',
+ \ ]
+ let after = [
+ \ 'quit',
+ \ ]
+ call mkdir('Xhere/plugin', 'p')
+ call writefile(['redir! > Xtestout', 'silent set runtimepath?', 'silent! call foo#Trigger()', 'redir END'], 'Xhere/plugin/here.vim')
+ call mkdir('Xhere/pack/foo/start/foobar/autoload', 'p')
+ call writefile(['function! foo#Trigger()', 'echo "autoloaded foo"', 'endfunction'], 'Xhere/pack/foo/start/foobar/autoload/foo.vim')
+
+ if RunVim(before, after, '')
+
+ let lines = filter(readfile('Xtestout'), '!empty(v:val)')
+ call assert_match('Xhere[/\\]pack[/\\]foo[/\\]start[/\\]foobar', get(lines, 0))
+ call assert_match('autoloaded foo', get(lines, 1))
+ endif
+
+ call delete('Xtestout')
+ call delete('Xhere', 'rf')
+endfunc
+
func Test_help_arg()
if !has('unix') && has('gui')
" this doesn't work with gvim on MS-Windows
@@ -76,11 +118,11 @@ func Test_help_arg()
let found = []
for line in lines
if line =~ '-R.*Read-only mode'
- call add(found, 'Readonly mode')
+ call add(found, 'Readonly mode')
endif
" Watch out for a second --version line in the Gnome version.
- if line =~ '--version.*Print version information and exit'
- call add(found, "--version")
+ if line =~ '--version.*Print version information'
+ call add(found, "--version")
endif
endfor
call assert_equal(['Readonly mode', '--version'], found)
diff --git a/src/nvim/testdir/test_syntax.vim b/src/nvim/testdir/test_syntax.vim
index af2cbbfe8e..6c084dd2a7 100644
--- a/src/nvim/testdir/test_syntax.vim
+++ b/src/nvim/testdir/test_syntax.vim
@@ -50,7 +50,7 @@ func Test_syn_iskeyword()
setlocal isk-=_
call assert_equal('DLTD_BY', GetSyntaxItem('DLTD'))
/\<D\k\+\>/:norm! ygn
- let b2=@0
+ let b2 = @0
call assert_equal('DLTD', @0)
syn iskeyword clear
@@ -76,3 +76,85 @@ func Test_syntax_after_reload()
call assert_true(exists('g:gotit'))
call delete('Xsomefile')
endfunc
+
+func Test_syntime()
+ if !has('profile')
+ return
+ endif
+
+ syntax on
+ syntime on
+ let a = execute('syntime report')
+ call assert_equal("\nNo Syntax items defined for this buffer", a)
+
+ view ../memfile_test.c
+ setfiletype cpp
+ redraw
+ let a = execute('syntime report')
+ call assert_match('^ TOTAL *COUNT *MATCH *SLOWEST *AVERAGE *NAME *PATTERN', a)
+ call assert_match(' \d*\.\d* \+[^0]\d* .* cppRawString ', a)
+ call assert_match(' \d*\.\d* \+[^0]\d* .* cppNumber ', a)
+
+ syntime off
+ syntime clear
+ let a = execute('syntime report')
+ call assert_match('^ TOTAL *COUNT *MATCH *SLOWEST *AVERAGE *NAME *PATTERN', a)
+ call assert_notmatch('.* cppRawString *', a)
+ call assert_notmatch('.* cppNumber*', a)
+ call assert_notmatch('[1-9]', a)
+
+ call assert_fails('syntime abc', 'E475')
+
+ syntax clear
+ let a = execute('syntime report')
+ call assert_equal("\nNo Syntax items defined for this buffer", a)
+
+ bd
+endfunc
+
+func Test_syntax_list()
+ syntax on
+ let a = execute('syntax list')
+ call assert_equal("\nNo Syntax items defined for this buffer", a)
+
+ view ../memfile_test.c
+ setfiletype c
+
+ let a = execute('syntax list')
+ call assert_match('cInclude*', a)
+ call assert_match('cDefine', a)
+
+ let a = execute('syntax list cDefine')
+ call assert_notmatch('cInclude*', a)
+ call assert_match('cDefine', a)
+ call assert_match(' links to Macro$', a)
+
+ call assert_fails('syntax list ABCD', 'E28:')
+ call assert_fails('syntax list @ABCD', 'E392:')
+
+ syntax clear
+ let a = execute('syntax list')
+ call assert_equal("\nNo Syntax items defined for this buffer", a)
+
+ bd
+endfunc
+
+func Test_syntax_completion()
+ call feedkeys(":syn \<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"syn case clear cluster conceal enable include iskeyword keyword list manual match off on region reset spell sync', @:)
+
+ call feedkeys(":syn case \<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"syn case ignore match', @:)
+
+ call feedkeys(":syn spell \<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"syn spell default notoplevel toplevel', @:)
+
+ call feedkeys(":syn sync \<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"syn sync ccomment clear fromstart linebreaks= linecont lines= match maxlines= minlines= region', @:)
+
+ call feedkeys(":syn list \<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_match('^"syn list Boolean Character ', @:)
+
+ call feedkeys(":syn match \<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_match('^"syn match Boolean Character ', @:)
+endfunc \ No newline at end of file
diff --git a/src/nvim/testdir/test_visual.vim b/src/nvim/testdir/test_visual.vim
index cf0e535937..8cb59ca32a 100644
--- a/src/nvim/testdir/test_visual.vim
+++ b/src/nvim/testdir/test_visual.vim
@@ -15,3 +15,23 @@ func Test_block_shift_multibyte()
call assert_equal(' ヹxxx', getline(2))
q!
endfunc
+
+func Test_Visual_ctrl_o()
+ new
+ call setline(1, ['one', 'two', 'three'])
+ call cursor(1,2)
+ set noshowmode
+ set tw=0
+ call feedkeys("\<c-v>jjlIa\<c-\>\<c-o>:set tw=88\<cr>\<esc>", 'tx')
+ call assert_equal(['oane', 'tawo', 'tahree'], getline(1, 3))
+ call assert_equal(88, &tw)
+ set tw&
+ bw!
+endfu
+
+func Test_Visual_vapo()
+ new
+ normal oxx
+ normal vapo
+ bwipe!
+endfunc
diff --git a/src/nvim/tui/input.c b/src/nvim/tui/input.c
index 03587d68f0..8bb5971bd4 100644
--- a/src/nvim/tui/input.c
+++ b/src/nvim/tui/input.c
@@ -8,6 +8,7 @@
#include "nvim/api/private/helpers.h"
#include "nvim/ascii.h"
#include "nvim/main.h"
+#include "nvim/aucmd.h"
#include "nvim/os/os.h"
#include "nvim/os/input.h"
#include "nvim/event/rstream.h"
@@ -280,9 +281,9 @@ static void timer_cb(TimeWatcher *watcher, void *data)
/// Handle focus events.
///
-/// If the upcoming sequence of bytes in the input stream matches either the
-/// escape code for focus gained `<ESC>[I` or focus lost `<ESC>[O` then consume
-/// that sequence and push the appropriate event into the input queue
+/// If the upcoming sequence of bytes in the input stream matches the termcode
+/// for "focus gained" or "focus lost", consume that sequence and schedule an
+/// event on the main loop.
///
/// @param input the input stream
/// @return true iff handle_focus_event consumed some input
@@ -294,11 +295,7 @@ static bool handle_focus_event(TermInput *input)
// Advance past the sequence
bool focus_gained = *rbuffer_get(input->read_stream.buffer, 2) == 'I';
rbuffer_consumed(input->read_stream.buffer, 3);
- if (focus_gained) {
- enqueue_input(input, FOCUSGAINED_KEY, sizeof(FOCUSGAINED_KEY) - 1);
- } else {
- enqueue_input(input, FOCUSLOST_KEY, sizeof(FOCUSLOST_KEY) - 1);
- }
+ aucmd_schedule_focusgained(focus_gained);
return true;
}
return false;
diff --git a/src/nvim/tui/terminfo.c b/src/nvim/tui/terminfo.c
index b8fffcb7d6..586fafba97 100644
--- a/src/nvim/tui/terminfo.c
+++ b/src/nvim/tui/terminfo.c
@@ -104,7 +104,9 @@ unibi_term *load_builtin_terminfo(const char * term)
return unibi_from_mem((const char *)interix_8colour_terminfo,
sizeof interix_8colour_terminfo);
} else if (terminfo_is_term_family(term, "iterm")
- || terminfo_is_term_family(term, "iTerm.app")) {
+ || terminfo_is_term_family(term, "iterm2")
+ || terminfo_is_term_family(term, "iTerm.app")
+ || terminfo_is_term_family(term, "iTerm2.app")) {
return unibi_from_mem((const char *)iterm_256colour_terminfo,
sizeof iterm_256colour_terminfo);
} else if (terminfo_is_term_family(term, "st")) {
diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c
index b5af5b0333..8e0e905bcd 100644
--- a/src/nvim/tui/tui.c
+++ b/src/nvim/tui/tui.c
@@ -52,6 +52,15 @@
#define LINUXSET0C "\x1b[?0c"
#define LINUXSET1C "\x1b[?1c"
+#ifdef NVIM_UNIBI_HAS_VAR_FROM
+#define UNIBI_SET_NUM_VAR(var, num) \
+ do { \
+ (var) = unibi_var_from_num((num)); \
+ } while (0)
+#else
+#define UNIBI_SET_NUM_VAR(var, num) (var).i = (num);
+#endif
+
// Per the commentary in terminfo, only a minus sign is a true suffix
// separator.
bool terminfo_is_term_family(const char *term, const char *family)
@@ -234,9 +243,9 @@ static void terminfo_start(UI *ui)
unibi_out(ui, unibi_keypad_xmit);
unibi_out(ui, unibi_clear_screen);
// Enable bracketed paste
- unibi_out(ui, data->unibi_ext.enable_bracketed_paste);
+ unibi_out_ext(ui, data->unibi_ext.enable_bracketed_paste);
// Enable focus reporting
- unibi_out(ui, data->unibi_ext.enable_focus_reporting);
+ unibi_out_ext(ui, data->unibi_ext.enable_focus_reporting);
uv_loop_init(&data->write_loop);
if (data->out_isatty) {
uv_tty_init(&data->write_loop, &data->output_handle.tty, data->out_fd, 0);
@@ -263,9 +272,9 @@ static void terminfo_stop(UI *ui)
unibi_out(ui, unibi_keypad_local);
unibi_out(ui, unibi_exit_ca_mode);
// Disable bracketed paste
- unibi_out(ui, data->unibi_ext.disable_bracketed_paste);
+ unibi_out_ext(ui, data->unibi_ext.disable_bracketed_paste);
// Disable focus reporting
- unibi_out(ui, data->unibi_ext.disable_focus_reporting);
+ unibi_out_ext(ui, data->unibi_ext.disable_focus_reporting);
flush_buf(ui, true);
uv_tty_reset_mode();
uv_close((uv_handle_t *)&data->output_handle, NULL);
@@ -279,7 +288,7 @@ static void terminfo_stop(UI *ui)
static void tui_terminal_start(UI *ui)
{
TUIData *data = ui->data;
- data->print_attrs = EMPTY_ATTRS;
+ data->print_attrs = HLATTRS_INIT;
ugrid_init(&data->grid);
terminfo_start(ui);
update_size(ui);
@@ -391,15 +400,15 @@ static void update_attrs(UI *ui, HlAttrs attrs)
if (unibi_get_str(data->ut, unibi_set_attributes)) {
if (attrs.bold || attrs.reverse || attrs.underline || attrs.undercurl) {
- data->params[0].i = 0; // standout
- data->params[1].i = attrs.underline || attrs.undercurl;
- data->params[2].i = attrs.reverse;
- data->params[3].i = 0; // blink
- data->params[4].i = 0; // dim
- data->params[5].i = attrs.bold;
- data->params[6].i = 0; // blank
- data->params[7].i = 0; // protect
- data->params[8].i = 0; // alternate character set
+ UNIBI_SET_NUM_VAR(data->params[0], 0); // standout
+ UNIBI_SET_NUM_VAR(data->params[1], attrs.underline || attrs.undercurl);
+ UNIBI_SET_NUM_VAR(data->params[2], attrs.reverse);
+ UNIBI_SET_NUM_VAR(data->params[3], 0); // blink
+ UNIBI_SET_NUM_VAR(data->params[4], 0); // dim
+ UNIBI_SET_NUM_VAR(data->params[5], attrs.bold);
+ UNIBI_SET_NUM_VAR(data->params[6], 0); // blank
+ UNIBI_SET_NUM_VAR(data->params[7], 0); // protect
+ UNIBI_SET_NUM_VAR(data->params[8], 0); // alternate character set
unibi_out(ui, unibi_set_attributes);
} else if (!data->default_attr) {
unibi_out(ui, unibi_exit_attribute_mode);
@@ -423,26 +432,26 @@ static void update_attrs(UI *ui, HlAttrs attrs)
}
if (ui->rgb) {
if (fg != -1) {
- data->params[0].i = (fg >> 16) & 0xff; // red
- data->params[1].i = (fg >> 8) & 0xff; // green
- data->params[2].i = fg & 0xff; // blue
- unibi_out(ui, data->unibi_ext.set_rgb_foreground);
+ UNIBI_SET_NUM_VAR(data->params[0], (fg >> 16) & 0xff); // red
+ UNIBI_SET_NUM_VAR(data->params[1], (fg >> 8) & 0xff); // green
+ UNIBI_SET_NUM_VAR(data->params[2], fg & 0xff); // blue
+ unibi_out_ext(ui, data->unibi_ext.set_rgb_foreground);
}
if (bg != -1) {
- data->params[0].i = (bg >> 16) & 0xff; // red
- data->params[1].i = (bg >> 8) & 0xff; // green
- data->params[2].i = bg & 0xff; // blue
- unibi_out(ui, data->unibi_ext.set_rgb_background);
+ UNIBI_SET_NUM_VAR(data->params[0], (bg >> 16) & 0xff); // red
+ UNIBI_SET_NUM_VAR(data->params[1], (bg >> 8) & 0xff); // green
+ UNIBI_SET_NUM_VAR(data->params[2], bg & 0xff); // blue
+ unibi_out_ext(ui, data->unibi_ext.set_rgb_background);
}
} else {
if (fg != -1) {
- data->params[0].i = fg;
+ UNIBI_SET_NUM_VAR(data->params[0], fg);
unibi_out(ui, unibi_set_a_foreground);
}
if (bg != -1) {
- data->params[0].i = bg;
+ UNIBI_SET_NUM_VAR(data->params[0], bg);
unibi_out(ui, unibi_set_a_background);
}
}
@@ -558,7 +567,7 @@ static void cursor_goto(UI *ui, int row, int col)
unibi_out(ui, unibi_cursor_left);
}
} else {
- data->params[0].i = n;
+ UNIBI_SET_NUM_VAR(data->params[0], n);
unibi_out(ui, unibi_parm_left_cursor);
}
ugrid_goto(grid, row, col);
@@ -570,7 +579,7 @@ static void cursor_goto(UI *ui, int row, int col)
unibi_out(ui, unibi_cursor_right);
}
} else {
- data->params[0].i = n;
+ UNIBI_SET_NUM_VAR(data->params[0], n);
unibi_out(ui, unibi_parm_right_cursor);
}
ugrid_goto(grid, row, col);
@@ -585,7 +594,7 @@ static void cursor_goto(UI *ui, int row, int col)
unibi_out(ui, unibi_cursor_down);
}
} else {
- data->params[0].i = n;
+ UNIBI_SET_NUM_VAR(data->params[0], n);
unibi_out(ui, unibi_parm_down_cursor);
}
ugrid_goto(grid, row, col);
@@ -597,7 +606,7 @@ static void cursor_goto(UI *ui, int row, int col)
unibi_out(ui, unibi_cursor_up);
}
} else {
- data->params[0].i = n;
+ UNIBI_SET_NUM_VAR(data->params[0], n);
unibi_out(ui, unibi_parm_up_cursor);
}
ugrid_goto(grid, row, col);
@@ -619,7 +628,7 @@ static void clear_region(UI *ui, int top, int bot, int left, int right)
if (grid->bg == -1 && right == ui->width -1) {
// Background is set to the default color and the right edge matches the
// screen end, try to use terminal codes for clearing the requested area.
- HlAttrs clear_attrs = EMPTY_ATTRS;
+ HlAttrs clear_attrs = HLATTRS_INIT;
clear_attrs.foreground = grid->fg;
clear_attrs.background = grid->bg;
update_attrs(ui, clear_attrs);
@@ -675,19 +684,19 @@ static void set_scroll_region(UI *ui)
TUIData *data = ui->data;
UGrid *grid = &data->grid;
- data->params[0].i = grid->top;
- data->params[1].i = grid->bot;
+ UNIBI_SET_NUM_VAR(data->params[0], grid->top);
+ UNIBI_SET_NUM_VAR(data->params[1], grid->bot);
unibi_out(ui, unibi_change_scroll_region);
if (grid->left != 0 || grid->right != ui->width - 1) {
- unibi_out(ui, data->unibi_ext.enable_lr_margin);
+ unibi_out_ext(ui, data->unibi_ext.enable_lr_margin);
if (data->can_set_lr_margin) {
- data->params[0].i = grid->left;
- data->params[1].i = grid->right;
+ UNIBI_SET_NUM_VAR(data->params[0], grid->left);
+ UNIBI_SET_NUM_VAR(data->params[1], grid->right);
unibi_out(ui, unibi_set_lr_margin);
} else {
- data->params[0].i = grid->left;
+ UNIBI_SET_NUM_VAR(data->params[0], grid->left);
unibi_out(ui, unibi_set_left_margin_parm);
- data->params[0].i = grid->right;
+ UNIBI_SET_NUM_VAR(data->params[0], grid->right);
unibi_out(ui, unibi_set_right_margin_parm);
}
}
@@ -700,24 +709,24 @@ static void reset_scroll_region(UI *ui)
UGrid *grid = &data->grid;
if (0 <= data->unibi_ext.reset_scroll_region) {
- unibi_out(ui, data->unibi_ext.reset_scroll_region);
+ unibi_out_ext(ui, data->unibi_ext.reset_scroll_region);
} else {
- data->params[0].i = 0;
- data->params[1].i = ui->height - 1;
+ UNIBI_SET_NUM_VAR(data->params[0], 0);
+ UNIBI_SET_NUM_VAR(data->params[1], ui->height - 1);
unibi_out(ui, unibi_change_scroll_region);
}
if (grid->left != 0 || grid->right != ui->width - 1) {
if (data->can_set_lr_margin) {
- data->params[0].i = 0;
- data->params[1].i = ui->width - 1;
+ UNIBI_SET_NUM_VAR(data->params[0], 0);
+ UNIBI_SET_NUM_VAR(data->params[1], ui->width - 1);
unibi_out(ui, unibi_set_lr_margin);
} else {
- data->params[0].i = 0;
+ UNIBI_SET_NUM_VAR(data->params[0], 0);
unibi_out(ui, unibi_set_left_margin_parm);
- data->params[0].i = ui->width - 1;
+ UNIBI_SET_NUM_VAR(data->params[0], ui->width - 1);
unibi_out(ui, unibi_set_right_margin_parm);
}
- unibi_out(ui, data->unibi_ext.disable_lr_margin);
+ unibi_out_ext(ui, data->unibi_ext.disable_lr_margin);
}
unibi_goto(ui, grid->row, grid->col);
}
@@ -728,9 +737,9 @@ static void tui_resize(UI *ui, Integer width, Integer height)
ugrid_resize(&data->grid, (int)width, (int)height);
if (!got_winch) { // Try to resize the terminal window.
- data->params[0].i = (int)height;
- data->params[1].i = (int)width;
- unibi_out(ui, data->unibi_ext.resize_screen);
+ UNIBI_SET_NUM_VAR(data->params[0], (int)height);
+ UNIBI_SET_NUM_VAR(data->params[1], (int)width);
+ unibi_out_ext(ui, data->unibi_ext.resize_screen);
// DECSLPP does not reset the scroll region.
if (data->scroll_region_is_full_screen) {
reset_scroll_region(ui);
@@ -836,7 +845,7 @@ static void tui_mouse_on(UI *ui)
{
TUIData *data = ui->data;
if (!data->mouse_enabled) {
- unibi_out(ui, data->unibi_ext.enable_mouse);
+ unibi_out_ext(ui, data->unibi_ext.enable_mouse);
data->mouse_enabled = true;
}
}
@@ -845,7 +854,7 @@ static void tui_mouse_off(UI *ui)
{
TUIData *data = ui->data;
if (data->mouse_enabled) {
- unibi_out(ui, data->unibi_ext.disable_mouse);
+ unibi_out_ext(ui, data->unibi_ext.disable_mouse);
data->mouse_enabled = false;
}
}
@@ -863,8 +872,8 @@ static void tui_set_mode(UI *ui, ModeShape mode)
int attr = syn_id2attr(c.id);
if (attr > 0) {
attrentry_T *aep = syn_cterm_attr2entry(attr);
- data->params[0].i = aep->rgb_bg_color;
- unibi_out(ui, data->unibi_ext.set_cursor_color);
+ UNIBI_SET_NUM_VAR(data->params[0], aep->rgb_bg_color);
+ unibi_out_ext(ui, data->unibi_ext.set_cursor_color);
}
}
@@ -874,8 +883,8 @@ static void tui_set_mode(UI *ui, ModeShape mode)
case SHAPE_VER: shape = 5; break;
default: WLOG("Unknown shape value %d", shape); break;
}
- data->params[0].i = shape + (int)(c.blinkon == 0);
- unibi_out(ui, data->unibi_ext.set_cursor_style);
+ UNIBI_SET_NUM_VAR(data->params[0], shape + (int)(c.blinkon == 0));
+ unibi_out_ext(ui, data->unibi_ext.set_cursor_style);
}
/// @param mode editor mode
@@ -917,7 +926,7 @@ static void tui_scroll(UI *ui, Integer count)
cursor_goto(ui, grid->top, grid->left);
// also set default color attributes or some terminals can become funny
if (scroll_clears_to_current_colour) {
- HlAttrs clear_attrs = EMPTY_ATTRS;
+ HlAttrs clear_attrs = HLATTRS_INIT;
clear_attrs.foreground = grid->fg;
clear_attrs.background = grid->bg;
update_attrs(ui, clear_attrs);
@@ -927,14 +936,14 @@ static void tui_scroll(UI *ui, Integer count)
if (count == 1) {
unibi_out(ui, unibi_delete_line);
} else {
- data->params[0].i = (int)count;
+ UNIBI_SET_NUM_VAR(data->params[0], (int)count);
unibi_out(ui, unibi_parm_delete_line);
}
} else {
if (count == -1) {
unibi_out(ui, unibi_insert_line);
} else {
- data->params[0].i = -(int)count;
+ UNIBI_SET_NUM_VAR(data->params[0], -(int)count);
unibi_out(ui, unibi_parm_insert_line);
}
}
@@ -1177,30 +1186,33 @@ end:
static void unibi_goto(UI *ui, int row, int col)
{
TUIData *data = ui->data;
- data->params[0].i = row;
- data->params[1].i = col;
+ UNIBI_SET_NUM_VAR(data->params[0], row);
+ UNIBI_SET_NUM_VAR(data->params[1], col);
unibi_out(ui, unibi_cursor_address);
}
+#define UNIBI_OUT(fn) \
+ do { \
+ TUIData *data = ui->data; \
+ const char *str = NULL; \
+ if (unibi_index >= 0) { \
+ str = fn(data->ut, (unsigned)unibi_index); \
+ } \
+ if (str) { \
+ unibi_var_t vars[26 + 26]; \
+ memset(&vars, 0, sizeof(vars)); \
+ unibi_format(vars, vars + 26, str, data->params, out, ui, NULL, NULL); \
+ } \
+ } while (0)
static void unibi_out(UI *ui, int unibi_index)
{
- TUIData *data = ui->data;
-
- const char *str = NULL;
-
- if (unibi_index >= 0) {
- if (unibi_index < unibi_string_begin_) {
- str = unibi_get_ext_str(data->ut, (unsigned)unibi_index);
- } else {
- str = unibi_get_str(data->ut, (unsigned)unibi_index);
- }
- }
-
- if (str) {
- unibi_var_t vars[26 + 26] = {{0}};
- unibi_format(vars, vars + 26, str, data->params, out, ui, NULL, NULL);
- }
+ UNIBI_OUT(unibi_get_str);
+}
+static void unibi_out_ext(UI *ui, int unibi_index)
+{
+ UNIBI_OUT(unibi_get_ext_str);
}
+#undef UNIBI_OUT
static void out(void *ctx, const char *str, size_t len)
{
@@ -1261,7 +1273,9 @@ static void patch_terminfo_bugs(TUIData *data, const char *term,
bool gnome = terminfo_is_term_family(term, "gnome")
|| terminfo_is_term_family(term, "vte");
bool iterm = terminfo_is_term_family(term, "iterm")
- || terminfo_is_term_family(term, "iTerm.app");
+ || terminfo_is_term_family(term, "iterm2")
+ || terminfo_is_term_family(term, "iTerm.app")
+ || terminfo_is_term_family(term, "iTerm2.app");
// None of the following work over SSH; see :help TERM .
bool iterm_pretending_xterm = xterm && iterm_env;
bool konsole_pretending_xterm = xterm && konsole;
@@ -1444,7 +1458,7 @@ static void patch_terminfo_bugs(TUIData *data, const char *term,
// teminfo entries. See
// https://github.com/gnachman/iTerm2/pull/92 for more.
// xterm even has an extended version that has a vertical bar.
- if (true_xterm // per xterm ctlseqs doco (since version 282)
+ if (!konsole && (true_xterm // per xterm ctlseqs doco (since version 282)
// per MinTTY 0.4.3-1 release notes from 2009
|| putty
// per https://bugzilla.gnome.org/show_bug.cgi?id=720821
@@ -1459,7 +1473,7 @@ static void patch_terminfo_bugs(TUIData *data, const char *term,
// Allows forcing the use of DECSCUSR on linux type terminals, such as
// console-terminal-emulator from the nosh toolset, which does indeed
// implement the xterm extension:
- || (linuxvt && (xterm_version || (vte_version > 0) || colorterm))) {
+ || (linuxvt && (xterm_version || (vte_version > 0) || colorterm)))) {
data->unibi_ext.set_cursor_style =
(int)unibi_add_ext_str(ut, "Ss", "\x1b[%p1%d q");
if (-1 == data->unibi_ext.reset_cursor_style) {
@@ -1533,7 +1547,9 @@ static void augment_terminfo(TUIData *data, const char *term,
bool screen = terminfo_is_term_family(term, "screen");
bool tmux = terminfo_is_term_family(term, "tmux") || !!os_getenv("TMUX");
bool iterm = terminfo_is_term_family(term, "iterm")
- || terminfo_is_term_family(term, "iTerm.app");
+ || terminfo_is_term_family(term, "iterm2")
+ || terminfo_is_term_family(term, "iTerm.app")
+ || terminfo_is_term_family(term, "iTerm2.app");
// None of the following work over SSH; see :help TERM .
bool iterm_pretending_xterm = xterm && iterm_env;
diff --git a/src/nvim/ugrid.c b/src/nvim/ugrid.c
index 7a0a16687e..2b5e96ee60 100644
--- a/src/nvim/ugrid.c
+++ b/src/nvim/ugrid.c
@@ -16,7 +16,7 @@
void ugrid_init(UGrid *grid)
{
- grid->attrs = EMPTY_ATTRS;
+ grid->attrs = HLATTRS_INIT;
grid->fg = grid->bg = -1;
grid->cells = NULL;
}
@@ -118,7 +118,7 @@ UCell *ugrid_put(UGrid *grid, uint8_t *text, size_t size)
static void clear_region(UGrid *grid, int top, int bot, int left, int right)
{
- HlAttrs clear_attrs = EMPTY_ATTRS;
+ HlAttrs clear_attrs = HLATTRS_INIT;
clear_attrs.foreground = grid->fg;
clear_attrs.background = grid->bg;
UGRID_FOREACH_CELL(grid, top, bot, left, right, {
diff --git a/src/nvim/ugrid.h b/src/nvim/ugrid.h
index 268362bf1b..1cf047502d 100644
--- a/src/nvim/ugrid.h
+++ b/src/nvim/ugrid.h
@@ -21,8 +21,6 @@ struct ugrid {
UCell **cells;
};
-#define EMPTY_ATTRS ((HlAttrs){ false, false, false, false, false, -1, -1, -1 })
-
#define UGRID_FOREACH_CELL(grid, top, bot, left, right, code) \
do { \
for (int row = top; row <= bot; row++) { \
diff --git a/src/nvim/ui.c b/src/nvim/ui.c
index b85a01814d..afe7a51d43 100644
--- a/src/nvim/ui.c
+++ b/src/nvim/ui.c
@@ -71,10 +71,10 @@ static char uilog_last_event[1024] = { 0 };
uilog_seen++; \
} else { \
if (uilog_seen > 0) { \
- do_log(DEBUG_LOG_LEVEL, "ui", 0, true, \
+ do_log(DEBUG_LOG_LEVEL, "UI: ", NULL, -1, true, \
"%s (+%zu times...)", uilog_last_event, uilog_seen); \
} \
- DLOG("ui: " STR(funname)); \
+ do_log(DEBUG_LOG_LEVEL, "UI: ", NULL, -1, true, STR(funname)); \
uilog_seen = 0; \
xstrlcpy(uilog_last_event, STR(funname), sizeof(uilog_last_event)); \
} \
@@ -166,6 +166,90 @@ void ui_event(char *name, Array args)
}
}
+
+/// Converts an attrentry_T into an HlAttrs
+///
+/// @param[in] aep data to convert
+/// @param use_rgb use 'gui*' settings if true, else resorts to 'cterm*'
+HlAttrs attrentry2hlattrs(const attrentry_T *aep, bool use_rgb)
+{
+ assert(aep);
+
+ HlAttrs attrs = HLATTRS_INIT;
+ int mask = 0;
+
+ mask = use_rgb ? aep->rgb_ae_attr : aep->cterm_ae_attr;
+
+ attrs.bold = mask & HL_BOLD;
+ attrs.underline = mask & HL_UNDERLINE;
+ attrs.undercurl = mask & HL_UNDERCURL;
+ attrs.italic = mask & HL_ITALIC;
+ attrs.reverse = mask & (HL_INVERSE | HL_STANDOUT);
+
+ if (use_rgb) {
+ if (aep->rgb_fg_color != -1) {
+ attrs.foreground = aep->rgb_fg_color;
+ }
+
+ if (aep->rgb_bg_color != -1) {
+ attrs.background = aep->rgb_bg_color;
+ }
+
+ if (aep->rgb_sp_color != -1) {
+ attrs.special = aep->rgb_sp_color;
+ }
+ } else {
+ if (cterm_normal_fg_color != aep->cterm_fg_color) {
+ attrs.foreground = aep->cterm_fg_color - 1;
+ }
+
+ if (cterm_normal_bg_color != aep->cterm_bg_color) {
+ attrs.background = aep->cterm_bg_color - 1;
+ }
+ }
+
+ return attrs;
+}
+
+Dictionary hlattrs2dict(HlAttrs attrs)
+{
+ Dictionary hl = ARRAY_DICT_INIT;
+
+ if (attrs.bold) {
+ PUT(hl, "bold", BOOLEAN_OBJ(true));
+ }
+
+ if (attrs.underline) {
+ PUT(hl, "underline", BOOLEAN_OBJ(true));
+ }
+
+ if (attrs.undercurl) {
+ PUT(hl, "undercurl", BOOLEAN_OBJ(true));
+ }
+
+ if (attrs.italic) {
+ PUT(hl, "italic", BOOLEAN_OBJ(true));
+ }
+
+ if (attrs.reverse) {
+ PUT(hl, "reverse", BOOLEAN_OBJ(true));
+ }
+
+ if (attrs.foreground != -1) {
+ PUT(hl, "foreground", INTEGER_OBJ(attrs.foreground));
+ }
+
+ if (attrs.background != -1) {
+ PUT(hl, "background", INTEGER_OBJ(attrs.background));
+ }
+
+ if (attrs.special != -1) {
+ PUT(hl, "special", INTEGER_OBJ(attrs.special));
+ }
+
+ return hl;
+}
+
void ui_refresh(void)
{
if (!ui_active()) {
@@ -405,54 +489,20 @@ void ui_flush(void)
static void set_highlight_args(int attr_code)
{
- HlAttrs rgb_attrs = { false, false, false, false, false, -1, -1, -1 };
+ HlAttrs rgb_attrs = HLATTRS_INIT;
HlAttrs cterm_attrs = rgb_attrs;
if (attr_code == HL_NORMAL) {
goto end;
}
-
- int rgb_mask = 0;
- int cterm_mask = 0;
attrentry_T *aep = syn_cterm_attr2entry(attr_code);
if (!aep) {
goto end;
}
- rgb_mask = aep->rgb_ae_attr;
- cterm_mask = aep->cterm_ae_attr;
-
- rgb_attrs.bold = rgb_mask & HL_BOLD;
- rgb_attrs.underline = rgb_mask & HL_UNDERLINE;
- rgb_attrs.undercurl = rgb_mask & HL_UNDERCURL;
- rgb_attrs.italic = rgb_mask & HL_ITALIC;
- rgb_attrs.reverse = rgb_mask & (HL_INVERSE | HL_STANDOUT);
- cterm_attrs.bold = cterm_mask & HL_BOLD;
- cterm_attrs.underline = cterm_mask & HL_UNDERLINE;
- cterm_attrs.undercurl = cterm_mask & HL_UNDERCURL;
- cterm_attrs.italic = cterm_mask & HL_ITALIC;
- cterm_attrs.reverse = cterm_mask & (HL_INVERSE | HL_STANDOUT);
-
- if (aep->rgb_fg_color != normal_fg) {
- rgb_attrs.foreground = aep->rgb_fg_color;
- }
-
- if (aep->rgb_bg_color != normal_bg) {
- rgb_attrs.background = aep->rgb_bg_color;
- }
-
- if (aep->rgb_sp_color != normal_sp) {
- rgb_attrs.special = aep->rgb_sp_color;
- }
-
- if (cterm_normal_fg_color != aep->cterm_fg_color) {
- cterm_attrs.foreground = aep->cterm_fg_color - 1;
- }
-
- if (cterm_normal_bg_color != aep->cterm_bg_color) {
- cterm_attrs.background = aep->cterm_bg_color - 1;
- }
+ rgb_attrs = attrentry2hlattrs(aep, true);
+ cterm_attrs = attrentry2hlattrs(aep, false);
end:
UI_CALL(highlight_set, (ui->rgb ? rgb_attrs : cterm_attrs));
diff --git a/src/nvim/ui.h b/src/nvim/ui.h
index 064f77fee1..f1ea0716e6 100644
--- a/src/nvim/ui.h
+++ b/src/nvim/ui.h
@@ -21,6 +21,9 @@ typedef struct {
int foreground, background, special;
} HlAttrs;
+#define HLATTRS_INIT \
+ ((HlAttrs){ false, false, false, false, false, -1, -1, -1 })
+
typedef struct ui_t UI;
struct ui_t {
diff --git a/src/nvim/version.c b/src/nvim/version.c
index f5b45caefc..7e59f3327a 100644
--- a/src/nvim/version.c
+++ b/src/nvim/version.c
@@ -77,6 +77,157 @@ static char *features[] = {
// clang-format off
static const int included_patches[] = {
+ // 1026,
+ 1025,
+ 1024,
+ // 1023,
+ // 1022,
+ // 1021,
+ // 1020,
+ // 1019,
+ // 1018,
+ // 1017,
+ // 1016,
+ // 1015,
+ // 1014,
+ // 1013,
+ // 1012,
+ // 1011,
+ // 1010,
+ // 1009,
+ // 1008,
+ // 1007,
+ // 1006,
+ // 1005,
+ // 1004,
+ // 1003,
+ // 1002,
+ // 1001,
+ // 1000,
+ // 999,
+ // 998,
+ // 997,
+ // 996,
+ // 995,
+ // 994,
+ // 993,
+ // 992,
+ // 991,
+ // 990,
+ // 989,
+ // 988,
+ // 987,
+ // 986,
+ // 985,
+ // 984,
+ // 983,
+ // 982,
+ // 981,
+ // 980,
+ // 979,
+ // 978,
+ // 977,
+ // 976,
+ // 975,
+ // 974,
+ // 973,
+ // 972,
+ // 971,
+ // 970,
+ // 969,
+ // 968,
+ // 967,
+ // 966,
+ // 965,
+ // 964,
+ // 963,
+ // 962,
+ // 961,
+ // 960,
+ // 959,
+ // 958,
+ // 957,
+ // 956,
+ // 955,
+ // 954,
+ // 953,
+ // 952,
+ // 951,
+ // 950,
+ // 949,
+ // 948,
+ // 947,
+ // 946,
+ // 945,
+ // 944,
+ // 943,
+ // 942,
+ // 941,
+ // 940,
+ // 939,
+ // 938,
+ // 937,
+ // 936,
+ // 935,
+ // 934,
+ // 933,
+ // 932,
+ // 931,
+ // 930,
+ // 929,
+ // 928,
+ // 927,
+ // 926,
+ // 925,
+ // 924,
+ // 923,
+ // 922,
+ // 921,
+ // 920,
+ // 919,
+ // 918,
+ // 917,
+ // 916,
+ // 915,
+ // 914,
+ // 913,
+ // 912,
+ // 911,
+ // 910,
+ // 909,
+ // 908,
+ // 907,
+ // 906,
+ // 905,
+ // 904,
+ // 903,
+ // 902,
+ // 901,
+ // 900,
+ // 899,
+ // 898,
+ // 897,
+ // 896,
+ // 895,
+ // 894,
+ // 893,
+ // 892,
+ // 891,
+ // 890,
+ // 889,
+ // 888,
+ // 887,
+ // 886,
+ // 885,
+ // 884,
+ // 883,
+ // 882,
+ // 881,
+ // 880,
+ // 879,
+ // 878,
+ // 877,
+ // 876,
// 875,
// 874,
// 873,
@@ -272,7 +423,7 @@ static const int included_patches[] = {
// 683,
// 682,
// 681,
- // 680,
+ 680,
679,
678,
// 677,
@@ -340,7 +491,7 @@ static const int included_patches[] = {
// 615,
614,
// 613,
- // 612,
+ 612,
// 611,
// 610,
// 609,
@@ -515,7 +666,7 @@ static const int included_patches[] = {
// 440,
// 439,
// 438,
- // 437,
+ 437,
// 436,
// 435,
// 434,
@@ -619,16 +770,16 @@ static const int included_patches[] = {
// 336,
// 335,
// 334,
- // 333,
+ 333,
// 332,
331,
- // 330,
+ 330,
// 329,
- // 328,
- // 327,
- // 326,
- // 325,
- // 324,
+ 328,
+ 327,
+ 326,
+ 325,
+ 324,
// 323,
322,
// 321,
@@ -644,24 +795,24 @@ static const int included_patches[] = {
311,
// 310,
// 309,
- // 308,
+ 308,
307,
// 306,
- // 305,
+ 305,
// 304,
// 303,
- // 302,
+ // 302, NA
// 301,
- // 300,
+ 300,
// 299,
// 298,
297,
// 296,
// 295,
- // 294,
+ 294,
// 293,
// 292,
- // 291,
+ 291,
290,
// 289,
// 288 NA
@@ -670,7 +821,7 @@ static const int included_patches[] = {
// 285 NA
// 284 NA
// 283,
- // 282,
+ 282,
// 281 NA
280,
// 279 NA
@@ -694,18 +845,18 @@ static const int included_patches[] = {
// 261,
// 260 NA
259,
- // 258,
+ 258,
// 257 NA
// 256,
// 255,
// 254,
- // 253,
+ 253,
// 252,
// 251,
250,
// 249 NA
// 248,
- // 247,
+ 247,
// 246 NA
// 245,
// 244,
@@ -743,7 +894,7 @@ static const int included_patches[] = {
// 212,
// 211 NA
// 210,
- // 209,
+ 209,
208,
// 207,
// 206,
@@ -764,14 +915,14 @@ static const int included_patches[] = {
// 191 NA
190,
// 189,
- // 188,
+ 188,
// 187 NA
- // 186,
+ 186,
// 185,
// 184,
// 183,
- // 182,
- // 181,
+ 182,
+ 181,
// 180,
179,
178,
@@ -788,29 +939,29 @@ static const int included_patches[] = {
167,
// 166,
165,
- // 164,
+ 164,
// 163 NA
// 162 NA
// 161 NA
// 160,
159,
158,
- // 157,
+ 157,
156,
- // 155,
+ 155,
// 154,
// 153,
// 152 NA
// 151,
150,
149,
- // 148,
+ 148,
147,
146,
// 145 NA
// 144 NA
143,
- // 142,
+ 142,
// 141,
// 140,
// 139 NA
@@ -820,14 +971,14 @@ static const int included_patches[] = {
135,
134,
133,
- // 132,
- // 131,
+ 132,
+ 131,
// 130 NA
// 129 NA
128,
127,
126,
- // 125,
+ 125,
124,
// 123 NA
// 122 NA
@@ -840,7 +991,7 @@ static const int included_patches[] = {
// 115 NA
// 114 NA
// 113 NA
- // 112,
+ 112,
111,
110,
// 109 NA
@@ -860,8 +1011,8 @@ static const int included_patches[] = {
// 95 NA
// 94 NA
// 93 NA
- // 92,
- // 91,
+ 92,
+ 91,
90,
// 89 NA
88,
@@ -1089,13 +1240,7 @@ static void list_features(void)
msg_putchar('\n');
}
} else {
- while (msg_col % width) {
- int old_msg_col = msg_col;
- msg_putchar(' ');
- if (old_msg_col == msg_col) {
- break; // XXX: Avoid infinite loop.
- }
- }
+ msg_putchar(' ');
}
} else {
if (msg_col > 0) {
@@ -1103,7 +1248,7 @@ static void list_features(void)
}
}
}
- MSG_PUTS("For differences from Vim, see :help vim-differences\n\n");
+ MSG_PUTS("See \":help feature-compile\"\n\n");
}
void list_version(void)
@@ -1144,7 +1289,7 @@ void list_version(void)
}
#endif // ifdef HAVE_PATHDEF
- version_msg(_("\n\nOptional features included (+) or not (-): "));
+ version_msg(_("\n\nFeatures: "));
list_features();
@@ -1216,7 +1361,6 @@ void intro_message(int colon)
static char *(lines[]) = {
N_(NVIM_VERSION_LONG),
"",
- N_("by al."),
N_("Nvim is open source and freely distributable"),
N_("https://neovim.io/community"),
"",
diff --git a/src/nvim/window.c b/src/nvim/window.c
index 081fc98816..c2d0a9b3b1 100644
--- a/src/nvim/window.c
+++ b/src/nvim/window.c
@@ -5515,11 +5515,14 @@ void restore_buffer(bufref_T *save_curbuf)
}
-// Add match to the match list of window 'wp'. The pattern 'pat' will be
-// highlighted with the group 'grp' with priority 'prio'.
-// Optionally, a desired ID 'id' can be specified (greater than or equal to 1).
-// If no particular ID is desired, -1 must be specified for 'id'.
-// Return ID of added match, -1 on failure.
+/// Add match to the match list of window 'wp'. The pattern 'pat' will be
+/// highlighted with the group 'grp' with priority 'prio'.
+/// Optionally, a desired ID 'id' can be specified (greater than or equal to 1).
+///
+/// @param[in] id a desired ID 'id' can be specified
+/// (greater than or equal to 1). -1 must be specified if no
+/// particular ID is desired
+/// @return ID of added match, -1 on failure.
int match_add(win_T *wp, const char *const grp, const char *const pat,
int prio, int id, list_T *pos_list,
const char *const conceal_char)
@@ -5697,10 +5700,9 @@ fail:
return -1;
}
-/*
- * Delete match with ID 'id' in the match list of window 'wp'.
- * Print error messages if 'perr' is TRUE.
- */
+
+/// Delete match with ID 'id' in the match list of window 'wp'.
+/// Print error messages if 'perr' is TRUE.
int match_delete(win_T *wp, int id, int perr)
{
matchitem_T *cur = wp->w_match_head;
diff --git a/test/.luacheckrc b/test/.luacheckrc
index 034b4f10df..abfa881754 100644
--- a/test/.luacheckrc
+++ b/test/.luacheckrc
@@ -17,4 +17,4 @@ ignore = {
}
-- Ignore whitespace issues in converted Vim legacy tests.
-files["functional/legacy"] = {ignore = { "611", "612", "613", "621" }}
+--files["functional/legacy"] = {ignore = { "611", "612", "613", "621" }}
diff --git a/test/functional/api/highlight_spec.lua b/test/functional/api/highlight_spec.lua
new file mode 100644
index 0000000000..2297a0760f
--- /dev/null
+++ b/test/functional/api/highlight_spec.lua
@@ -0,0 +1,103 @@
+local helpers = require('test.functional.helpers')(after_each)
+local clear, nvim = helpers.clear, helpers.nvim
+local Screen = require('test.functional.ui.screen')
+local eq, eval = helpers.eq, helpers.eval
+local command = helpers.command
+local meths = helpers.meths
+
+describe('highlight api',function()
+ local expected_rgb = {
+ background = Screen.colors.Yellow,
+ foreground = Screen.colors.Red,
+ special = Screen.colors.Blue,
+ bold = true,
+ }
+ local expected_cterm = {
+ background = 10,
+ underline = true,
+ }
+ local expected_rgb2 = {
+ background = Screen.colors.Yellow,
+ foreground = Screen.colors.Red,
+ special = Screen.colors.Blue,
+ bold = true,
+ italic = true,
+ reverse = true,
+ undercurl = true,
+ underline = true,
+ }
+
+ before_each(function()
+ clear()
+ command("hi NewHighlight cterm=underline ctermbg=green guifg=red guibg=yellow guisp=blue gui=bold")
+ end)
+
+ it("nvim_get_hl_by_id", function()
+ local hl_id = eval("hlID('NewHighlight')")
+ eq(expected_cterm, nvim("get_hl_by_id", hl_id, false))
+
+ hl_id = eval("hlID('NewHighlight')")
+ -- Test valid id.
+ eq(expected_rgb, nvim("get_hl_by_id", hl_id, true))
+
+ -- Test invalid id.
+ local err, emsg = pcall(meths.get_hl_by_id, 30000, false)
+ eq(false, err)
+ eq('Invalid highlight id: 30000', string.match(emsg, 'Invalid.*'))
+
+ -- Test all highlight properties.
+ command('hi NewHighlight gui=underline,bold,undercurl,italic,reverse')
+ eq(expected_rgb2, nvim("get_hl_by_id", hl_id, true))
+
+ -- Test nil argument.
+ err, emsg = pcall(meths.get_hl_by_id, { nil }, false)
+ eq(false, err)
+ eq('Wrong type for argument 1, expecting Integer',
+ string.match(emsg, 'Wrong.*'))
+
+ -- Test 0 argument.
+ err, emsg = pcall(meths.get_hl_by_id, 0, false)
+ eq(false, err)
+ eq('Invalid highlight id: 0',
+ string.match(emsg, 'Invalid.*'))
+
+ -- Test -1 argument.
+ err, emsg = pcall(meths.get_hl_by_id, -1, false)
+ eq(false, err)
+ eq('Invalid highlight id: -1',
+ string.match(emsg, 'Invalid.*'))
+ end)
+
+ it("nvim_get_hl_by_name", function()
+ local expected_normal = { background = Screen.colors.Yellow,
+ foreground = Screen.colors.Red }
+
+ -- Test `Normal` default values.
+ eq({}, nvim("get_hl_by_name", 'Normal', true))
+
+ eq(expected_cterm, nvim("get_hl_by_name", 'NewHighlight', false))
+ eq(expected_rgb, nvim("get_hl_by_name", 'NewHighlight', true))
+
+ -- Test `Normal` modified values.
+ command('hi Normal guifg=red guibg=yellow')
+ eq(expected_normal, nvim("get_hl_by_name", 'Normal', true))
+
+ -- Test invalid name.
+ local err, emsg = pcall(meths.get_hl_by_name , 'unknown_highlight', false)
+ eq(false, err)
+ eq('Invalid highlight name: unknown_highlight',
+ string.match(emsg, 'Invalid.*'))
+
+ -- Test nil argument.
+ err, emsg = pcall(meths.get_hl_by_name , { nil }, false)
+ eq(false, err)
+ eq('Wrong type for argument 1, expecting String',
+ string.match(emsg, 'Wrong.*'))
+
+ -- Test empty string argument.
+ err, emsg = pcall(meths.get_hl_by_name , '', false)
+ eq(false, err)
+ eq('Invalid highlight name: ',
+ string.match(emsg, 'Invalid.*'))
+ end)
+end)
diff --git a/test/functional/api/server_requests_spec.lua b/test/functional/api/server_requests_spec.lua
index 6a32f979ea..9f245d913b 100644
--- a/test/functional/api/server_requests_spec.lua
+++ b/test/functional/api/server_requests_spec.lua
@@ -20,6 +20,22 @@ describe('server -> client', function()
cid = nvim('get_api_info')[1]
end)
+ it('handles unexpected closed stream while preparing RPC response', function()
+ source([[
+ let g:_nvim_args = [v:progpath, '--embed', '-n', '-u', 'NONE', '-i', 'NONE', ]
+ let ch1 = jobstart(g:_nvim_args, {'rpc': v:true})
+ let child1_ch = rpcrequest(ch1, "nvim_get_api_info")[0]
+ call rpcnotify(ch1, 'nvim_eval', 'rpcrequest('.child1_ch.', "nvim_get_api_info")')
+
+ let ch2 = jobstart(g:_nvim_args, {'rpc': v:true})
+ let child2_ch = rpcrequest(ch2, "nvim_get_api_info")[0]
+ call rpcnotify(ch2, 'nvim_eval', 'rpcrequest('.child2_ch.', "nvim_get_api_info")')
+
+ call jobstop(ch1)
+ ]])
+ eq(2, eval("1+1")) -- Still alive?
+ end)
+
describe('simple call', function()
it('works', function()
local function on_setup()
@@ -141,7 +157,7 @@ describe('server -> client', function()
end)
end)
- describe('when the client is a recursive vim instance', function()
+ describe('recursive (child) nvim client', function()
if os.getenv("TRAVIS") and helpers.os_name() == "osx" then
-- XXX: Hangs Travis macOS since e9061117a5b8f195c3f26a5cb94e18ddd7752d86.
pending("[Hangs on Travis macOS. #5002]", function() end)
@@ -155,7 +171,7 @@ describe('server -> client', function()
after_each(function() command('call rpcstop(vim)') end)
- it('can send/recieve notifications and make requests', function()
+ it('can send/receive notifications and make requests', function()
nvim('command', "call rpcnotify(vim, 'vim_set_current_line', 'SOME TEXT')")
-- Wait for the notification to complete.
@@ -188,7 +204,7 @@ describe('server -> client', function()
end)
end)
- describe('when using jobstart', function()
+ describe('jobstart()', function()
local jobid
before_each(function()
local channel = nvim('get_api_info')[1]
@@ -227,7 +243,7 @@ describe('server -> client', function()
end)
end)
- describe('when connecting to another nvim instance', function()
+ describe('connecting to another (peer) nvim', function()
local function connect_test(server, mode, address)
local serverpid = funcs.getpid()
local client = spawn(nvim_argv)
@@ -256,7 +272,7 @@ describe('server -> client', function()
client:close()
end
- it('over a named pipe', function()
+ it('via named pipe', function()
local server = spawn(nvim_argv)
set_session(server)
local address = funcs.serverlist()[1]
@@ -265,7 +281,7 @@ describe('server -> client', function()
connect_test(server, 'pipe', address)
end)
- it('to an ip adress', function()
+ it('via ip address', function()
local server = spawn(nvim_argv)
set_session(server)
local address = funcs.serverstart("127.0.0.1:")
@@ -273,7 +289,7 @@ describe('server -> client', function()
connect_test(server, 'tcp', address)
end)
- it('to a hostname', function()
+ it('via hostname', function()
local server = spawn(nvim_argv)
set_session(server)
local address = funcs.serverstart("localhost:")
diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua
index e59b5d712d..b849304d45 100644
--- a/test/functional/api/vim_spec.lua
+++ b/test/functional/api/vim_spec.lua
@@ -329,24 +329,92 @@ describe('api', function()
}
eq({ { {mode='n', blocking=false},
13,
- {mode='n', blocking=false}, -- TODO: should be blocked=true
+ {mode='n', blocking=false}, -- TODO: should be blocked=true ?
1 },
NIL}, meths.call_atomic(req))
eq({mode='r', blocking=true}, nvim("get_mode"))
end)
- -- TODO: bug #6166
it("during insert-mode map-pending, returns blocking=true #6166", function()
command("inoremap xx foo")
nvim("input", "ix")
eq({mode='i', blocking=true}, nvim("get_mode"))
end)
- -- TODO: bug #6166
it("during normal-mode gU, returns blocking=false #6166", function()
nvim("input", "gu")
eq({mode='no', blocking=false}, nvim("get_mode"))
end)
end)
+ describe('RPC (K_EVENT) #6166', function()
+ it('does not complete ("interrupt") normal-mode operator-pending', function()
+ helpers.insert([[
+ FIRST LINE
+ SECOND LINE]])
+ nvim('input', 'gg')
+ nvim('input', 'gu')
+ -- Make any RPC request (can be non-async: op-pending does not block).
+ nvim('get_current_buf')
+ -- Buffer should not change.
+ helpers.expect([[
+ FIRST LINE
+ SECOND LINE]])
+ -- Now send input to complete the operator.
+ nvim('input', 'j')
+ helpers.expect([[
+ first line
+ second line]])
+ end)
+
+ it('does not complete ("interrupt") `d` #3732', function()
+ local screen = Screen.new(20, 4)
+ screen:attach()
+ command('set listchars=eol:$')
+ command('set list')
+ feed('ia<cr>b<cr>c<cr><Esc>kkk')
+ feed('d')
+ -- Make any RPC request (can be non-async: op-pending does not block).
+ nvim('get_current_buf')
+ screen:expect([[
+ ^a$ |
+ b$ |
+ c$ |
+ |
+ ]])
+ end)
+
+ it('does not complete ("interrupt") normal-mode map-pending', function()
+ command("nnoremap dd :let g:foo='it worked...'<CR>")
+ helpers.insert([[
+ FIRST LINE
+ SECOND LINE]])
+ nvim('input', 'gg')
+ nvim('input', 'd')
+ -- Make any RPC request (must be async, because map-pending blocks).
+ nvim('get_api_info')
+ -- Send input to complete the mapping.
+ nvim('input', 'd')
+ helpers.expect([[
+ FIRST LINE
+ SECOND LINE]])
+ eq('it worked...', helpers.eval('g:foo'))
+ end)
+ it('does not complete ("interrupt") insert-mode map-pending', function()
+ command('inoremap xx foo')
+ command('set timeoutlen=9999')
+ helpers.insert([[
+ FIRST LINE
+ SECOND LINE]])
+ nvim('input', 'ix')
+ -- Make any RPC request (must be async, because map-pending blocks).
+ nvim('get_api_info')
+ -- Send input to complete the mapping.
+ nvim('input', 'x')
+ helpers.expect([[
+ FIRST LINE
+ SECOND LINfooE]])
+ end)
+ end)
+
describe('nvim_replace_termcodes', function()
it('escapes K_SPECIAL as K_SPECIAL KS_SPECIAL KE_FILLER', function()
eq('\128\254X', helpers.nvim('replace_termcodes', '\128', true, true, true))
diff --git a/test/functional/autocmd/termclose_spec.lua b/test/functional/autocmd/termclose_spec.lua
index 8cc49c0d4c..c6c30494dd 100644
--- a/test/functional/autocmd/termclose_spec.lua
+++ b/test/functional/autocmd/termclose_spec.lua
@@ -57,7 +57,9 @@ describe('TermClose event', function()
command('call jobstop(g:test_job)')
retry(nil, nil, function() eq(1, eval('get(g:, "test_job_exited", 0)')) end)
local duration = os.time() - start
- eq(4, duration)
+ -- nvim starts sending kill after 2*KILL_TIMEOUT_MS
+ helpers.ok(4 <= duration)
+ helpers.ok(duration <= 7) -- <= 4 + delta because of slow CI
end)
it('reports the correct <abuf>', function()
diff --git a/test/functional/clipboard/clipboard_provider_spec.lua b/test/functional/clipboard/clipboard_provider_spec.lua
index eb2eeee0da..b90335e70a 100644
--- a/test/functional/clipboard/clipboard_provider_spec.lua
+++ b/test/functional/clipboard/clipboard_provider_spec.lua
@@ -4,6 +4,8 @@ local helpers = require('test.functional.helpers')(after_each)
local Screen = require('test.functional.ui.screen')
local clear, feed, insert = helpers.clear, helpers.feed, helpers.insert
local feed_command, expect, eq, eval = helpers.feed_command, helpers.expect, helpers.eq, helpers.eval
+local command = helpers.command
+local meths = helpers.meths
local function basic_register_test(noblock)
insert("some words")
@@ -80,15 +82,73 @@ local function basic_register_test(noblock)
expect("two and three and one")
end
-describe('the unnamed register', function()
+describe('clipboard', function()
before_each(clear)
- it('works without provider', function()
+
+ it('unnamed register works without provider', function()
eq('"', eval('v:register'))
basic_register_test()
end)
+
+ 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([[
+ ^ |
+ ~ |
+ ~ |
+ clipboard: No provider. Try ":CheckHealth" or ":h clipboard". |
+ ]], nil, {{bold = true, foreground = Screen.colors.Blue}})
+ end)
+
+ 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([[
+ ~ |
+ clipboard: No provider. Try ":CheckHealth" or ":h clipboard". |
+ E492: Not an editor command: bogus_cmd | redir END |
+ Press ENTER or type command to continue^ |
+ ]], nil, {{bold = true, foreground = Screen.colors.Blue}})
+ end)
+
+ it('invalid g:clipboard shows hint if :redir is not active', function()
+ command("let g:clipboard = 'bogus'")
+ 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"')
+ screen:expect([[
+ ^ |
+ ~ |
+ ~ |
+ clipboard: No provider. Try ":CheckHealth" or ":h clipboard". |
+ ]], nil, {{bold = true, foreground = Screen.colors.Blue}})
+ end)
+
+ it('valid g:clipboard', function()
+ -- provider#clipboard#Executable() only checks the structure.
+ meths.set_var('clipboard', {
+ ['name'] = 'clippy!',
+ ['copy'] = { ['+'] = 'any command', ['*'] = 'some other' },
+ ['paste'] = { ['+'] = 'any command', ['*'] = 'some other' },
+ })
+ eq('clippy!', eval('provider#clipboard#Executable()'))
+ eq('', eval('provider#clipboard#Error()'))
+ end)
end)
-describe('clipboard usage', function()
+describe('clipboard', function()
local function reset(...)
clear('--cmd', 'let &rtp = "test/functional/fixtures,".&rtp', ...)
end
@@ -98,7 +158,36 @@ describe('clipboard usage', function()
feed_command('call getreg("*")') -- force load of provider
end)
- it('has independent "* and unnamed registers per default', function()
+ it('`:redir @+>` invokes clipboard once-per-message', function()
+ eq(0, eval("g:clip_called_set"))
+ feed_command('redir @+> | :silent echo system("cat CONTRIBUTING.md") | redir END')
+ -- Assuming CONTRIBUTING.md has >100 lines.
+ assert(eval("g:clip_called_set") > 100)
+ end)
+
+ it('`:redir @">` does NOT invoke clipboard', function()
+ -- :redir to a non-clipboard register, with `:set clipboard=unnamed` does
+ -- NOT propagate to the clipboard. This is consistent with Vim.
+ command("set clipboard=unnamedplus")
+ eq(0, eval("g:clip_called_set"))
+ feed_command('redir @"> | :silent echo system("cat CONTRIBUTING.md") | redir END')
+ eq(0, eval("g:clip_called_set"))
+ end)
+
+ it('`:redir @+>|bogus_cmd|redir END` must not recurse #7184',
+ function()
+ local screen = Screen.new(72, 4)
+ screen:attach()
+ feed_command('redir @+> | bogus_cmd | redir END')
+ screen:expect([[
+ ^ |
+ ~ |
+ ~ |
+ E492: Not an editor command: bogus_cmd | redir END |
+ ]], nil, {{bold = true, foreground = Screen.colors.Blue}})
+ end)
+
+ it('has independent "* and unnamed registers by default', function()
insert("some words")
feed('^"*dwdw"*P')
expect('some ')
@@ -139,7 +228,7 @@ describe('clipboard usage', function()
eq({'some\ntext', '\nvery binary\n'}, eval("getreg('*', 1, 1)"))
end)
- it('support autodectection of regtype', function()
+ it('autodetects regtype', function()
feed_command("let g:test_clip['*'] = ['linewise stuff','']")
feed_command("let g:test_clip['+'] = ['charwise','stuff']")
eq("V", eval("getregtype('*')"))
@@ -169,7 +258,7 @@ describe('clipboard usage', function()
eq({{' much', 'ktext', ''}, 'b'}, eval("g:test_clip['+']"))
end)
- it('supports setreg', function()
+ it('supports setreg()', function()
feed_command('call setreg("*", "setted\\ntext", "c")')
feed_command('call setreg("+", "explicitly\\nlines", "l")')
feed('"+P"*p')
@@ -187,7 +276,7 @@ describe('clipboard usage', function()
]])
end)
- it('supports let @+ (issue #1427)', function()
+ it('supports :let @+ (issue #1427)', function()
feed_command("let @+ = 'some'")
feed_command("let @* = ' other stuff'")
eq({{'some'}, 'v'}, eval("g:test_clip['+']"))
@@ -303,9 +392,16 @@ describe('clipboard usage', function()
eq('---', eval('getreg("*")'))
end)
+ it('works in the cmdline window', function()
+ feed('q:itext<esc>yy')
+ eq({{'text', ''}, 'V'}, eval("g:test_clip['*']"))
+ command("let g:test_clip['*'] = [['star'], 'c']")
+ feed('p')
+ eq('textstar', meths.get_current_line())
+ end)
end)
- describe('with clipboard=unnamedplus', function()
+ describe('clipboard=unnamedplus', function()
before_each(function()
feed_command('set clipboard=unnamedplus')
end)
@@ -349,6 +445,7 @@ describe('clipboard usage', function()
really unnamed
the plus]])
end)
+
it('is updated on global changes', function()
insert([[
text
diff --git a/test/functional/core/job_spec.lua b/test/functional/core/job_spec.lua
index 54e56f7f41..1b8a5b1b95 100644
--- a/test/functional/core/job_spec.lua
+++ b/test/functional/core/job_spec.lua
@@ -677,12 +677,12 @@ describe("pty process teardown", function()
-- Exiting should terminate all descendants (PTY, its children, ...).
screen:expect([[
- |
+ ^ |
[Process exited 0] |
|
|
|
- -- TERMINAL -- |
+ |
]])
end)
end)
diff --git a/test/functional/core/path_spec.lua b/test/functional/core/path_spec.lua
new file mode 100644
index 0000000000..669bc99136
--- /dev/null
+++ b/test/functional/core/path_spec.lua
@@ -0,0 +1,56 @@
+local helpers = require('test.functional.helpers')(after_each)
+local clear = helpers.clear
+local eq = helpers.eq
+local eval = helpers.eval
+local command = helpers.command
+local iswin = helpers.iswin
+
+describe('path collapse', function()
+ local targetdir
+ local expected_path
+
+ local function join_path(...)
+ local pathsep = (iswin() and '\\' or '/')
+ return table.concat({...}, pathsep)
+ end
+
+ before_each(function()
+ targetdir = join_path('test', 'functional', 'fixtures')
+ clear()
+ command('edit '..join_path(targetdir, 'tty-test.c'))
+ expected_path = eval('expand("%:p")')
+ end)
+
+ it('with /./ segment #7117', function()
+ command('edit '..join_path(targetdir, '.', 'tty-test.c'))
+ eq(expected_path, eval('expand("%:p")'))
+ end)
+
+ it('with ./ prefix #7117', function()
+ command('edit '..join_path('.', targetdir, 'tty-test.c'))
+ eq(expected_path, eval('expand("%:p")'))
+ end)
+
+ it('with ./ prefix, after directory change #7117', function()
+ command('edit '..join_path('.', targetdir, 'tty-test.c'))
+ command('cd test')
+ eq(expected_path, eval('expand("%:p")'))
+ end)
+
+ it('with /../ segment #7117', function()
+ command('edit '..join_path(targetdir, '..', 'fixtures', 'tty-test.c'))
+ eq(expected_path, eval('expand("%:p")'))
+ end)
+
+ it('with ../ and different starting directory #7117', function()
+ command('cd test')
+ command('edit '..join_path('..', targetdir, 'tty-test.c'))
+ eq(expected_path, eval('expand("%:p")'))
+ end)
+
+ it('with ./../ and different starting directory #7117', function()
+ command('cd test')
+ command('edit '..join_path('.', '..', targetdir, 'tty-test.c'))
+ eq(expected_path, eval('expand("%:p")'))
+ end)
+end)
diff --git a/test/functional/eval/input_spec.lua b/test/functional/eval/input_spec.lua
index 5ae23e17d0..1e6b107c60 100644
--- a/test/functional/eval/input_spec.lua
+++ b/test/functional/eval/input_spec.lua
@@ -239,6 +239,25 @@ describe('input()', function()
{RBP1:(}{RBP2:()}{RBP1:)}^ |
]])
end)
+ it('is not hidden by :silent', function()
+ feed([[:silent call input('Foo: ')<CR>]])
+ screen:expect([[
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ Foo: ^ |
+ |
+ ]])
+ feed('Bar')
+ screen:expect([[
+ {EOB:~ }|
+ {EOB:~ }|
+ {EOB:~ }|
+ Foo: Bar^ |
+ |
+ ]])
+ feed('<CR>')
+ end)
end)
describe('inputdialog()', function()
it('works with multiline prompts', function()
diff --git a/test/functional/fixtures/autoload/provider/clipboard.vim b/test/functional/fixtures/autoload/provider/clipboard.vim
index 411e095c71..6d777255c8 100644
--- a/test/functional/fixtures/autoload/provider/clipboard.vim
+++ b/test/functional/fixtures/autoload/provider/clipboard.vim
@@ -5,7 +5,13 @@ let s:methods = {}
let g:cliplossy = 0
let g:cliperror = 0
+" Count how many times the clipboard was invoked.
+let g:clip_called_get = 0
+let g:clip_called_set = 0
+
function! s:methods.get(reg)
+ let g:clip_called_get += 1
+
if g:cliperror
return 0
end
@@ -19,6 +25,8 @@ function! s:methods.get(reg)
endfunction
function! s:methods.set(lines, regtype, reg)
+ let g:clip_called_set += 1
+
if a:reg == '"'
call s:methods.set(a:lines,a:regtype,'+')
call s:methods.set(a:lines,a:regtype,'*')
diff --git a/test/functional/legacy/003_cindent_spec.lua b/test/functional/legacy/003_cindent_spec.lua
index 27835fea28..58e87354fb 100644
--- a/test/functional/legacy/003_cindent_spec.lua
+++ b/test/functional/legacy/003_cindent_spec.lua
@@ -15,6 +15,8 @@ local function insert_(content)
feed_command('1', 'set cin ts=4 sw=4')
end
+-- luacheck: ignore 621 (Indentation)
+-- luacheck: ignore 613 (Trailing whitespace in a string)
describe('cindent', function()
before_each(clear)
@@ -3915,6 +3917,26 @@ describe('cindent', function()
{
111111111111111111;
}
+ namespace test::cpp17
+ {
+ 111111111111111111;
+ }
+ namespace ::incorrectcpp17
+ {
+ 111111111111111111;
+ }
+ namespace test::incorrectcpp17::
+ {
+ 111111111111111111;
+ }
+ namespace test:incorrectcpp17
+ {
+ 111111111111111111;
+ }
+ namespace test:::incorrectcpp17
+ {
+ 111111111111111111;
+ }
namespace{
111111111111111111;
}
@@ -3986,6 +4008,26 @@ describe('cindent', function()
{
111111111111111111;
}
+ namespace test::cpp17
+ {
+ 111111111111111111;
+ }
+ namespace ::incorrectcpp17
+ {
+ 111111111111111111;
+ }
+ namespace test::incorrectcpp17::
+ {
+ 111111111111111111;
+ }
+ namespace test:incorrectcpp17
+ {
+ 111111111111111111;
+ }
+ namespace test:::incorrectcpp17
+ {
+ 111111111111111111;
+ }
namespace{
111111111111111111;
}
@@ -4676,4 +4718,38 @@ describe('cindent', function()
JSEND
]=])
end)
+
+ it('line continuations in macros / vim-patch 8.0.0148', function()
+ insert_([=[
+ /* start of define */
+ {
+ }
+ #define AAA \
+ BBB\
+ CCC
+
+ #define CNT \
+ 1 + \
+ 2 + \
+ 4
+ /* end of define */]=])
+
+ feed_command('set cino&')
+ feed_command('/start of define')
+ feed('=/end of define<cr>')
+
+ expect([=[
+ /* start of define */
+ {
+ }
+ #define AAA \
+ BBB\
+ CCC
+
+ #define CNT \
+ 1 + \
+ 2 + \
+ 4
+ /* end of define */]=])
+ end)
end)
diff --git a/test/functional/legacy/005_bufleave_delete_buffer_spec.lua b/test/functional/legacy/005_bufleave_delete_buffer_spec.lua
index 417842c52d..8b92c877a6 100644
--- a/test/functional/legacy/005_bufleave_delete_buffer_spec.lua
+++ b/test/functional/legacy/005_bufleave_delete_buffer_spec.lua
@@ -9,6 +9,7 @@ local wait = helpers.wait
describe('test5', function()
setup(clear)
+ -- luacheck: ignore 621 (Indentation)
it('is working', function()
insert([[
start of test file Xxx
diff --git a/test/functional/legacy/006_argument_list_spec.lua b/test/functional/legacy/006_argument_list_spec.lua
index dac58df8a5..9f75a91fa8 100644
--- a/test/functional/legacy/006_argument_list_spec.lua
+++ b/test/functional/legacy/006_argument_list_spec.lua
@@ -78,8 +78,8 @@ describe('argument list', function()
end)
teardown(function()
- os.remove('Xxx1')
- os.remove('Xxx2')
- os.remove('Xxx3')
+ os.remove('Xxx1')
+ os.remove('Xxx2')
+ os.remove('Xxx3')
end)
end)
diff --git a/test/functional/legacy/007_ball_buffer_list_spec.lua b/test/functional/legacy/007_ball_buffer_list_spec.lua
index 8501faabec..a180e73301 100644
--- a/test/functional/legacy/007_ball_buffer_list_spec.lua
+++ b/test/functional/legacy/007_ball_buffer_list_spec.lua
@@ -36,10 +36,10 @@ describe(':ball', function()
-- Open window for all args, close Xxx2
feed('$r4:ball<cr>')
-
+
-- Write contents of this file
feed_command('%yank A')
-
+
-- Append contents of second window (Xxx1)
feed('')
feed_command('%yank A')
diff --git a/test/functional/legacy/011_autocommands_spec.lua b/test/functional/legacy/011_autocommands_spec.lua
index e01af4583b..d969a8bd37 100644
--- a/test/functional/legacy/011_autocommands_spec.lua
+++ b/test/functional/legacy/011_autocommands_spec.lua
@@ -94,6 +94,8 @@ describe('file reading, writing and bufnew and filter autocommands', function()
eq(gzip_data, io.open('Xtestfile.gz'):read('*all'))
end)
+ -- luacheck: ignore 621 (Indentation)
+ -- luacheck: ignore 611 (Line contains only whitespaces)
it('FileReadPre, FileReadPost', function()
prepare_gz_file('Xtestfile', text1)
feed_command('au! FileReadPre *.gz exe "silent !gzip -d " . shellescape(expand("<afile>"))')
diff --git a/test/functional/legacy/015_alignment_spec.lua b/test/functional/legacy/015_alignment_spec.lua
index 8423aa3d11..d73ff06972 100644
--- a/test/functional/legacy/015_alignment_spec.lua
+++ b/test/functional/legacy/015_alignment_spec.lua
@@ -9,6 +9,7 @@ local clear, feed_command, expect = helpers.clear, helpers.feed_command, helpers
describe('alignment', function()
setup(clear)
+ -- luacheck: ignore 621 (Indentation)
it('is working', function()
insert([[
test for :left
@@ -112,7 +113,7 @@ describe('alignment', function()
asxa;ofa axxxoikey
asdfaqwer axxxoikey
- xxxxx xx xxxxxx
+ xxxxx xx xxxxxx
xxxxxxx xxxxxxxxx xxx xxxx xxxxx xxxxx xxx xx
xxxxxxxxxxxxxxxxxx xxxxx xxxx, xxxx xxxx xxxx xxxx xxx xx xx
xx xxxxxxx. xxxx xxxx.
diff --git a/test/functional/legacy/019_smarttab_expandtab_spec.lua b/test/functional/legacy/019_smarttab_expandtab_spec.lua
index ecb24885bb..7b03ee8e99 100644
--- a/test/functional/legacy/019_smarttab_expandtab_spec.lua
+++ b/test/functional/legacy/019_smarttab_expandtab_spec.lua
@@ -8,6 +8,7 @@ local clear, feed_command, expect = helpers.clear, helpers.feed_command, helpers
describe([[performing "r<Tab>" with 'smarttab' and 'expandtab' set/not set, and "dv_"]], function()
setup(clear)
+ -- luacheck: ignore 621 (Indentation)
it('is working', function()
insert([[
start text
diff --git a/test/functional/legacy/029_join_spec.lua b/test/functional/legacy/029_join_spec.lua
index 460b9291bf..b28f276a7c 100644
--- a/test/functional/legacy/029_join_spec.lua
+++ b/test/functional/legacy/029_join_spec.lua
@@ -11,6 +11,8 @@ local feed_command = helpers.feed_command
describe('joining lines', function()
before_each(clear)
+ -- luacheck: ignore 613 (Trailing whitespaces in a string)
+ -- luacheck: ignore 611 (Line contains only whitespaces)
it("keeps marks with different 'joinspaces' settings", function()
insert([[
firstline
diff --git a/test/functional/legacy/033_lisp_indent_spec.lua b/test/functional/legacy/033_lisp_indent_spec.lua
index 2b79ee024b..5132333a5c 100644
--- a/test/functional/legacy/033_lisp_indent_spec.lua
+++ b/test/functional/legacy/033_lisp_indent_spec.lua
@@ -9,6 +9,7 @@ local wait = helpers.wait
describe('lisp indent', function()
setup(clear)
+ -- luacheck: ignore 621 (Indentation)
it('is working', function()
insert([[
(defun html-file (base)
@@ -22,7 +23,7 @@ describe('lisp indent', function()
:if-exists :supersede)
(let ((,ti ,title))
(as title ,ti)
- (with center
+ (with center
(as h2 (string-upcase ,ti)))
(brs 3)
,@body))))
@@ -58,7 +59,7 @@ describe('lisp indent', function()
:if-exists :supersede)
(let ((,ti ,title))
(as title ,ti)
- (with center
+ (with center
(as h2 (string-upcase ,ti)))
(brs 3)
,@body))))
diff --git a/test/functional/legacy/038_virtual_replace_spec.lua b/test/functional/legacy/038_virtual_replace_spec.lua
index 2dfc959a8c..8dd7bdda6e 100644
--- a/test/functional/legacy/038_virtual_replace_spec.lua
+++ b/test/functional/legacy/038_virtual_replace_spec.lua
@@ -7,6 +7,7 @@ local clear, feed_command, expect = helpers.clear, helpers.feed_command, helpers
describe('Virtual replace mode', function()
setup(clear)
+ -- luacheck: ignore 621 (Indentation)
it('is working', function()
-- Make sure that backspace works, no matter what termcap is used.
feed_command('set t_kD=x7f t_kb=x08')
diff --git a/test/functional/legacy/039_visual_block_mode_commands_spec.lua b/test/functional/legacy/039_visual_block_mode_commands_spec.lua
index dffef50950..135058c579 100644
--- a/test/functional/legacy/039_visual_block_mode_commands_spec.lua
+++ b/test/functional/legacy/039_visual_block_mode_commands_spec.lua
@@ -43,6 +43,7 @@ describe('Visual block mode', function()
abcdqqqqijklm]])
end)
+ -- luacheck: ignore 611 (Line contains only whitespaces)
it('should insert a block using cursor keys for movement', function()
insert([[
aaaaaa
@@ -104,6 +105,7 @@ describe('Visual block mode', function()
456ab7]])
end)
+ -- luacheck: ignore 621 (Indentation)
it('should insert and append a block when virtualedit=all', function()
insert([[
line1
diff --git a/test/functional/legacy/051_highlight_spec.lua b/test/functional/legacy/051_highlight_spec.lua
index 60d29246ff..2ef74196ee 100644
--- a/test/functional/legacy/051_highlight_spec.lua
+++ b/test/functional/legacy/051_highlight_spec.lua
@@ -37,6 +37,7 @@ describe(':highlight', function()
feed('q')
wait() -- wait until we're back to normal
command('hi Search')
+ command('hi Normal')
-- Test setting colors.
-- Test clearing one color and all doesn't generate error or warning
diff --git a/test/functional/legacy/055_list_and_dict_types_spec.lua b/test/functional/legacy/055_list_and_dict_types_spec.lua
index e84c415eb0..dcbd8b7dff 100644
--- a/test/functional/legacy/055_list_and_dict_types_spec.lua
+++ b/test/functional/legacy/055_list_and_dict_types_spec.lua
@@ -191,6 +191,7 @@ describe('list and dictionary types', function()
[3]]=])
end)
+ -- luacheck: ignore 613 (Trailing whitespace in a string)
it('assignment to a list', function()
source([[
let l = [0, 1, 2, 3]
diff --git a/test/functional/legacy/060_exists_and_has_functions_spec.lua b/test/functional/legacy/060_exists_and_has_functions_spec.lua
index 3e99f6df57..1794f23b3a 100644
--- a/test/functional/legacy/060_exists_and_has_functions_spec.lua
+++ b/test/functional/legacy/060_exists_and_has_functions_spec.lua
@@ -12,7 +12,7 @@ describe('exists() and has() functions', function()
write_file('test60.vim', [[
" Vim script for exists() function test
" Script-local variables are checked here
-
+
" Existing script-local variable
let s:script_var = 1
echo 's:script_var: 1'
@@ -21,7 +21,7 @@ describe('exists() and has() functions', function()
else
echo "FAILED"
endif
-
+
" Non-existing script-local variable
unlet s:script_var
echo 's:script_var: 0'
@@ -30,7 +30,7 @@ describe('exists() and has() functions', function()
else
echo "FAILED"
endif
-
+
" Existing script-local list
let s:script_list = ["blue", "orange"]
echo 's:script_list: 1'
@@ -39,7 +39,7 @@ describe('exists() and has() functions', function()
else
echo "FAILED"
endif
-
+
" Non-existing script-local list
unlet s:script_list
echo 's:script_list: 0'
@@ -48,7 +48,7 @@ describe('exists() and has() functions', function()
else
echo "FAILED"
endif
-
+
" Existing script-local dictionary
let s:script_dict = {"xcord":100, "ycord":2}
echo 's:script_dict: 1'
@@ -57,7 +57,7 @@ describe('exists() and has() functions', function()
else
echo "FAILED"
endif
-
+
" Non-existing script-local dictionary
unlet s:script_dict
echo 's:script_dict: 0'
@@ -66,7 +66,7 @@ describe('exists() and has() functions', function()
else
echo "FAILED"
endif
-
+
" Existing script curly-brace variable
let str = "script"
let s:curly_{str}_var = 1
@@ -76,7 +76,7 @@ describe('exists() and has() functions', function()
else
echo "FAILED"
endif
-
+
" Non-existing script-local curly-brace variable
unlet s:curly_{str}_var
echo 's:curly_' . str . '_var: 0'
@@ -85,21 +85,21 @@ describe('exists() and has() functions', function()
else
echo "FAILED"
endif
-
+
" Existing script-local function
function! s:my_script_func()
endfunction
-
+
echo '*s:my_script_func: 1'
if exists('*s:my_script_func')
echo "OK"
else
echo "FAILED"
endif
-
+
" Non-existing script-local function
delfunction s:my_script_func
-
+
echo '*s:my_script_func: 0'
if !exists('*s:my_script_func')
echo "OK"
@@ -644,7 +644,7 @@ describe('exists() and has() functions', function()
-- Assert buffer contents.
expect([[
-
+
#myagroup: 1
OK
#myagroup+b: 0
diff --git a/test/functional/legacy/066_visual_block_tab_spec.lua b/test/functional/legacy/066_visual_block_tab_spec.lua
index 7c4984362f..f10152d8ea 100644
--- a/test/functional/legacy/066_visual_block_tab_spec.lua
+++ b/test/functional/legacy/066_visual_block_tab_spec.lua
@@ -15,7 +15,7 @@ describe('visual block shift and tab characters', function()
one two three
one two three
one two three
-
+
abcdefghijklmnopqrstuvwxyz
abcdefghijklmnopqrstuvwxyz
abcdefghijklmnopqrstuvwxyz
@@ -49,7 +49,7 @@ describe('visual block shift and tab characters', function()
on1 two three
on1 two three
on1 two three
-
+
abcdefghijklmnopqrstuvwxyz
abcdefghij
abc defghijklmnopqrstuvwxyz
diff --git a/test/functional/legacy/068_text_formatting_spec.lua b/test/functional/legacy/068_text_formatting_spec.lua
index 772dbc14cf..3a1b21bf87 100644
--- a/test/functional/legacy/068_text_formatting_spec.lua
+++ b/test/functional/legacy/068_text_formatting_spec.lua
@@ -9,6 +9,7 @@ local expect = helpers.expect
describe('text formatting', function()
setup(clear)
+ -- luacheck: ignore 613 (Trailing whitespace in a string)
it('is working', function()
-- The control character <C-A> (byte \x01) needs to be put in the buffer
-- directly. But the insert function sends the text to nvim in insert
diff --git a/test/functional/legacy/069_multibyte_formatting_spec.lua b/test/functional/legacy/069_multibyte_formatting_spec.lua
index 38ca25d57a..9c248e3aa8 100644
--- a/test/functional/legacy/069_multibyte_formatting_spec.lua
+++ b/test/functional/legacy/069_multibyte_formatting_spec.lua
@@ -27,7 +27,7 @@ describe('multibyte text', function()
XYZ
abc
XYZ
-
+
XYZ
abc
XYZ
@@ -62,7 +62,7 @@ describe('multibyte text', function()
-
+
a
@@ -125,7 +125,7 @@ describe('multibyte text', function()
ab
-
+
a
@@ -166,7 +166,7 @@ describe('multibyte text', function()
a
-
+
a
@@ -190,7 +190,7 @@ describe('multibyte text', function()
a
-
+
a
@@ -239,7 +239,7 @@ describe('multibyte text', function()
XX
XXa
XXY
-
+
Xa
Xa
@@ -259,7 +259,7 @@ describe('multibyte text', function()
it('formatting in replace mode', function()
insert([[
{
-
+
}]])
feed_command('/^{/+1')
feed_command('set tw=2 fo=tm')
diff --git a/test/functional/legacy/078_swapfile_recover_spec.lua b/test/functional/legacy/078_swapfile_recover_spec.lua
index 4390ba2ca8..45f0aed37a 100644
--- a/test/functional/legacy/078_swapfile_recover_spec.lua
+++ b/test/functional/legacy/078_swapfile_recover_spec.lua
@@ -22,32 +22,32 @@ describe('78', function()
let linecount = 10000
while i <= linecount | call append(i - 1, i . text) | let i += 1 | endwhile
preserve
-
+
" Get the name of the swap file, and clean up the :redir capture.
redir => g:swapname | swapname | redir END
let g:swapname = substitute(g:swapname, '[[:blank:][:cntrl:]]*\(.\{-}\)[[:blank:][:cntrl:]]*$', '\1', 'g')
let g:swapname = fnameescape(g:swapname)
-
+
" Make a copy of the swap file in Xswap
set bin
exe 'sp ' . g:swapname
w! Xswap
-
+
set nobin
new
only!
bwipe! Xtest
call rename('Xswap', g:swapname)
-
+
"TODO(jkeyes): without 'silent', this hangs the test " at message:
" 'Recovery completed. You should check if everything is OK.'
silent recover Xtest
-
+
call delete(g:swapname)
new
call append(0, 'recovery start')
wincmd w
-
+
let g:linedollar = line('$')
if g:linedollar < linecount
wincmd w
@@ -56,7 +56,7 @@ describe('78', function()
wincmd w
let linecount = g:linedollar
endif
-
+
let i = 1
while i <= linecount
if getline(i) != i . text
@@ -72,7 +72,7 @@ describe('78', function()
expect([[
recovery start
-
+
recovery end]])
end)
end)
diff --git a/test/functional/legacy/081_coptions_movement_spec.lua b/test/functional/legacy/081_coptions_movement_spec.lua
index 993aff2ba2..d82c46a3d3 100644
--- a/test/functional/legacy/081_coptions_movement_spec.lua
+++ b/test/functional/legacy/081_coptions_movement_spec.lua
@@ -7,6 +7,7 @@ local feed_command, expect = helpers.feed_command, helpers.expect
describe('coptions', function()
setup(clear)
+ -- luacheck: ignore 613 (Trailing whitespace in a string)
it('is working', function()
insert([[
aaa two three four
diff --git a/test/functional/legacy/082_string_comparison_spec.lua b/test/functional/legacy/082_string_comparison_spec.lua
index cfc0b96bce..311822c34f 100644
--- a/test/functional/legacy/082_string_comparison_spec.lua
+++ b/test/functional/legacy/082_string_comparison_spec.lua
@@ -115,9 +115,9 @@ describe('case-insensitive string comparison in UTF-8', function()
-- Assert buffer contents.
expect([=[
3732 checks passed
-
+
ABCD
-
+
defg]=])
end)
end)
diff --git a/test/functional/legacy/084_curswant_spec.lua b/test/functional/legacy/084_curswant_spec.lua
index 9809ce5b88..42cb2fc56d 100644
--- a/test/functional/legacy/084_curswant_spec.lua
+++ b/test/functional/legacy/084_curswant_spec.lua
@@ -7,6 +7,7 @@ local clear, expect = helpers.clear, helpers.expect
describe('curswant', function()
setup(clear)
+ -- luacheck: ignore 621 (Indentation)
it('is working', function()
insert([[
start target options
diff --git a/test/functional/legacy/088_conceal_tabs_spec.lua b/test/functional/legacy/088_conceal_tabs_spec.lua
index c9414679ab..a4c7e26583 100644
--- a/test/functional/legacy/088_conceal_tabs_spec.lua
+++ b/test/functional/legacy/088_conceal_tabs_spec.lua
@@ -12,6 +12,7 @@ end
describe('cursor and column position with conceal and tabulators', function()
setup(clear)
+ -- luacheck: ignore 621 (Indentation)
it('are working', function()
insert([[
start:
diff --git a/test/functional/legacy/089_number_relnumber_findfile_spec.lua b/test/functional/legacy/089_number_relnumber_findfile_spec.lua
index 7a87fc8603..6708fd50b7 100644
--- a/test/functional/legacy/089_number_relnumber_findfile_spec.lua
+++ b/test/functional/legacy/089_number_relnumber_findfile_spec.lua
@@ -63,26 +63,26 @@ describe("setting 'number' and 'relativenumber'", function()
-- Assert buffer contents.
expect([[
results:
-
+
number
relativenumber
-
+
number
relativenumber
:setlocal must NOT reset the other global value
-
+
number
-
+
relativenumber
:setglobal MUST reset the other global value
-
+
number
-
+
relativenumber
:set MUST reset the other global value
-
+
number
-
+
relativenumber]])
end)
end)
@@ -108,7 +108,7 @@ describe('findfile', function()
expect([[
Testing findfile
-
+
src/nvim/api/vim.c
api/vim.c
api/vim.c]])
diff --git a/test/functional/legacy/092_mksession_cursor_cols_utf8_spec.lua b/test/functional/legacy/092_mksession_cursor_cols_utf8_spec.lua
index 44f1664abe..3c46c29951 100644
--- a/test/functional/legacy/092_mksession_cursor_cols_utf8_spec.lua
+++ b/test/functional/legacy/092_mksession_cursor_cols_utf8_spec.lua
@@ -15,6 +15,7 @@ describe('store cursor position in session file in UTF-8', function()
os.remove('test.out')
end)
+ -- luacheck: ignore 621 (Indentation)
it('is working', function()
insert([[
start:
diff --git a/test/functional/legacy/093_mksession_cursor_cols_latin1_spec.lua b/test/functional/legacy/093_mksession_cursor_cols_latin1_spec.lua
index 49bc43f76f..b1221ff8b6 100644
--- a/test/functional/legacy/093_mksession_cursor_cols_latin1_spec.lua
+++ b/test/functional/legacy/093_mksession_cursor_cols_latin1_spec.lua
@@ -17,6 +17,7 @@ describe('store cursor position in session file in Latin-1', function()
os.remove('test.out')
end)
+ -- luacheck: ignore 621 (Indentation)
it('is working', function()
insert([[
start:
diff --git a/test/functional/legacy/094_visual_mode_operators_spec.lua b/test/functional/legacy/094_visual_mode_operators_spec.lua
index 84e384050a..ff1d3e7bec 100644
--- a/test/functional/legacy/094_visual_mode_operators_spec.lua
+++ b/test/functional/legacy/094_visual_mode_operators_spec.lua
@@ -372,6 +372,7 @@ describe('Visual mode and operator', function()
end)
end)
+ -- luacheck: ignore 613 (Trailing whitespace in a string)
it('gv in exclusive select mode after operation', function()
source([[
$put ='zzz '
diff --git a/test/functional/legacy/103_visual_mode_reset_spec.lua b/test/functional/legacy/103_visual_mode_reset_spec.lua
index d05b47fa32..f5cd861019 100644
--- a/test/functional/legacy/103_visual_mode_reset_spec.lua
+++ b/test/functional/legacy/103_visual_mode_reset_spec.lua
@@ -32,7 +32,7 @@ describe('E315 error', function()
-- :del the ex-way will require the colon operator which resets the
-- visual mode thus preventing the problem:
feed('GV:call TriggerTheProblem()<cr>')
-
+
source([[
%del _
call append(line('$'), g:msg)
@@ -41,7 +41,7 @@ describe('E315 error', function()
-- Assert buffer contents.
expect([[
-
+
Everything's fine.]])
end)
end)
diff --git a/test/functional/legacy/106_errorformat_spec.lua b/test/functional/legacy/106_errorformat_spec.lua
index 5d76adc786..3f017a704f 100644
--- a/test/functional/legacy/106_errorformat_spec.lua
+++ b/test/functional/legacy/106_errorformat_spec.lua
@@ -15,9 +15,9 @@ describe('errorformat', function()
command("$put =strtrans(string(map(getqflist(), '[v:val.text, v:val.valid]')))")
command("cgetexpr ['WWWW', 'GGGG', 'ZZZZ', 'EEEE', 'CCCC', 'YYYY']")
command("$put =strtrans(string(map(getqflist(), '[v:val.text, v:val.valid]')))")
-
+
expect([=[
-
+
[['W', 1], ['E^@CCCC', 1]]
[['W', 1], ['E^@CCCC', 1]]
[['W', 1], ['ZZZZ', 0], ['E^@CCCC', 1], ['YYYY', 0]]]=])
diff --git a/test/functional/legacy/108_backtrace_debug_commands_spec.lua b/test/functional/legacy/108_backtrace_debug_commands_spec.lua
index b2e2fa4ed3..ff1917e90c 100644
--- a/test/functional/legacy/108_backtrace_debug_commands_spec.lua
+++ b/test/functional/legacy/108_backtrace_debug_commands_spec.lua
@@ -89,18 +89,18 @@ describe('108', function()
-- Assert buffer contents.
expect([=[
-
-
-
+
+
+
- show backtrace:
-
+
2 function Foo[2]
1 Bar[2]
->0 Bazz
line 2: let var3 = "another var"
-
+
show variables on different levels:
-
+
6
2 function Foo[2]
->1 Bar[2]
@@ -112,9 +112,9 @@ describe('108', function()
0 Bazz
line 2: let var3 = "another var"
1
-
+
- undefined vars:
-
+
undefined var3 on former level:
Error detected while processing function Foo[2]..Bar[2]..Bazz:
line 3:
@@ -122,7 +122,7 @@ describe('108', function()
E15: Invalid expression: var3
here var3 is defined with "another var":
another var
-
+
undefined var2 on former level
Error detected while processing function Foo[2]..Bar:
line 3:
@@ -130,37 +130,37 @@ describe('108', function()
E15: Invalid expression: var2
here var2 is defined with 10:
10
-
+
- backtrace movements:
-
+
1 function Foo[2]
->0 Bar
line 3: End of function
-
+
next command cannot go down, we are on bottom
-
+
frame is zero
-
+
next command cannot go up, we are on top
-
+
frame at highest level: 1
->1 function Foo[2]
0 Bar
line 3: End of function
fil is not frame or finish, it is file
"[No Name]" --No lines in buffer--
-
+
- relative backtrace movement
-
+
1 function Foo[2]
->0 Bar
line 3: End of function
->1 function Foo[2]
0 Bar
line 3: End of function
-
+
- go beyond limits does not crash
-
+
frame at highest level: 1
->1 function Foo[2]
0 Bar
@@ -169,7 +169,7 @@ describe('108', function()
1 function Foo[2]
->0 Bar
line 3: End of function
-
+
- final result 19:
19
]=])
diff --git a/test/functional/legacy/assert_spec.lua b/test/functional/legacy/assert_spec.lua
index d646e8dbf4..381461dc4f 100644
--- a/test/functional/legacy/assert_spec.lua
+++ b/test/functional/legacy/assert_spec.lua
@@ -89,7 +89,7 @@ describe('assert function:', function()
it('should change v:errors when expected is equal to actual', function()
call('assert_notequal', 'foo', 'foo')
- expected_errors({"Expected 'foo' differs from 'foo'"})
+ expected_errors({"Expected not equal to 'foo'"})
end)
end)
diff --git a/test/functional/legacy/breakindent_spec.lua b/test/functional/legacy/breakindent_spec.lua
index 7594dba16c..fd25e809e0 100644
--- a/test/functional/legacy/breakindent_spec.lua
+++ b/test/functional/legacy/breakindent_spec.lua
@@ -7,6 +7,9 @@ local clear, feed_command, expect = helpers.clear, helpers.feed_command, helpers
describe('breakindent', function()
setup(clear)
+ -- luacheck: ignore 621 (Indentation)
+ -- luacheck: ignore 613 (Trailing whitespace in a string)
+ -- luacheck: ignore 611 (Line contains only whitespaces)
it('is working', function()
insert('dummy text')
diff --git a/test/functional/legacy/command_count_spec.lua b/test/functional/legacy/command_count_spec.lua
index ad5368430a..8707c0459c 100644
--- a/test/functional/legacy/command_count_spec.lua
+++ b/test/functional/legacy/command_count_spec.lua
@@ -4,6 +4,7 @@ local helpers = require('test.functional.helpers')(after_each)
local clear, source, expect = helpers.clear, helpers.source, helpers.expect
local feed_command = helpers.feed_command
+-- luacheck: ignore 613 (Trailing whitespace in a string)
describe('command_count', function()
it('is working', function()
-- It is relevant for the test to load a file initially. If this is
@@ -133,8 +134,8 @@ describe('command_count', function()
let g:lines = []
func BufStatus()
call add(g:lines,
- \ 'aaa: ' . buflisted(g:buf_aaa) .
- \ ' bbb: ' . buflisted(g:buf_bbb) .
+ \ 'aaa: ' . buflisted(g:buf_aaa) .
+ \ ' bbb: ' . buflisted(g:buf_bbb) .
\ ' ccc: ' . buflisted(g:buf_ccc))
endfunc
se nohidden
@@ -214,7 +215,7 @@ describe('command_count', function()
RangeTabsAll 1 5
RangeLines 2 5
LocalRangeLines 2 5
-
+
5argu E16: Invalid range
4argu d
1argu a
@@ -225,7 +226,7 @@ describe('command_count', function()
$tabe 2
$+tabe E16: Invalid range
0tabm x
-
+
aaa: 1 bbb: 1 ccc: 1
aaa: 1 bbb: 0 ccc: 0
aaa: 0 bbb: 0 ccc: 0
diff --git a/test/functional/legacy/erasebackword_spec.lua b/test/functional/legacy/erasebackword_spec.lua
index 33b7704b65..8ca64df328 100644
--- a/test/functional/legacy/erasebackword_spec.lua
+++ b/test/functional/legacy/erasebackword_spec.lua
@@ -6,6 +6,7 @@ local clear, feed, expect = helpers.clear, helpers.feed, helpers.expect
describe('CTRL-W in Insert mode', function()
setup(clear)
+ -- luacheck: ignore 611 (Line contains only whitespaces)
it('works for multi-byte characters', function()
for i = 1, 6 do
diff --git a/test/functional/legacy/increment_spec.lua b/test/functional/legacy/increment_spec.lua
index 15273a4ad5..d51f9a2e02 100644
--- a/test/functional/legacy/increment_spec.lua
+++ b/test/functional/legacy/increment_spec.lua
@@ -685,7 +685,7 @@ describe('Ctrl-A/Ctrl-X on visual selections', function()
" Text:
" 1 23
" 4 56
- "
+ "
" Expected:
" 1) f2 Ctrl-V jl <ctrl-a>, repeat twice afterwards with .
" 1 26
diff --git a/test/functional/legacy/listchars_spec.lua b/test/functional/legacy/listchars_spec.lua
index 3c0fa48e76..cffb9fd376 100644
--- a/test/functional/legacy/listchars_spec.lua
+++ b/test/functional/legacy/listchars_spec.lua
@@ -4,12 +4,14 @@ local helpers = require('test.functional.helpers')(after_each)
local feed, insert, source = helpers.feed, helpers.insert, helpers.source
local clear, feed_command, expect = helpers.clear, helpers.feed_command, helpers.expect
+-- luacheck: ignore 621 (Indentation)
describe("'listchars'", function()
before_each(function()
clear()
feed_command('set listchars&vi')
end)
+ -- luacheck: ignore 613 (Trailing whitespace in a string)
it("works with 'list'", function()
source([[
function GetScreenCharsForLine(lnum)
diff --git a/test/functional/legacy/listlbr_spec.lua b/test/functional/legacy/listlbr_spec.lua
index d39125c9e6..f70d55f4a3 100644
--- a/test/functional/legacy/listlbr_spec.lua
+++ b/test/functional/legacy/listlbr_spec.lua
@@ -7,6 +7,9 @@ local clear, feed_command, expect = helpers.clear, helpers.feed_command, helpers
describe('listlbr', function()
setup(clear)
+ -- luacheck: ignore 621 (Indentation)
+ -- luacheck: ignore 611 (Line contains only whitespaces)
+ -- luacheck: ignore 613 (Trailing whitespaces in a string)
it('is working', function()
insert([[
dummy text]])
@@ -20,20 +23,20 @@ describe('listlbr', function()
feed_command('set ts=4 sw=4 sts=4 linebreak sbr=+ wrap')
source([[
fu! ScreenChar(width)
- let c=''
- for j in range(1,4)
- for i in range(1,a:width)
- let c.=nr2char(screenchar(j, i))
- endfor
- let c.="\n"
- endfor
- return c
+ let c=''
+ for j in range(1,4)
+ for i in range(1,a:width)
+ let c.=nr2char(screenchar(j, i))
+ endfor
+ let c.="\n"
+ endfor
+ return c
endfu
fu! DoRecordScreen()
- wincmd l
- $put =printf(\"\n%s\", g:test)
- $put =g:line
- wincmd p
+ wincmd l
+ $put =printf(\"\n%s\", g:test)
+ $put =g:line
+ wincmd p
endfu
]])
feed_command('let g:test="Test 1: set linebreak"')
diff --git a/test/functional/legacy/listlbr_utf8_spec.lua b/test/functional/legacy/listlbr_utf8_spec.lua
index f06bca72ba..d7f4c71af2 100644
--- a/test/functional/legacy/listlbr_utf8_spec.lua
+++ b/test/functional/legacy/listlbr_utf8_spec.lua
@@ -8,6 +8,8 @@ local clear, expect = helpers.clear, helpers.expect
describe('linebreak', function()
setup(clear)
+ -- luacheck: ignore 621 (Indentation)
+ -- luacheck: ignore 613 (Trailing whitespaces in a string)
it('is working', function()
source([[
set wildchar=^E
@@ -18,20 +20,20 @@ describe('linebreak', function()
norm! zt
set ts=4 sw=4 sts=4 linebreak sbr=+ wrap
fu! ScreenChar(width, lines)
- let c=''
- for j in range(1,a:lines)
- for i in range(1,a:width)
- let c.=nr2char(screenchar(j, i))
- endfor
+ let c=''
+ for j in range(1,a:lines)
+ for i in range(1,a:width)
+ let c.=nr2char(screenchar(j, i))
+ endfor
let c.="\n"
- endfor
- return c
+ endfor
+ return c
endfu
fu! DoRecordScreen()
- wincmd l
- $put =printf(\"\n%s\", g:test)
- $put =g:line
- wincmd p
+ wincmd l
+ $put =printf(\"\n%s\", g:test)
+ $put =g:line
+ wincmd p
endfu
"
let g:test ="Test 1: set linebreak + set list + fancy listchars"
@@ -148,22 +150,22 @@ describe('linebreak', function()
-- Assert buffer contents.
expect([[
-
+
abcdef hijklmn pqrstuvwxyz 1060ABCDEFGHIJKLMNOP
-
+
Test 1: set linebreak + set list + fancy listchars
▕———abcdef
+hijklmn▕———
+pqrstuvwxyz␣1060ABC
+DEFGHIJKLMNOPˑ¶
-
+
Test 2: set nolinebreak list
▕———abcdef hijklmn▕—
+pqrstuvwxyz␣1060ABC
+DEFGHIJKLMNOPˑ¶
*mask = nil;
-
+
Test 3: set linebreak nolist
*mask = nil;
~
@@ -177,7 +179,7 @@ describe('linebreak', function()
#define MSG_MODE_CONSOLE 2
#define MSG_MODE_FILE_AND_CONSOLE 3
#define MSG_MODE_FILE_THEN_CONSOLE 4
-
+
Test 4: set linebreak list listchars and concealing
#define ABCDE>-->---1
#define >CDEF>-->---1
@@ -187,7 +189,7 @@ describe('linebreak', function()
#define >_CONSOLE>---------->---2
#define >_FILE_AND_CONSOLE>---------3
bbeeeeee ; some text
-
+
Test 5: set linebreak list listchars and concealing part2
eeeeee>--->-;>some text
Test 6: Screenattributes for comment
@@ -196,10 +198,10 @@ describe('linebreak', function()
Attribut 0 and 1 and 3 and 5 are different!
Test 8: set linebreak with visual block mode and v_b_A and selection=exclusive and multibyte char
long line: foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar TARGETÃx' at end
-
+
a b c
a b c
-
+
Test 9: a multibyte sign and colorcolumn
+a b c¶
diff --git a/test/functional/legacy/marks_spec.lua b/test/functional/legacy/marks_spec.lua
index bcec179ca2..470ea49652 100644
--- a/test/functional/legacy/marks_spec.lua
+++ b/test/functional/legacy/marks_spec.lua
@@ -7,6 +7,7 @@ describe('marks', function()
clear()
end)
+ -- luacheck: ignore 621 (Indentation)
it('restores a deleted mark after delete-undo-redo-undo', function()
insert([[
diff --git a/test/functional/legacy/options_spec.lua b/test/functional/legacy/options_spec.lua
index 4f4d4ceaf9..1db7afc7a7 100644
--- a/test/functional/legacy/options_spec.lua
+++ b/test/functional/legacy/options_spec.lua
@@ -21,7 +21,7 @@ describe('set', function()
$put =&path]])
expect([[
-
+
foo,,bar]])
end)
end)
diff --git a/test/functional/legacy/packadd_spec.lua b/test/functional/legacy/packadd_spec.lua
index c280888dda..2dfd36142b 100644
--- a/test/functional/legacy/packadd_spec.lua
+++ b/test/functional/legacy/packadd_spec.lua
@@ -83,6 +83,41 @@ describe('packadd', function()
call assert_equal(new_rtp, &rtp)
endfunc
+ func Test_packadd_symlink_dir()
+ if !has('unix')
+ return
+ endif
+ let top2_dir = s:topdir . '/Xdir2'
+ let real_dir = s:topdir . '/Xsym'
+ call mkdir(real_dir, 'p')
+ exec "silent! !ln -s Xsym" top2_dir
+ let &rtp = top2_dir . ',' . top2_dir . '/after'
+ let &packpath = &rtp
+
+ let s:plugdir = top2_dir . '/pack/mine/opt/mytest'
+ call mkdir(s:plugdir . '/plugin', 'p')
+
+ exe 'split ' . s:plugdir . '/plugin/test.vim'
+ call setline(1, 'let g:plugin_works = 44')
+ wq
+ let g:plugin_works = 0
+
+ packadd mytest
+
+ " Must have been inserted in the middle, not at the end
+ call assert_true(&rtp =~ '/pack/mine/opt/mytest,')
+ call assert_equal(44, g:plugin_works)
+
+ " No change when doing it again.
+ let rtp_before = &rtp
+ packadd mytest
+ call assert_equal(rtp_before, &rtp)
+
+ set rtp&
+ let rtp = &rtp
+ exec "silent !rm" top2_dir
+ endfunc
+
func Test_packloadall()
" plugin foo with an autoload directory
let fooplugindir = &packpath . '/pack/mine/start/foo/plugin'
@@ -137,9 +172,9 @@ describe('packadd', function()
helptags ALL
- let tags1 = readfile(docdir1 . '/tags')
+ let tags1 = readfile(docdir1 . '/tags')
call assert_true(tags1[0] =~ 'look-here')
- let tags2 = readfile(docdir2 . '/tags')
+ let tags2 = readfile(docdir2 . '/tags')
call assert_true(tags2[0] =~ 'look-away')
endfunc
@@ -227,6 +262,11 @@ describe('packadd', function()
expected_empty()
end)
+ it('works with symlinks', function()
+ call('Test_packadd_symlink_dir')
+ expected_empty()
+ end)
+
it('works with :packloadall', function()
call('Test_packloadall')
expected_empty()
diff --git a/test/functional/legacy/tagcase_spec.lua b/test/functional/legacy/tagcase_spec.lua
index ed2876a375..9ca0e0009f 100644
--- a/test/functional/legacy/tagcase_spec.lua
+++ b/test/functional/legacy/tagcase_spec.lua
@@ -53,11 +53,11 @@ describe("'tagcase' option", function()
-- Verify that the correct number of matching tags is found for all values of
-- 'ignorecase' and global and local values 'tagcase', in all combinations.
insert([[
-
+
Foo
Bar
foo
-
+
end text]])
source([[
@@ -70,7 +70,7 @@ describe("'tagcase' option", function()
endfor
endfor
endfor
-
+
1,/^end text$/d]])
expect([[
diff --git a/test/functional/legacy/utf8_spec.lua b/test/functional/legacy/utf8_spec.lua
index 02de6ab735..5b93f25b24 100644
--- a/test/functional/legacy/utf8_spec.lua
+++ b/test/functional/legacy/utf8_spec.lua
@@ -54,6 +54,7 @@ describe('utf8', function()
eq(1, eval('strchars("\\u20dd", 1)'))
end)
+ -- luacheck: ignore 613 (Trailing whitespace in a string)
it('customlist completion', function()
source([[
function! CustomComplete1(lead, line, pos)
diff --git a/test/functional/plugin/health_spec.lua b/test/functional/plugin/health_spec.lua
index 3739540b09..8646ec98bf 100644
--- a/test/functional/plugin/health_spec.lua
+++ b/test/functional/plugin/health_spec.lua
@@ -1,4 +1,5 @@
local helpers = require('test.functional.helpers')(after_each)
+local Screen = require('test.functional.ui.screen')
local plugin_helpers = require('test.functional.plugin.helpers')
local command = helpers.command
@@ -30,13 +31,13 @@ describe('health.vim', function()
## Check Bar
- - SUCCESS: Bar status
- - SUCCESS: Other Bar status
+ - OK: Bar status
+ - OK: Other Bar status
- WARNING: Zub
## Baz
- WARNING: Zim
- - SUGGESTIONS:
+ - ADVICE:
- suggestion 1
- suggestion 2]]),
result)
@@ -51,15 +52,15 @@ describe('health.vim', function()
health#success1#check
========================================================================
## report 1
- - SUCCESS: everything is fine
+ - OK: everything is fine
## report 2
- - SUCCESS: nothing to see here
+ - OK: nothing to see here
health#success2#check
========================================================================
## another 1
- - SUCCESS: ok
+ - OK: ok
]])
end)
@@ -75,6 +76,36 @@ describe('health.vim', function()
]])
end)
+ it("highlights OK, ERROR", function()
+ local screen = Screen.new(72, 10)
+ screen:attach()
+ screen:set_default_attr_ids({
+ Ok = { foreground = Screen.colors.Grey3, background = 6291200 },
+ Error = { foreground = Screen.colors.Grey100, background = Screen.colors.Red },
+ })
+ screen:set_default_attr_ignore({
+ Heading = { bold=true, foreground=Screen.colors.Magenta },
+ Heading2 = { foreground = Screen.colors.SlateBlue },
+ Bar = { foreground=Screen.colors.Purple },
+ Bullet = { bold=true, foreground=Screen.colors.Brown },
+ })
+ command("CheckHealth foo success1")
+ command("1tabclose")
+ command("set laststatus=0")
+ screen:expect([[
+ ^ |
+ health#foo#check |
+ ========================================================================|
+ - {Error:ERROR:} No healthcheck found for "foo" plugin. |
+ |
+ health#success1#check |
+ ========================================================================|
+ ## report 1 |
+ - {Ok:OK:} everything is fine |
+ |
+ ]])
+ end)
+
it("gracefully handles invalid healthcheck", function()
command("CheckHealth non_existent_healthcheck")
helpers.expect([[
diff --git a/test/functional/shada/compatibility_spec.lua b/test/functional/shada/compatibility_spec.lua
index 1287ac010c..a5ef60d91f 100644
--- a/test/functional/shada/compatibility_spec.lua
+++ b/test/functional/shada/compatibility_spec.lua
@@ -10,6 +10,13 @@ local read_shada_file = shada_helpers.read_shada_file
local wshada, sdrcmd, shada_fname = get_shada_rw('Xtest-functional-shada-compatibility.shada')
+local mock_file_path = '/a/b/'
+local mock_file_path2 = '/d/e/'
+if helpers.iswin() then
+ mock_file_path = 'C:/a/'
+ mock_file_path2 = 'C:/d/'
+end
+
describe('ShaDa forward compatibility support code', function()
before_each(reset)
after_each(function()
@@ -114,14 +121,14 @@ describe('ShaDa forward compatibility support code', function()
funcs.garbagecollect(1)
end)
- for _, v in ipairs({{name='global mark', mpack='\007\001\018\131\162mX\195\161f\196\006/a/b/c\161nA'},
- {name='jump', mpack='\008\001\018\131\162mX\195\161f\196\006/a/b/c\161l\002'},
- {name='local mark', mpack='\010\001\018\131\162mX\195\161f\196\006/a/b/c\161na'},
- {name='change', mpack='\011\001\015\130\162mX\195\161f\196\006/a/b/c'},
+ for _, v in ipairs({{name='global mark', mpack='\007\001\018\131\162mX\195\161f\196\006' .. mock_file_path .. 'c\161nA'},
+ {name='jump', mpack='\008\001\018\131\162mX\195\161f\196\006' .. mock_file_path .. 'c\161l\002'},
+ {name='local mark', mpack='\010\001\018\131\162mX\195\161f\196\006' .. mock_file_path .. 'c\161na'},
+ {name='change', mpack='\011\001\015\130\162mX\195\161f\196\006' .. mock_file_path .. 'c'},
}) do
it('works with ' .. v.name .. ' item with BOOL unknown (mX) key value', function()
- nvim_command('silent noautocmd edit /a/b/c')
- eq('/a/b/c', funcs.bufname('%'))
+ nvim_command('silent noautocmd edit ' .. mock_file_path .. 'c')
+ eq('' .. mock_file_path .. 'c', funcs.bufname('%'))
funcs.setline('.', {'1', '2', '3'})
wshada(v.mpack)
eq(0, exc_exec(sdrcmd(true)))
@@ -159,12 +166,12 @@ describe('ShaDa forward compatibility support code', function()
if v.name == 'global mark' or v.name == 'local mark' then
it('works with ' .. v.name .. ' item with <C-a> name', function()
- nvim_command('silent noautocmd edit /a/b/c')
- eq('/a/b/c', funcs.bufname('%'))
+ nvim_command('silent noautocmd edit ' .. mock_file_path .. 'c')
+ eq('' .. mock_file_path .. 'c', funcs.bufname('%'))
funcs.setline('.', {'1', '2', '3'})
wshada(v.mpack:gsub('n.$', 'n\001')
.. v.mpack:gsub('n.$', 'n\002')
- .. v.mpack:gsub('n.$', 'n\003'):gsub('/a/b/c', '/d/e/f'))
+ .. v.mpack:gsub('n.$', 'n\003'):gsub('' .. mock_file_path .. 'c', '' .. mock_file_path2 .. 'f'))
eq(0, exc_exec(sdrcmd(true)))
nvim_command('wshada ' .. shada_fname)
local found = 0
@@ -307,10 +314,10 @@ describe('ShaDa forward compatibility support code', function()
it('works with buffer list item with BOOL unknown (bX) key', function()
nvim_command('set shada+=%')
- wshada('\009\000\016\145\130\161f\196\006/a/b/c\162bX\195')
+ wshada('\009\000\016\145\130\161f\196\006' .. mock_file_path .. 'c\162bX\195')
eq(0, exc_exec(sdrcmd()))
eq(2, funcs.bufnr('$'))
- eq('/a/b/c', funcs.bufname(2))
+ eq('' .. mock_file_path .. 'c', funcs.bufname(2))
os.remove(shada_fname)
nvim_command('wshada ' .. shada_fname)
local found = false
diff --git a/test/functional/shada/merging_spec.lua b/test/functional/shada/merging_spec.lua
index 25c73b99eb..7a15c8908b 100644
--- a/test/functional/shada/merging_spec.lua
+++ b/test/functional/shada/merging_spec.lua
@@ -13,6 +13,11 @@ local read_shada_file = shada_helpers.read_shada_file
local wshada, sdrcmd, shada_fname =
get_shada_rw('Xtest-functional-shada-merging.shada')
+local mock_file_path = '/a/b/'
+if helpers.iswin() then
+ mock_file_path = 'C:/a/'
+end
+
describe('ShaDa history merging code', function()
before_each(reset)
after_each(function()
@@ -512,9 +517,9 @@ describe('ShaDa marks support code', function()
it('uses last A mark with gt timestamp from instance when reading',
function()
- wshada('\007\001\018\131\162mX\195\161f\196\006/a/b/-\161nA')
+ wshada('\007\001\018\131\162mX\195\161f\196\006' .. mock_file_path .. '-\161nA')
eq(0, exc_exec(sdrcmd()))
- wshada('\007\000\018\131\162mX\195\161f\196\006/a/b/?\161nA')
+ wshada('\007\000\018\131\162mX\195\161f\196\006' .. mock_file_path .. '?\161nA')
eq(0, exc_exec(sdrcmd()))
nvim_command('normal! `A')
eq('-', funcs.fnamemodify(curbufmeths.get_name(), ':t'))
@@ -522,9 +527,9 @@ describe('ShaDa marks support code', function()
it('uses last A mark with gt timestamp from file when reading with !',
function()
- wshada('\007\001\018\131\162mX\195\161f\196\006/a/b/-\161nA')
+ wshada('\007\001\018\131\162mX\195\161f\196\006' .. mock_file_path .. '-\161nA')
eq(0, exc_exec(sdrcmd()))
- wshada('\007\000\018\131\162mX\195\161f\196\006/a/b/?\161nA')
+ wshada('\007\000\018\131\162mX\195\161f\196\006' .. mock_file_path .. '?\161nA')
eq(0, exc_exec(sdrcmd(true)))
nvim_command('normal! `A')
eq('?', funcs.fnamemodify(curbufmeths.get_name(), ':t'))
@@ -532,9 +537,9 @@ describe('ShaDa marks support code', function()
it('uses last A mark with eq timestamp from instance when reading',
function()
- wshada('\007\001\018\131\162mX\195\161f\196\006/a/b/-\161nA')
+ wshada('\007\001\018\131\162mX\195\161f\196\006' .. mock_file_path .. '-\161nA')
eq(0, exc_exec(sdrcmd()))
- wshada('\007\001\018\131\162mX\195\161f\196\006/a/b/?\161nA')
+ wshada('\007\001\018\131\162mX\195\161f\196\006' .. mock_file_path .. '?\161nA')
eq(0, exc_exec(sdrcmd()))
nvim_command('normal! `A')
eq('-', funcs.fnamemodify(curbufmeths.get_name(), ':t'))
@@ -542,9 +547,9 @@ describe('ShaDa marks support code', function()
it('uses last A mark with gt timestamp from file when reading',
function()
- wshada('\007\001\018\131\162mX\195\161f\196\006/a/b/-\161nA')
+ 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/a/b/?\161nA')
+ wshada('\007\002\018\131\162mX\195\161f\196\006' .. mock_file_path .. '?\161nA')
eq(0, exc_exec(sdrcmd()))
nvim_command('normal! `A')
eq('?', funcs.fnamemodify(curbufmeths.get_name(), ':t'))
@@ -552,15 +557,15 @@ describe('ShaDa marks support code', function()
it('uses last A mark with gt timestamp from instance when writing',
function()
- wshada('\007\001\018\131\162mX\195\161f\196\006/a/b/-\161nA')
+ wshada('\007\001\018\131\162mX\195\161f\196\006' .. mock_file_path .. '-\161nA')
eq(0, exc_exec(sdrcmd()))
- wshada('\007\000\018\131\162mX\195\161f\196\006/a/b/?\161nA')
+ wshada('\007\000\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
for _, v in ipairs(read_shada_file(shada_fname)) do
- if v.type == 7 and v.value.f == '/a/b/-' then
+ if v.type == 7 and v.value.f == '' .. mock_file_path .. '-' then
found = found + 1
end
end
@@ -569,15 +574,15 @@ describe('ShaDa marks support code', function()
it('uses last A mark with eq timestamp from instance when writing',
function()
- wshada('\007\001\018\131\162mX\195\161f\196\006/a/b/-\161nA')
+ wshada('\007\001\018\131\162mX\195\161f\196\006' .. mock_file_path .. '-\161nA')
eq(0, exc_exec(sdrcmd()))
- wshada('\007\001\018\131\162mX\195\161f\196\006/a/b/?\161nA')
+ wshada('\007\001\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
for _, v in ipairs(read_shada_file(shada_fname)) do
- if v.type == 7 and v.value.f == '/a/b/-' then
+ if v.type == 7 and v.value.f == mock_file_path .. '-' then
found = found + 1
end
end
@@ -586,15 +591,15 @@ describe('ShaDa marks support code', function()
it('uses last A mark with gt timestamp from file when writing',
function()
- wshada('\007\001\018\131\162mX\195\161f\196\006/a/b/-\161nA')
+ 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/a/b/?\161nA')
+ 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
for _, v in ipairs(read_shada_file(shada_fname)) do
- if v.type == 7 and v.value.f == '/a/b/?' then
+ if v.type == 7 and v.value.f == '' .. mock_file_path .. '?' then
found = found + 1
end
end
@@ -603,11 +608,11 @@ describe('ShaDa marks support code', function()
it('uses last a mark with gt timestamp from instance when reading',
function()
- nvim_command('edit /a/b/-')
+ nvim_command('edit ' .. mock_file_path .. '-')
funcs.setline(1, {'-', '?'})
- wshada('\010\001\017\131\161l\001\161f\196\006/a/b/-\161na')
+ wshada('\010\001\017\131\161l\001\161f\196\006' .. mock_file_path .. '-\161na')
eq(0, exc_exec(sdrcmd()))
- wshada('\010\000\017\131\161l\002\161f\196\006/a/b/-\161na')
+ wshada('\010\000\017\131\161l\002\161f\196\006' .. mock_file_path .. '-\161na')
eq(0, exc_exec(sdrcmd()))
nvim_command('normal! `a')
eq('-', funcs.getline('.'))
@@ -615,11 +620,11 @@ describe('ShaDa marks support code', function()
it('uses last a mark with gt timestamp from file when reading with !',
function()
- nvim_command('edit /a/b/-')
+ nvim_command('edit ' .. mock_file_path .. '-')
funcs.setline(1, {'-', '?'})
- wshada('\010\001\017\131\161l\001\161f\196\006/a/b/-\161na')
+ wshada('\010\001\017\131\161l\001\161f\196\006' .. mock_file_path .. '-\161na')
eq(0, exc_exec(sdrcmd()))
- wshada('\010\000\017\131\161l\002\161f\196\006/a/b/-\161na')
+ wshada('\010\000\017\131\161l\002\161f\196\006' .. mock_file_path .. '-\161na')
eq(0, exc_exec(sdrcmd(true)))
nvim_command('normal! `a')
eq('?', funcs.getline('.'))
@@ -627,11 +632,11 @@ describe('ShaDa marks support code', function()
it('uses last a mark with eq timestamp from instance when reading',
function()
- nvim_command('edit /a/b/-')
+ nvim_command('edit ' .. mock_file_path .. '-')
funcs.setline(1, {'-', '?'})
- wshada('\010\001\017\131\161l\001\161f\196\006/a/b/-\161na')
+ wshada('\010\001\017\131\161l\001\161f\196\006' .. mock_file_path .. '-\161na')
eq(0, exc_exec(sdrcmd()))
- wshada('\010\001\017\131\161l\002\161f\196\006/a/b/-\161na')
+ wshada('\010\001\017\131\161l\002\161f\196\006' .. mock_file_path .. '-\161na')
eq(0, exc_exec(sdrcmd()))
nvim_command('normal! `a')
eq('-', funcs.getline('.'))
@@ -639,11 +644,11 @@ describe('ShaDa marks support code', function()
it('uses last a mark with gt timestamp from file when reading',
function()
- nvim_command('edit /a/b/-')
+ nvim_command('edit ' .. mock_file_path .. '-')
funcs.setline(1, {'-', '?'})
- wshada('\010\001\017\131\161l\001\161f\196\006/a/b/-\161na')
+ wshada('\010\001\017\131\161l\001\161f\196\006' .. mock_file_path .. '-\161na')
eq(0, exc_exec(sdrcmd()))
- wshada('\010\002\017\131\161l\002\161f\196\006/a/b/-\161na')
+ wshada('\010\002\017\131\161l\002\161f\196\006' .. mock_file_path .. '-\161na')
eq(0, exc_exec(sdrcmd()))
nvim_command('normal! `a')
eq('?', funcs.getline('.'))
@@ -651,17 +656,17 @@ describe('ShaDa marks support code', function()
it('uses last a mark with gt timestamp from instance when writing',
function()
- nvim_command('edit /a/b/-')
+ nvim_command('edit ' .. mock_file_path .. '-')
funcs.setline(1, {'-', '?'})
- wshada('\010\001\017\131\161l\001\161f\196\006/a/b/-\161na')
+ wshada('\010\001\017\131\161l\001\161f\196\006' .. mock_file_path .. '-\161na')
eq(0, exc_exec(sdrcmd()))
- wshada('\010\000\017\131\161l\002\161f\196\006/a/b/-\161na')
+ wshada('\010\000\017\131\161l\002\161f\196\006' .. mock_file_path .. '-\161na')
nvim_command('normal! `a')
eq('-', funcs.getline('.'))
eq(0, exc_exec('wshada ' .. shada_fname))
local found = 0
for _, v in ipairs(read_shada_file(shada_fname)) do
- if v.type == 10 and v.value.f == '/a/b/-' and v.value.n == ('a'):byte() then
+ if v.type == 10 and v.value.f == '' .. mock_file_path .. '-' and v.value.n == ('a'):byte() then
eq(true, v.value.l == 1 or v.value.l == nil)
found = found + 1
end
@@ -671,17 +676,17 @@ describe('ShaDa marks support code', function()
it('uses last a mark with eq timestamp from instance when writing',
function()
- nvim_command('edit /a/b/-')
+ nvim_command('edit ' .. mock_file_path .. '-')
funcs.setline(1, {'-', '?'})
- wshada('\010\001\017\131\161l\001\161f\196\006/a/b/-\161na')
+ wshada('\010\001\017\131\161l\001\161f\196\006' .. mock_file_path .. '-\161na')
eq(0, exc_exec(sdrcmd()))
- wshada('\010\001\017\131\161l\002\161f\196\006/a/b/-\161na')
+ wshada('\010\001\017\131\161l\002\161f\196\006' .. mock_file_path .. '-\161na')
nvim_command('normal! `a')
eq('-', funcs.getline('.'))
eq(0, exc_exec('wshada ' .. shada_fname))
local found = 0
for _, v in ipairs(read_shada_file(shada_fname)) do
- if v.type == 10 and v.value.f == '/a/b/-' and v.value.n == ('a'):byte() then
+ if v.type == 10 and v.value.f == '' .. mock_file_path .. '-' and v.value.n == ('a'):byte() then
eq(true, v.value.l == 1 or v.value.l == nil)
found = found + 1
end
@@ -691,17 +696,17 @@ describe('ShaDa marks support code', function()
it('uses last a mark with gt timestamp from file when writing',
function()
- nvim_command('edit /a/b/-')
+ nvim_command('edit ' .. mock_file_path .. '-')
funcs.setline(1, {'-', '?'})
- wshada('\010\001\017\131\161l\001\161f\196\006/a/b/-\161na')
+ wshada('\010\001\017\131\161l\001\161f\196\006' .. mock_file_path .. '-\161na')
eq(0, exc_exec(sdrcmd()))
- wshada('\010\002\017\131\161l\002\161f\196\006/a/b/-\161na')
+ wshada('\010\002\017\131\161l\002\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
for _, v in ipairs(read_shada_file(shada_fname)) do
- if v.type == 10 and v.value.f == '/a/b/-' and v.value.n == ('a'):byte() then
+ if v.type == 10 and v.value.f == '' .. mock_file_path .. '-' and v.value.n == ('a'):byte() then
eq(2, v.value.l)
found = found + 1
end
@@ -813,41 +818,41 @@ describe('ShaDa jumps support code', function()
end)
it('merges jumps when reading', function()
- wshada('\008\001\018\131\162mX\195\161f\196\006/a/b/c\161l\002'
- .. '\008\004\018\131\162mX\195\161f\196\006/a/b/d\161l\002'
- .. '\008\007\018\131\162mX\195\161f\196\006/a/b/e\161l\002')
+ wshada('\008\001\018\131\162mX\195\161f\196\006' .. mock_file_path .. 'c\161l\002'
+ .. '\008\004\018\131\162mX\195\161f\196\006' .. mock_file_path .. 'd\161l\002'
+ .. '\008\007\018\131\162mX\195\161f\196\006' .. mock_file_path .. 'e\161l\002')
eq(0, exc_exec(sdrcmd()))
- wshada('\008\001\018\131\162mX\195\161f\196\006/a/b/c\161l\002'
- .. '\008\004\018\131\162mX\195\161f\196\006/a/b/d\161l\003'
- .. '\008\007\018\131\162mX\195\161f\196\006/a/b/f\161l\002')
+ wshada('\008\001\018\131\162mX\195\161f\196\006' .. mock_file_path .. 'c\161l\002'
+ .. '\008\004\018\131\162mX\195\161f\196\006' .. mock_file_path .. 'd\161l\003'
+ .. '\008\007\018\131\162mX\195\161f\196\006' .. mock_file_path .. 'f\161l\002')
eq(0, exc_exec(sdrcmd()))
eq('', curbufmeths.get_name())
eq('\n'
.. ' jump line col file/text\n'
- .. ' 6 2 0 /a/b/c\n'
- .. ' 5 2 0 /a/b/d\n'
- .. ' 4 3 0 /a/b/d\n'
- .. ' 3 2 0 /a/b/e\n'
- .. ' 2 2 0 /a/b/f\n'
+ .. ' 6 2 0 ' .. mock_file_path .. 'c\n'
+ .. ' 5 2 0 ' .. mock_file_path .. 'd\n'
+ .. ' 4 3 0 ' .. mock_file_path .. 'd\n'
+ .. ' 3 2 0 ' .. mock_file_path .. 'e\n'
+ .. ' 2 2 0 ' .. mock_file_path .. 'f\n'
.. ' 1 1 0 \n'
.. '>', redir_exec('jumps'))
end)
it('merges jumps when writing', function()
- wshada('\008\001\018\131\162mX\195\161f\196\006/a/b/c\161l\002'
- .. '\008\004\018\131\162mX\195\161f\196\006/a/b/d\161l\002'
- .. '\008\007\018\131\162mX\195\161f\196\006/a/b/e\161l\002')
+ wshada('\008\001\018\131\162mX\195\161f\196\006' .. mock_file_path .. 'c\161l\002'
+ .. '\008\004\018\131\162mX\195\161f\196\006' .. mock_file_path .. 'd\161l\002'
+ .. '\008\007\018\131\162mX\195\161f\196\006' .. mock_file_path .. 'e\161l\002')
eq(0, exc_exec(sdrcmd()))
- wshada('\008\001\018\131\162mX\195\161f\196\006/a/b/c\161l\002'
- .. '\008\004\018\131\162mX\195\161f\196\006/a/b/d\161l\003'
- .. '\008\007\018\131\162mX\195\161f\196\006/a/b/f\161l\002')
+ wshada('\008\001\018\131\162mX\195\161f\196\006' .. mock_file_path .. 'c\161l\002'
+ .. '\008\004\018\131\162mX\195\161f\196\006' .. mock_file_path .. 'd\161l\003'
+ .. '\008\007\018\131\162mX\195\161f\196\006' .. mock_file_path .. 'f\161l\002')
eq(0, exc_exec('wshada ' .. shada_fname))
local jumps = {
- {file='/a/b/c', line=2},
- {file='/a/b/d', line=2},
- {file='/a/b/d', line=3},
- {file='/a/b/e', line=2},
- {file='/a/b/f', line=2},
+ {file='' .. mock_file_path .. 'c', line=2},
+ {file='' .. mock_file_path .. 'd', line=2},
+ {file='' .. mock_file_path .. 'd', line=3},
+ {file='' .. mock_file_path .. 'e', line=2},
+ {file='' .. mock_file_path .. 'f', line=2},
}
local found = 0
for _, v in ipairs(read_shada_file(shada_fname)) do
@@ -864,9 +869,9 @@ describe('ShaDa jumps support code', function()
local jumps = {}
local shada = ''
for i = 1,100 do
- shada = shada .. ('\008%c\018\131\162mX\195\161f\196\006/a/b/c\161l%c'
+ shada = shada .. ('\008%c\018\131\162mX\195\161f\196\006' .. mock_file_path .. 'c\161l%c'
):format(i, i)
- jumps[i] = {file='/a/b/c', line=i}
+ jumps[i] = {file='' .. mock_file_path .. 'c', line=i}
end
wshada(shada)
eq(0, exc_exec(sdrcmd()))
@@ -874,9 +879,9 @@ describe('ShaDa jumps support code', function()
for i = 1,101 do
local t = i * 2
shada = shada .. (
- '\008\204%c\019\131\162mX\195\161f\196\006/a/b/c\161l\204%c'
+ '\008\204%c\019\131\162mX\195\161f\196\006' .. mock_file_path .. 'c\161l\204%c'
):format(t, t)
- jumps[(t > #jumps + 1) and (#jumps + 1) or t] = {file='/a/b/c', line=t}
+ jumps[(t > #jumps + 1) and (#jumps + 1) or t] = {file='' .. mock_file_path .. 'c', line=t}
end
wshada(shada)
eq(0, exc_exec('wshada ' .. shada_fname))
@@ -904,15 +909,15 @@ describe('ShaDa changes support code', function()
end)
it('merges changes when reading', function()
- nvim_command('edit /a/b/c')
+ nvim_command('edit ' .. mock_file_path .. 'c')
nvim_command('keepjumps call setline(1, range(7))')
- wshada('\011\001\018\131\162mX\195\161f\196\006/a/b/c\161l\001'
- .. '\011\004\018\131\162mX\195\161f\196\006/a/b/c\161l\002'
- .. '\011\007\018\131\162mX\195\161f\196\006/a/b/c\161l\003')
+ wshada('\011\001\018\131\162mX\195\161f\196\006' .. mock_file_path .. 'c\161l\001'
+ .. '\011\004\018\131\162mX\195\161f\196\006' .. mock_file_path .. 'c\161l\002'
+ .. '\011\007\018\131\162mX\195\161f\196\006' .. mock_file_path .. 'c\161l\003')
eq(0, exc_exec(sdrcmd()))
- wshada('\011\001\018\131\162mX\194\161f\196\006/a/b/c\161l\001'
- .. '\011\004\018\131\162mX\195\161f\196\006/a/b/c\161l\005'
- .. '\011\008\018\131\162mX\195\161f\196\006/a/b/c\161l\004')
+ wshada('\011\001\018\131\162mX\194\161f\196\006' .. mock_file_path .. 'c\161l\001'
+ .. '\011\004\018\131\162mX\195\161f\196\006' .. mock_file_path .. 'c\161l\005'
+ .. '\011\008\018\131\162mX\195\161f\196\006' .. mock_file_path .. 'c\161l\004')
eq(0, exc_exec(sdrcmd()))
eq('\n'
.. 'change line col text\n'
@@ -925,15 +930,15 @@ describe('ShaDa changes support code', function()
end)
it('merges changes when writing', function()
- nvim_command('edit /a/b/c')
+ nvim_command('edit ' .. mock_file_path .. 'c')
nvim_command('keepjumps call setline(1, range(7))')
- wshada('\011\001\018\131\162mX\195\161f\196\006/a/b/c\161l\001'
- .. '\011\004\018\131\162mX\195\161f\196\006/a/b/c\161l\002'
- .. '\011\007\018\131\162mX\195\161f\196\006/a/b/c\161l\003')
+ wshada('\011\001\018\131\162mX\195\161f\196\006' .. mock_file_path .. 'c\161l\001'
+ .. '\011\004\018\131\162mX\195\161f\196\006' .. mock_file_path .. 'c\161l\002'
+ .. '\011\007\018\131\162mX\195\161f\196\006' .. mock_file_path .. 'c\161l\003')
eq(0, exc_exec(sdrcmd()))
- wshada('\011\001\018\131\162mX\194\161f\196\006/a/b/c\161l\001'
- .. '\011\004\018\131\162mX\195\161f\196\006/a/b/c\161l\005'
- .. '\011\008\018\131\162mX\195\161f\196\006/a/b/c\161l\004')
+ wshada('\011\001\018\131\162mX\194\161f\196\006' .. mock_file_path .. 'c\161l\001'
+ .. '\011\004\018\131\162mX\195\161f\196\006' .. mock_file_path .. 'c\161l\005'
+ .. '\011\008\018\131\162mX\195\161f\196\006' .. mock_file_path .. 'c\161l\004')
eq(0, exc_exec('wshada ' .. shada_fname))
local changes = {
{line=1},
@@ -944,7 +949,7 @@ describe('ShaDa changes support code', function()
}
local found = 0
for _, v in ipairs(read_shada_file(shada_fname)) do
- if v.type == 11 and v.value.f == '/a/b/c' then
+ if v.type == 11 and v.value.f == '' .. mock_file_path .. 'c' then
found = found + 1
eq(changes[found].line, v.value.l or 1)
end
@@ -953,12 +958,12 @@ describe('ShaDa changes support code', function()
end)
it('merges JUMPLISTSIZE changes when writing', function()
- nvim_command('edit /a/b/c')
+ nvim_command('edit ' .. mock_file_path .. 'c')
nvim_command('keepjumps call setline(1, range(202))')
local changes = {}
local shada = ''
for i = 1,100 do
- shada = shada .. ('\011%c\018\131\162mX\195\161f\196\006/a/b/c\161l%c'
+ shada = shada .. ('\011%c\018\131\162mX\195\161f\196\006' .. mock_file_path .. 'c\161l%c'
):format(i, i)
changes[i] = {line=i}
end
@@ -968,7 +973,7 @@ describe('ShaDa changes support code', function()
for i = 1,101 do
local t = i * 2
shada = shada .. (
- '\011\204%c\019\131\162mX\195\161f\196\006/a/b/c\161l\204%c'
+ '\011\204%c\019\131\162mX\195\161f\196\006' .. mock_file_path .. 'c\161l\204%c'
):format(t, t)
changes[(t > #changes + 1) and (#changes + 1) or t] = {line=t}
end
@@ -980,7 +985,7 @@ describe('ShaDa changes support code', function()
end
local found = 0
for _, v in ipairs(read_shada_file(shada_fname)) do
- if v.type == 11 and v.value.f == '/a/b/c' then
+ if v.type == 11 and v.value.f == '' .. mock_file_path .. 'c' then
found = found + 1
eq(changes[found].line, v.value.l)
end
@@ -990,20 +995,20 @@ describe('ShaDa changes support code', function()
it('merges JUMPLISTSIZE changes when writing, with new items between old',
function()
- nvim_command('edit /a/b/c')
+ nvim_command('edit ' .. mock_file_path .. 'c')
nvim_command('keepjumps call setline(1, range(202))')
local shada = ''
for i = 1,101 do
local t = i * 2
shada = shada .. (
- '\011\204%c\019\131\162mX\195\161f\196\006/a/b/c\161l\204%c'
+ '\011\204%c\019\131\162mX\195\161f\196\006' .. mock_file_path .. 'c\161l\204%c'
):format(t, t)
end
wshada(shada)
eq(0, exc_exec(sdrcmd()))
shada = ''
for i = 1,100 do
- shada = shada .. ('\011%c\018\131\162mX\195\161f\196\006/a/b/c\161l%c'
+ shada = shada .. ('\011%c\018\131\162mX\195\161f\196\006' .. mock_file_path .. 'c\161l%c'
):format(i, i)
end
local changes = {}
@@ -1022,7 +1027,7 @@ describe('ShaDa changes support code', function()
end
local found = 0
for _, v in ipairs(read_shada_file(shada_fname)) do
- if v.type == 11 and v.value.f == '/a/b/c' then
+ if v.type == 11 and v.value.f == '' .. mock_file_path .. 'c' then
found = found + 1
eq(changes[found].line, v.value.l)
end
@@ -1030,3 +1035,5 @@ describe('ShaDa changes support code', function()
eq(found, 100)
end)
end)
+
+-- vim: ts=2 sw=2
diff --git a/test/functional/terminal/ex_terminal_spec.lua b/test/functional/terminal/ex_terminal_spec.lua
index 9930efc402..e015df10db 100644
--- a/test/functional/terminal/ex_terminal_spec.lua
+++ b/test/functional/terminal/ex_terminal_spec.lua
@@ -3,6 +3,7 @@ local Screen = require('test.functional.ui.screen')
local clear, wait, nvim = helpers.clear, helpers.wait, helpers.nvim
local nvim_dir, source, eq = helpers.nvim_dir, helpers.source, helpers.eq
local feed_command, eval = helpers.feed_command, helpers.eval
+local retry = helpers.retry
local iswin = helpers.iswin
describe(':terminal', function()
@@ -70,19 +71,19 @@ describe(':terminal (with fake shell)', function()
it('with no argument, acts like termopen()', function()
terminal_with_fake_shell()
- wait()
+ retry(3, 4 * screen.timeout, function()
screen:expect([[
- ready $ |
+ ^ready $ |
[Process exited 0] |
|
- -- TERMINAL -- |
+ :terminal |
]])
+ end)
end)
it("with no argument, and 'shell' is set to empty string", function()
nvim('set_option', 'shell', '')
terminal_with_fake_shell()
- wait()
screen:expect([[
^ |
~ |
@@ -94,46 +95,42 @@ describe(':terminal (with fake shell)', function()
it("with no argument, but 'shell' has arguments, acts like termopen()", function()
nvim('set_option', 'shell', nvim_dir..'/shell-test -t jeff')
terminal_with_fake_shell()
- wait()
screen:expect([[
- jeff $ |
+ ^jeff $ |
[Process exited 0] |
|
- -- TERMINAL -- |
+ :terminal |
]])
end)
it('executes a given command through the shell', function()
terminal_with_fake_shell('echo hi')
- wait()
screen:expect([[
- ready $ echo hi |
+ ^ready $ echo hi |
|
[Process exited 0] |
- -- TERMINAL -- |
+ :terminal echo hi |
]])
end)
it("executes a given command through the shell, when 'shell' has arguments", function()
nvim('set_option', 'shell', nvim_dir..'/shell-test -t jeff')
terminal_with_fake_shell('echo hi')
- wait()
screen:expect([[
- jeff $ echo hi |
+ ^jeff $ echo hi |
|
[Process exited 0] |
- -- TERMINAL -- |
+ :terminal echo hi |
]])
end)
it('allows quotes and slashes', function()
terminal_with_fake_shell([[echo 'hello' \ "world"]])
- wait()
screen:expect([[
- ready $ echo 'hello' \ "world" |
+ ^ready $ echo 'hello' \ "world" |
|
[Process exited 0] |
- -- TERMINAL -- |
+ :terminal echo 'hello' \ "world" |
]])
end)
@@ -164,12 +161,11 @@ describe(':terminal (with fake shell)', function()
it('works with :find', function()
terminal_with_fake_shell()
- wait()
screen:expect([[
- ready $ |
+ ^ready $ |
[Process exited 0] |
|
- -- TERMINAL -- |
+ :terminal |
]])
eq('term://', string.match(eval('bufname("%")'), "^term://"))
helpers.feed([[<C-\><C-N>]])
@@ -184,10 +180,10 @@ describe(':terminal (with fake shell)', function()
it('works with gf', function()
terminal_with_fake_shell([[echo "scripts/shadacat.py"]])
screen:expect([[
- ready $ echo "scripts/shadacat.py" |
+ ^ready $ echo "scripts/shadacat.py" |
|
[Process exited 0] |
- -- TERMINAL -- |
+ :terminal echo "scripts/shadacat.py" |
]])
helpers.feed([[<C-\><C-N>]])
eq('term://', string.match(eval('bufname("%")'), "^term://"))
diff --git a/test/functional/terminal/tui_spec.lua b/test/functional/terminal/tui_spec.lua
index 21b907c8f7..d36eb46e54 100644
--- a/test/functional/terminal/tui_spec.lua
+++ b/test/functional/terminal/tui_spec.lua
@@ -1,5 +1,6 @@
--- Some sanity checks for the TUI using the builtin terminal emulator
--- as a simple way to send keys and assert screen state.
+-- TUI acceptance tests.
+-- Uses :terminal as a way to send keys and assert screen state.
+local global_helpers = require('test.helpers')
local helpers = require('test.functional.helpers')(after_each)
local thelpers = require('test.functional.terminal.helpers')
local feed_data = thelpers.feed_data
@@ -194,7 +195,7 @@ describe('tui with non-tty file descriptors', function()
end)
end)
-describe('tui focus event handling', function()
+describe('tui FocusGained/FocusLost', function()
local screen
before_each(function()
@@ -206,7 +207,8 @@ describe('tui focus event handling', function()
feed_data("\034\016") -- CTRL-\ CTRL-N
end)
- it('can handle focus events in normal mode', function()
+ it('in normal-mode', function()
+ retry(2, 3 * screen.timeout, function()
feed_data('\027[I')
screen:expect([[
{1: } |
@@ -228,11 +230,13 @@ describe('tui focus event handling', function()
lost |
{3:-- TERMINAL --} |
]])
+ end)
end)
- it('can handle focus events in insert mode', function()
+ it('in insert-mode', function()
feed_command('set noshowmode')
feed_data('i')
+ retry(2, 3 * screen.timeout, function()
feed_data('\027[I')
screen:expect([[
{1: } |
@@ -253,9 +257,12 @@ describe('tui focus event handling', function()
lost |
{3:-- TERMINAL --} |
]])
+ end)
end)
- it('can handle focus events in cmdline mode', function()
+ -- During cmdline-mode we ignore :echo invoked by timers/events.
+ -- See commit: 5cc87d4dabd02167117be7a978b5c8faaa975419.
+ it('in cmdline-mode does NOT :echo', function()
feed_data(':')
feed_data('\027[I')
screen:expect([[
@@ -264,7 +271,7 @@ describe('tui focus event handling', function()
{4:~ }|
{4:~ }|
{5:[No Name] }|
- g{1:a}ined |
+ :{1: } |
{3:-- TERMINAL --} |
]])
feed_data('\027[O')
@@ -274,21 +281,52 @@ describe('tui focus event handling', function()
{4:~ }|
{4:~ }|
{5:[No Name] }|
- l{1:o}st |
+ :{1: } |
{3:-- TERMINAL --} |
]])
end)
- it('can handle focus events in terminal mode', function()
+ it('in cmdline-mode', function()
+ -- Set up autocmds that modify the buffer, instead of just calling :echo.
+ -- This is how we can test handling of focus gained/lost during cmdline-mode.
+ -- See commit: 5cc87d4dabd02167117be7a978b5c8faaa975419.
+ feed_data(":autocmd!\n")
+ feed_data(":autocmd FocusLost * call append(line('$'), 'lost')\n")
+ feed_data(":autocmd FocusGained * call append(line('$'), 'gained')\n")
+ retry(2, 3 * screen.timeout, function()
+ -- Enter cmdline-mode.
+ feed_data(':')
+ screen:sleep(1)
+ -- Send focus lost/gained termcodes.
+ feed_data('\027[O')
+ feed_data('\027[I')
+ screen:sleep(1)
+ -- Exit cmdline-mode. Redraws from timers/events are blocked during
+ -- cmdline-mode, so the buffer won't be updated until we exit cmdline-mode.
+ feed_data('\n')
+ screen:expect([[
+ {1: } |
+ lost |
+ gained |
+ {4:~ }|
+ {5:[No Name] [+] }|
+ : |
+ {3:-- TERMINAL --} |
+ ]])
+ end)
+ end)
+
+ it('in terminal-mode', function()
feed_data(':set shell='..nvim_dir..'/shell-test\n')
feed_data(':set noshowmode laststatus=0\n')
retry(2, 3 * screen.timeout, function()
feed_data(':terminal\n')
+ screen:sleep(1)
feed_data('\027[I')
screen:expect([[
- ready $ |
- [Process exited 0]{1: } |
+ {1:r}eady $ |
+ [Process exited 0] |
|
|
|
@@ -297,8 +335,8 @@ describe('tui focus event handling', function()
]])
feed_data('\027[O')
screen:expect([[
- ready $ |
- [Process exited 0]{1: } |
+ {1:r}eady $ |
+ [Process exited 0] |
|
|
|
@@ -311,13 +349,30 @@ describe('tui focus event handling', function()
feed_data(':bwipeout!\n')
end)
end)
+
+ it('in press-enter prompt', function()
+ feed_data(":echom 'msg1'|echom 'msg2'|echom 'msg3'|echom 'msg4'|echom 'msg5'\n")
+ -- Execute :messages to provoke the press-enter prompt.
+ feed_data(":messages\n")
+ feed_data('\027[I')
+ feed_data('\027[I')
+ screen:expect([[
+ msg1 |
+ msg2 |
+ msg3 |
+ msg4 |
+ msg5 |
+ {10:Press ENTER or type command to continue}{1: } |
+ {3:-- TERMINAL --} |
+ ]])
+ end)
end)
-- These tests require `thelpers` because --headless/--embed
-- does not initialize the TUI.
describe("tui 't_Co' (terminal colors)", function()
local screen
- local is_freebsd = (helpers.eval("system('uname') =~? 'FreeBSD'") == 1)
+ local is_freebsd = (string.lower(global_helpers.uname()) == 'freebsd')
local function assert_term_colors(term, colorterm, maxcolors)
helpers.clear({env={TERM=term}, args={}})
diff --git a/test/functional/ui/highlight_spec.lua b/test/functional/ui/highlight_spec.lua
index d1357ea525..077b0ec14c 100644
--- a/test/functional/ui/highlight_spec.lua
+++ b/test/functional/ui/highlight_spec.lua
@@ -518,7 +518,7 @@ describe("'listchars' highlight", function()
]])
feed_command('set cursorline')
screen:expect([[
- {2:^>-------.}{1:abcd}{2:.}{1:Lorem}{4:>}|
+ {2:^>-------.}{1:abcd}{2:.}{1:Lorem}{3:>}|
{5:>-------.}abcd{5:*}{4:¬} |
{4:¬} |
{4:~ }|
@@ -526,7 +526,7 @@ describe("'listchars' highlight", function()
]])
feed('$')
screen:expect([[
- {4:<}{1:r}{2:.}{1:sit}{2:.}{1:ame^t}{3:¬}{1: }|
+ {3:<}{1:r}{2:.}{1:sit}{2:.}{1:ame^t}{3:¬}{1: }|
{4:<} |
{4:<} |
{4:~ }|
@@ -607,7 +607,7 @@ describe("'listchars' highlight", function()
feed('<esc>$')
screen:expect([[
{4:<} |
- {4:<}{1:r}{2:.}{1:sit}{2:.}{1:ame^t}{3:¬}{1: }|
+ {3:<}{1:r}{2:.}{1:sit}{2:.}{1:ame^t}{3:¬}{1: }|
{4:<} |
{4:~ }|
|
diff --git a/test/functional/ui/inccommand_spec.lua b/test/functional/ui/inccommand_spec.lua
index 64965ccb94..c8fa2888d1 100644
--- a/test/functional/ui/inccommand_spec.lua
+++ b/test/functional/ui/inccommand_spec.lua
@@ -14,6 +14,7 @@ local neq = helpers.neq
local ok = helpers.ok
local source = helpers.source
local wait = helpers.wait
+local nvim = helpers.nvim
local default_text = [[
Inc substitution on
@@ -892,6 +893,31 @@ describe(":substitute, inccommand=split", function()
]])
end)
+ it('previews correctly when previewhight is small', function()
+ feed_command('set cwh=3')
+ feed_command('set hls')
+ feed('ggdG')
+ insert(string.rep('abc abc abc\n', 20))
+ feed(':%s/abc/MMM/g')
+ screen:expect([[
+ MMM MMM MMM |
+ MMM MMM MMM |
+ MMM MMM MMM |
+ MMM MMM MMM |
+ MMM MMM MMM |
+ MMM MMM MMM |
+ MMM MMM MMM |
+ MMM MMM MMM |
+ MMM MMM MMM |
+ {11:[No Name] [+] }|
+ | 1| {12:MMM} {12:MMM} {12:MMM} |
+ | 2| {12:MMM} {12:MMM} {12:MMM} |
+ | 3| {12:MMM} {12:MMM} {12:MMM} |
+ {10:[Preview] }|
+ :%s/abc/MMM/g^ |
+ ]])
+ end)
+
it('actually replaces text', function()
feed(":%s/tw/XX/g<Enter>")
@@ -1622,3 +1648,29 @@ describe("'inccommand' split windows", function()
end)
end)
+
+describe("'inccommand' with 'gdefault'", function()
+ before_each(function()
+ clear()
+ end)
+
+ it("does not lock up #7244", function()
+ common_setup(nil, "nosplit", "{")
+ command("set gdefault")
+ feed(":s/{\\n")
+ eq({mode='c', blocking=false}, nvim("get_mode"))
+ feed("/A<Enter>")
+ expect("A")
+ eq({mode='n', blocking=false}, nvim("get_mode"))
+ end)
+
+ it("with multiline text and range, does not lock up #7244", function()
+ common_setup(nil, "nosplit", "{\n\n{")
+ command("set gdefault")
+ feed(":%s/{\\n")
+ eq({mode='c', blocking=false}, nvim("get_mode"))
+ feed("/A<Enter>")
+ expect("A\nA")
+ eq({mode='n', blocking=false}, nvim("get_mode"))
+ end)
+end)
diff --git a/test/functional/ui/screen_basic_spec.lua b/test/functional/ui/screen_basic_spec.lua
index bfcdc7f652..b31d9cb32f 100644
--- a/test/functional/ui/screen_basic_spec.lua
+++ b/test/functional/ui/screen_basic_spec.lua
@@ -5,6 +5,7 @@ local feed, command = helpers.feed, helpers.command
local insert = helpers.insert
local eq = helpers.eq
local eval = helpers.eval
+local iswin = helpers.iswin
describe('screen', function()
local screen
@@ -119,9 +120,10 @@ describe('Screen', function()
end)
it('has correct default title with named file', function()
- local expected = 'myfile (/mydir) - NVIM'
+ local expected = (iswin() and 'myfile (C:\\mydir) - NVIM'
+ or 'myfile (/mydir) - NVIM')
command('set title')
- command('file /mydir/myfile')
+ command(iswin() and 'file C:\\mydir\\myfile' or 'file /mydir/myfile')
screen:expect(function()
eq(expected, screen.title)
end)
diff --git a/test/unit/path_spec.lua b/test/unit/path_spec.lua
index a9cba7df84..befb204d0a 100644
--- a/test/unit/path_spec.lua
+++ b/test/unit/path_spec.lua
@@ -481,6 +481,20 @@ describe('path.c', function()
eq('/tmp', ffi.string(buffer))
eq(OK, result)
end)
+
+ itp('expands "./" to the current directory #7117', function()
+ local force_expansion = 1
+ local result = vim_FullName('./unit-test-directory/test.file', buffer, length, force_expansion)
+ eq(OK, result)
+ eq(lfs.currentdir() .. '/unit-test-directory/test.file', (ffi.string(buffer)))
+ end)
+
+ itp('collapses "foo/../foo" to "foo" #7117', function()
+ local force_expansion = 1
+ local result = vim_FullName('unit-test-directory/../unit-test-directory/test.file', buffer, length, force_expansion)
+ eq(OK, result)
+ eq(lfs.currentdir() .. '/unit-test-directory/test.file', (ffi.string(buffer)))
+ end)
end)
describe('path_fix_case', function()