aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-x.ci/before_script.sh4
-rw-r--r--.ci/common/build.sh10
-rwxr-xr-x.ci/install.sh4
-rw-r--r--CMakeLists.txt8
-rw-r--r--cmake/FindMsgpack.cmake24
-rw-r--r--config/CMakeLists.txt1
-rw-r--r--config/config.h.in1
-rw-r--r--runtime/CMakeLists.txt11
-rw-r--r--runtime/autoload/man.vim4
-rw-r--r--runtime/autoload/provider/clipboard.vim12
-rw-r--r--runtime/doc/change.txt13
-rw-r--r--runtime/doc/eval.txt7
-rw-r--r--runtime/doc/nvim_provider.txt2
-rw-r--r--runtime/doc/options.txt43
-rw-r--r--runtime/doc/tabpage.txt23
-rw-r--r--runtime/doc/various.txt1
-rw-r--r--runtime/indent/html.vim4
-rw-r--r--runtime/syntax/python.vim19
-rw-r--r--runtime/syntax/sh.vim156
-rw-r--r--runtime/syntax/tex.vim56
-rw-r--r--runtime/vimrc_example.vim4
-rw-r--r--src/nvim/README.md26
-rw-r--r--src/nvim/buffer.c67
-rw-r--r--src/nvim/buffer.h1
-rw-r--r--src/nvim/charset.c73
-rw-r--r--src/nvim/edit.c8
-rw-r--r--src/nvim/eval.c77
-rw-r--r--src/nvim/ex_cmds.c59
-rw-r--r--src/nvim/ex_docmd.c53
-rw-r--r--src/nvim/ex_getln.c4
-rw-r--r--src/nvim/fileio.c10
-rw-r--r--src/nvim/fold.c6
-rw-r--r--src/nvim/globals.h9
-rw-r--r--src/nvim/keymap.c4
-rw-r--r--src/nvim/log.c4
-rw-r--r--src/nvim/main.c42
-rw-r--r--src/nvim/normal.c215
-rw-r--r--src/nvim/ops.c452
-rw-r--r--src/nvim/ops.h64
-rw-r--r--src/nvim/option.c7
-rw-r--r--src/nvim/option_defs.h90
-rw-r--r--src/nvim/os/fs.c42
-rw-r--r--src/nvim/os/unix_defs.h2
-rw-r--r--src/nvim/os/win_defs.h1
-rw-r--r--src/nvim/quickfix.c13
-rw-r--r--src/nvim/screen.c94
-rw-r--r--src/nvim/screen.h23
-rw-r--r--src/nvim/search.c16
-rw-r--r--src/nvim/shada.c3
-rw-r--r--src/nvim/spell.c4
-rw-r--r--src/nvim/tag.c47
-rw-r--r--src/nvim/testdir/Makefile5
-rw-r--r--src/nvim/testdir/test13.in6
-rw-r--r--src/nvim/testdir/test13.ok1
-rw-r--r--src/nvim/testdir/test30.in58
-rw-r--r--src/nvim/testdir/test30.ok9
-rw-r--r--src/nvim/testdir/test45.in80
-rw-r--r--src/nvim/testdir/test45.ok18
-rw-r--r--src/nvim/testdir/test_marks.in34
-rw-r--r--src/nvim/testdir/test_marks.ok16
-rw-r--r--src/nvim/undo.c7
-rw-r--r--src/nvim/version.c280
-rw-r--r--src/nvim/vim.h10
-rw-r--r--src/nvim/window.c30
-rw-r--r--test/functional/api/server_requests_spec.lua2
-rw-r--r--test/functional/legacy/039_visual_block_mode_commands_spec.lua2
-rw-r--r--test/functional/legacy/045_folding_spec.lua139
-rw-r--r--test/functional/legacy/057_sort_spec.lua91
-rw-r--r--test/functional/legacy/059_utf8_spell_checking_spec.lua70
-rw-r--r--test/functional/legacy/062_tab_pages_spec.lua22
-rw-r--r--test/functional/legacy/063_match_and_matchadd_spec.lua4
-rw-r--r--test/functional/legacy/eval_spec.lua2
-rw-r--r--test/functional/legacy/glob2regpat_spec.lua2
-rw-r--r--test/functional/legacy/increment_spec.lua723
-rw-r--r--test/functional/legacy/quickfix_spec.lua3
-rw-r--r--test/functional/legacy/set_spec.lua15
-rw-r--r--test/functional/legacy/textobjects_spec.lua61
-rw-r--r--test/functional/ui/highlight_spec.lua9
-rw-r--r--test/functional/ui/mouse_spec.lua169
-rw-r--r--test/unit/strings_spec.lua1
80 files changed, 2856 insertions, 936 deletions
diff --git a/.ci/before_script.sh b/.ci/before_script.sh
index 026ab0afc9..6babc582ea 100755
--- a/.ci/before_script.sh
+++ b/.ci/before_script.sh
@@ -19,6 +19,10 @@ if [[ -n "${LLVM_SYMBOLIZER}" ]] && [[ ! $(type -P "${LLVM_SYMBOLIZER}") ]]; the
echo "\$LLVM_SYMBOLIZER: '${LLVM_SYMBOLIZER}' is not executable."
exit 1
fi
+if [ "${BUILD_32BIT}" = ON ] && [ "${BUILD_MINGW}" = ON ]; then
+ >&2 echo "32-bit MinGW builds not supported."
+ exit 1
+fi
if [[ "${TRAVIS_OS_NAME}" == osx ]]; then
# Adds user to a dummy group.
diff --git a/.ci/common/build.sh b/.ci/common/build.sh
index 3d517b9b09..f635ee4960 100644
--- a/.ci/common/build.sh
+++ b/.ci/common/build.sh
@@ -1,10 +1,5 @@
build_deps() {
if [[ "${BUILD_32BIT}" == ON ]]; then
- if [[ "${BUILD_MINGW}" == ON ]]; then
- >&2 echo "32-bit MinGW builds not supported."
- exit 1
- fi
-
DEPS_CMAKE_FLAGS="${DEPS_CMAKE_FLAGS} ${CMAKE_FLAGS_32BIT}"
fi
if [[ "${BUILD_MINGW}" == ON ]]; then
@@ -42,11 +37,6 @@ build_nvim() {
CMAKE_FLAGS="${CMAKE_FLAGS} -DCLANG_${CLANG_SANITIZER}=ON"
fi
if [[ "${BUILD_32BIT}" == ON ]]; then
- if [[ "${BUILD_MINGW}" == ON ]]; then
- >&2 echo "32-bit MinGW builds not supported."
- exit 1
- fi
-
CMAKE_FLAGS="${CMAKE_FLAGS} ${CMAKE_FLAGS_32BIT}"
fi
if [[ "${BUILD_MINGW}" == ON ]]; then
diff --git a/.ci/install.sh b/.ci/install.sh
index ad3ef1b8b7..fb5d1c09c1 100755
--- a/.ci/install.sh
+++ b/.ci/install.sh
@@ -14,7 +14,9 @@ elif [[ "${BUILD_MINGW}" == ON ]]; then
# binutils-mingw-w64-i686 gcc-mingw-w64-i686 g++-mingw-w64-i686 mingw-w64-dev mingw-w64-tools
echo "Downloading MinGW..."
- curl -sSL "http://downloads.sourceforge.net/project/mingw-w64/Toolchains%20targetting%20Win32/Personal%20Builds/rubenvb/gcc-4.8-release/i686-w64-mingw32-gcc-4.8.0-linux64_rubenvb.tar.xz" | tar xJf - -C "${HOME}/.local"
+ curl -sSL "https://github.com/neovim/deps/raw/master/opt/i686-w64-mingw32-gcc-4.8.0-linux64_rubenvb.tar.xz" \
+ | tar xJf - -C "${HOME}/.local"
+
fi
# Set CC to default to avoid compilation problems
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 6c3f4d927d..c6ed0f0cdf 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -55,7 +55,7 @@ set_property(CACHE CMAKE_BUILD_TYPE PROPERTY
# version string, else it is combined with the result of `git describe`.
set(NVIM_VERSION_MAJOR 0)
set(NVIM_VERSION_MINOR 1)
-set(NVIM_VERSION_PATCH 2)
+set(NVIM_VERSION_PATCH 3)
set(NVIM_VERSION_PRERELEASE "-dev") # for package maintainers
file(TO_CMAKE_PATH ${CMAKE_CURRENT_LIST_DIR}/.git FORCED_GIT_DIR)
@@ -254,6 +254,10 @@ if(CMAKE_COMPILER_IS_GNUCXX AND CMAKE_SYSTEM_NAME STREQUAL "Linux")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--no-undefined")
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--no-undefined")
set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -Wl,--no-undefined")
+
+ # For O_CLOEXEC, O_DIRECTORY, and O_NOFOLLOW flags on older systems
+ # (pre POSIX.1-2008: glibc 2.11 and earlier). #4042
+ add_definitions(-D_GNU_SOURCE)
endif()
if(CMAKE_COMPILER_IS_GNUCXX AND CMAKE_SYSTEM_NAME STREQUAL "SunOS")
@@ -279,7 +283,7 @@ include(CheckLibraryExists)
find_package(LibUV REQUIRED)
include_directories(SYSTEM ${LIBUV_INCLUDE_DIRS})
-find_package(Msgpack REQUIRED)
+find_package(Msgpack 1.0.0 REQUIRED)
include_directories(SYSTEM ${MSGPACK_INCLUDE_DIRS})
find_package(LuaJit REQUIRED)
diff --git a/cmake/FindMsgpack.cmake b/cmake/FindMsgpack.cmake
index 60afc88839..015737d658 100644
--- a/cmake/FindMsgpack.cmake
+++ b/cmake/FindMsgpack.cmake
@@ -7,7 +7,9 @@
if(NOT MSGPACK_USE_BUNDLED)
find_package(PkgConfig)
if (PKG_CONFIG_FOUND)
- pkg_search_module(PC_MSGPACK QUIET msgpackc>=1.0 msgpack>=1.0)
+ pkg_search_module(PC_MSGPACK QUIET
+ msgpackc>=${Msgpack_FIND_VERSION}
+ msgpack>=${Msgpack_FIND_VERSION})
endif()
else()
set(PC_MSGPACK_INCLUDEDIR)
@@ -19,10 +21,20 @@ endif()
set(MSGPACK_DEFINITIONS ${PC_MSGPACK_CFLAGS_OTHER})
-find_path(MSGPACK_INCLUDE_DIR msgpack.h
+find_path(MSGPACK_INCLUDE_DIR msgpack/version_master.h
HINTS ${PC_MSGPACK_INCLUDEDIR} ${PC_MSGPACK_INCLUDE_DIRS}
${LIMIT_SEARCH})
+if(MSGPACK_INCLUDE_DIR)
+ file(READ ${MSGPACK_INCLUDE_DIR}/msgpack/version_master.h msgpack_version_h)
+ string(REGEX REPLACE ".*MSGPACK_VERSION_MAJOR +([0-9]+).*" "\\1" MSGPACK_VERSION_MAJOR "${msgpack_version_h}")
+ string(REGEX REPLACE ".*MSGPACK_VERSION_MINOR +([0-9]+).*" "\\1" MSGPACK_VERSION_MINOR "${msgpack_version_h}")
+ string(REGEX REPLACE ".*MSGPACK_VERSION_REVISION +([0-9]+).*" "\\1" MSGPACK_VERSION_REVISION "${msgpack_version_h}")
+ set(MSGPACK_VERSION_STRING "${MSGPACK_VERSION_MAJOR}.${MSGPACK_VERSION_MINOR}.${MSGPACK_VERSION_REVISION}")
+else()
+ set(MSGPACK_VERSION_STRING)
+endif()
+
# If we're asked to use static linkage, add libmsgpack{,c}.a as a preferred library name.
if(MSGPACK_USE_STATIC)
list(APPEND MSGPACK_NAMES
@@ -33,6 +45,9 @@ endif()
list(APPEND MSGPACK_NAMES msgpackc msgpack)
find_library(MSGPACK_LIBRARY NAMES ${MSGPACK_NAMES}
+ # Check each directory for all names to avoid using headers/libraries from
+ # different places.
+ NAMES_PER_DIR
HINTS ${PC_MSGPACK_LIBDIR} ${PC_MSGPACK_LIBRARY_DIRS}
${LIMIT_SEARCH})
@@ -44,6 +59,7 @@ set(MSGPACK_INCLUDE_DIRS ${MSGPACK_INCLUDE_DIR})
include(FindPackageHandleStandardArgs)
# handle the QUIETLY and REQUIRED arguments and set MSGPACK_FOUND to TRUE
# if all listed variables are TRUE
-find_package_handle_standard_args(Msgpack DEFAULT_MSG
- MSGPACK_LIBRARY MSGPACK_INCLUDE_DIR)
+find_package_handle_standard_args(Msgpack
+ REQUIRED_VARS MSGPACK_LIBRARY MSGPACK_INCLUDE_DIR
+ VERSION_VAR MSGPACK_VERSION_STRING)
diff --git a/config/CMakeLists.txt b/config/CMakeLists.txt
index 2d3c484845..eaf06ba7f2 100644
--- a/config/CMakeLists.txt
+++ b/config/CMakeLists.txt
@@ -26,7 +26,6 @@ if(NOT HAVE_SYS_WAIT_H AND UNIX)
message(SEND_ERROR "header sys/wait.h is required for Unix")
endif()
check_include_files(sys/utsname.h HAVE_SYS_UTSNAME_H)
-check_include_files(unistd.h HAVE_UNISTD_H)
check_include_files(utime.h HAVE_UTIME_H)
# Functions
diff --git a/config/config.h.in b/config/config.h.in
index 1eafc8cb95..27705f8b38 100644
--- a/config/config.h.in
+++ b/config/config.h.in
@@ -39,7 +39,6 @@
#cmakedefine HAVE_STRNCASECMP
#cmakedefine HAVE_SYS_UTSNAME_H
#cmakedefine HAVE_SYS_WAIT_H
-#cmakedefine HAVE_UNISTD_H
#cmakedefine HAVE_UTIME
#cmakedefine HAVE_UTIME_H
#cmakedefine HAVE_UTIMES
diff --git a/runtime/CMakeLists.txt b/runtime/CMakeLists.txt
index ef8e38b553..4a90c11734 100644
--- a/runtime/CMakeLists.txt
+++ b/runtime/CMakeLists.txt
@@ -26,15 +26,12 @@ foreach(DF ${DOCFILES})
list(APPEND BUILDDOCFILES ${GENERATED_RUNTIME_DIR}/doc/${F})
endforeach()
-add_custom_command(OUTPUT ${BUILDDOCFILES}
- COMMAND ${CMAKE_COMMAND} -E copy_directory
+add_custom_command(OUTPUT copy_docfiles
+ COMMAND ${CMAKE_COMMAND} -E copy_directory
${PROJECT_SOURCE_DIR}/runtime/doc ${GENERATED_RUNTIME_DIR}/doc
- DEPENDS
- ${DOCFILES})
+)
add_custom_command(OUTPUT ${GENERATED_HELP_TAGS}
- COMMAND ${CMAKE_COMMAND} -E copy_directory
- ${PROJECT_SOURCE_DIR}/runtime/doc ${GENERATED_RUNTIME_DIR}/doc
COMMAND "${PROJECT_BINARY_DIR}/bin/nvim"
-u NONE
-i NONE
@@ -43,7 +40,7 @@ add_custom_command(OUTPUT ${GENERATED_HELP_TAGS}
-c "helptags ++t ."
-c quit
DEPENDS
- ${BUILDDOCFILES}
+ copy_docfiles
nvim
WORKING_DIRECTORY "${GENERATED_RUNTIME_DIR}/doc"
)
diff --git a/runtime/autoload/man.vim b/runtime/autoload/man.vim
index d481d9eaf0..49663d7e5a 100644
--- a/runtime/autoload/man.vim
+++ b/runtime/autoload/man.vim
@@ -75,7 +75,9 @@ function man#get_page(...) abort
setlocal modifiable
silent keepjumps norm! 1G"_dG
- let $MANWIDTH = winwidth(0)
+ if empty($MANWIDTH)
+ let $MANWIDTH = winwidth(0)
+ endif
silent exec 'r!/usr/bin/man '.s:cmd(sect, page).' | col -b'
" Remove blank lines from top and bottom.
while getline(1) =~ '^\s*$'
diff --git a/runtime/autoload/provider/clipboard.vim b/runtime/autoload/provider/clipboard.vim
index 3728eb9367..5ea9df92fe 100644
--- a/runtime/autoload/provider/clipboard.vim
+++ b/runtime/autoload/provider/clipboard.vim
@@ -37,16 +37,16 @@ if executable('pbcopy')
let s:copy['*'] = s:copy['+']
let s:paste['*'] = s:paste['+']
let s:cache_enabled = 0
-elseif executable('xclip')
- let s:copy['+'] = 'xclip -quiet -i -selection clipboard'
- let s:paste['+'] = 'xclip -o -selection clipboard'
- let s:copy['*'] = 'xclip -quiet -i -selection primary'
- let s:paste['*'] = 'xclip -o -selection primary'
-elseif executable('xsel')
+elseif exists('$DISPLAY') && executable('xsel')
let s:copy['+'] = 'xsel --nodetach -i -b'
let s:paste['+'] = 'xsel -o -b'
let s:copy['*'] = 'xsel --nodetach -i -p'
let s:paste['*'] = 'xsel -o -p'
+elseif exists('$DISPLAY') && executable('xclip')
+ let s:copy['+'] = 'xclip -quiet -i -selection clipboard'
+ let s:paste['+'] = 'xclip -o -selection clipboard'
+ let s:copy['*'] = 'xclip -quiet -i -selection primary'
+ let s:paste['*'] = 'xclip -o -selection primary'
else
echom 'clipboard: No clipboard tool available. See :help nvim-clipboard'
finish
diff --git a/runtime/doc/change.txt b/runtime/doc/change.txt
index 42dc84e0de..30b7dcaa4a 100644
--- a/runtime/doc/change.txt
+++ b/runtime/doc/change.txt
@@ -370,11 +370,14 @@ CTRL-A Add [count] to the number or alphabetic character at
CTRL-X Subtract [count] from the number or alphabetic
character at or after the cursor.
-The CTRL-A and CTRL-X commands work for (signed) decimal numbers, unsigned
-binary/octal/hexadecimal numbers and alphabetic characters. This
-depends on the 'nrformats' option.
-- When 'nrformats' includes "bin", Vim considers numbers starting with '0b' or
- '0B' as binary.
+The CTRL-A and CTRL-X commands can work for:
+- signed and unsigned decimal numbers
+- unsigned binary, octal and hexadecimal numbers
+- alphabetic characters
+
+This depends on the 'nrformats' option:
+- When 'nrformats' includes "bin", Vim assumes numbers starting with '0b' or
+ '0B' are binary.
- When 'nrformats' includes "octal", Vim considers numbers starting with a '0'
to be octal, unless the number includes a '8' or '9'. Other numbers are
decimal and may have a preceding minus sign.
diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt
index 6bdfa8dc8a..bb7ca77de7 100644
--- a/runtime/doc/eval.txt
+++ b/runtime/doc/eval.txt
@@ -1019,7 +1019,7 @@ A string constant accepts these special characters:
\X. same as \x.
\u.... character specified with up to 4 hex numbers, stored according to the
current value of 'encoding' (e.g., "\u02a4")
-\U.... same as \u....
+\U.... same as \u but allows up to 8 hex numbers.
\b backspace <BS>
\e escape <Esc>
\f formfeed <FF>
@@ -3794,7 +3794,9 @@ glob2regpat({expr}) *glob2regpat()*
if filename =~ glob2regpat('Make*.mak')
< This is equivalent to: >
if filename =~ '^Make.*\.mak$'
-<
+< When {expr} is an empty string the result is "^$", match an
+ empty string.
+
*globpath()*
globpath({path}, {expr} [, {nosuf} [, {list} [, {allinks}]]])
Perform glob() on all directories in {path} and concatenate
@@ -7061,6 +7063,7 @@ statusline Compiled with support for 'statusline', 'rulerformat'
syntax Compiled with syntax highlighting support |syntax|.
syntax_items There are active syntax highlighting items for the
current buffer.
+tablineat 'tabline' option accepts %@Func@ items.
tag_binary Compiled with binary searching in tags files
|tag-binary-search|.
tag_old_static Compiled with support for old static tags
diff --git a/runtime/doc/nvim_provider.txt b/runtime/doc/nvim_provider.txt
index a737d51ac4..91cd5fbfc7 100644
--- a/runtime/doc/nvim_provider.txt
+++ b/runtime/doc/nvim_provider.txt
@@ -26,7 +26,7 @@ are now decoupled from Nvim core as providers:
The first example is clipboard integration: in the original Vim source code,
clipboard functions account for more than 1k lines of C source code (and that
-is just on ui.c), all to peform two tasks that are now accomplished with
+is just on ui.c), all to perform two tasks that are now accomplished with
simple shell commands such as xclip or pbcopy/pbpaste.
The other example is Python scripting support: Vim has three files dedicated to
diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt
index bbd9cc1e2b..51bfc12f9d 100644
--- a/runtime/doc/options.txt
+++ b/runtime/doc/options.txt
@@ -4396,7 +4396,7 @@ A jump table for the options with a short description can be found at |Q_op|.
recognized as a multi click.
*'nrformats'* *'nf'*
-'nrformats' 'nf' string (default "hex")
+'nrformats' 'nf' string (default "bin,hex")
local to buffer
This defines what bases Vim will consider for numbers when using the
CTRL-A and CTRL-X commands for adding to and subtracting from a number
@@ -4409,6 +4409,9 @@ A jump table for the options with a short description can be found at |Q_op|.
hex If included, numbers starting with "0x" or "0X" will be
considered to be hexadecimal. Example: Using CTRL-X on
"0x100" results in "0x0ff".
+ bin If included, numbers starting with "0b" or "0B" will be
+ considered to be binary. Example: Using CTRL-X on
+ "0b1000" subtracts one, resulting in "0b0111".
Numbers which simply begin with a digit in the range 1-9 are always
considered decimal. This also happens for numbers that are not
recognized as octal or hex.
@@ -6008,11 +6011,39 @@ A jump table for the options with a short description can be found at |Q_op|.
( - Start of item group. Can be used for setting the width and
alignment of a section. Must be followed by %) somewhere.
) - End of item group. No width fields allowed.
- T N For 'tabline': start of tab page N label. Use %T after the last
- label. This information is used for mouse clicks.
- X N For 'tabline': start of close tab N label. Use %X after the
- label, e.g.: %3Xclose%X. Use %999X for a "close current tab"
- mark. This information is used for mouse clicks.
+ T N For 'tabline': start of tab page N label. Use %T or %X to end
+ the label. Clicking this label with left mouse button switches
+ to the specified tab page.
+ X N For 'tabline': start of close tab N label. Use %X or %T to end
+ the label, e.g.: %3Xclose%X. Use %999X for a "close current
+ tab" label. Clicking this label with left mouse button closes
+ specified tab page.
+ @ N For 'tabline': start of execute function label. Use %X or %T to
+ end the label, e.g.: %10@SwitchBuffer@foo.c%X. Clicking this
+ label runs specified function: in the example when clicking once
+ using left mouse button on "foo.c" "SwitchBuffer(10, 1, 'l',
+ ' ')" expression will be run. Function receives the
+ following arguments in order:
+ 1. minwid field value or zero if no N was specified
+ 2. number of mouse clicks to detect multiple clicks
+ 3. mouse button used: "l", "r" or "m" for left, right or middle
+ button respectively; one should not rely on third argument
+ being only "l", "r" or "m": any other non-empty string value
+ that contains only ASCII lower case letters may be expected
+ for other mouse buttons
+ 4. modifiers pressed: string which contains "s" if shift
+ modifier was pressed, "c" for control, "a" for alt and "m"
+ for meta; currently if modifier is not pressed string
+ contains space instead, but one should not rely on presence
+ of spaces or specific order of modifiers: use |stridx()| to
+ test whether some modifier is present; string is guaranteed
+ to contain only ASCII letters and spaces, one letter per
+ modifier; "?" modifier may also be present, but its presence
+ is a bug that denotes that new mouse button recognition was
+ added without modifying code that reacts on mouse clicks on
+ this label.
+ Note: to test whether your version of Neovim contains this
+ feature use `has('tablineat')`.
< - Where to truncate line if too long. Default is at the start.
No width fields allowed.
= - Separation point between left and right aligned items.
diff --git a/runtime/doc/tabpage.txt b/runtime/doc/tabpage.txt
index 13944dc02a..59c4a28ff2 100644
--- a/runtime/doc/tabpage.txt
+++ b/runtime/doc/tabpage.txt
@@ -197,22 +197,29 @@ REORDERING TAB PAGES:
Move the current tab page to after tab page N. Use zero to
make the current tab page the first one. Without N the tab
page is made the last one. >
+ :.tabmove " do nothing
:-tabmove " move the tab page to the left
- :tabmove " move the tab page to the right
- :.tabmove " as above
- :+tabmove " as above
+ :+tabmove " move the tab page to the right
:0tabmove " move the tab page to the beginning of the tab
" list
- :$tabmove " move the tab page to the end of the tab list
-<
+ :tabmove 0 " as above
+ :tabmove " move the tab page to the last
+ :$tabmove " as above
+ :tabmove $ " as above
+
:tabm[ove] +[N]
:tabm[ove] -[N]
Move the current tab page N places to the right (with +) or to
- the left (with -).
+ the left (with -). >
+ :tabmove - " move the tab page to the left
+ :tabmove -1 " as above
+ :tabmove + " move the tab page to the right
+ :tabmove +1 " as above
+
Note that although it is possible to move a tab behind the N-th one by using
-:Ntabmove, it is impossible to move it by N places by using :+Ntabmove. For
-clarification what +N means in this context see |[range]|.
+:Ntabmove. And move it by N places by using :+Ntabmove. For clarification what
++N means in this context see |[range]|.
LOOPING OVER TAB PAGES:
diff --git a/runtime/doc/various.txt b/runtime/doc/various.txt
index 26ff8f0783..ff37466a14 100644
--- a/runtime/doc/various.txt
+++ b/runtime/doc/various.txt
@@ -363,6 +363,7 @@ N *+startuptime* |--startuptime| argument
N *+statusline* Options 'statusline', 'rulerformat' and special
formats of 'titlestring' and 'iconstring'
N *+syntax* Syntax highlighting |syntax|
+N *+tablineat* 'tabline' option recognizing %@Func@ items.
N *+tag_binary* binary searching in tags file |tag-binary-search|
N *+tag_old_static* old method for static tags |tag-old-static|
m *+tag_any_white* any white space allowed in tags file |tag-any-white|
diff --git a/runtime/indent/html.vim b/runtime/indent/html.vim
index 71443abe5b..7eb963b7b2 100644
--- a/runtime/indent/html.vim
+++ b/runtime/indent/html.vim
@@ -2,7 +2,7 @@
" Header: "{{{
" Maintainer: Bram Moolenaar
" Original Author: Andy Wokula <anwoku@yahoo.de>
-" Last Change: 2015 Jan 11
+" Last Change: 2015 Jun 12
" Version: 1.0
" Description: HTML indent script with cached state for faster indenting on a
" range of lines.
@@ -94,7 +94,7 @@ func! HtmlIndent_CheckUserSettings()
let autotags = g:html_indent_autotags
endif
let b:hi_removed_tags = {}
- if autotags
+ if len(autotags) > 0
call s:RemoveITags(b:hi_removed_tags, split(autotags, ","))
endif
diff --git a/runtime/syntax/python.vim b/runtime/syntax/python.vim
index d2162dee5a..c608aeedeb 100644
--- a/runtime/syntax/python.vim
+++ b/runtime/syntax/python.vim
@@ -1,9 +1,8 @@
" Vim syntax file
" Language: Python
-" Maintainer: Neil Schemenauer <nas@python.ca>
-" Last Change: 2014 Jul 16
-" Credits: Zvezdan Petkovic <zpetkovic@acm.org>
-" Neil Schemenauer <nas@python.ca>
+" Maintainer: Zvezdan Petkovic <zpetkovic@acm.org>
+" Last Change: 2015 Jun 19
+" Credits: Neil Schemenauer <nas@python.ca>
" Dmitry Vasiliev
"
" This version is a major rewrite by Zvezdan Petkovic.
@@ -95,16 +94,16 @@ syn match pythonComment "#.*$" contains=pythonTodo,@Spell
syn keyword pythonTodo FIXME NOTE NOTES TODO XXX contained
" Triple-quoted strings can contain doctests.
-syn region pythonString
+syn region pythonString matchgroup=pythonQuotes
\ start=+[uU]\=\z(['"]\)+ end="\z1" skip="\\\\\|\\\z1"
\ contains=pythonEscape,@Spell
-syn region pythonString
+syn region pythonString matchgroup=pythonTripleQuotes
\ start=+[uU]\=\z('''\|"""\)+ skip=+\\["']+ end="\z1" keepend
\ contains=pythonEscape,pythonSpaceError,pythonDoctest,@Spell
-syn region pythonRawString
+syn region pythonRawString matchgroup=pythonQuotes
\ start=+[uU]\=[rR]\z(['"]\)+ end="\z1" skip="\\\\\|\\\z1"
\ contains=@Spell
-syn region pythonRawString
+syn region pythonRawString matchgroup=pythonTripleQuotes
\ start=+[uU]\=[rR]\z('''\|"""\)+ end="\z1" keepend
\ contains=pythonSpaceError,pythonDoctest,@Spell
@@ -113,7 +112,7 @@ syn match pythonEscape "\\\o\{1,3}" contained
syn match pythonEscape "\\x\x\{2}" contained
syn match pythonEscape "\%(\\u\x\{4}\|\\U\x\{8}\)" contained
" Python allows case-insensitive Unicode IDs: http://www.unicode.org/charts/
-syn match pythonEscape "\\N{.\{-}}" contained
+syn match pythonEscape "\\N{\a\+\%(\s\a\+\)*}" contained
syn match pythonEscape "\\$"
if exists("python_highlight_all")
@@ -274,6 +273,8 @@ if version >= 508 || !exists("did_python_syn_inits")
HiLink pythonTodo Todo
HiLink pythonString String
HiLink pythonRawString String
+ HiLink pythonQuotes String
+ HiLink pythonTripleQuotes pythonQuotes
HiLink pythonEscape Special
if !exists("python_no_number_highlight")
HiLink pythonNumber Number
diff --git a/runtime/syntax/sh.vim b/runtime/syntax/sh.vim
index ad0df1f117..4087aff46e 100644
--- a/runtime/syntax/sh.vim
+++ b/runtime/syntax/sh.vim
@@ -2,8 +2,8 @@
" Language: shell (sh) Korn shell (ksh) bash (sh)
" Maintainer: Charles E. Campbell <NdrOchipS@PcampbellAfamily.Mbiz>
" Previous Maintainer: Lennart Schultz <Lennart.Schultz@ecmwf.int>
-" Last Change: Apr 10, 2015
-" Version: 136
+" Last Change: May 29, 2015
+" Version: 137
" URL: http://www.drchip.org/astronaut/vim/index.html#SYNTAX_SH
" For options and settings, please use: :help ft-sh-syntax
" This file includes many ideas from ?ric Brunet (eric.brunet@ens.fr)
@@ -17,7 +17,7 @@ elseif exists("b:current_syntax")
endif
" AFAICT "." should be considered part of the iskeyword. Using iskeywords in
-" syntax is dicey, so the following code permits the user to prevent/override
+" syntax is dicey, so the following code permits the user to
" g:sh_isk set to a string : specify iskeyword.
" g:sh_noisk exists : don't change iskeyword
" g:sh_noisk does not exist : (default) append "." to iskeyword
@@ -108,8 +108,7 @@ syn cluster shArithParenList contains=shArithmetic,shCaseEsac,shComment,shDeref,
syn cluster shArithList contains=@shArithParenList,shParenError
syn cluster shCaseEsacList contains=shCaseStart,shCase,shCaseBar,shCaseIn,shComment,shDeref,shDerefSimple,shCaseCommandSub,shCaseExSingleQuote,shCaseSingleQuote,shCaseDoubleQuote,shCtrlSeq,@shErrorList,shStringSpecial,shCaseRange
syn cluster shCaseList contains=@shCommandSubList,shCaseEsac,shColon,shCommandSub,shComment,shDo,shEcho,shExpr,shFor,shHereDoc,shIf,shRedir,shSetList,shSource,shStatement,shVariable,shCtrlSeq
-"syn cluster shColonList contains=@shCaseList
-syn cluster shCommandSubList contains=shArithmetic,shDeref,shDerefSimple,shEcho,shEscape,shNumber,shOption,shPosnParm,shExSingleQuote,shSingleQuote,shExDoubleQuote,shDoubleQuote,shStatement,shVariable,shSubSh,shAlias,shTest,shCtrlSeq,shSpecial,shCmdParenRegion
+syn cluster shCommandSubList contains=shAlias,shArithmetic,shCmdParenRegion,shCtrlSeq,shDeref,shDerefSimple,shDoubleQuote,shEcho,shEscape,shExDoubleQuote,shExpr,shExSingleQuote,shNumber,shOperator,shOption,shPosnParm,shSingleQuote,shSpecial,shStatement,shSubSh,shTest,shVariable
syn cluster shCurlyList contains=shNumber,shComma,shDeref,shDerefSimple,shDerefSpecial
syn cluster shDblQuoteList contains=shCommandSub,shDeref,shDerefSimple,shEscape,shPosnParm,shCtrlSeq,shSpecial
syn cluster shDerefList contains=shDeref,shDerefSimple,shDerefVar,shDerefSpecial,shDerefWordError,shDerefPPS
@@ -182,7 +181,7 @@ syn match shRedir "\d<<-\="
syn match shOperator "<<\|>>" contained
syn match shOperator "[!&;|]" contained
syn match shOperator "\[[[^:]\|\]]" contained
-syn match shOperator "!\==" skipwhite nextgroup=shPattern
+syn match shOperator "[-=/*+%]\==" skipwhite nextgroup=shPattern
syn match shPattern "\<\S\+\())\)\@=" contained contains=shExSingleQuote,shSingleQuote,shExDoubleQuote,shDoubleQuote,shDeref
" Subshells: {{{1
@@ -194,8 +193,8 @@ syn region shSubSh transparent matchgroup=shSubShRegion start="[^(]\zs(" end=")"
"=======
syn region shExpr matchgroup=shRange start="\[" skip=+\\\\\|\\$\|\[+ end="\]" contains=@shTestList,shSpecial
syn region shTest transparent matchgroup=shStatement start="\<test\s" skip=+\\\\\|\\$+ matchgroup=NONE end="[;&|]"me=e-1 end="$" contains=@shExprList1
+syn match shTestOpr contained '[^-+/%]\zs=' skipwhite nextgroup=shTestDoubleQuote,shTestSingleQuote,shTestPattern
syn match shTestOpr contained "<=\|>=\|!=\|==\|-.\>\|-\(nt\|ot\|ef\|eq\|ne\|lt\|le\|gt\|ge\)\>\|[!<>]"
-syn match shTestOpr contained '=' skipwhite nextgroup=shTestDoubleQuote,shTestSingleQuote,shTestPattern
syn match shTestPattern contained '\w\+'
syn region shTestDoubleQuote contained start='\%(\%(\\\\\)*\\\)\@<!"' skip=+\\\\\|\\"+ end='"'
syn match shTestSingleQuote contained '\\.'
@@ -322,12 +321,13 @@ elseif !exists("g:sh_no_error")
endif
syn region shSingleQuote matchgroup=shQuote start=+'+ end=+'+ contains=@Spell
syn region shDoubleQuote matchgroup=shQuote start=+\%(\%(\\\\\)*\\\)\@<!"+ skip=+\\"+ end=+"+ contains=@shDblQuoteList,shStringSpecial,@Spell
-"syn region shDoubleQuote matchgroup=shQuote start=+"+ skip=+\\"+ end=+"+ contains=@shDblQuoteList,shStringSpecial,@Spell
-syn match shStringSpecial "[^[:print:] \t]" contained
+syn region shDoubleQuote matchgroup=shQuote start=+"+ skip=+\\"+ end=+"+ contains=@shDblQuoteList,shStringSpecial,@Spell
+syn match shStringSpecial "[^[:print:] \t]" contained
syn match shStringSpecial "\%(\\\\\)*\\[\\"'`$()#]"
-syn match shSpecial "[^\\]\zs\%(\\\\\)*\\[\\"'`$()#]" nextgroup=shMoreSpecial,shComment
-syn match shSpecial "^\%(\\\\\)*\\[\\"'`$()#]" nextgroup=shComment
-syn match shMoreSpecial "\%(\\\\\)*\\[\\"'`$()#]" nextgroup=shMoreSpecial contained
+" COMBAK: why is ,shComment on next line???
+syn match shSpecial "[^\\]\zs\%(\\\\\)*\\[\\"'`$()#]" nextgroup=shMoreSpecial,shComment
+syn match shSpecial "^\%(\\\\\)*\\[\\"'`$()#]" nextgroup=shComment
+syn match shMoreSpecial "\%(\\\\\)*\\[\\"'`$()#]" nextgroup=shMoreSpecial contained
" Comments: {{{1
"==========
@@ -341,42 +341,42 @@ syn match shQuickComment contained "#.*$"
" Here Documents: {{{1
" =========================================
if version < 600
- syn region shHereDoc matchgroup=shRedir01 start="<<\s*\**END[a-zA-Z_0-9]*\**" matchgroup=shRedir01 end="^END[a-zA-Z_0-9]*$" contains=@shDblQuoteList
- syn region shHereDoc matchgroup=shRedir02 start="<<-\s*\**END[a-zA-Z_0-9]*\**" matchgroup=shRedir02 end="^\s*END[a-zA-Z_0-9]*$" contains=@shDblQuoteList
- syn region shHereDoc matchgroup=shRedir03 start="<<\s*\**EOF\**" matchgroup=shRedir03 end="^EOF$" contains=@shDblQuoteList
- syn region shHereDoc matchgroup=shRedir04 start="<<-\s*\**EOF\**" matchgroup=shRedir04 end="^\s*EOF$" contains=@shDblQuoteList
- syn region shHereDoc matchgroup=shRedir05 start="<<\s*\**\.\**" matchgroup=shRedir05 end="^\.$" contains=@shDblQuoteList
- syn region shHereDoc matchgroup=shRedir06 start="<<-\s*\**\.\**" matchgroup=shRedir06 end="^\s*\.$" contains=@shDblQuoteList
+ syn region shHereDoc matchgroup=shHereDoc01 start="<<\s*\**END[a-zA-Z_0-9]*\**" matchgroup=shHereDoc01 end="^END[a-zA-Z_0-9]*$" contains=@shDblQuoteList
+ syn region shHereDoc matchgroup=shHereDoc02 start="<<-\s*\**END[a-zA-Z_0-9]*\**" matchgroup=shHereDoc02 end="^\s*END[a-zA-Z_0-9]*$" contains=@shDblQuoteList
+ syn region shHereDoc matchgroup=shHereDoc03 start="<<\s*\**EOF\**" matchgroup=shHereDoc03 end="^EOF$" contains=@shDblQuoteList
+ syn region shHereDoc matchgroup=shHereDoc04 start="<<-\s*\**EOF\**" matchgroup=shHereDoc04 end="^\s*EOF$" contains=@shDblQuoteList
+ syn region shHereDoc matchgroup=shHereDoc05 start="<<\s*\**\.\**" matchgroup=shHereDoc05 end="^\.$" contains=@shDblQuoteList
+ syn region shHereDoc matchgroup=shHereDoc06 start="<<-\s*\**\.\**" matchgroup=shHereDoc06 end="^\s*\.$" contains=@shDblQuoteList
elseif s:sh_fold_heredoc
- syn region shHereDoc matchgroup=shRedir07 fold start="<<\s*\z([^ \t|]*\)" matchgroup=shRedir07 end="^\z1\s*$" contains=@shDblQuoteList
- syn region shHereDoc matchgroup=shRedir08 fold start="<<\s*\"\z([^ \t|]*\)\"" matchgroup=shRedir08 end="^\z1\s*$"
- syn region shHereDoc matchgroup=shRedir09 fold start="<<\s*'\z([^ \t|]*\)'" matchgroup=shRedir09 end="^\z1\s*$"
- syn region shHereDoc matchgroup=shRedir10 fold start="<<-\s*\z([^ \t|]*\)" matchgroup=shRedir10 end="^\s*\z1\s*$" contains=@shDblQuoteList
- syn region shHereDoc matchgroup=shRedir11 fold start="<<-\s*\"\z([^ \t|]*\)\"" matchgroup=shRedir11 end="^\s*\z1\s*$"
- syn region shHereDoc matchgroup=shRedir12 fold start="<<-\s*'\z([^ \t|]*\)'" matchgroup=shRedir12 end="^\s*\z1\s*$"
- syn region shHereDoc matchgroup=shRedir13 fold start="<<\s*\\\_$\_s*\z([^ \t|]*\)" matchgroup=shRedir13 end="^\z1\s*$"
- syn region shHereDoc matchgroup=shRedir14 fold start="<<\s*\\\_$\_s*\"\z([^ \t|]*\)\"" matchgroup=shRedir14 end="^\z1\s*$"
- syn region shHereDoc matchgroup=shRedir15 fold start="<<-\s*\\\_$\_s*'\z([^ \t|]*\)'" matchgroup=shRedir15 end="^\s*\z1\s*$"
- syn region shHereDoc matchgroup=shRedir16 fold start="<<-\s*\\\_$\_s*\z([^ \t|]*\)" matchgroup=shRedir16 end="^\s*\z1\s*$"
- syn region shHereDoc matchgroup=shRedir17 fold start="<<-\s*\\\_$\_s*\"\z([^ \t|]*\)\"" matchgroup=shRedir17 end="^\s*\z1\s*$"
- syn region shHereDoc matchgroup=shRedir18 fold start="<<\s*\\\_$\_s*'\z([^ \t|]*\)'" matchgroup=shRedir18 end="^\z1\s*$"
- syn region shHereDoc matchgroup=shRedir19 fold start="<<\\\z([^ \t|]*\)" matchgroup=shRedir19 end="^\z1\s*$"
+ syn region shHereDoc matchgroup=shHereDoc07 fold start="<<\s*\z([^ \t|]*\)" matchgroup=shHereDoc07 end="^\z1\s*$" contains=@shDblQuoteList
+ syn region shHereDoc matchgroup=shHereDoc08 fold start="<<\s*\"\z([^ \t|]*\)\"" matchgroup=shHereDoc08 end="^\z1\s*$"
+ syn region shHereDoc matchgroup=shHereDoc09 fold start="<<\s*'\z([^ \t|]*\)'" matchgroup=shHereDoc09 end="^\z1\s*$"
+ syn region shHereDoc matchgroup=shHereDoc10 fold start="<<-\s*\z([^ \t|]*\)" matchgroup=shHereDoc10 end="^\s*\z1\s*$" contains=@shDblQuoteList
+ syn region shHereDoc matchgroup=shHereDoc11 fold start="<<-\s*\"\z([^ \t|]*\)\"" matchgroup=shHereDoc11 end="^\s*\z1\s*$"
+ syn region shHereDoc matchgroup=shHereDoc12 fold start="<<-\s*'\z([^ \t|]*\)'" matchgroup=shHereDoc12 end="^\s*\z1\s*$"
+ syn region shHereDoc matchgroup=shHereDoc13 fold start="<<\s*\\\_$\_s*\z([^ \t|]*\)" matchgroup=shHereDoc13 end="^\z1\s*$"
+ syn region shHereDoc matchgroup=shHereDoc14 fold start="<<\s*\\\_$\_s*\"\z([^ \t|]*\)\"" matchgroup=shHereDoc14 end="^\z1\s*$"
+ syn region shHereDoc matchgroup=shHereDoc15 fold start="<<-\s*\\\_$\_s*'\z([^ \t|]*\)'" matchgroup=shHereDoc15 end="^\s*\z1\s*$"
+ syn region shHereDoc matchgroup=shHereDoc16 fold start="<<-\s*\\\_$\_s*\z([^ \t|]*\)" matchgroup=shHereDoc16 end="^\s*\z1\s*$"
+ syn region shHereDoc matchgroup=shHereDoc17 fold start="<<-\s*\\\_$\_s*\"\z([^ \t|]*\)\"" matchgroup=shHereDoc17 end="^\s*\z1\s*$"
+ syn region shHereDoc matchgroup=shHereDoc18 fold start="<<\s*\\\_$\_s*'\z([^ \t|]*\)'" matchgroup=shHereDoc18 end="^\z1\s*$"
+ syn region shHereDoc matchgroup=shHereDoc19 fold start="<<\\\z([^ \t|]*\)" matchgroup=shHereDoc19 end="^\z1\s*$"
else
- syn region shHereDoc matchgroup=shRedir20 start="<<\s*\\\=\z([^ \t|]*\)" matchgroup=shRedir20 end="^\z1\s*$" contains=@shDblQuoteList
- syn region shHereDoc matchgroup=shRedir21 start="<<\s*\"\z([^ \t|]*\)\"" matchgroup=shRedir21 end="^\z1\s*$"
- syn region shHereDoc matchgroup=shRedir22 start="<<-\s*\z([^ \t|]*\)" matchgroup=shRedir22 end="^\s*\z1\s*$" contains=@shDblQuoteList
- syn region shHereDoc matchgroup=shRedir23 start="<<-\s*'\z([^ \t|]*\)'" matchgroup=shRedir23 end="^\s*\z1\s*$"
- syn region shHereDoc matchgroup=shRedir24 start="<<\s*'\z([^ \t|]*\)'" matchgroup=shRedir24 end="^\z1\s*$"
- syn region shHereDoc matchgroup=shRedir25 start="<<-\s*\"\z([^ \t|]*\)\"" matchgroup=shRedir25 end="^\s*\z1\s*$"
- syn region shHereDoc matchgroup=shRedir26 start="<<\s*\\\_$\_s*\z([^ \t|]*\)" matchgroup=shRedir26 end="^\z1\s*$"
- syn region shHereDoc matchgroup=shRedir27 start="<<-\s*\\\_$\_s*\z([^ \t|]*\)" matchgroup=shRedir27 end="^\s*\z1\s*$"
- syn region shHereDoc matchgroup=shRedir28 start="<<-\s*\\\_$\_s*'\z([^ \t|]*\)'" matchgroup=shRedir28 end="^\s*\z1\s*$"
- syn region shHereDoc matchgroup=shRedir29 start="<<\s*\\\_$\_s*'\z([^ \t|]*\)'" matchgroup=shRedir29 end="^\z1\s*$"
- syn region shHereDoc matchgroup=shRedir30 start="<<\s*\\\_$\_s*\"\z([^ \t|]*\)\"" matchgroup=shRedir30 end="^\z1\s*$"
- syn region shHereDoc matchgroup=shRedir31 start="<<-\s*\\\_$\_s*\"\z([^ \t|]*\)\"" matchgroup=shRedir31 end="^\s*\z1\s*$"
- syn region shHereDoc matchgroup=shRedir32 start="<<\\\z([^ \t|]*\)" matchgroup=shRedir32 end="^\z1\s*$"
+ syn region shHereDoc matchgroup=shHereDoc20 start="<<\s*\\\=\z([^ \t|]*\)" matchgroup=shHereDoc20 end="^\z1\s*$" contains=@shDblQuoteList
+ syn region shHereDoc matchgroup=shHereDoc21 start="<<\s*\"\z([^ \t|]*\)\"" matchgroup=shHereDoc21 end="^\z1\s*$"
+ syn region shHereDoc matchgroup=shHereDoc22 start="<<-\s*\z([^ \t|]*\)" matchgroup=shHereDoc22 end="^\s*\z1\s*$" contains=@shDblQuoteList
+ syn region shHereDoc matchgroup=shHereDoc23 start="<<-\s*'\z([^ \t|]*\)'" matchgroup=shHereDoc23 end="^\s*\z1\s*$"
+ syn region shHereDoc matchgroup=shHereDoc24 start="<<\s*'\z([^ \t|]*\)'" matchgroup=shHereDoc24 end="^\z1\s*$"
+ syn region shHereDoc matchgroup=shHereDoc25 start="<<-\s*\"\z([^ \t|]*\)\"" matchgroup=shHereDoc25 end="^\s*\z1\s*$"
+ syn region shHereDoc matchgroup=shHereDoc26 start="<<\s*\\\_$\_s*\z([^ \t|]*\)" matchgroup=shHereDoc26 end="^\z1\s*$"
+ syn region shHereDoc matchgroup=shHereDoc27 start="<<-\s*\\\_$\_s*\z([^ \t|]*\)" matchgroup=shHereDoc27 end="^\s*\z1\s*$"
+ syn region shHereDoc matchgroup=shHereDoc28 start="<<-\s*\\\_$\_s*'\z([^ \t|]*\)'" matchgroup=shHereDoc28 end="^\s*\z1\s*$"
+ syn region shHereDoc matchgroup=shHereDoc29 start="<<\s*\\\_$\_s*'\z([^ \t|]*\)'" matchgroup=shHereDoc29 end="^\z1\s*$"
+ syn region shHereDoc matchgroup=shHereDoc30 start="<<\s*\\\_$\_s*\"\z([^ \t|]*\)\"" matchgroup=shHereDoc30 end="^\z1\s*$"
+ syn region shHereDoc matchgroup=shHereDoc31 start="<<-\s*\\\_$\_s*\"\z([^ \t|]*\)\"" matchgroup=shHereDoc31 end="^\s*\z1\s*$"
+ syn region shHereDoc matchgroup=shHereDoc32 start="<<\\\z([^ \t|]*\)" matchgroup=shHereDoc32 end="^\z1\s*$"
endif
" Here Strings: {{{1
@@ -389,8 +389,8 @@ endif
" Identifiers: {{{1
"=============
syn match shSetOption "\s\zs[-+][a-zA-Z0-9]\+\>" contained
-syn match shVariable "\<\([bwglsav]:\)\=[a-zA-Z0-9.!@_%+,]*\ze=" nextgroup=shSetIdentifier
-syn match shSetIdentifier "=" contained nextgroup=shCmdParenRegion,shPattern,shDeref,shDerefSimple,shDoubleQuote,shExDoubleQuote,shSingleQuote,shExSingleQuote
+syn match shVariable "\<\([bwglsav]:\)\=[a-zA-Z0-9.!@_%+,]*\ze=" nextgroup=shVarAssign
+syn match shVarAssign "=" contained nextgroup=shCmdParenRegion,shPattern,shDeref,shDerefSimple,shDoubleQuote,shExDoubleQuote,shSingleQuote,shExSingleQuote
syn region shAtExpr contained start="@(" end=")" contains=@shIdList
if exists("b:is_bash")
syn region shSetList oneline matchgroup=shSet start="\<\(declare\|typeset\|local\|export\|unset\)\>\ze[^/]" end="$" matchgroup=shSetListDelim end="\ze[}|);&]" matchgroup=NONE end="\ze\s\+#\|=" contains=@shIdList
@@ -668,38 +668,38 @@ hi def link shStatement Statement
hi def link shString String
hi def link shTodo Todo
hi def link shAlias Identifier
-hi def link shRedir01 shRedir
-hi def link shRedir02 shRedir
-hi def link shRedir03 shRedir
-hi def link shRedir04 shRedir
-hi def link shRedir05 shRedir
-hi def link shRedir06 shRedir
-hi def link shRedir07 shRedir
-hi def link shRedir08 shRedir
-hi def link shRedir09 shRedir
-hi def link shRedir10 shRedir
-hi def link shRedir11 shRedir
-hi def link shRedir12 shRedir
-hi def link shRedir13 shRedir
-hi def link shRedir14 shRedir
-hi def link shRedir15 shRedir
-hi def link shRedir16 shRedir
-hi def link shRedir17 shRedir
-hi def link shRedir18 shRedir
-hi def link shRedir19 shRedir
-hi def link shRedir20 shRedir
-hi def link shRedir21 shRedir
-hi def link shRedir22 shRedir
-hi def link shRedir23 shRedir
-hi def link shRedir24 shRedir
-hi def link shRedir25 shRedir
-hi def link shRedir26 shRedir
-hi def link shRedir27 shRedir
-hi def link shRedir28 shRedir
-hi def link shRedir29 shRedir
-hi def link shRedir30 shRedir
-hi def link shRedir31 shRedir
-hi def link shRedir32 shRedir
+hi def link shHereDoc01 shRedir
+hi def link shHereDoc02 shRedir
+hi def link shHereDoc03 shRedir
+hi def link shHereDoc04 shRedir
+hi def link shHereDoc05 shRedir
+hi def link shHereDoc06 shRedir
+hi def link shHereDoc07 shRedir
+hi def link shHereDoc08 shRedir
+hi def link shHereDoc09 shRedir
+hi def link shHereDoc10 shRedir
+hi def link shHereDoc11 shRedir
+hi def link shHereDoc12 shRedir
+hi def link shHereDoc13 shRedir
+hi def link shHereDoc14 shRedir
+hi def link shHereDoc15 shRedir
+hi def link shHereDoc16 shRedir
+hi def link shHereDoc17 shRedir
+hi def link shHereDoc18 shRedir
+hi def link shHereDoc19 shRedir
+hi def link shHereDoc20 shRedir
+hi def link shHereDoc21 shRedir
+hi def link shHereDoc22 shRedir
+hi def link shHereDoc23 shRedir
+hi def link shHereDoc24 shRedir
+hi def link shHereDoc25 shRedir
+hi def link shHereDoc26 shRedir
+hi def link shHereDoc27 shRedir
+hi def link shHereDoc28 shRedir
+hi def link shHereDoc29 shRedir
+hi def link shHereDoc30 shRedir
+hi def link shHereDoc31 shRedir
+hi def link shHereDoc32 shRedir
" Set Current Syntax: {{{1
" ===================
diff --git a/runtime/syntax/tex.vim b/runtime/syntax/tex.vim
index f704766877..b95ff4d8cb 100644
--- a/runtime/syntax/tex.vim
+++ b/runtime/syntax/tex.vim
@@ -1,8 +1,8 @@
" Vim syntax file
" Language: TeX
" Maintainer: Charles E. Campbell <NdrchipO@ScampbellPfamily.AbizM>
-" Last Change: Apr 02, 2015
-" Version: 84
+" Last Change: Jun 11, 2015
+" Version: 87
" URL: http://www.drchip.org/astronaut/vim/index.html#SYNTAX_TEX
"
" Notes: {{{1
@@ -207,7 +207,7 @@ if s:tex_fast =~ 'M'
if !exists("s:tex_no_error") || !s:tex_no_error
syn match texMathError "}" contained
endif
- syn region texMathMatcher matchgroup=Delimiter start="{" skip="\\\\\|\\}" end="}" end="%stopzone\>" contained contains=@texMathMatchGroup
+ syn region texMathMatcher matchgroup=Delimiter start="{" skip="\(\\\\\)*\\}" end="}" end="%stopzone\>" contained contains=@texMathMatchGroup
endif
endif
@@ -226,7 +226,7 @@ endif
" TeX/LaTeX delimiters: {{{1
syn match texDelimiter "&"
syn match texDelimiter "\\\\"
-syn match texDelimiter "[{}]"
+"%syn match texDelimiter "[{}]"
" Tex/Latex Options: {{{1
syn match texOption "[^\\]\zs#\d\+\|^#\d\+"
@@ -247,7 +247,7 @@ syn match texLigature "\\\([ijolL]\|ae\|oe\|ss\|AA\|AE\|OE\)$"
" \begin{}/\end{} section markers: {{{1
syn match texBeginEnd "\\begin\>\|\\end\>" nextgroup=texBeginEndName
if s:tex_fast =~ 'm'
- syn region texBeginEndName matchgroup=Delimiter start="{" end="}" contained nextgroup=texBeginEndModifier contains=texComment
+ syn region texBeginEndName matchgroup=Delimiter start="{" end="}" contained nextgroup=texBeginEndModifier contains=texComment
syn region texBeginEndModifier matchgroup=Delimiter start="\[" end="]" contained contains=texComment,@NoSpell
endif
@@ -392,22 +392,22 @@ endif
if s:tex_fast =~ 'b'
if s:tex_conceal =~ 'b'
if !exists("g:tex_nospell") || !g:tex_nospell
- syn region texBoldStyle matchgroup=texTypeStyle start="\\textbf\s*\ze{" matchgroup=Delimiter end="}" concealends contains=@texBoldGroup,@Spell
- syn region texBoldItalStyle matchgroup=texTypeStyle start="\\textit\s*\ze{" matchgroup=Delimiter end="}" concealends contains=@texItalGroup,@Spell
- syn region texItalStyle matchgroup=texTypeStyle start="\\textit\s*\ze{" matchgroup=Delimiter end="}" concealends contains=@texItalGroup,@Spell
- syn region texItalBoldStyle matchgroup=texTypeStyle start="\\textbf\s*\ze{" matchgroup=Delimiter end="}" concealends contains=@texBoldGroup,@Spell
- else
- syn region texBoldStyle matchgroup=texTypeStyle start="\\textbf\s*\ze{" matchgroup=Delimiter end="}" concealends contains=@texBoldGroup
- syn region texBoldItalStyle matchgroup=texTypeStyle start="\\textit\s*\ze{" matchgroup=Delimiter end="}" concealends contains=@texItalGroup
- syn region texItalStyle matchgroup=texTypeStyle start="\\textit\s*\ze{" matchgroup=Delimiter end="}" concealends contains=@texItalGroup
- syn region texItalBoldStyle matchgroup=texTypeStyle start="\\textbf\s*\ze{" matchgroup=Delimiter end="}" concealends contains=@texBoldGroup
+ syn region texBoldStyle matchgroup=texTypeStyle start="\\textbf\s*{" matchgroup=texTypeStyle end="}" concealends contains=@texBoldGroup,@Spell
+ syn region texBoldItalStyle matchgroup=texTypeStyle start="\\textit\s*{" matchgroup=texTypeStyle end="}" concealends contains=@texItalGroup,@Spell
+ syn region texItalStyle matchgroup=texTypeStyle start="\\textit\s*{" matchgroup=texTypeStyle end="}" concealends contains=@texItalGroup,@Spell
+ syn region texItalBoldStyle matchgroup=texTypeStyle start="\\textbf\s*{" matchgroup=texTypeStyle end="}" concealends contains=@texBoldGroup,@Spell
+ else
+ syn region texBoldStyle matchgroup=texTypeStyle start="\\textbf\s*{" matchgroup=texTypeStyle end="}" concealends contains=@texBoldGroup
+ syn region texBoldItalStyle matchgroup=texTypeStyle start="\\textit\s*{" matchgroup=texTypeStyle end="}" concealends contains=@texItalGroup
+ syn region texItalStyle matchgroup=texTypeStyle start="\\textit\s*{" matchgroup=texTypeStyle end="}" concealends contains=@texItalGroup
+ syn region texItalBoldStyle matchgroup=texTypeStyle start="\\textbf\s*{" matchgroup=texTypeStyle end="}" concealends contains=@texBoldGroup
endif
endif
endif
" Bad Math (mismatched): {{{1
if !exists("g:tex_no_math") && (!exists("s:tex_no_error") || !s:tex_no_error)
- syn match texBadMath "\\end\s*{\s*\(array\|gathered\|bBpvV]matrix\|split\|subequations\|smallmatrix\|xxalignat\)\s*}"
+ syn match texBadMath "\\end\s*{\s*\(array\|gathered\|bBpvV]matrix\|split\|smallmatrix\|xxalignat\)\s*}"
syn match texBadMath "\\end\s*{\s*\(align\|alignat\|displaymath\|displaymath\|eqnarray\|equation\|flalign\|gather\|math\|multline\|xalignat\)\*\=\s*}"
syn match texBadMath "\\[\])]"
endif
@@ -456,24 +456,23 @@ if !exists("g:tex_no_math")
call TexNewMathZone("G","gather",1)
call TexNewMathZone("H","math",1)
call TexNewMathZone("I","multline",1)
- call TexNewMathZone("J","subequations",0)
- call TexNewMathZone("K","xalignat",1)
- call TexNewMathZone("L","xxalignat",0)
+ call TexNewMathZone("J","xalignat",1)
+ call TexNewMathZone("K","xxalignat",0)
" Inline Math Zones: {{{2
if s:tex_fast =~ 'M'
if has("conceal") && &enc == 'utf-8' && s:tex_conceal =~ 'd'
- syn region texMathZoneV matchgroup=Delimiter start="\\(" matchgroup=Delimiter end="\\)\|%stopzone\>" keepend concealends contains=@texMathZoneGroup
- syn region texMathZoneW matchgroup=Delimiter start="\\\[" matchgroup=Delimiter end="\\]\|%stopzone\>" keepend concealends contains=@texMathZoneGroup
- syn region texMathZoneX matchgroup=Delimiter start="\$" skip="\\\\\|\\\$" matchgroup=Delimiter end="\$" end="%stopzone\>" concealends contains=@texMathZoneGroup
- syn region texMathZoneY matchgroup=Delimiter start="\$\$" matchgroup=Delimiter end="\$\$" end="%stopzone\>" concealends keepend contains=@texMathZoneGroup
+ syn region texMathZoneV matchgroup=Delimiter start="\\(" matchgroup=Delimiter end="\\)\|%stopzone\>" keepend concealends contains=@texMathZoneGroup
+ syn region texMathZoneW matchgroup=Delimiter start="\\\[" matchgroup=Delimiter end="\\]\|%stopzone\>" keepend concealends contains=@texMathZoneGroup
+ syn region texMathZoneX matchgroup=Delimiter start="\$" skip="\\\\\|\\\$" matchgroup=Delimiter end="\$" end="%stopzone\>" concealends contains=@texMathZoneGroup
+ syn region texMathZoneY matchgroup=Delimiter start="\$\$" matchgroup=Delimiter end="\$\$" end="%stopzone\>" keepend concealends contains=@texMathZoneGroup
else
- syn region texMathZoneV matchgroup=Delimiter start="\\(" matchgroup=Delimiter end="\\)\|%stopzone\>" keepend contains=@texMathZoneGroup
- syn region texMathZoneW matchgroup=Delimiter start="\\\[" matchgroup=Delimiter end="\\]\|%stopzone\>" keepend contains=@texMathZoneGroup
- syn region texMathZoneX matchgroup=Delimiter start="\$" skip="\\\\\|\\\$" matchgroup=Delimiter end="\$" end="%stopzone\>" contains=@texMathZoneGroup
- syn region texMathZoneY matchgroup=Delimiter start="\$\$" matchgroup=Delimiter end="\$\$" end="%stopzone\>" keepend contains=@texMathZoneGroup
+ syn region texMathZoneV matchgroup=Delimiter start="\\(" matchgroup=Delimiter end="\\)\|%stopzone\>" keepend contains=@texMathZoneGroup
+ syn region texMathZoneW matchgroup=Delimiter start="\\\[" matchgroup=Delimiter end="\\]\|%stopzone\>" keepend contains=@texMathZoneGroup
+ syn region texMathZoneX matchgroup=Delimiter start="\$" skip="\\\\\|\\\$" matchgroup=Delimiter end="\$" end="%stopzone\>" contains=@texMathZoneGroup
+ syn region texMathZoneY matchgroup=Delimiter start="\$\$" matchgroup=Delimiter end="\$\$" end="%stopzone\>" keepend contains=@texMathZoneGroup
endif
- syn region texMathZoneZ matchgroup=texStatement start="\\ensuremath\s*{" matchgroup=texStatement end="}" end="%stopzone\>" contains=@texMathZoneGroup
+ syn region texMathZoneZ matchgroup=texStatement start="\\ensuremath\s*{" matchgroup=texStatement end="}" end="%stopzone\>" contains=@texMathZoneGroup
endif
syn match texMathOper "[_^=]" contained
@@ -1062,11 +1061,12 @@ if has("conceal") && &enc == 'utf-8'
syn region texSuperscript matchgroup=Delimiter start='\^{' skip="\\\\\|\\[{}]" end='}' contained concealends contains=texSpecialChar,texSuperscripts,texStatement,texSubscript,texSuperscript,texMathMatcher
syn region texSubscript matchgroup=Delimiter start='_{' skip="\\\\\|\\[{}]" end='}' contained concealends contains=texSpecialChar,texSubscripts,texStatement,texSubscript,texSuperscript,texMathMatcher
endif
+ " s:SuperSub:
fun! s:SuperSub(group,leader,pat,cchar)
if a:pat =~ '^\\' || (a:leader == '\^' && a:pat =~ g:tex_superscripts) || (a:leader == '_' && a:pat =~ g:tex_subscripts)
" call Decho("SuperSub: group<".a:group."> leader<".a:leader."> pat<".a:pat."> cchar<".a:cchar.">")
exe 'syn match '.a:group." '".a:leader.a:pat."' contained conceal cchar=".a:cchar
- exe 'syn match '.a:group."s '".a:pat."' contained conceal cchar=".a:cchar.' nextgroup='.a:group.'s'
+ exe 'syn match '.a:group."s '".a:pat ."' contained conceal cchar=".a:cchar.' nextgroup='.a:group.'s'
endif
endfun
call s:SuperSub('texSuperscript','\^','0','⁰')
diff --git a/runtime/vimrc_example.vim b/runtime/vimrc_example.vim
index 48c7a3535a..c53dde8ceb 100644
--- a/runtime/vimrc_example.vim
+++ b/runtime/vimrc_example.vim
@@ -1,8 +1,8 @@
" An example for a vimrc file.
"
" To use it, copy it to
-" for Unix: ~/.vimrc
-" for Windows: $VIM\_vimrc
+" for Unix: $HOME/.config/nvim/init.vim
+" for Windows: %LOCALAPPDATA%\nvim\init.vim
set backup " keep a backup file (restore to previous version)
set undofile " keep an undo file (undo changes after closing)
diff --git a/src/nvim/README.md b/src/nvim/README.md
index e4939d94fd..f16c6de12f 100644
--- a/src/nvim/README.md
+++ b/src/nvim/README.md
@@ -11,7 +11,7 @@ that are constantly changing. As the code becomes more organized and stable,
this document will be updated to reflect the changes.
If you are looking for module-specific details, it is best to read the source
-code. Some files are extensively commented at the top(eg: terminal.c,
+code. Some files are extensively commented at the top (e.g. terminal.c,
screen.c).
### Top-level program loops
@@ -43,13 +43,13 @@ a typical editing session:
Note that we have split user actions into sequences of inputs that change the
state of the editor. While there's no documentation about a "g command
-mode"(step 16), internally it is implemented similarly to "operator-pending
+mode" (step 16), internally it is implemented similarly to "operator-pending
mode".
From this we can see that Vim has the behavior of a input-driven state
-machine(more specifically, a pushdown automaton since it requires a stack for
+machine (more specifically, a pushdown automaton since it requires a stack for
transitioning back from states). Assuming each state has a callback responsible
-for handling keys, this pseudocode(a python-like language) shows a good
+for handling keys, this pseudocode (a python-like language) shows a good
representation of the main program loop:
```py
@@ -129,20 +129,20 @@ def insert_state(data, key):
While the actual code is much more complicated, the above gives an idea of how
Neovim is organized internally. Some states like the `g_command_state` or
`get_operator_count_state` do not have a dedicated `state_enter` callback, but
-are implicitly embedded into other states(this will change later as we continue
+are implicitly embedded into other states (this will change later as we continue
the refactoring effort). To start reading the actual code, here's the
recommended order:
-1. `state_enter()` function(state.c). This is the actual program loop,
+1. `state_enter()` function (state.c). This is the actual program loop,
note that a `VimState` structure is used, which contains function pointers
for the callback and state data.
-2. `main()` function(main.c). After all startup, `normal_enter` is called
+2. `main()` function (main.c). After all startup, `normal_enter` is called
at the end of function to enter normal mode.
-3. `normal_enter()` function(normal.c) is a small wrapper for setting
+3. `normal_enter()` function (normal.c) is a small wrapper for setting
up the NormalState structure and calling `state_enter`.
-4. `normal_check()` function(normal.c) is called before each iteration of
+4. `normal_check()` function (normal.c) is called before each iteration of
normal mode.
-5. `normal_execute()` function(normal.c) is called when a key is read in normal
+5. `normal_execute()` function (normal.c) is called when a key is read in normal
mode.
The basic structure described for normal mode in 3, 4 and 5 is used for other
@@ -159,7 +159,7 @@ asynchronous events, which can include:
- msgpack-rpc requests
- job control callbacks
-- timers(not implemented yet but the support code is already there)
+- timers (not implemented yet but the support code is already there)
Neovim implements this functionality by entering another event loop while
waiting for characters, so instead of:
@@ -180,11 +180,11 @@ def state_enter(state_callback, data):
while state_callback(data, event) # invoke the callback for the current state
```
-where `event` is something the operating system delivers to us, including(but
+where `event` is something the operating system delivers to us, including (but
not limited to) user input. The `read_next_event()` part is internally
implemented by libuv, the platform layer used by Neovim.
Since Neovim inherited its code from Vim, the states are not prepared to receive
-"arbitrary events", so we use a special key to represent those(When a state
+"arbitrary events", so we use a special key to represent those (When a state
receives an "arbitrary event", it normally doesn't do anything other update the
screen).
diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c
index a6e3fedd3f..34e24712cd 100644
--- a/src/nvim/buffer.c
+++ b/src/nvim/buffer.c
@@ -22,6 +22,7 @@
#include "nvim/api/private/handle.h"
#include "nvim/ascii.h"
+#include "nvim/assert.h"
#include "nvim/vim.h"
#include "nvim/buffer.h"
#include "nvim/charset.h"
@@ -2826,7 +2827,7 @@ typedef enum {
/// @param fillchar Character to use when filling empty space in the statusline
/// @param maxwidth The maximum width to make the statusline
/// @param hltab HL attributes (can be NULL)
-/// @param tabtab tab page nrs (can be NULL)
+/// @param tabtab Tab clicks definition (can be NULL).
///
/// @return The final width of the statusline
int build_stl_str_hl(
@@ -2838,13 +2839,15 @@ int build_stl_str_hl(
int fillchar,
int maxwidth,
struct stl_hlrec *hltab,
- struct stl_hlrec *tabtab
+ StlClickRecord *tabtab
)
{
int groupitem[STL_MAX_ITEM];
struct stl_item {
// Where the item starts in the status line output buffer
- char_u *start;
+ char_u *start;
+ // Function to run for ClickFunc items.
+ char *cmd;
// The minimum width of the item
int minwid;
// The maximum width of the item
@@ -2856,10 +2859,10 @@ int build_stl_str_hl(
Middle,
Highlight,
TabPage,
+ ClickFunc,
Trunc
- } type;
- } item[STL_MAX_ITEM];
-
+ } type;
+ } item[STL_MAX_ITEM];
#define TMPLEN 70
char_u tmp[TMPLEN];
char_u *usefmt = fmt;
@@ -3164,6 +3167,24 @@ int build_stl_str_hl(
continue;
}
+ if (*fmt_p == STL_CLICK_FUNC) {
+ fmt_p++;
+ char *t = (char *) fmt_p;
+ while (*fmt_p != STL_CLICK_FUNC && *fmt_p) {
+ fmt_p++;
+ }
+ if (*fmt_p != STL_CLICK_FUNC) {
+ break;
+ }
+ item[curitem].type = ClickFunc;
+ item[curitem].start = out_p;
+ item[curitem].cmd = xmemdupz(t, (size_t) (((char *) fmt_p - t)));
+ item[curitem].minwid = minwid;
+ fmt_p++;
+ curitem++;
+ continue;
+ }
+
// Denotes the end of the minwid
// the maxwid may follow immediately after
if (*fmt_p == '.') {
@@ -3281,6 +3302,7 @@ int build_stl_str_hl(
}
break;
}
+
case STL_LINE:
num = (wp->w_buffer->b_ml.ml_flags & ML_EMPTY)
? 0L : (long)(wp->w_cursor.lnum);
@@ -3821,16 +3843,37 @@ int build_stl_str_hl(
// Store the info about tab pages labels.
if (tabtab != NULL) {
- struct stl_hlrec *sp = tabtab;
+ StlClickRecord *cur_tab_rec = tabtab;
for (long l = 0; l < itemcnt; l++) {
if (item[l].type == TabPage) {
- sp->start = item[l].start;
- sp->userhl = item[l].minwid;
- sp++;
+ cur_tab_rec->start = (char *) item[l].start;
+ if (item[l].minwid == 0) {
+ cur_tab_rec->def.type = kStlClickDisabled;
+ cur_tab_rec->def.tabnr = 0;
+ } else {
+ int tabnr = item[l].minwid;
+ if (item[l].minwid > 0) {
+ cur_tab_rec->def.type = kStlClickTabSwitch;
+ } else {
+ cur_tab_rec->def.type = kStlClickTabClose;
+ tabnr = -tabnr;
+ }
+ cur_tab_rec->def.tabnr = tabnr;
+ }
+ cur_tab_rec->def.func = NULL;
+ cur_tab_rec++;
+ } else if (item[l].type == ClickFunc) {
+ cur_tab_rec->start = (char *) item[l].start;
+ cur_tab_rec->def.type = kStlClickFuncRun;
+ cur_tab_rec->def.tabnr = item[l].minwid;
+ cur_tab_rec->def.func = item[l].cmd;
+ cur_tab_rec++;
}
}
- sp->start = NULL;
- sp->userhl = 0;
+ cur_tab_rec->start = NULL;
+ cur_tab_rec->def.type = kStlClickDisabled;
+ cur_tab_rec->def.tabnr = 0;
+ cur_tab_rec->def.func = NULL;
}
return width;
diff --git a/src/nvim/buffer.h b/src/nvim/buffer.h
index 49025d3925..d51a2f7dae 100644
--- a/src/nvim/buffer.h
+++ b/src/nvim/buffer.h
@@ -4,6 +4,7 @@
#include "nvim/window.h"
#include "nvim/pos.h" // for linenr_T
#include "nvim/ex_cmds_defs.h" // for exarg_T
+#include "nvim/screen.h" // for StlClickRecord
// Values for buflist_getfile()
enum getf_values {
diff --git a/src/nvim/charset.c b/src/nvim/charset.c
index 9c63eca1f2..9a0e1440cc 100644
--- a/src/nvim/charset.c
+++ b/src/nvim/charset.c
@@ -1767,29 +1767,26 @@ int vim_isblankline(char_u *lbuf)
/// If "len" is not NULL, the length of the number in characters is returned.
/// If "nptr" is not NULL, the signed result is returned in it.
/// If "unptr" is not NULL, the unsigned result is returned in it.
-/// If "dobin" is non-zero recognize binary numbers, when > 1 always assume
-/// binary number.
-/// If "dooct" is non-zero recognize octal numbers, when > 1 always assume
-/// octal number.
-/// If "dohex" is non-zero recognize hex numbers, when > 1 always assume
-/// hex number.
+/// If "what" contains STR2NR_BIN recognize binary numbers.
+/// If "what" contains STR2NR_OCT recognize octal numbers.
+/// If "what" contains STR2NR_HEX recognize hex numbers.
+/// If "what" contains STR2NR_FORCE always assume bin/oct/hex.
+/// If maxlen > 0, check at a maximum maxlen chars.
///
/// @param start
/// @param prep Returns type of number 0 = decimal, 'x' or 'X' is hex,
-// '0' = octal, 'b' or 'B' is bin
+/// '0' = octal, 'b' or 'B' is bin
/// @param len Returns the detected length of number.
-/// @param dobin recognize binary number
-/// @param dooct recognize octal number
-/// @param dohex recognize hex number
+/// @param what Recognizes what number passed.
/// @param nptr Returns the signed result.
/// @param unptr Returns the unsigned result.
-void vim_str2nr(char_u *start, int *prep, int *len,
- int dobin, int dooct, int dohex,
- long *nptr, unsigned long *unptr)
+/// @param maxlen Max length of string to check.
+void vim_str2nr(char_u *start, int *prep, int *len, int what,
+ long *nptr, unsigned long *unptr, int maxlen)
{
char_u *ptr = start;
int pre = 0; // default is decimal
- int negative = false;
+ bool negative = false;
unsigned long un = 0;
if (ptr[0] == '-') {
@@ -1797,25 +1794,28 @@ void vim_str2nr(char_u *start, int *prep, int *len,
ptr++;
}
- // Recognize hex, octal, and bin.
- if ((ptr[0] == '0') && (ptr[1] != '8') && (ptr[1] != '9')) {
+ // Recognize hex, octal and bin.
+ if ((ptr[0] == '0') && (ptr[1] != '8') && (ptr[1] != '9')
+ && (maxlen == 0 || maxlen > 1)) {
pre = ptr[1];
- if (dohex
+ if ((what & STR2NR_HEX)
&& ((pre == 'X') || (pre == 'x'))
- && ascii_isxdigit(ptr[2])) {
+ && ascii_isxdigit(ptr[2])
+ && (maxlen == 0 || maxlen > 2)) {
// hexadecimal
ptr += 2;
- } else if (dobin
+ } else if ((what & STR2NR_BIN)
&& ((pre == 'B') || (pre == 'b'))
- && ascii_isbdigit(ptr[2])) {
+ && ascii_isbdigit(ptr[2])
+ && (maxlen == 0 || maxlen > 2)) {
// binary
ptr += 2;
} else {
- // default is decimal
+ // decimal or octal, default is decimal
pre = 0;
- if (dooct) {
+ if (what & STR2NR_OCT) {
// Don't interpret "0", "08" or "0129" as octal.
for (int n = 1; ascii_isdigit(ptr[n]); ++n) {
if (ptr[n] > '7') {
@@ -1827,35 +1827,58 @@ void vim_str2nr(char_u *start, int *prep, int *len,
// assume octal
pre = '0';
}
+ if (n == maxlen) {
+ break;
+ }
}
}
}
}
// Do the string-to-numeric conversion "manually" to avoid sscanf quirks.
- if ((pre == 'B') || (pre == 'b') || (dobin > 1)) {
+ int n = 1;
+ if ((pre == 'B') || (pre == 'b') || what == STR2NR_BIN + STR2NR_FORCE) {
// bin
+ if (pre != 0) {
+ n += 2; // skip over "0b"
+ }
while ('0' <= *ptr && *ptr <= '1') {
un = 2 * un + (unsigned long)(*ptr - '0');
ptr++;
+ if (n++ == maxlen) {
+ break;
+ }
}
- } else if ((pre == '0') || (dooct > 1)) {
+ } else if ((pre == '0') || what == STR2NR_OCT + STR2NR_FORCE) {
// octal
while ('0' <= *ptr && *ptr <= '7') {
un = 8 * un + (unsigned long)(*ptr - '0');
ptr++;
+ if (n++ == maxlen) {
+ break;
+ }
}
- } else if ((pre == 'X') || (pre == 'x') || dohex > 1) {
+ } else if ((pre == 'X') || (pre == 'x')
+ || what == STR2NR_HEX + STR2NR_FORCE) {
// hex
+ if (pre != 0) {
+ n += 2; // skip over "0x"
+ }
while (ascii_isxdigit(*ptr)) {
un = 16 * un + (unsigned long)hex2nr(*ptr);
ptr++;
+ if (n++ == maxlen) {
+ break;
+ }
}
} else {
// decimal
while (ascii_isdigit(*ptr)) {
un = 10 * un + (unsigned long)(*ptr - '0');
ptr++;
+ if (n++ == maxlen) {
+ break;
+ }
}
}
diff --git a/src/nvim/edit.c b/src/nvim/edit.c
index dbbcf4f1b9..213df4f65a 100644
--- a/src/nvim/edit.c
+++ b/src/nvim/edit.c
@@ -2548,8 +2548,12 @@ void ins_compl_show_pum(void)
}
}
- /* Compute the screen column of the start of the completed text.
- * Use the cursor to get all wrapping and other settings right. */
+ // In Replace mode when a $ is displayed at the end of the line only
+ // part of the screen would be updated. We do need to redraw here.
+ dollar_vcol = -1;
+
+ // Compute the screen column of the start of the completed text.
+ // Use the cursor to get all wrapping and other settings right.
col = curwin->w_cursor.col;
curwin->w_cursor.col = compl_col;
pum_display(compl_match_array, compl_match_arraysize, cur);
diff --git a/src/nvim/eval.c b/src/nvim/eval.c
index a1c5f958d1..a9af7d94c1 100644
--- a/src/nvim/eval.c
+++ b/src/nvim/eval.c
@@ -1147,7 +1147,7 @@ int call_vim_function(
len = 0;
} else {
// Recognize a number argument, the others must be strings.
- vim_str2nr(argv[i], NULL, &len, true, true, true, &n, NULL);
+ vim_str2nr(argv[i], NULL, &len, STR2NR_ALL, &n, NULL, 0);
}
if (len != 0 && len == (int)STRLEN(argv[i])) {
argvars[i].v_type = VAR_NUMBER;
@@ -4138,7 +4138,7 @@ static int eval7(
rettv->vval.v_float = f;
}
} else {
- vim_str2nr(*arg, NULL, &len, true, true, true, &n, NULL);
+ vim_str2nr(*arg, NULL, &len, STR2NR_ALL, &n, NULL, 0);
*arg += len;
if (evaluate) {
rettv->v_type = VAR_NUMBER;
@@ -10930,6 +10930,7 @@ static void f_has(typval_T *argvars, typval_T *rettv)
#if !defined(UNIX)
"system", // TODO(SplinterOfChaos): This IS defined for UNIX!
#endif
+ "tablineat",
"tag_binary",
"tag_old_static",
"termresponse",
@@ -10987,8 +10988,6 @@ static void f_has(typval_T *argvars, typval_T *rettv)
#endif
} else if (STRICMP(name, "syntax_items") == 0) {
n = syntax_present(curwin);
- } else if (STRICMP(name, "gui_running") == 0) {
- n = ui_rgb_attached();
}
}
@@ -15209,6 +15208,7 @@ static void f_setmatches(typval_T *argvars, typval_T *rettv)
list_T *l;
listitem_T *li;
dict_T *d;
+ list_T *s = NULL;
rettv->vval.v_number = -1;
if (argvars[0].v_type != VAR_LIST) {
@@ -15227,7 +15227,8 @@ static void f_setmatches(typval_T *argvars, typval_T *rettv)
return;
}
if (!(dict_find(d, (char_u *)"group", -1) != NULL
- && dict_find(d, (char_u *)"pattern", -1) != NULL
+ && (dict_find(d, (char_u *)"pattern", -1) != NULL
+ || dict_find(d, (char_u *)"pos1", -1) != NULL)
&& dict_find(d, (char_u *)"priority", -1) != NULL
&& dict_find(d, (char_u *)"id", -1) != NULL)) {
EMSG(_(e_invarg));
@@ -15239,11 +15240,47 @@ static void f_setmatches(typval_T *argvars, typval_T *rettv)
clear_matches(curwin);
li = l->lv_first;
while (li != NULL) {
+ int i = 0;
+ char_u buf[5];
+ dictitem_T *di;
d = li->li_tv.vval.v_dict;
- match_add(curwin, get_dict_string(d, (char_u *)"group", FALSE),
- get_dict_string(d, (char_u *)"pattern", FALSE),
- (int)get_dict_number(d, (char_u *)"priority"),
- (int)get_dict_number(d, (char_u *)"id"), NULL);
+
+ if (dict_find(d, (char_u *)"pattern", -1) == NULL) {
+ if (s == NULL) {
+ s = list_alloc();
+ if (s == NULL) {
+ return;
+ }
+ }
+
+ // match from matchaddpos()
+ for (i = 1; i < 9; ++i) {
+ snprintf((char *)buf, sizeof(buf), (char *)"pos%d", i);
+ if ((di = dict_find(d, (char_u *)buf, -1)) != NULL) {
+ if (di->di_tv.v_type != VAR_LIST) {
+ return;
+ }
+
+ list_append_tv(s, &di->di_tv);
+ s->lv_refcount++;
+ } else {
+ break;
+ }
+ }
+ }
+
+ if (i == 0) {
+ match_add(curwin, get_dict_string(d, (char_u *)"group", false),
+ get_dict_string(d, (char_u *)"pattern", false),
+ (int)get_dict_number(d, (char_u *)"priority"),
+ (int)get_dict_number(d, (char_u *)"id"), NULL);
+ } else {
+ match_add(curwin, get_dict_string(d, (char_u *)"group", false),
+ NULL, (int)get_dict_number(d, (char_u *)"priority"),
+ (int)get_dict_number(d, (char_u *)"id"), s);
+ list_unref(s);
+ s = NULL;
+ }
li = li->li_next;
}
rettv->vval.v_number = 0;
@@ -16037,6 +16074,7 @@ static void f_str2nr(typval_T *argvars, typval_T *rettv)
int base = 10;
char_u *p;
long n;
+ int what;
if (argvars[1].v_type != VAR_UNKNOWN) {
base = get_tv_number(&argvars[1]);
@@ -16050,11 +16088,20 @@ static void f_str2nr(typval_T *argvars, typval_T *rettv)
if (*p == '+') {
p = skipwhite(p + 1);
}
- vim_str2nr(p, NULL, NULL,
- base == 2 ? 2 : 0,
- base == 8 ? 2 : 0,
- base == 16 ? 2 : 0,
- &n, NULL);
+ switch (base) {
+ case 2:
+ what = STR2NR_BIN + STR2NR_FORCE;
+ break;
+ case 8:
+ what = STR2NR_OCT + STR2NR_FORCE;
+ break;
+ case 16:
+ what = STR2NR_HEX + STR2NR_FORCE;
+ break;
+ default:
+ what = 0;
+ }
+ vim_str2nr(p, NULL, NULL, what, &n, NULL, 0);
rettv->vval.v_number = n;
}
@@ -18336,7 +18383,7 @@ long get_tv_number_chk(typval_T *varp, int *denote)
case VAR_STRING:
if (varp->vval.v_string != NULL) {
vim_str2nr(varp->vval.v_string, NULL, NULL,
- true, true, true, &n, NULL);
+ STR2NR_ALL, &n, NULL, 0);
}
return n;
case VAR_LIST:
diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c
index 407dded6af..4d62dd0ff9 100644
--- a/src/nvim/ex_cmds.c
+++ b/src/nvim/ex_cmds.c
@@ -342,27 +342,27 @@ void ex_sort(exarg_T *eap)
char_u *s;
char_u *s2;
char_u c; // temporary character storage
- int unique = false;
+ bool unique = false;
long deleted;
colnr_T start_col;
colnr_T end_col;
- int sort_bin; // sort on bin number
- int sort_oct; // sort on octal number
- int sort_hex; // sort on hex number
+ int sort_what = 0;
// Sorting one line is really quick!
if (count <= 1) {
return;
}
- if (u_save((linenr_T)(eap->line1 - 1), (linenr_T)(eap->line2 + 1)) == FAIL)
+ if (u_save((linenr_T)(eap->line1 - 1), (linenr_T)(eap->line2 + 1)) == FAIL) {
return;
+ }
sortbuf1 = NULL;
sortbuf2 = NULL;
regmatch.regprog = NULL;
sorti_T *nrs = xmalloc(count * sizeof(sorti_T));
- sort_abort = sort_ic = sort_rx = sort_nr = sort_bin = sort_oct = sort_hex = 0;
+ sort_abort = sort_ic = sort_rx = sort_nr = 0;
+ size_t format_found = 0;
for (p = eap->arg; *p != NUL; ++p) {
if (ascii_iswhite(*p)) {
@@ -372,12 +372,16 @@ void ex_sort(exarg_T *eap)
sort_rx = true;
} else if (*p == 'n') {
sort_nr = 2;
+ format_found++;
} else if (*p == 'b') {
- sort_bin = 2;
+ sort_what = STR2NR_BIN + STR2NR_FORCE;
+ format_found++;
} else if (*p == 'o') {
- sort_oct = 2;
+ sort_what = STR2NR_OCT + STR2NR_FORCE;
+ format_found++;
} else if (*p == 'x') {
- sort_hex = 2;
+ sort_what = STR2NR_HEX + STR2NR_FORCE;
+ format_found++;
} else if (*p == 'u') {
unique = true;
} else if (*p == '"') {
@@ -415,13 +419,13 @@ void ex_sort(exarg_T *eap)
}
// Can only have one of 'n', 'b', 'o' and 'x'.
- if (sort_nr + sort_bin + sort_oct + sort_hex > 2) {
+ if (format_found > 1) {
EMSG(_(e_invarg));
goto sortend;
}
// From here on "sort_nr" is used as a flag for any number sorting.
- sort_nr += sort_bin + sort_oct + sort_hex;
+ sort_nr += sort_what;
// Make an array with all line numbers. This avoids having to copy all
// the lines into allocated memory.
@@ -457,22 +461,23 @@ void ex_sort(exarg_T *eap)
*s2 = NUL;
// Sorting on number: Store the number itself.
p = s + start_col;
- if (sort_hex) {
+ if (sort_what & STR2NR_HEX) {
s = skiptohex(p);
- } else if (sort_bin) {
+ } else if (sort_what & STR2NR_BIN) {
s = (char_u*) skiptobin((char*) p);
} else {
s = skiptodigit(p);
}
if (s > p && s[-1] == '-') {
- --s; // include preceding negative sign
+ // include preceding negative sign
+ s--;
}
if (*s == NUL) {
// empty line should sort before any number
nrs[lnum - eap->line1].start_col_nr = -MAXLNUM;
} else {
- vim_str2nr(s, NULL, NULL, sort_bin, sort_oct, sort_hex,
- &nrs[lnum - eap->line1].start_col_nr, NULL);
+ vim_str2nr(s, NULL, NULL, sort_what,
+ &nrs[lnum - eap->line1].start_col_nr, NULL, 0);
}
*s2 = c;
} else {
@@ -685,9 +690,17 @@ int do_move(linenr_T line1, linenr_T line2, linenr_T dest)
{
char_u *str;
linenr_T l;
- linenr_T extra; /* Num lines added before line1 */
- linenr_T num_lines; /* Num lines moved */
- linenr_T last_line; /* Last line in file after adding new text */
+ linenr_T extra; // Num lines added before line1
+ linenr_T num_lines; // Num lines moved
+ linenr_T last_line; // Last line in file after adding new text
+
+ // Moving lines seems to corrupt the folds, delete folding info now
+ // and recreate it when finished. Don't do this for manual folding, it
+ // would delete all folds.
+ bool isFolded = hasAnyFolding(curwin) && !foldmethodIsManual(curwin);
+ if (isFolded) {
+ deleteFoldRecurse(&curwin->w_folds);
+ }
if (dest >= line1 && dest < line2) {
EMSG(_("E134: Move lines into themselves"));
@@ -772,8 +785,14 @@ int do_move(linenr_T line1, linenr_T line2, linenr_T dest)
if (dest > last_line + 1)
dest = last_line + 1;
changed_lines(line1, 0, dest, 0L);
- } else
+ } else {
changed_lines(dest + 1, 0, line1 + num_lines, 0L);
+ }
+
+ // recreate folds
+ if (isFolded) {
+ foldUpdateAll(curwin);
+ }
return OK;
}
diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c
index cbe7c1a231..28ff6fded4 100644
--- a/src/nvim/ex_docmd.c
+++ b/src/nvim/ex_docmd.c
@@ -5656,8 +5656,13 @@ static void ex_quit(exarg_T *eap)
|| (only_one_window() && check_changed_any(eap->forceit))) {
not_exiting();
} else {
- if (only_one_window()) {
- // quit last window
+ // quit last window
+ // Note: only_one_window() returns true, even so a help window is
+ // still open. In that case only quit, if no address has been
+ // specified. Example:
+ // :h|wincmd w|1q - don't quit
+ // :h|wincmd w|q - quit
+ if (only_one_window() && (firstwin == lastwin || eap->addr_count == 0)) {
getout(0);
}
/* close window; may free buffer */
@@ -6345,7 +6350,7 @@ static void ex_tabnext(exarg_T *eap)
*/
static void ex_tabmove(exarg_T *eap)
{
- int tab_number = 9999;
+ int tab_number;
if (eap->arg && *eap->arg != NUL) {
char_u *p = eap->arg;
@@ -6361,17 +6366,35 @@ static void ex_tabmove(exarg_T *eap)
} else
p = eap->arg;
- if (p == skipdigits(p)) {
- /* No numbers as argument. */
- eap->errmsg = e_invarg;
- return;
+ if (relative == 0) {
+ if (STRCMP(p, "$") == 0) {
+ tab_number = LAST_TAB_NR;
+ } else if (p == skipdigits(p)) {
+ // No numbers as argument.
+ eap->errmsg = e_invarg;
+ return;
+ } else {
+ tab_number = getdigits(&p);
+ }
+ } else {
+ if (*p != NUL) {
+ tab_number = getdigits(&p);
+ } else {
+ tab_number = 1;
+ }
+ tab_number = tab_number * relative + tabpage_index(curtab);
+ if (relative == -1) {
+ --tab_number;
+ }
}
-
- tab_number = getdigits_int(&p);
- if (relative != 0)
- tab_number = tab_number * relative + tabpage_index(curtab) - 1; ;
- } else if (eap->addr_count != 0)
+ } else if (eap->addr_count != 0) {
tab_number = eap->line2;
+ if (**eap->cmdlinep == '-') {
+ --tab_number;
+ }
+ } else {
+ tab_number = LAST_TAB_NR;
+ }
tabpage_move(tab_number);
}
@@ -8345,8 +8368,7 @@ makeopens (
{
int only_save_windows = TRUE;
int nr;
- int cnr = 1;
- int restore_size = TRUE;
+ int restore_size = true;
win_T *wp;
char_u *sname;
win_T *edited_win = NULL;
@@ -8463,7 +8485,8 @@ makeopens (
tab_firstwin = firstwin; /* first window in tab page "tabnr" */
tab_topframe = topframe;
for (tabnr = 1;; ++tabnr) {
- int need_tabnew = FALSE;
+ int need_tabnew = false;
+ int cnr = 1;
if ((ssop_flags & SSOP_TABPAGES)) {
tabpage_T *tp = find_tabpage(tabnr);
diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c
index b19331ad06..96bf2c78d2 100644
--- a/src/nvim/ex_getln.c
+++ b/src/nvim/ex_getln.c
@@ -4786,7 +4786,7 @@ int get_list_range(char_u **str, int *num1, int *num2)
*str = skipwhite(*str);
if (**str == '-' || ascii_isdigit(**str)) { // parse "from" part of range
- vim_str2nr(*str, NULL, &len, false, false, false, &num, NULL);
+ vim_str2nr(*str, NULL, &len, 0, &num, NULL, 0);
*str += len;
*num1 = (int)num;
first = true;
@@ -4794,7 +4794,7 @@ int get_list_range(char_u **str, int *num1, int *num2)
*str = skipwhite(*str);
if (**str == ',') { // parse "to" part of range
*str = skipwhite(*str + 1);
- vim_str2nr(*str, NULL, &len, false, false, false, &num, NULL);
+ vim_str2nr(*str, NULL, &len, 0, &num, NULL, 0);
if (len > 0) {
*num2 = (int)num;
*str = skipwhite(*str + len);
diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c
index badb5b85b0..90987d0b3d 100644
--- a/src/nvim/fileio.c
+++ b/src/nvim/fileio.c
@@ -1543,12 +1543,12 @@ rewind_retry:
if (fileformat == EOL_UNKNOWN) {
/* First try finding a NL, for Dos and Unix */
if (try_dos || try_unix) {
- for (p = ptr; p < ptr + size; ++p) {
- // Reset the carriage return counter.
- if (try_mac) {
- try_mac = 1;
- }
+ // Reset the carriage return counter.
+ if (try_mac) {
+ try_mac = 1;
+ }
+ for (p = ptr; p < ptr + size; ++p) {
if (*p == NL) {
if (!try_unix
|| (try_dos && p > ptr && p[-1] == CAR))
diff --git a/src/nvim/fold.c b/src/nvim/fold.c
index 2e32e78062..6c135ef47b 100644
--- a/src/nvim/fold.c
+++ b/src/nvim/fold.c
@@ -767,9 +767,9 @@ void foldUpdate(win_T *wp, linenr_T top, linenr_T bot)
return;
}
- /* Mark all folds from top to bot as maybe-small. */
- (void)foldFind(&curwin->w_folds, top, &fp);
- while (fp < (fold_T *)curwin->w_folds.ga_data + curwin->w_folds.ga_len
+ // Mark all folds from top to bot as maybe-small.
+ (void)foldFind(&wp->w_folds, top, &fp);
+ while (fp < (fold_T *)wp->w_folds.ga_data + wp->w_folds.ga_len
&& fp->fd_top < bot) {
fp->fd_small = MAYBE;
++fp;
diff --git a/src/nvim/globals.h b/src/nvim/globals.h
index b45f13de4c..697a4a765a 100644
--- a/src/nvim/globals.h
+++ b/src/nvim/globals.h
@@ -159,15 +159,6 @@ EXTERN int Screen_mco INIT(= 0); /* value of p_mco used when
* These are single-width. */
EXTERN schar_T *ScreenLines2 INIT(= NULL);
-/*
- * Indexes for tab page line:
- * N > 0 for label of tab page N
- * N == 0 for no label
- * N < 0 for closing tab page -N
- * N == -999 for closing current tab page
- */
-EXTERN short *TabPageIdxs INIT(= NULL);
-
EXTERN int screen_Rows INIT(= 0); /* actual size of ScreenLines[] */
EXTERN int screen_Columns INIT(= 0); /* actual size of ScreenLines[] */
diff --git a/src/nvim/keymap.c b/src/nvim/keymap.c
index 7054bb822a..65c808eb06 100644
--- a/src/nvim/keymap.c
+++ b/src/nvim/keymap.c
@@ -574,7 +574,7 @@ int find_special_key(
if (bp[0] == 't' && bp[1] == '_' && bp[2] && bp[3]) {
bp += 3; // skip t_xx, xx may be '-' or '>'
} else if (STRNICMP(bp, "char-", 5) == 0) {
- vim_str2nr(bp + 5, NULL, &l, true, true, true, NULL, NULL);
+ vim_str2nr(bp + 5, NULL, &l, STR2NR_ALL, NULL, NULL, 0);
bp += l + 5;
break;
}
@@ -600,7 +600,7 @@ int find_special_key(
if (STRNICMP(last_dash + 1, "char-", 5) == 0
&& ascii_isdigit(last_dash[6])) {
// <Char-123> or <Char-033> or <Char-0x33>
- vim_str2nr(last_dash + 6, NULL, NULL, true, true, true, NULL, &n);
+ vim_str2nr(last_dash + 6, NULL, NULL, STR2NR_ALL, NULL, &n, 0);
key = (int)n;
} else {
/*
diff --git a/src/nvim/log.c b/src/nvim/log.c
index 5767da03af..773d497881 100644
--- a/src/nvim/log.c
+++ b/src/nvim/log.c
@@ -10,10 +10,6 @@
#include "nvim/os/os.h"
#include "nvim/os/time.h"
-#ifdef HAVE_UNISTD_H
-# include <unistd.h>
-#endif
-
#define USR_LOG_FILE "$HOME" _PATHSEPSTR ".nvimlog"
static uv_mutex_t mutex;
diff --git a/src/nvim/main.c b/src/nvim/main.c
index cef10d12d5..a8c2cebbbd 100644
--- a/src/nvim/main.c
+++ b/src/nvim/main.c
@@ -219,9 +219,10 @@ int main(int argc, char **argv)
{
argv0 = (char *)path_tail((char_u *)argv[0]);
- char_u *fname = NULL; /* file name from command line */
- mparm_T params; /* various parameters passed between
- * main() and other functions. */
+ char_u *fname = NULL; // file name from command line
+ mparm_T params; // various parameters passed between
+ // main() and other functions.
+ char_u *cwd = NULL; // current workding dir on startup
time_init();
/* Many variables are in "params" so that we can pass them to invoked
@@ -461,11 +462,10 @@ int main(int argc, char **argv)
TIME_MSG("jump to first error");
}
- /*
- * If opened more than one window, start editing files in the other
- * windows.
- */
- edit_buffers(&params);
+ // If opened more than one window, start editing files in the other
+ // windows.
+ edit_buffers(&params, cwd);
+ xfree(cwd);
if (params.diff_mode) {
/* set options in each window for "nvim -d". */
@@ -1182,12 +1182,19 @@ static char_u *get_fname(mparm_T *parmp)
* Expand wildcards in file names.
*/
if (!parmp->literal) {
- /* Temporarily add '(' and ')' to 'isfname'. These are valid
- * filename characters but are excluded from 'isfname' to make
- * "gf" work on a file name in parenthesis (e.g.: see vim.h). */
+ cwd = xmalloc(MAXPATHL);
+ if (cwd != NULL) {
+ os_dirname(cwd, MAXPATHL);
+ }
+ // Temporarily add '(' and ')' to 'isfname'. These are valid
+ // filename characters but are excluded from 'isfname' to make
+ // "gf" work on a file name in parenthesis (e.g.: see vim.h).
do_cmdline_cmd(":set isf+=(,)");
alist_expand(NULL, 0);
do_cmdline_cmd(":set isf&");
+ if (cwd != NULL) {
+ os_chdir((char *)cwd);
+ }
}
#endif
return alist_name(&GARGLIST[0]);
@@ -1417,11 +1424,9 @@ static void create_windows(mparm_T *parmp)
}
}
-/*
- * If opened more than one window, start editing files in the other
- * windows. make_windows() has already opened the windows.
- */
-static void edit_buffers(mparm_T *parmp)
+/// If opened more than one window, start editing files in the other
+/// windows. make_windows() has already opened the windows.
+static void edit_buffers(mparm_T *parmp, char_u *cwd)
{
int arg_idx; /* index in argument list */
int i;
@@ -1442,7 +1447,10 @@ static void edit_buffers(mparm_T *parmp)
arg_idx = 1;
for (i = 1; i < parmp->window_count; ++i) {
- /* When w_arg_idx is -1 remove the window (see create_windows()). */
+ if (cwd != NULL) {
+ os_chdir((char *)cwd);
+ }
+ // When w_arg_idx is -1 remove the window (see create_windows()).
if (curwin->w_arg_idx == -1) {
++arg_idx;
win_close(curwin, TRUE);
diff --git a/src/nvim/normal.c b/src/nvim/normal.c
index a116b5a0bd..9a9cf50e48 100644
--- a/src/nvim/normal.c
+++ b/src/nvim/normal.c
@@ -1414,11 +1414,12 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank)
int lbr_saved = curwin->w_p_lbr;
- /* The visual area is remembered for redo */
- static int redo_VIsual_mode = NUL; /* 'v', 'V', or Ctrl-V */
- static linenr_T redo_VIsual_line_count; /* number of lines */
- static colnr_T redo_VIsual_vcol; /* number of cols or end column */
- static long redo_VIsual_count; /* count for Visual operator */
+ // The visual area is remembered for redo
+ static int redo_VIsual_mode = NUL; // 'v', 'V', or Ctrl-V
+ static linenr_T redo_VIsual_line_count; // number of lines
+ static colnr_T redo_VIsual_vcol; // number of cols or end column
+ static long redo_VIsual_count; // count for Visual operator
+ static int redo_VIsual_arg; // extra argument
bool include_line_break = false;
old_cursor = curwin->w_cursor;
@@ -1656,6 +1657,7 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank)
redo_VIsual_vcol = resel_VIsual_vcol;
redo_VIsual_line_count = resel_VIsual_line_count;
redo_VIsual_count = cap->count0;
+ redo_VIsual_arg = cap->arg;
}
}
@@ -1705,10 +1707,7 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank)
VIsual_active = false;
setmouse();
mouse_dragging = 0;
- if (mode_displayed)
- clear_cmdline = true; /* unshow visual mode later */
- else
- clear_showcmd();
+ may_clear_cmdline();
if ((oap->op_type == OP_YANK
|| oap->op_type == OP_COLON
|| oap->op_type == OP_FUNCTION
@@ -1993,6 +1992,20 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank)
deleteFold(oap->start.lnum, oap->end.lnum,
oap->op_type == OP_FOLDDELREC, oap->is_VIsual);
break;
+
+ case OP_NR_ADD:
+ case OP_NR_SUB:
+ if (empty_region_error) {
+ vim_beep(BO_OPER);
+ CancelRedo();
+ } else {
+ VIsual_active = true;
+ curwin->w_p_lbr = lbr_saved;
+ op_addsub(oap, cap->count1, redo_VIsual_arg);
+ VIsual_active = false;
+ }
+ check_cursor_col();
+ break;
default:
clearopbeep(oap);
}
@@ -2334,8 +2347,9 @@ do_mouse (
if (mouse_row == 0 && firstwin->w_winrow > 0) {
if (is_drag) {
if (in_tab_line) {
- c1 = TabPageIdxs[mouse_col];
- tabpage_move(c1 <= 0 ? 9999 : c1 - 1);
+ tabpage_move(tab_page_click_defs[mouse_col].type == kStlClickTabClose
+ ? 9999
+ : tab_page_click_defs[mouse_col].tabnr - 1);
}
return false;
}
@@ -2345,41 +2359,114 @@ do_mouse (
&& cmdwin_type == 0
&& mouse_col < Columns) {
in_tab_line = true;
- c1 = TabPageIdxs[mouse_col];
- if (c1 >= 0) {
- if ((mod_mask & MOD_MASK_MULTI_CLICK) == MOD_MASK_2CLICK) {
- /* double click opens new page */
- end_visual_mode();
- tabpage_new();
- tabpage_move(c1 == 0 ? 9999 : c1 - 1);
- } else {
- /* Go to specified tab page, or next one if not clicking
- * on a label. */
- goto_tabpage(c1);
-
- /* It's like clicking on the status line of a window. */
- if (curwin != old_curwin)
+ c1 = tab_page_click_defs[mouse_col].tabnr;
+ switch (tab_page_click_defs[mouse_col].type) {
+ case kStlClickDisabled: {
+ break;
+ }
+ case kStlClickTabClose: {
+ tabpage_T *tp;
+
+ // Close the current or specified tab page.
+ if (c1 == 999) {
+ tp = curtab;
+ } else {
+ tp = find_tabpage(c1);
+ }
+ if (tp == curtab) {
+ if (first_tabpage->tp_next != NULL) {
+ tabpage_close(false);
+ }
+ } else if (tp != NULL) {
+ tabpage_close_other(tp, false);
+ }
+ break;
+ }
+ case kStlClickTabSwitch: {
+ if ((mod_mask & MOD_MASK_MULTI_CLICK) == MOD_MASK_2CLICK) {
+ // double click opens new page
end_visual_mode();
+ tabpage_new();
+ tabpage_move(c1 == 0 ? 9999 : c1 - 1);
+ } else {
+ // Go to specified tab page, or next one if not clicking
+ // on a label.
+ goto_tabpage(c1);
+
+ // It's like clicking on the status line of a window.
+ if (curwin != old_curwin) {
+ end_visual_mode();
+ }
+ }
+ break;
+ }
+ case kStlClickFuncRun: {
+ typval_T argv[] = {
+ {
+ .v_lock = VAR_FIXED,
+ .v_type = VAR_NUMBER,
+ .vval = {
+ .v_number = (varnumber_T) tab_page_click_defs[mouse_col].tabnr
+ },
+ },
+ {
+ .v_lock = VAR_FIXED,
+ .v_type = VAR_NUMBER,
+ .vval = {
+ .v_number = (((mod_mask & MOD_MASK_MULTI_CLICK)
+ == MOD_MASK_4CLICK)
+ ? 4
+ : ((mod_mask & MOD_MASK_MULTI_CLICK)
+ == MOD_MASK_3CLICK)
+ ? 3
+ : ((mod_mask & MOD_MASK_MULTI_CLICK)
+ == MOD_MASK_2CLICK)
+ ? 2
+ : 1)
+ },
+ },
+ {
+ .v_lock = VAR_FIXED,
+ .v_type = VAR_STRING,
+ .vval = { .v_string = (char_u *) (which_button == MOUSE_LEFT
+ ? "l"
+ : which_button == MOUSE_RIGHT
+ ? "r"
+ : which_button == MOUSE_MIDDLE
+ ? "m"
+ : "?") },
+ },
+ {
+ .v_lock = VAR_FIXED,
+ .v_type = VAR_STRING,
+ .vval = {
+ .v_string = (char_u[]) {
+ (char_u) (mod_mask & MOD_MASK_SHIFT ? 's' : ' '),
+ (char_u) (mod_mask & MOD_MASK_CTRL ? 'c' : ' '),
+ (char_u) (mod_mask & MOD_MASK_ALT ? 'a' : ' '),
+ (char_u) (mod_mask & MOD_MASK_META ? 'm' : ' '),
+ NUL
+ }
+ },
+ }
+ };
+ typval_T rettv;
+ int doesrange;
+ (void) call_func((char_u *) tab_page_click_defs[mouse_col].func,
+ (int) strlen(tab_page_click_defs[mouse_col].func),
+ &rettv, ARRAY_SIZE(argv), argv,
+ curwin->w_cursor.lnum, curwin->w_cursor.lnum,
+ &doesrange, true, NULL);
+ clear_tv(&rettv);
+ break;
}
- } else if (c1 < 0) {
- tabpage_T *tp;
-
- /* Close the current or specified tab page. */
- if (c1 == -999)
- tp = curtab;
- else
- tp = find_tabpage(-c1);
- if (tp == curtab) {
- if (first_tabpage->tp_next != NULL)
- tabpage_close(false);
- } else if (tp != NULL)
- tabpage_close_other(tp, false);
}
}
return true;
} else if (is_drag && in_tab_line) {
- c1 = TabPageIdxs[mouse_col];
- tabpage_move(c1 <= 0 ? 9999 : c1 - 1);
+ tabpage_move(tab_page_click_defs[mouse_col].type == kStlClickTabClose
+ ? 9999
+ : tab_page_click_defs[mouse_col].tabnr - 1);
in_tab_line = false;
return false;
}
@@ -2852,10 +2939,7 @@ void end_visual_mode(void)
if (!virtual_active())
curwin->w_cursor.coladd = 0;
- if (mode_displayed)
- clear_cmdline = true; /* unshow visual mode later */
- else
- clear_showcmd();
+ may_clear_cmdline();
adjust_cursor_eol();
}
@@ -3121,10 +3205,19 @@ static void unshift_special(cmdarg_T *cap)
cap->cmdchar = simplify_key(cap->cmdchar, &mod_mask);
}
-/*
- * Routines for displaying a partly typed command
- */
+/// If the mode is currently displayed clear the command line or update the
+/// command displayed.
+static void may_clear_cmdline(void)
+{
+ if (mode_displayed) {
+ // unshow visual mode later
+ clear_cmdline = true;
+ } else {
+ clear_showcmd();
+ }
+}
+// Routines for displaying a partly typed command
# define SHOWCMD_BUFLEN SHOWCMD_COLS + 1 + 30
static char_u showcmd_buf[SHOWCMD_BUFLEN];
static char_u old_showcmd_buf[SHOWCMD_BUFLEN]; /* For push_showcmd() */
@@ -3503,9 +3596,16 @@ static void nv_help(cmdarg_T *cap)
*/
static void nv_addsub(cmdarg_T *cap)
{
- if (!checkclearopq(cap->oap)
- && do_addsub(cap->cmdchar, cap->count1))
+ if (!VIsual_active && cap->oap->op_type == OP_NOP) {
prep_redo_cmd(cap);
+ cap->oap->op_type = cap->cmdchar == Ctrl_A ? OP_NR_ADD : OP_NR_SUB;
+ op_addsub(cap->oap, cap->count1, cap->arg);
+ cap->oap->op_type = OP_NOP;
+ } else if (VIsual_active) {
+ nv_operator(cap);
+ } else {
+ clearop(cap->oap);
+ }
}
/*
@@ -6327,9 +6427,20 @@ static void nv_g_cmd(cmdarg_T *cap)
bool flag = false;
switch (cap->nchar) {
- /*
- * "gR": Enter virtual replace mode.
- */
+ // "g^A/g^X": Sequentially increment visually selected region.
+ case Ctrl_A:
+ case Ctrl_X:
+ if (VIsual_active) {
+ cap->arg = true;
+ cap->cmdchar = cap->nchar;
+ cap->nchar = NUL;
+ nv_addsub(cap);
+ } else {
+ clearopbeep(oap);
+ }
+ break;
+
+ // "gR": Enter virtual replace mode.
case 'R':
cap->arg = true;
nv_Replace(cap);
diff --git a/src/nvim/ops.c b/src/nvim/ops.c
index 19dbd0f9f6..7614e6365a 100644
--- a/src/nvim/ops.c
+++ b/src/nvim/ops.c
@@ -87,34 +87,36 @@ struct block_def {
*/
static char opchars[][3] =
{
- {NUL, NUL, FALSE}, /* OP_NOP */
- {'d', NUL, FALSE}, /* OP_DELETE */
- {'y', NUL, FALSE}, /* OP_YANK */
- {'c', NUL, FALSE}, /* OP_CHANGE */
- {'<', NUL, TRUE}, /* OP_LSHIFT */
- {'>', NUL, TRUE}, /* OP_RSHIFT */
- {'!', NUL, TRUE}, /* OP_FILTER */
- {'g', '~', FALSE}, /* OP_TILDE */
- {'=', NUL, TRUE}, /* OP_INDENT */
- {'g', 'q', TRUE}, /* OP_FORMAT */
- {':', NUL, TRUE}, /* OP_COLON */
- {'g', 'U', FALSE}, /* OP_UPPER */
- {'g', 'u', FALSE}, /* OP_LOWER */
- {'J', NUL, TRUE}, /* DO_JOIN */
- {'g', 'J', TRUE}, /* DO_JOIN_NS */
- {'g', '?', FALSE}, /* OP_ROT13 */
- {'r', NUL, FALSE}, /* OP_REPLACE */
- {'I', NUL, FALSE}, /* OP_INSERT */
- {'A', NUL, FALSE}, /* OP_APPEND */
- {'z', 'f', TRUE}, /* OP_FOLD */
- {'z', 'o', TRUE}, /* OP_FOLDOPEN */
- {'z', 'O', TRUE}, /* OP_FOLDOPENREC */
- {'z', 'c', TRUE}, /* OP_FOLDCLOSE */
- {'z', 'C', TRUE}, /* OP_FOLDCLOSEREC */
- {'z', 'd', TRUE}, /* OP_FOLDDEL */
- {'z', 'D', TRUE}, /* OP_FOLDDELREC */
- {'g', 'w', TRUE}, /* OP_FORMAT2 */
- {'g', '@', FALSE}, /* OP_FUNCTION */
+ { NUL, NUL, false }, // OP_NOP
+ { 'd', NUL, false }, // OP_DELETE
+ { 'y', NUL, false }, // OP_YANK
+ { 'c', NUL, false }, // OP_CHANGE
+ { '<', NUL, true }, // OP_LSHIFT
+ { '>', NUL, true }, // OP_RSHIFT
+ { '!', NUL, true }, // OP_FILTER
+ { 'g', '~', false }, // OP_TILDE
+ { '=', NUL, true }, // OP_INDENT
+ { 'g', 'q', true }, // OP_FORMAT
+ { ':', NUL, true }, // OP_COLON
+ { 'g', 'U', false }, // OP_UPPER
+ { 'g', 'u', false }, // OP_LOWER
+ { 'J', NUL, true }, // DO_JOIN
+ { 'g', 'J', true }, // DO_JOIN_NS
+ { 'g', '?', false }, // OP_ROT13
+ { 'r', NUL, false }, // OP_REPLACE
+ { 'I', NUL, false }, // OP_INSERT
+ { 'A', NUL, false }, // OP_APPEND
+ { 'z', 'f', true }, // OP_FOLD
+ { 'z', 'o', true }, // OP_FOLDOPEN
+ { 'z', 'O', true }, // OP_FOLDOPENREC
+ { 'z', 'c', true }, // OP_FOLDCLOSE
+ { 'z', 'C', true }, // OP_FOLDCLOSEREC
+ { 'z', 'd', true }, // OP_FOLDDEL
+ { 'z', 'D', true }, // OP_FOLDDELREC
+ { 'g', 'w', true }, // OP_FORMAT2
+ { 'g', '@', false }, // OP_FUNCTION
+ { Ctrl_A, NUL, false }, // OP_NR_ADD
+ { Ctrl_X, NUL, false }, // OP_NR_SUB
};
/*
@@ -125,13 +127,27 @@ int get_op_type(int char1, int char2)
{
int i;
- if (char1 == 'r') /* ignore second character */
+ if (char1 == 'r') {
+ // ignore second character
return OP_REPLACE;
- if (char1 == '~') /* when tilde is an operator */
+ }
+ if (char1 == '~') {
+ // when tilde is an operator
return OP_TILDE;
- for (i = 0;; i++)
- if (opchars[i][0] == char1 && opchars[i][1] == char2)
+ }
+ if (char1 == 'g' && char2 == Ctrl_A) {
+ // add
+ return OP_NR_ADD;
+ }
+ if (char1 == 'g' && char2 == Ctrl_X) {
+ // subtract
+ return OP_NR_SUB;
+ }
+ for (i = 0;; i++) {
+ if (opchars[i][0] == char1 && opchars[i][1] == char2) {
break;
+ }
+ }
return i;
}
@@ -4181,134 +4197,241 @@ static void block_prep(oparg_T *oap, struct block_def *bdp, linenr_T lnum, int i
bdp->textstart = pstart;
}
-
-static void reverse_line(char_u *s)
+/// Handle the add/subtract operator.
+///
+/// @param[in] oap Arguments of operator.
+/// @param[in] Prenum1 Amount of addition or subtraction.
+/// @param[in] g_cmd Prefixed with `g`.
+void op_addsub(oparg_T *oap, linenr_T Prenum1, bool g_cmd)
{
- int i, j;
- char_u c;
+ pos_T pos;
+ struct block_def bd;
+ ssize_t change_cnt = 0;
+ linenr_T amount = Prenum1;
- if ((i = (int)STRLEN(s) - 1) <= 0)
- return;
+ if (!VIsual_active) {
+ pos = curwin->w_cursor;
+ if (u_save_cursor() == FAIL) {
+ return;
+ }
+ change_cnt = do_addsub(oap->op_type, &pos, 0, amount);
+ if (change_cnt) {
+ changed_lines(pos.lnum, 0, pos.lnum + 1, 0L);
+ }
+ } else {
+ int one_change;
+ int length;
+ pos_T startpos;
- curwin->w_cursor.col = i - curwin->w_cursor.col;
- for (j = 0; j < i; j++, i--) {
- c = s[i]; s[i] = s[j]; s[j] = c;
+ if (u_save((linenr_T)(oap->start.lnum - 1),
+ (linenr_T)(oap->end.lnum + 1)) == FAIL) {
+ return;
+ }
+
+ pos = oap->start;
+ for (; pos.lnum <= oap->end.lnum; ++pos.lnum) {
+ if (oap->motion_type == MBLOCK) {
+ // Visual block mode
+ block_prep(oap, &bd, pos.lnum, false);
+ pos.col = bd.textcol;
+ length = bd.textlen;
+ } else if (oap->motion_type == MLINE) {
+ curwin->w_cursor.col = 0;
+ pos.col = 0;
+ length = (colnr_T)STRLEN(ml_get(pos.lnum));
+ } else {
+ // oap->motion_type == MCHAR
+ if (!oap->inclusive) {
+ dec(&(oap->end));
+ }
+ length = (colnr_T)STRLEN(ml_get(pos.lnum));
+ pos.col = 0;
+ if (pos.lnum == oap->start.lnum) {
+ pos.col += oap->start.col;
+ length -= oap->start.col;
+ }
+ if (pos.lnum == oap->end.lnum) {
+ length = (int)STRLEN(ml_get(oap->end.lnum));
+ if (oap->end.col >= length) {
+ oap->end.col = length - 1;
+ }
+ length = oap->end.col - pos.col + 1;
+ }
+ }
+ one_change = do_addsub(oap->op_type, &pos, length, amount);
+ if (one_change) {
+ // Remember the start position of the first change.
+ if (change_cnt == 0) {
+ startpos = curbuf->b_op_start;
+ }
+ change_cnt++;
+ }
+
+ if (g_cmd && one_change) {
+ amount += Prenum1;
+ }
+ }
+ if (change_cnt) {
+ changed_lines(oap->start.lnum, 0, oap->end.lnum + 1, 0L);
+ }
+
+ if (!change_cnt && oap->is_VIsual) {
+ // No change: need to remove the Visual selection
+ redraw_curbuf_later(INVERTED);
+ }
+
+ // Set '[ mark if something changed. Keep the last end
+ // position from do_addsub().
+ if (change_cnt > 0) {
+ curbuf->b_op_start = startpos;
+ }
+
+ if (change_cnt > p_report) {
+ if (change_cnt == 1) {
+ MSG(_("1 line changed"));
+ } else {
+ smsg((char *)_("%" PRId64 " lines changed"), (int64_t)change_cnt);
+ }
+ }
}
}
-# define RLADDSUBFIX(ptr) if (curwin->w_p_rl) reverse_line(ptr);
-
/// Add or subtract from a number in a line.
///
-/// @param command CTRL-A for add, CTRL-X for subtract
-// @param Prenum1 number to add or subtract
+/// @param op_type OP_NR_ADD or OP_NR_SUB.
+/// @param pos Cursor position.
+/// @param length Target number length.
+/// @param Prenum1 Amount of addition or subtraction.
///
-/// @return FAIL for failure, OK otherwise
-int do_addsub(int command, linenr_T Prenum1)
+/// @return true if some character was changed.
+int do_addsub(int op_type, pos_T *pos, int length, linenr_T Prenum1)
{
int col;
char_u *buf1;
char_u buf2[NUMBUFLEN];
- int pre; // 'X' or 'x': hex; '0': octal; 'B' or 'b': bin
- static int hexupper = false; // 0xABC
- unsigned long n, oldn;
+ int pre; // 'X' or 'x': hex; '0': octal; 'B' or 'b': bin
+ static bool hexupper = false; // 0xABC
+ unsigned long n;
+ unsigned long oldn;
char_u *ptr;
int c;
- int length = 0; // character length of the number
int todel;
- int dohex;
- int dooct;
- int dobin;
- int doalp;
+ bool dohex;
+ bool dooct;
+ bool dobin;
+ bool doalp;
int firstdigit;
- int negative;
- int subtract;
+ bool subtract;
+ bool negative = false;
+ bool was_positive = true;
+ bool visual = VIsual_active;
+ bool did_change = false;
+ pos_T save_cursor = curwin->w_cursor;
+ int maxlen = 0;
+ pos_T startpos;
+ pos_T endpos;
dohex = (vim_strchr(curbuf->b_p_nf, 'x') != NULL); // "heX"
dooct = (vim_strchr(curbuf->b_p_nf, 'o') != NULL); // "Octal"
dobin = (vim_strchr(curbuf->b_p_nf, 'b') != NULL); // "Bin"
doalp = (vim_strchr(curbuf->b_p_nf, 'p') != NULL); // "alPha"
- ptr = get_cursor_line_ptr();
- RLADDSUBFIX(ptr);
+ curwin->w_cursor = *pos;
+ ptr = ml_get(pos->lnum);
+ col = pos->col;
+
+ if (*ptr == NUL) {
+ goto theend;
+ }
// First check if we are on a hexadecimal number, after the "0x".
- col = curwin->w_cursor.col;
+ if (!VIsual_active) {
+ if (dobin) {
+ while (col > 0 && ascii_isbdigit(ptr[col])) {
+ col--;
+ }
+ }
- if (dobin) {
- while (col > 0 && ascii_isbdigit(ptr[col])) {
- col--;
+ if (dohex) {
+ while (col > 0 && ascii_isxdigit(ptr[col])) {
+ col--;
+ }
}
- }
+ if (dobin
+ && dohex
+ && !((col > 0
+ && (ptr[col] == 'X' ||
+ ptr[col] == 'x')
+ && ptr[col - 1] == '0'
+ && ascii_isxdigit(ptr[col + 1])))) {
+ // In case of binary/hexadecimal pattern overlap match, rescan
- if (dohex) {
- while (col > 0 && ascii_isxdigit(ptr[col])) {
- col--;
+ col = curwin->w_cursor.col;
+
+ while (col > 0 && ascii_isdigit(ptr[col])) {
+ col--;
+ }
}
- }
- if (dobin
- && dohex
- && !((col > 0
- && (ptr[col] == 'X' ||
- ptr[col] == 'x')
- && ptr[col - 1] == '0'
- && ascii_isxdigit(ptr[col + 1])))) {
- // In case of binary/hexadecimal pattern overlap match, rescan
- col = curwin->w_cursor.col;
+ if ((dohex
+ && col > 0
+ && (ptr[col] == 'X'
+ || ptr[col] == 'x')
+ && ptr[col - 1] == '0'
+ && ascii_isxdigit(ptr[col + 1])) ||
+ (dobin
+ && col > 0
+ && (ptr[col] == 'B'
+ || ptr[col] == 'b')
+ && ptr[col - 1] == '0'
+ && ascii_isbdigit(ptr[col + 1]))) {
+ // Found hexadecimal or binary number, move to its start.
+ col--;
+ } else {
+ // Search forward and then backward to find the start of number.
+ col = pos->col;
+
+ while (ptr[col] != NUL
+ && !ascii_isdigit(ptr[col])
+ && !(doalp && ASCII_ISALPHA(ptr[col]))) {
+ col++;
+ }
- while (col > 0 && ascii_isdigit(ptr[col])) {
+ while (col > 0
+ && ascii_isdigit(ptr[col - 1])
+ && !(doalp && ASCII_ISALPHA(ptr[col]))) {
col--;
}
+ }
}
- if ((dohex
- && col > 0
- && (ptr[col] == 'X'
- || ptr[col] == 'x')
- && ptr[col - 1] == '0'
- && ascii_isxdigit(ptr[col + 1])) ||
- (dobin
- && col > 0
- && (ptr[col] == 'B'
- || ptr[col] == 'b')
- && ptr[col - 1] == '0'
- && ascii_isbdigit(ptr[col + 1]))) {
- // Found hexadecimal or binary number, move to its start.
- col--;
- } else {
- // Search forward and then backward to find the start of number.
- col = curwin->w_cursor.col;
-
- while (ptr[col] != NUL
- && !ascii_isdigit(ptr[col])
- && !(doalp && ASCII_ISALPHA(ptr[col]))) {
+ if (visual) {
+ while (ptr[col] != NUL && length > 0 && !ascii_isdigit(ptr[col]) &&
+ !(doalp && ASCII_ISALPHA(ptr[col]))) {
col++;
+ length--;
}
- while (col > 0
- && ascii_isdigit(ptr[col - 1])
- && !(doalp && ASCII_ISALPHA(ptr[col]))) {
- col--;
+ if (length == 0) {
+ goto theend;
+ }
+
+ if (col > pos->col && ptr[col - 1] == '-') {
+ negative = true;
+ was_positive = false;
}
}
// If a number was found, and saving for undo works, replace the number.
firstdigit = ptr[col];
- RLADDSUBFIX(ptr);
- if ((!ascii_isdigit(firstdigit) && !(doalp && ASCII_ISALPHA(firstdigit)))
- || u_save_cursor() != OK) {
+ if (!ascii_isdigit(firstdigit) && !(doalp && ASCII_ISALPHA(firstdigit))) {
beep_flush();
- return FAIL;
+ goto theend;
}
- // get ptr again, because u_save() may have changed it
- ptr = get_cursor_line_ptr();
- RLADDSUBFIX(ptr);
-
if (doalp && ASCII_ISALPHA(firstdigit)) {
// decrement or increment alphabetic character
- if (command == Ctrl_X) {
+ if (op_type == OP_NR_SUB) {
if (CharOrd(firstdigit) < Prenum1) {
if (isupper(firstdigit)) {
firstdigit = 'A';
@@ -4330,28 +4453,44 @@ int do_addsub(int command, linenr_T Prenum1)
}
}
curwin->w_cursor.col = col;
+ if (!did_change) {
+ startpos = curwin->w_cursor;
+ }
+ did_change = true;
(void)del_char(false);
ins_char(firstdigit);
+ endpos = curwin->w_cursor;
+ curwin->w_cursor.col = col;
} else {
- negative = false;
- if (col > 0 && ptr[col - 1] == '-') { // negative number
- --col;
+ if (col > 0 && ptr[col - 1] == '-' && !visual) {
+ // negative number
+ col--;
negative = true;
}
// get the number value (unsigned)
- vim_str2nr(ptr + col, &pre, &length, dobin, dooct, dohex, NULL, &n);
+ if (visual && VIsual_mode != 'V') {
+ maxlen = (curbuf->b_visual.vi_curswant == MAXCOL
+ ? (int)STRLEN(ptr) - col
+ : length);
+ }
+
+ vim_str2nr(ptr + col, &pre, &length,
+ 0 + (dobin ? STR2NR_BIN : 0)
+ + (dooct ? STR2NR_OCT : 0)
+ + (dohex ? STR2NR_HEX : 0),
+ NULL, &n, maxlen);
// ignore leading '-' for hex, octal and bin numbers
if (pre && negative) {
- ++col;
- --length;
+ col++;
+ length--;
negative = false;
}
// add or subtract
subtract = false;
- if (command == Ctrl_X) {
+ if (op_type == OP_NR_SUB) {
subtract ^= true;
}
if (negative) {
@@ -4370,7 +4509,8 @@ int do_addsub(int command, linenr_T Prenum1)
n = 1 + (n ^ (unsigned long)-1);
negative ^= true;
}
- } else { /* add */
+ } else {
+ // add
if (n < oldn) {
n = (n ^ (unsigned long)-1);
negative ^= true;
@@ -4381,15 +4521,25 @@ int do_addsub(int command, linenr_T Prenum1)
}
}
+ if (visual && !was_positive && !negative && col > 0) {
+ // need to remove the '-'
+ col--;
+ length++;
+ }
+
// Delete the old number.
curwin->w_cursor.col = col;
+ if (!did_change) {
+ startpos = curwin->w_cursor;
+ }
+ did_change = true;
todel = length;
c = gchar_cursor();
// Don't include the '-' in the length, only the length of the part
// after it is kept the same.
if (c == '-') {
- --length;
+ length--;
}
while (todel-- > 0) {
if (c < 0x100 && isalpha(c)) {
@@ -4405,47 +4555,52 @@ int do_addsub(int command, linenr_T Prenum1)
}
// Prepare the leading characters in buf1[].
- // When there are many leading zeros it could be very long. Allocate
- // a bit too much.
+ // When there are many leading zeros it could be very long.
+ // Allocate a bit too much.
buf1 = xmalloc(length + NUMBUFLEN);
+ if (buf1 == NULL) {
+ goto theend;
+ }
ptr = buf1;
- if (negative) {
+ if (negative && (!visual || (visual && was_positive))) {
*ptr++ = '-';
}
if (pre) {
*ptr++ = '0';
- --length;
+ length--;
}
if (pre == 'b' || pre == 'B' ||
pre == 'x' || pre == 'X') {
*ptr++ = pre;
- --length;
+ length--;
}
// Put the number characters in buf2[].
if (pre == 'b' || pre == 'B') {
size_t bits = 0;
- size_t pos = 0;
+ size_t i = 0;
// leading zeros
- for (bits = 8 * sizeof(unsigned long); bits > 0; bits--) {
- if ((n >> (bits - 1)) & 0x1) { break; }
+ for (bits = 8 * sizeof(n); bits > 0; bits--) {
+ if ((n >> (bits - 1)) & 0x1) {
+ break;
+ }
}
while (bits > 0) {
- buf2[pos++] = ((n >> --bits) & 0x1) ? '1' : '0';
+ buf2[i++] = ((n >> --bits) & 0x1) ? '1' : '0';
}
- buf2[pos] = '\0';
+ buf2[i] = '\0';
} else if (pre == 0) {
- snprintf((char *)buf2, NUMBUFLEN, "%" PRIu64, (uint64_t)n);
+ vim_snprintf((char *)buf2, ARRAY_SIZE(buf2), "%" PRIu64, (uint64_t)n);
} else if (pre == '0') {
- snprintf((char *)buf2, NUMBUFLEN, "%" PRIo64, (uint64_t)n);
+ vim_snprintf((char *)buf2, ARRAY_SIZE(buf2), "%" PRIo64, (uint64_t)n);
} else if (pre && hexupper) {
- snprintf((char *)buf2, NUMBUFLEN, "%" PRIX64, (uint64_t)n);
+ vim_snprintf((char *)buf2, ARRAY_SIZE(buf2), "%" PRIX64, (uint64_t)n);
} else {
- snprintf((char *)buf2, NUMBUFLEN, "%" PRIx64, (uint64_t)n);
+ vim_snprintf((char *)buf2, ARRAY_SIZE(buf2), "%" PRIx64, (uint64_t)n);
}
length -= (int)STRLEN(buf2);
@@ -4460,14 +4615,29 @@ int do_addsub(int command, linenr_T Prenum1)
}
*ptr = NUL;
STRCAT(buf1, buf2);
- ins_str(buf1); /* insert the new number */
+ ins_str(buf1); // insert the new number
xfree(buf1);
+ endpos = curwin->w_cursor;
+ if (did_change && curwin->w_cursor.col) {
+ curwin->w_cursor.col--;
+ }
}
- --curwin->w_cursor.col;
- curwin->w_set_curswant = true;
- ptr = ml_get_buf(curbuf, curwin->w_cursor.lnum, true);
- RLADDSUBFIX(ptr);
- return OK;
+
+ if (did_change) {
+ // set the '[ and '] marks
+ curbuf->b_op_start = startpos;
+ curbuf->b_op_end = endpos;
+ if (curbuf->b_op_end.col > 0) {
+ curbuf->b_op_end.col--;
+ }
+ }
+
+theend:
+ if (visual) {
+ curwin->w_cursor = save_cursor;
+ }
+
+ return did_change;
}
/*
diff --git a/src/nvim/ops.h b/src/nvim/ops.h
index 507f933acf..f33e87572f 100644
--- a/src/nvim/ops.h
+++ b/src/nvim/ops.h
@@ -35,37 +35,39 @@ typedef int (*Indenter)(void);
#define PLUS_REGISTER 38
#define NUM_REGISTERS 39
-/*
- * Operator IDs; The order must correspond to opchars[] in ops.c!
- */
-#define OP_NOP 0 /* no pending operation */
-#define OP_DELETE 1 /* "d" delete operator */
-#define OP_YANK 2 /* "y" yank operator */
-#define OP_CHANGE 3 /* "c" change operator */
-#define OP_LSHIFT 4 /* "<" left shift operator */
-#define OP_RSHIFT 5 /* ">" right shift operator */
-#define OP_FILTER 6 /* "!" filter operator */
-#define OP_TILDE 7 /* "g~" switch case operator */
-#define OP_INDENT 8 /* "=" indent operator */
-#define OP_FORMAT 9 /* "gq" format operator */
-#define OP_COLON 10 /* ":" colon operator */
-#define OP_UPPER 11 /* "gU" make upper case operator */
-#define OP_LOWER 12 /* "gu" make lower case operator */
-#define OP_JOIN 13 /* "J" join operator, only for Visual mode */
-#define OP_JOIN_NS 14 /* "gJ" join operator, only for Visual mode */
-#define OP_ROT13 15 /* "g?" rot-13 encoding */
-#define OP_REPLACE 16 /* "r" replace chars, only for Visual mode */
-#define OP_INSERT 17 /* "I" Insert column, only for Visual mode */
-#define OP_APPEND 18 /* "A" Append column, only for Visual mode */
-#define OP_FOLD 19 /* "zf" define a fold */
-#define OP_FOLDOPEN 20 /* "zo" open folds */
-#define OP_FOLDOPENREC 21 /* "zO" open folds recursively */
-#define OP_FOLDCLOSE 22 /* "zc" close folds */
-#define OP_FOLDCLOSEREC 23 /* "zC" close folds recursively */
-#define OP_FOLDDEL 24 /* "zd" delete folds */
-#define OP_FOLDDELREC 25 /* "zD" delete folds recursively */
-#define OP_FORMAT2 26 /* "gw" format operator, keeps cursor pos */
-#define OP_FUNCTION 27 /* "g@" call 'operatorfunc' */
+// Operator IDs; The order must correspond to opchars[] in ops.c!
+#define OP_NOP 0 // no pending operation
+#define OP_DELETE 1 // "d" delete operator
+#define OP_YANK 2 // "y" yank operator
+#define OP_CHANGE 3 // "c" change operator
+#define OP_LSHIFT 4 // "<" left shift operator
+#define OP_RSHIFT 5 // ">" right shift operator
+#define OP_FILTER 6 // "!" filter operator
+#define OP_TILDE 7 // "g~" switch case operator
+#define OP_INDENT 8 // "=" indent operator
+#define OP_FORMAT 9 // "gq" format operator
+#define OP_COLON 10 // ":" colon operator
+#define OP_UPPER 11 // "gU" make upper case operator
+#define OP_LOWER 12 // "gu" make lower case operator
+#define OP_JOIN 13 // "J" join operator, only for Visual mode
+#define OP_JOIN_NS 14 // "gJ" join operator, only for Visual mode
+#define OP_ROT13 15 // "g?" rot-13 encoding
+#define OP_REPLACE 16 // "r" replace chars, only for Visual mode
+#define OP_INSERT 17 // "I" Insert column, only for Visual mode
+#define OP_APPEND 18 // "A" Append column, only for Visual mode
+#define OP_FOLD 19 // "zf" define a fold
+#define OP_FOLDOPEN 20 // "zo" open folds
+#define OP_FOLDOPENREC 21 // "zO" open folds recursively
+#define OP_FOLDCLOSE 22 // "zc" close folds
+#define OP_FOLDCLOSEREC 23 // "zC" close folds recursively
+#define OP_FOLDDEL 24 // "zd" delete folds
+#define OP_FOLDDELREC 25 // "zD" delete folds recursively
+#define OP_FORMAT2 26 // "gw" format operator, keeps cursor pos
+#define OP_FUNCTION 27 // "g@" call 'operatorfunc'
+#define OP_NR_ADD 28 // "<C-A>" Add to the number or alphabetic
+ // character (OP_ADD conflicts with Perl)
+#define OP_NR_SUB 29 // "<C-X>" Subtract from the number or
+ // alphabetic character
/// Flags for get_reg_contents().
enum GRegFlags {
diff --git a/src/nvim/option.c b/src/nvim/option.c
index b4054dc28c..d3a2ce971d 100644
--- a/src/nvim/option.c
+++ b/src/nvim/option.c
@@ -1432,7 +1432,7 @@ do_set (
} else if (*arg == '-' || ascii_isdigit(*arg)) {
// Allow negative (for 'undolevels'), octal and
// hex numbers.
- vim_str2nr(arg, NULL, &i, true, true, true, &value, NULL);
+ vim_str2nr(arg, NULL, &i, STR2NR_ALL, &value, NULL, 0);
if (arg[i] != NUL && !ascii_iswhite(arg[i])) {
errmsg = e_invarg;
goto skip;
@@ -1673,6 +1673,11 @@ do_set (
&& *newval != NUL);
if (adding) {
i = (int)STRLEN(origval);
+ // Strip a trailing comma, would get 2.
+ if (comma && i > 1 && origval[i - 1] == ','
+ && origval[i - 2] != '\\') {
+ --i;
+ }
memmove(newval + i + comma, newval,
STRLEN(newval) + 1);
memmove(newval, origval, (size_t)i);
diff --git a/src/nvim/option_defs.h b/src/nvim/option_defs.h
index 7a837de45c..11b5e31f77 100644
--- a/src/nvim/option_defs.h
+++ b/src/nvim/option_defs.h
@@ -209,44 +209,58 @@
#define COM_ALL "nbsmexflrO" /* all flags for 'comments' option */
#define COM_MAX_LEN 50 /* maximum length of a part */
-/* flags for 'statusline' option */
-#define STL_FILEPATH 'f' /* path of file in buffer */
-#define STL_FULLPATH 'F' /* full path of file in buffer */
-#define STL_FILENAME 't' /* last part (tail) of file path */
-#define STL_COLUMN 'c' /* column og cursor*/
-#define STL_VIRTCOL 'v' /* virtual column */
-#define STL_VIRTCOL_ALT 'V' /* - with 'if different' display */
-#define STL_LINE 'l' /* line number of cursor */
-#define STL_NUMLINES 'L' /* number of lines in buffer */
-#define STL_BUFNO 'n' /* current buffer number */
-#define STL_KEYMAP 'k' /* 'keymap' when active */
-#define STL_OFFSET 'o' /* offset of character under cursor*/
-#define STL_OFFSET_X 'O' /* - in hexadecimal */
-#define STL_BYTEVAL 'b' /* byte value of character */
-#define STL_BYTEVAL_X 'B' /* - in hexadecimal */
-#define STL_ROFLAG 'r' /* readonly flag */
-#define STL_ROFLAG_ALT 'R' /* - other display */
-#define STL_HELPFLAG 'h' /* window is showing a help file */
-#define STL_HELPFLAG_ALT 'H' /* - other display */
-#define STL_FILETYPE 'y' /* 'filetype' */
-#define STL_FILETYPE_ALT 'Y' /* - other display */
-#define STL_PREVIEWFLAG 'w' /* window is showing the preview buf */
-#define STL_PREVIEWFLAG_ALT 'W' /* - other display */
-#define STL_MODIFIED 'm' /* modified flag */
-#define STL_MODIFIED_ALT 'M' /* - other display */
-#define STL_QUICKFIX 'q' /* quickfix window description */
-#define STL_PERCENTAGE 'p' /* percentage through file */
-#define STL_ALTPERCENT 'P' /* percentage as TOP BOT ALL or NN% */
-#define STL_ARGLISTSTAT 'a' /* argument list status as (x of y) */
-#define STL_PAGENUM 'N' /* page number (when printing)*/
-#define STL_VIM_EXPR '{' /* start of expression to substitute */
-#define STL_MIDDLEMARK '=' /* separation between left and right */
-#define STL_TRUNCMARK '<' /* truncation mark if line is too long*/
-#define STL_USER_HL '*' /* highlight from (User)1..9 or 0 */
-#define STL_HIGHLIGHT '#' /* highlight name */
-#define STL_TABPAGENR 'T' /* tab page label nr */
-#define STL_TABCLOSENR 'X' /* tab page close nr */
-#define STL_ALL ((char_u *) "fFtcvVlLknoObBrRhHmYyWwMqpPaN{#")
+/// 'statusline' option flags
+enum {
+ STL_FILEPATH = 'f', ///< Path of file in buffer.
+ STL_FULLPATH = 'F', ///< Full path of file in buffer.
+ STL_FILENAME = 't', ///< Last part (tail) of file path.
+ STL_COLUMN = 'c', ///< Column og cursor.
+ STL_VIRTCOL = 'v', ///< Virtual column.
+ STL_VIRTCOL_ALT = 'V', ///< - with 'if different' display.
+ STL_LINE = 'l', ///< Line number of cursor.
+ STL_NUMLINES = 'L', ///< Number of lines in buffer.
+ STL_BUFNO = 'n', ///< Current buffer number.
+ STL_KEYMAP = 'k', ///< 'keymap' when active.
+ STL_OFFSET = 'o', ///< Offset of character under cursor.
+ STL_OFFSET_X = 'O', ///< - in hexadecimal.
+ STL_BYTEVAL = 'b', ///< Byte value of character.
+ STL_BYTEVAL_X = 'B', ///< - in hexadecimal.
+ STL_ROFLAG = 'r', ///< Readonly flag.
+ STL_ROFLAG_ALT = 'R', ///< - other display.
+ STL_HELPFLAG = 'h', ///< Window is showing a help file.
+ STL_HELPFLAG_ALT = 'H', ///< - other display.
+ STL_FILETYPE = 'y', ///< 'filetype'.
+ STL_FILETYPE_ALT = 'Y', ///< - other display.
+ STL_PREVIEWFLAG = 'w', ///< Window is showing the preview buf.
+ STL_PREVIEWFLAG_ALT = 'W', ///< - other display.
+ STL_MODIFIED = 'm', ///< Modified flag.
+ STL_MODIFIED_ALT = 'M', ///< - other display.
+ STL_QUICKFIX = 'q', ///< Quickfix window description.
+ STL_PERCENTAGE = 'p', ///< Percentage through file.
+ STL_ALTPERCENT = 'P', ///< Percentage as TOP BOT ALL or NN%.
+ STL_ARGLISTSTAT = 'a', ///< Argument list status as (x of y).
+ STL_PAGENUM = 'N', ///< Page number (when printing).
+ STL_VIM_EXPR = '{', ///< Start of expression to substitute.
+ STL_MIDDLEMARK = '=', ///< Separation between left and right.
+ STL_TRUNCMARK = '<', ///< Truncation mark if line is too long.
+ STL_USER_HL = '*', ///< Highlight from (User)1..9 or 0.
+ STL_HIGHLIGHT = '#', ///< Highlight name.
+ STL_TABPAGENR = 'T', ///< Tab page label nr.
+ STL_TABCLOSENR = 'X', ///< Tab page close nr.
+ STL_CLICK_FUNC = '@', ///< Click region start.
+};
+/// C string containing all 'statusline' option flags
+#define STL_ALL ((char_u[]) { \
+ STL_FILEPATH, STL_FULLPATH, STL_FILENAME, STL_COLUMN, STL_VIRTCOL, \
+ STL_VIRTCOL_ALT, STL_LINE, STL_NUMLINES, STL_BUFNO, STL_KEYMAP, STL_OFFSET, \
+ STL_OFFSET_X, STL_BYTEVAL, STL_BYTEVAL_X, STL_ROFLAG, STL_ROFLAG_ALT, \
+ STL_HELPFLAG, STL_HELPFLAG_ALT, STL_FILETYPE, STL_FILETYPE_ALT, \
+ STL_PREVIEWFLAG, STL_PREVIEWFLAG_ALT, STL_MODIFIED, STL_MODIFIED_ALT, \
+ STL_QUICKFIX, STL_PERCENTAGE, STL_ALTPERCENT, STL_ARGLISTSTAT, STL_PAGENUM, \
+ STL_VIM_EXPR, STL_MIDDLEMARK, STL_TRUNCMARK, STL_USER_HL, STL_HIGHLIGHT, \
+ STL_TABPAGENR, STL_TABCLOSENR, STL_CLICK_FUNC, \
+ 0, \
+})
/* flags used for parsed 'wildmode' */
#define WIM_FULL 1
diff --git a/src/nvim/os/fs.c b/src/nvim/os/fs.c
index 21f0fc6f41..2e671653ed 100644
--- a/src/nvim/os/fs.c
+++ b/src/nvim/os/fs.c
@@ -146,6 +146,16 @@ static bool is_executable_in_path(const char_u *name, char_u **abspath)
}
size_t buf_len = STRLEN(name) + STRLEN(path) + 2;
+
+#ifdef WIN32
+ const char *pathext = os_getenv("PATHEXT");
+ if (!pathext) {
+ pathext = ".com;.exe;.bat;.cmd";
+ }
+
+ buf_len += STRLEN(pathext);
+#endif
+
char_u *buf = xmalloc(buf_len);
// Walk through all entries in $PATH to check if "name" exists there and
@@ -169,6 +179,38 @@ static bool is_executable_in_path(const char_u *name, char_u **abspath)
return true;
}
+#ifdef WIN32
+ // Try appending file extensions from $PATHEXT to the name.
+ char *buf_end = xstrchrnul((char *)buf, '\0');
+ for (const char *ext = pathext; *ext; ext++) {
+ // Skip the extension if there is no suffix after a '.'.
+ if (ext[0] == '.' && (ext[1] == '\0' || ext[1] == ';')) {
+ *ext++;
+
+ continue;
+ }
+
+ const char *ext_end = xstrchrnul(ext, ENV_SEPCHAR);
+ STRLCPY(buf_end, ext, ext_end - ext + 1);
+
+ if (is_executable(buf)) {
+ // Check if the caller asked for a copy of the path.
+ if (abspath != NULL) {
+ *abspath = save_absolute_path(buf);
+ }
+
+ xfree(buf);
+
+ return true;
+ }
+
+ if (*ext_end != ENV_SEPCHAR) {
+ break;
+ }
+ ext = ext_end;
+ }
+#endif
+
if (*e != ENV_SEPCHAR) {
// End of $PATH without finding any executable called name.
xfree(buf);
diff --git a/src/nvim/os/unix_defs.h b/src/nvim/os/unix_defs.h
index 78fc9331d1..690a39c3cd 100644
--- a/src/nvim/os/unix_defs.h
+++ b/src/nvim/os/unix_defs.h
@@ -2,7 +2,7 @@
#define NVIM_OS_UNIX_DEFS_H
// Windows doesn't have unistd.h, so we include it here to avoid numerous
-// instances of `#ifdef HAVE_UNISTD_H'.
+// instances of `#ifdef WIN32'.
#include <unistd.h>
// POSIX.1-2008 says that NAME_MAX should be in here
diff --git a/src/nvim/os/win_defs.h b/src/nvim/os/win_defs.h
index ba96347a12..242d355f77 100644
--- a/src/nvim/os/win_defs.h
+++ b/src/nvim/os/win_defs.h
@@ -3,6 +3,7 @@
#include <windows.h>
#include <sys/stat.h>
+#include <io.h>
#include <stdio.h>
// Windows does not have S_IFLNK but libuv defines it
diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c
index 85c69af192..f3abf864fb 100644
--- a/src/nvim/quickfix.c
+++ b/src/nvim/quickfix.c
@@ -1606,13 +1606,12 @@ win_found:
}
if (qf_ptr->qf_col > 0) {
curwin->w_cursor.col = qf_ptr->qf_col - 1;
- if (qf_ptr->qf_viscol == TRUE) {
- /*
- * Check each character from the beginning of the error
- * line up to the error column. For each tab character
- * found, reduce the error column value by the length of
- * a tab character.
- */
+ curwin->w_cursor.coladd = 0;
+ if (qf_ptr->qf_viscol == true) {
+ // Check each character from the beginning of the error
+ // line up to the error column. For each tab character
+ // found, reduce the error column value by the length of
+ // a tab character.
line = get_cursor_line_ptr();
screen_col = 0;
for (char_col = 0; char_col < curwin->w_cursor.col; ++char_col) {
diff --git a/src/nvim/screen.c b/src/nvim/screen.c
index 43bc2c1f68..e036c49be4 100644
--- a/src/nvim/screen.c
+++ b/src/nvim/screen.c
@@ -147,6 +147,9 @@ static foldinfo_T win_foldinfo; /* info for 'foldcolumn' */
*/
static schar_T *current_ScreenLine;
+StlClickDefinition *tab_page_click_defs = NULL;
+long tab_page_click_defs_size = 0;
+
# define SCREEN_LINE(r, o, e, c, rl) screen_line((r), (o), (e), (c), (rl))
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "screen.c.generated.h"
@@ -5009,8 +5012,8 @@ win_redr_custom (
char_u *stl;
char_u *p;
struct stl_hlrec hltab[STL_MAX_ITEM];
- struct stl_hlrec tabtab[STL_MAX_ITEM];
- int use_sandbox = FALSE;
+ StlClickRecord tabtab[STL_MAX_ITEM];
+ int use_sandbox = false;
win_T *ewp;
int p_crb_save;
@@ -5126,20 +5129,24 @@ win_redr_custom (
screen_puts(p >= buf + len ? (char_u *)"" : p, row, col, curattr);
if (wp == NULL) {
- /* Fill the TabPageIdxs[] array for clicking in the tab pagesline. */
+ // Fill the tab_page_click_defs array for clicking in the tab pages line.
col = 0;
len = 0;
p = buf;
- fillchar = 0;
+ StlClickDefinition cur_click_def = {
+ .type = kStlClickDisabled,
+ };
for (n = 0; tabtab[n].start != NULL; n++) {
- len += vim_strnsize(p, (int)(tabtab[n].start - p));
- while (col < len)
- TabPageIdxs[col++] = fillchar;
- p = tabtab[n].start;
- fillchar = tabtab[n].userhl;
+ len += vim_strnsize(p, (int)(tabtab[n].start - (char *) p));
+ while (col < len) {
+ tab_page_click_defs[col++] = cur_click_def;
+ }
+ p = (char_u *) tabtab[n].start;
+ cur_click_def = tabtab[n].def;
+ }
+ while (col < Columns) {
+ tab_page_click_defs[col++] = cur_click_def;
}
- while (col < Columns)
- TabPageIdxs[col++] = fillchar;
}
theend:
@@ -5958,9 +5965,9 @@ void screenalloc(bool doclear)
sattr_T *new_ScreenAttrs;
unsigned *new_LineOffset;
char_u *new_LineWraps;
- short *new_TabPageIdxs;
- static int entered = FALSE; /* avoid recursiveness */
- static int done_outofmem_msg = FALSE; /* did outofmem message */
+ StlClickDefinition *new_tab_page_click_defs;
+ static bool entered = false; // avoid recursiveness
+ static bool done_outofmem_msg = false;
int retry_count = 0;
const bool l_enc_utf8 = enc_utf8;
const int l_enc_dbcs = enc_dbcs;
@@ -6033,7 +6040,8 @@ retry:
new_ScreenAttrs = xmalloc((size_t)((Rows + 1) * Columns * sizeof(sattr_T)));
new_LineOffset = xmalloc((size_t)(Rows * sizeof(unsigned)));
new_LineWraps = xmalloc((size_t)(Rows * sizeof(char_u)));
- new_TabPageIdxs = xmalloc((size_t)(Columns * sizeof(short)));
+ new_tab_page_click_defs = xcalloc(
+ (size_t) Columns, sizeof(*new_tab_page_click_defs));
FOR_ALL_TAB_WINDOWS(tp, wp) {
win_alloc_lines(wp);
@@ -6051,7 +6059,7 @@ retry:
|| new_ScreenAttrs == NULL
|| new_LineOffset == NULL
|| new_LineWraps == NULL
- || new_TabPageIdxs == NULL
+ || new_tab_page_click_defs == NULL
|| outofmem) {
if (ScreenLines != NULL || !done_outofmem_msg) {
/* guess the size */
@@ -6077,8 +6085,8 @@ retry:
new_LineOffset = NULL;
xfree(new_LineWraps);
new_LineWraps = NULL;
- xfree(new_TabPageIdxs);
- new_TabPageIdxs = NULL;
+ xfree(new_tab_page_click_defs);
+ new_tab_page_click_defs = NULL;
} else {
done_outofmem_msg = FALSE;
@@ -6157,7 +6165,8 @@ retry:
ScreenAttrs = new_ScreenAttrs;
LineOffset = new_LineOffset;
LineWraps = new_LineWraps;
- TabPageIdxs = new_TabPageIdxs;
+ tab_page_click_defs = new_tab_page_click_defs;
+ tab_page_click_defs_size = Columns;
/* It's important that screen_Rows and screen_Columns reflect the actual
* size of ScreenLines[]. Set them before calling anything. */
@@ -6196,7 +6205,25 @@ void free_screenlines(void)
xfree(ScreenAttrs);
xfree(LineOffset);
xfree(LineWraps);
- xfree(TabPageIdxs);
+ clear_tab_page_click_defs(tab_page_click_defs, tab_page_click_defs_size);
+ xfree(tab_page_click_defs);
+}
+
+/// Clear tab_page_click_defs table
+///
+/// @param[out] tpcd Table to clear.
+/// @param[in] tpcd_size Size of the table.
+void clear_tab_page_click_defs(StlClickDefinition *const tpcd,
+ const long tpcd_size)
+{
+ if (tpcd != NULL) {
+ for (long i = 0; i < tpcd_size; i++) {
+ if (i == 0 || tpcd[i].func != tpcd[i - 1].func) {
+ xfree(tpcd[i].func);
+ }
+ }
+ memset(tpcd, 0, (size_t) tpcd_size * sizeof(tpcd[0]));
+ }
}
void screenclear(void)
@@ -6804,9 +6831,9 @@ static void draw_tabline(void)
return;
- /* Init TabPageIdxs[] to zero: Clicking outside of tabs has no effect. */
- for (scol = 0; scol < Columns; ++scol)
- TabPageIdxs[scol] = 0;
+ // Init TabPageIdxs[] to zero: Clicking outside of tabs has no effect.
+ assert(Columns == tab_page_click_defs_size);
+ clear_tab_page_click_defs(tab_page_click_defs, tab_page_click_defs_size);
/* Use the 'tabline' option if it's set. */
if (*p_tal != NUL) {
@@ -6904,11 +6931,16 @@ static void draw_tabline(void)
}
screen_putchar(' ', 0, col++, attr);
- /* Store the tab page number in TabPageIdxs[], so that
- * jump_to_mouse() knows where each one is. */
- ++tabcount;
- while (scol < col)
- TabPageIdxs[scol++] = tabcount;
+ // Store the tab page number in tab_page_click_defs[], so that
+ // jump_to_mouse() knows where each one is.
+ tabcount++;
+ while (scol < col) {
+ tab_page_click_defs[scol++] = (StlClickDefinition) {
+ .type = kStlClickTabSwitch,
+ .tabnr = tabcount,
+ .func = NULL,
+ };
+ }
}
if (use_sep_chars)
@@ -6920,7 +6952,11 @@ static void draw_tabline(void)
/* Put an "X" for closing the current tab if there are several. */
if (first_tabpage->tp_next != NULL) {
screen_putchar('X', 0, (int)Columns - 1, attr_nosel);
- TabPageIdxs[Columns - 1] = -999;
+ tab_page_click_defs[Columns - 1] = (StlClickDefinition) {
+ .type = kStlClickTabClose,
+ .tabnr = 999,
+ .func = NULL,
+ };
}
}
diff --git a/src/nvim/screen.h b/src/nvim/screen.h
index debf86ae67..81a8b9ed4c 100644
--- a/src/nvim/screen.h
+++ b/src/nvim/screen.h
@@ -16,6 +16,29 @@
#define NOT_VALID 40 /* buffer needs complete redraw */
#define CLEAR 50 /* screen messed up, clear it */
+/// Status line click definition
+typedef struct {
+ enum {
+ kStlClickDisabled = 0, ///< Clicks to this area are ignored.
+ kStlClickTabSwitch, ///< Switch to the given tab.
+ kStlClickTabClose, ///< Close given tab.
+ kStlClickFuncRun, ///< Run user function.
+ } type; ///< Type of the click.
+ int tabnr; ///< Tab page number.
+ char *func; ///< Function to run.
+} StlClickDefinition;
+
+/// Used for tabline clicks
+typedef struct {
+ StlClickDefinition def; ///< Click definition.
+ const char *start; ///< Location where region starts.
+} StlClickRecord;
+
+/// Array defining what should be done when tabline is clicked
+extern StlClickDefinition *tab_page_click_defs;
+
+/// Size of the tab_page_click_defs array
+extern long tab_page_click_defs_size;
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "screen.h.generated.h"
diff --git a/src/nvim/search.c b/src/nvim/search.c
index d393ee7d02..2dd0201259 100644
--- a/src/nvim/search.c
+++ b/src/nvim/search.c
@@ -3076,18 +3076,18 @@ current_block (
} else
old_end = VIsual;
- /*
- * Search backwards for unclosed '(', '{', etc..
- * Put this position in start_pos.
- * Ignore quotes here.
- */
+ // Search backwards for unclosed '(', '{', etc..
+ // Put this position in start_pos.
+ // Ignore quotes here. Keep the "M" flag in 'cpo', as that is what the
+ // user wants.
save_cpo = p_cpo;
- p_cpo = (char_u *)"%";
+ p_cpo = (char_u *)(vim_strchr(p_cpo, CPO_MATCHBSL) != NULL ? "%M" : "%");
while (count-- > 0) {
- if ((pos = findmatch(NULL, what)) == NULL)
+ if ((pos = findmatch(NULL, what)) == NULL) {
break;
+ }
curwin->w_cursor = *pos;
- start_pos = *pos; /* the findmatch for end_pos will overwrite *pos */
+ start_pos = *pos; // the findmatch for end_pos will overwrite *pos
}
p_cpo = save_cpo;
diff --git a/src/nvim/shada.c b/src/nvim/shada.c
index dcdf2195f8..def2de9b1a 100644
--- a/src/nvim/shada.c
+++ b/src/nvim/shada.c
@@ -6,9 +6,6 @@
#include <inttypes.h>
#include <errno.h>
#include <fcntl.h>
-#ifdef HAVE_UNISTD_H
-# include <unistd.h>
-#endif
#include <assert.h>
#include <msgpack.h>
diff --git a/src/nvim/spell.c b/src/nvim/spell.c
index b2028109be..cc7dc6210c 100644
--- a/src/nvim/spell.c
+++ b/src/nvim/spell.c
@@ -12910,8 +12910,8 @@ void ex_spelldump(exarg_T *eap)
do_cmdline_cmd("new");
// enable spelling locally in the new window
- set_option_value((char_u*)"spell", TRUE, (char_u*)"", OPT_LOCAL);
- set_option_value((char_u*)"spl", dummy, spl, OPT_LOCAL);
+ set_option_value((char_u*)"spell", true, (char_u*)"", OPT_LOCAL);
+ set_option_value((char_u*)"spl", dummy, spl, OPT_LOCAL);
xfree(spl);
if (!bufempty() || !buf_valid(curbuf))
diff --git a/src/nvim/tag.c b/src/nvim/tag.c
index d832924efd..8fcb02c3b6 100644
--- a/src/nvim/tag.c
+++ b/src/nvim/tag.c
@@ -445,17 +445,10 @@ do_tag (
tagmatchname = vim_strsave(name);
}
- /*
- * If a count is supplied to the ":tag <name>" command, then
- * jump to count'th matching tag.
- */
- if (type == DT_TAG && *tag != NUL && count > 0)
- cur_match = count - 1;
-
- if (type == DT_SELECT || type == DT_JUMP
- || type == DT_LTAG
- )
+ if (type == DT_TAG || type == DT_SELECT || type == DT_JUMP
+ || type == DT_LTAG) {
cur_match = MAXCOL - 1;
+ }
max_num_matches = cur_match + 1;
/* when the argument starts with '/', use it as a regexp */
@@ -506,18 +499,19 @@ do_tag (
EMSG2(_("E426: tag not found: %s"), name);
g_do_tagpreview = 0;
} else {
- int ask_for_selection = FALSE;
+ bool ask_for_selection = false;
if (type == DT_CSCOPE && num_matches > 1) {
cs_print_tags();
- ask_for_selection = TRUE;
- } else if (type == DT_SELECT ||
- (type == DT_JUMP && num_matches > 1)) {
- /*
- * List all the matching tags.
- * Assume that the first match indicates how long the tags can
- * be, and align the file names to that.
- */
+ ask_for_selection = true;
+ } else if (type == DT_TAG) {
+ // If a count is supplied to the ":tag <name>" command, then
+ // jump to count'th matching tag.
+ cur_match = count > 0 ? count - 1 : 0;
+ } else if (type == DT_SELECT || (type == DT_JUMP && num_matches > 1)) {
+ // List all the matching tags.
+ // Assume that the first match indicates how long the tags can
+ // be, and align the file names to that.
parse_match(matches[0], &tagp);
taglen = (int)(tagp.tagname_end - tagp.tagname + 2);
if (taglen < 18)
@@ -666,9 +660,10 @@ do_tag (
msg_putchar('\n');
os_breakcheck();
}
- if (got_int)
- got_int = FALSE; /* only stop the listing */
- ask_for_selection = TRUE;
+ if (got_int) {
+ got_int = false; // only stop the listing
+ }
+ ask_for_selection = true;
} else if (type == DT_LTAG) {
list_T *list;
char_u tag_name[128 + 1];
@@ -801,10 +796,8 @@ do_tag (
cur_match = 0; /* Jump to the first tag */
}
- if (ask_for_selection == TRUE) {
- /*
- * Ask to select a tag from the list.
- */
+ if (ask_for_selection) {
+ // Ask to select a tag from the list.
i = prompt_for_number(NULL);
if (i <= 0 || i > num_matches || got_int) {
/* no valid choice: don't change anything */
@@ -851,7 +844,7 @@ do_tag (
ic = (matches[cur_match][0] & MT_IC_OFF);
- if (type != DT_SELECT && type != DT_JUMP
+ if (type != DT_TAG && type != DT_SELECT && type != DT_JUMP
&& type != DT_CSCOPE
&& (num_matches > 1 || ic)
&& !skip_msg) {
diff --git a/src/nvim/testdir/Makefile b/src/nvim/testdir/Makefile
index 41ce2daa91..d1a7abfbf7 100644
--- a/src/nvim/testdir/Makefile
+++ b/src/nvim/testdir/Makefile
@@ -15,7 +15,7 @@ SCRIPTS := \
test30.out \
test32.out test34.out \
test36.out test37.out test40.out \
- test42.out test45.out \
+ test42.out \
test47.out test48.out test49.out \
test52.out test53.out test55.out \
test64.out \
@@ -28,6 +28,7 @@ SCRIPTS := \
test_charsearch.out \
test_close_count.out \
test_command_count.out \
+ test_marks.out \
NEW_TESTS =
@@ -131,7 +132,7 @@ test1.out: .gdbinit test1.in
# Check if the test.out file matches test.ok.
@/bin/sh -c "if test -f test.out; then \
- if diff test.out $*.ok; then \
+ if diff -u test.out $*.ok; then \
mv -f test.out $*.out; \
else \
echo $* FAILED >> test.log; \
diff --git a/src/nvim/testdir/test13.in b/src/nvim/testdir/test13.in
index cb8a6fff89..6713f80e88 100644
--- a/src/nvim/testdir/test13.in
+++ b/src/nvim/testdir/test13.in
@@ -48,6 +48,12 @@ otestje3
:au BufWipeout Xtestje1 buf Xtestje1
:bwipe
:w >>test.out
+:only
+:new|set buftype=help
+:wincmd w
+:1quit
+:$put ='Final line'
+:$w >>test.out
:qa!
ENDTEST
diff --git a/src/nvim/testdir/test13.ok b/src/nvim/testdir/test13.ok
index 0f1fc347a4..66ebce63f7 100644
--- a/src/nvim/testdir/test13.ok
+++ b/src/nvim/testdir/test13.ok
@@ -28,3 +28,4 @@ testje1
contents
contents
end of testfile
+Final line
diff --git a/src/nvim/testdir/test30.in b/src/nvim/testdir/test30.in
index 3f7b9eb472..2a89eac73d 100644
--- a/src/nvim/testdir/test30.in
+++ b/src/nvim/testdir/test30.in
@@ -7,32 +7,27 @@ STARTTEST
:" first write three test files, one in each format
:set fileformat=unix
:set fileformats=
-:/^1/w! XX1
-:/^2/w! XX2
-:/^3/w! XX3
-:/^4/w! XX4
-:/^5/w! XX5
-:/^6/w! XX6
-:/^7/w! XX7
-:/^8/w! XX8
-:/^9/w! XX9
-:/^10/w! XX10
:/^unix/;/eof/-1w! XXUnix
:/^dos/;/eof/-1w! XXDos
:set bin noeol
:$w! XXMac
+Gonoeol
+:$w! XXEol
:set nobin eol
+:enew!
:bwipe XXUnix XXDos XXMac
:" create mixed format files
:if has("win32")
: !copy /b XXUnix+XXDos XXUxDs
: !copy /b XXUnix+XXMac XXUxMac
: !copy /b XXDos+XXMac XXDosMac
+: !copy /b XXMac+XXEol XXMacEol
: !copy /b XXUnix+XXDos+XXMac XXUxDsMc
:else
: !cat XXUnix XXDos >XXUxDs
: !cat XXUnix XXMac >XXUxMac
: !cat XXDos XXMac >XXDosMac
+: !cat XXMac XXEol >XXMacEol
: !cat XXUnix XXDos XXMac >XXUxDsMc
:endif
:"
@@ -97,26 +92,48 @@ STARTTEST
:e! XXDosMac
:w! XXtt53
:bwipe XXDosMac
+:e! XXEol
+ggO=&ffs
+:=&ff
+:w! XXtt54
+:bwipe XXEol
:set fileformats=dos,mac
:e! XXUxDs
:w! XXtt61
:bwipe XXUxDs
:e! XXUxMac
-:w! XXtt62
+ggO=&ffs
+:=&ff
+:w! XXtt62
:bwipe XXUxMac
:e! XXUxDsMc
:w! XXtt63
:bwipe XXUxDsMc
+:e! XXMacEol
+ggO=&ffs
+:=&ff
+:w! XXtt64
+:bwipe XXMacEol
:"
:" try reading and writing with 'fileformats' set to three formats
:set fileformats=unix,dos,mac
:e! XXUxDsMc
:w! XXtt71
:bwipe XXUxDsMc
+:e! XXEol
+ggO=&ffs
+:=&ff
+:w! XXtt72
+:bwipe XXEol
:set fileformats=mac,dos,unix
:e! XXUxDsMc
:w! XXtt81
:bwipe XXUxDsMc
+:e! XXEol
+ggO=&ffs
+:=&ff
+:w! XXtt82
+:bwipe XXEol
:" try with 'binary' set
:set fileformats=mac,unix,dos
:set binary
@@ -150,11 +167,15 @@ ggdGaEND:w >>XXtt01
:w >>XXtt51
:w >>XXtt52
:w >>XXtt53
+:w >>XXtt54
:w >>XXtt61
:w >>XXtt62
:w >>XXtt63
+:w >>XXtt64
:w >>XXtt71
+:w >>XXtt72
:w >>XXtt81
+:w >>XXtt82
:w >>XXtt91
:w >>XXtt92
:w >>XXtt93
@@ -181,11 +202,15 @@ Go4:$r XXtt41
Go5:$r XXtt51
:$r XXtt52
:$r XXtt53
+:$r XXtt54
Go6:$r XXtt61
:$r XXtt62
:$r XXtt63
+:$r XXtt64
Go7:$r XXtt71
+:$r XXtt72
Go8:$r XXtt81
+:$r XXtt82
Go9:$r XXtt91
:$r XXtt92
:$r XXtt93
@@ -195,17 +220,6 @@ Go10:$r XXUnix
:qa!
ENDTEST
-1
-2
-3
-4
-5
-6
-7
-8
-9
-10
-
unix
unix
eof
diff --git a/src/nvim/testdir/test30.ok b/src/nvim/testdir/test30.ok
index 380ce67061..b35f4f5904 100644
--- a/src/nvim/testdir/test30.ok
+++ b/src/nvim/testdir/test30.ok
@@ -70,12 +70,16 @@ END
dos
dos
mac mac END
+unix,mac:unix
+noeol
+END
6
unix
unix
dos
dos
END
+dos,mac:dos
unix
unix
mac mac
@@ -86,6 +90,7 @@ dos
dos
mac mac
END
+dos,mac:mac mac mac noeol END
7
unix
unix
@@ -93,6 +98,9 @@ dos
dos
mac mac
END
+unix,dos,mac:unix
+noeol
+END
8
unix
unix
@@ -100,6 +108,7 @@ dos
dos
mac mac
END
+mac,dos,unix:mac noeol END
9
unix
unix
diff --git a/src/nvim/testdir/test45.in b/src/nvim/testdir/test45.in
deleted file mode 100644
index e5af5073d9..0000000000
--- a/src/nvim/testdir/test45.in
+++ /dev/null
@@ -1,80 +0,0 @@
-Tests for folding. vim: set ft=vim :
-
-STARTTEST
-:so small.vim
-:" We also need the +syntax feature here.
-:if !has("syntax")
- e! test.ok
- w! test.out
- qa!
-:endif
-:" basic test if a fold can be created, opened, moving to the end and closed
-/^1
-zf2j:call append("$", "manual " . getline(foldclosed(".")))
-zo:call append("$", foldclosed("."))
-]z:call append("$", getline("."))
-zc:call append("$", getline(foldclosed(".")))
-:" test folding with markers.
-:set fdm=marker fdl=1 fdc=3
-/^5
-:call append("$", "marker " . foldlevel("."))
-[z:call append("$", foldlevel("."))
-jo{{ r{jj:call append("$", foldlevel("."))
-kYpj:call append("$", foldlevel("."))
-:" test folding with indent
-:set fdm=indent sw=2
-/^2 b
-i jI :call append("$", "indent " . foldlevel("."))
-k:call append("$", foldlevel("."))
-:" test syntax folding
-:set fdm=syntax fdl=0
-:syn region Hup start="dd" end="ii" fold contains=Fd1,Fd2,Fd3
-:syn region Fd1 start="ee" end="ff" fold contained
-:syn region Fd2 start="gg" end="hh" fold contained
-:syn region Fd3 start="commentstart" end="commentend" fold contained
-Gzk:call append("$", "folding " . getline("."))
-k:call append("$", getline("."))
-jAcommentstart Acommentend:set fdl=1
-3j:call append("$", getline("."))
-:set fdl=0
-zO j:call append("$", getline("."))
-:" test expression folding
-:fun Flvl()
- let l = getline(v:lnum)
- if l =~ "bb$"
- return 2
- elseif l =~ "gg$"
- return "s1"
- elseif l =~ "ii$"
- return ">2"
- elseif l =~ "kk$"
- return "0"
- endif
- return "="
-endfun
-:set fdm=expr fde=Flvl()
-/bb$
-:call append("$", "expr " . foldlevel("."))
-/hh$
-:call append("$", foldlevel("."))
-/ii$
-:call append("$", foldlevel("."))
-/kk$
-:call append("$", foldlevel("."))
-:/^last/+1,$w! test.out
-:delfun Flvl
-:qa!
-ENDTEST
-
-1 aa
-2 bb
-3 cc
-4 dd {{{
-5 ee {{{ }}}
-6 ff }}}
-7 gg
-8 hh
-9 ii
-a jj
-b kk
-last
diff --git a/src/nvim/testdir/test45.ok b/src/nvim/testdir/test45.ok
deleted file mode 100644
index f04996e337..0000000000
--- a/src/nvim/testdir/test45.ok
+++ /dev/null
@@ -1,18 +0,0 @@
-manual 1 aa
--1
-3 cc
-1 aa
-marker 2
-1
-1
-0
-indent 2
-1
-folding 9 ii
- 3 cc
-7 gg
-8 hh
-expr 2
-1
-2
-0
diff --git a/src/nvim/testdir/test_marks.in b/src/nvim/testdir/test_marks.in
new file mode 100644
index 0000000000..23c2fb65fe
--- /dev/null
+++ b/src/nvim/testdir/test_marks.in
@@ -0,0 +1,34 @@
+Tests for marks.
+
+STARTTEST
+:so small.vim
+:" test that a deleted mark is restored after delete-undo-redo-undo
+:/^\t/+1
+:set nocp viminfo+=nviminfo
+madduu
+:let a = string(getpos("'a"))
+:$put ='Mark after delete-undo-redo-undo: '.a
+:''
+ENDTEST
+
+ textline A
+ textline B
+ textline C
+
+STARTTEST
+:" test that CTRL-A and CTRL-X updates last changed mark '[, '].
+:/^123/
+:execute "normal! \<C-A>`[v`]rAjwvjw\<C-X>`[v`]rX"
+ENDTEST
+
+CTRL-A CTRL-X:
+123 123 123
+123 123 123
+123 123 123
+
+STARTTEST
+:g/^STARTTEST/.,/^ENDTEST/d
+:wq! test.out
+ENDTEST
+
+Results:
diff --git a/src/nvim/testdir/test_marks.ok b/src/nvim/testdir/test_marks.ok
new file mode 100644
index 0000000000..e6c02ee7b0
--- /dev/null
+++ b/src/nvim/testdir/test_marks.ok
@@ -0,0 +1,16 @@
+Tests for marks.
+
+
+ textline A
+ textline B
+ textline C
+
+
+CTRL-A CTRL-X:
+AAA 123 123
+123 XXXXXXX
+XXX 123 123
+
+
+Results:
+Mark after delete-undo-redo-undo: [0, 15, 2, 0]
diff --git a/src/nvim/undo.c b/src/nvim/undo.c
index 6b60f95f22..b8cdffcda0 100644
--- a/src/nvim/undo.c
+++ b/src/nvim/undo.c
@@ -2222,12 +2222,17 @@ static void u_undoredo(int undo)
/*
* restore marks from before undo/redo
*/
- for (i = 0; i < NMARKS; ++i)
+ for (i = 0; i < NMARKS; ++i) {
if (curhead->uh_namedm[i].mark.lnum != 0) {
free_fmark(curbuf->b_namedm[i]);
curbuf->b_namedm[i] = curhead->uh_namedm[i];
+ }
+ if (namedm[i].mark.lnum != 0) {
curhead->uh_namedm[i] = namedm[i];
+ } else {
+ curhead->uh_namedm[i].mark.lnum = 0;
}
+ }
if (curhead->uh_visual.vi_start.lnum != 0) {
curbuf->b_visual = curhead->uh_visual;
curhead->uh_visual = visualinfo;
diff --git a/src/nvim/version.c b/src/nvim/version.c
index e7e6d8b55c..b28d5706c8 100644
--- a/src/nvim/version.c
+++ b/src/nvim/version.c
@@ -69,16 +69,170 @@ static char *features[] = {
// clang-format off
static int included_patches[] = {
+ // 1219 NA
+ // 1218 NA
+ // 1217 NA
+ // 1216 NA
+ // 1215 NA
+ // 1214 NA
+ // 1213 NA
+ // 1212 NA
+ // 1211 NA
+ // 1210 NA
+ // 1209 NA
+ // 1208 NA
+ // 1207 NA
+ // 1206 NA
+ // 1205 NA
+ // 1204 NA
+ // 1203 NA
+ // 1202 NA
+ // 1201 NA
+ // 1200 NA
+ // 1199 NA
+ // 1198 NA
+ // 1197 NA
+ // 1196 NA
+ // 1195 NA
+ // 1194 NA
+ // 1193 NA
+ // 1192 NA
+ // 1191 NA
+ // 1190 NA
+ // 1189 NA
+ // 1188,
+ // 1187 NA
+ // 1186,
+ // 1185 NA
+ // 1184 NA
+ // 1183 NA
+ // 1182 NA
+ // 1181,
+ 1180,
+ // 1179,
+ // 1178,
+ // 1177 NA
+ // 1176 NA
+ // 1175 NA
+ // 1174 NA
+ // 1173,
+ // 1172 NA
+ // 1171 NA
+ // 1170 NA
+ // 1169 NA
+ // 1168,
+ // 1167,
+ // 1166,
+ // 1165 NA
+ // 1164,
+ // 1163,
+ // 1162 NA
+ // 1161,
+ // 1160,
+ // 1159 NA
+ // 1158 NA
+ // 1157,
+ // 1156,
+ // 1155 NA
+ // 1154,
+ // 1153,
+ // 1152 NA
+ // 1151,
+ // 1150,
+ 1149,
+ // 1148 NA
+ // 1147,
+ // 1146 NA
+ // 1145 NA
+ // 1144 NA
+ // 1143,
+ // 1142,
+ // 1141,
+ // 1140,
+ // 1139 NA
+ // 1138 NA
1137,
-
-
-
+ // 1136,
+ // 1135 NA,
+ // 1134 NA,
+ // 1133 NA
+ // 1132,
+ // 1131 NA
+ // 1130,
+ // 1129 NA
+ // 1128 NA
+ // 1127 NA
+ // 1126,
+ // 1125 NA
+ // 1124 NA
+ // 1123,
+ // 1122 NA
+ // 1121,
+ // 1120,
+ // 1119,
+ // 1118,
+ // 1117,
+ // 1116,
+ // 1115 NA
+ // 1114,
+ // 1113,
+ // 1112,
+ // 1111,
+ // 1110,
+ // 1109 NA
+ // 1108,
+ // 1107,
+ // 1106 NA
+ // 1105,
+ // 1104 NA
+ // 1103 NA
+ // 1102,
+ // 1101,
+ // 1100 NA
+ // 1099 NA
+ // 1098 NA
+ // 1097,
+ // 1096,
+ // 1095 NA
+ // 1094,
+ // 1093,
+ // 1092,
+ // 1091,
+ // 1090,
+ 1089,
+ 1088,
+ 1087,
+ // 1086,
+ 1085,
+ 1084,
+ // 1083 NA,
+ // 1082 NA,
1081,
-
-
-
-
-
+ // 1080 NA,
+ // 1079,
+ // 1078 NA,
+ // 1077 NA,
+ 1076,
+ // 1075,
+ // 1074 NA,
+ // 1073,
+ 1072,
+ // 1071,
+ // 1070 NA,
+ // 1069 NA,
+ // 1068,
+ // 1067 NA,
+ // 1066 NA,
+ 1065,
+ // 1064,
+ // 1063 NA,
+ // 1062 NA,
+ // 1061,
+ // 1060 NA,
+ // 1059,
+ // 1058,
+ // 1057,
+ // 1056,
1055,
// 1054,
// 1053,
@@ -89,50 +243,50 @@ static int included_patches[] = {
// 1048,
// 1047,
// 1046,
- // 1045,
- // 1044,
- // 1043,
+ // 1045 NA,
+ // 1044 NA,
+ // 1043 NA,
// 1042,
// 1041,
- // 1040,
+ // 1040 NA,
// 1039,
- // 1038,
+ // 1038 NA,
// 1037,
// 1036,
// 1035,
// 1034,
- // 1033,
+ // 1033 NA,
1032,
- // 1031,
+ // 1031 NA,
// 1030,
- // 1029,
- // 1028,
- // 1027,
- // 1026,
- // 1025,
- // 1024,
- // 1023,
- // 1022,
- // 1021,
- // 1020,
- // 1019,
+ 1029,
+ // 1028 NA,
+ 1027,
+ // 1026 NA,
+ // 1025 NA,
+ // 1024 NA,
+ // 1023 NA,
+ // 1022 NA,
+ // 1021 NA,
+ // 1020 NA,
+ // 1019 NA,
// 1018,
// 1017,
- // 1016,
+ // 1016 NA,
// 1015,
- // 1014,
- // 1013,
- // 1012,
- // 1011,
+ // 1014 NA,
+ 1013,
+ // 1012 NA,
+ // 1011 NA,
// 1010,
- // 1009,
- // 1008,
+ // 1009 NA,
+ // 1008 NA,
// 1007,
// 1006,
// 1005,
- // 1004,
- // 1003,
- // 1002,
+ // 1004 NA,
+ // 1003 NA,
+ // 1002 NA,
// 1001,
// 1000,
// 999 NA
@@ -286,7 +440,7 @@ static int included_patches[] = {
// 851 NA
// 850 NA
849,
- // 848,
+ 848,
// 847,
// 846 NA
// 845,
@@ -311,7 +465,7 @@ static int included_patches[] = {
826,
// 825,
// 824 NA
- // 823,
+ 823,
// 822,
// 821,
// 820,
@@ -327,8 +481,8 @@ static int included_patches[] = {
// 810,
809,
// 808 NA
- // 807,
- // 806,
+ 807,
+ 806,
// 805,
// 804,
803,
@@ -352,11 +506,11 @@ static int included_patches[] = {
785,
784,
// 783 NA
- // 782,
+ 782,
781,
- // 780 NA
- // 779,
- // 778,
+ 780,
+ 779,
+ 778,
// 777 NA
776,
775,
@@ -369,8 +523,8 @@ static int included_patches[] = {
768,
// 767,
// 766 NA
- // 765,
- // 764,
+ 765,
+ 764,
// 763 NA
// 762 NA
// 761 NA
@@ -380,21 +534,21 @@ static int included_patches[] = {
// 757 NA
// 756 NA
// 755,
- // 754,
+ 754,
753,
// 752,
// 751 NA
// 750 NA
// 749,
- // 748,
- // 747,
- // 746,
- // 745,
+ 748,
+ 747,
+ 746,
+ 745,
// 744 NA
// 743,
// 742,
- // 741,
- // 740,
+ 741,
+ 740,
739,
// 738 NA
// 737,
@@ -425,7 +579,7 @@ static int included_patches[] = {
712,
711,
710,
- // 709,
+ 709,
// 708,
707,
706,
@@ -434,19 +588,19 @@ static int included_patches[] = {
// 703 NA
702,
// 701 NA
- // 700,
+ 700,
699,
698,
- // 697,
+ 697,
696,
695,
- // 694,
- // 693,
+ 694,
+ 693,
// 692 NA
// 691 NA
690,
- // 689,
- // 688,
+ 689,
+ 688,
// 687 NA
686,
685,
@@ -472,7 +626,7 @@ static int included_patches[] = {
665,
// 664 NA
// 663 NA
- // 662,
+ 662,
// 661 NA
660,
659,
@@ -491,7 +645,7 @@ static int included_patches[] = {
646,
645,
// 644 NA
- // 643,
+ 643,
642,
// 641 NA
640,
@@ -500,7 +654,7 @@ static int included_patches[] = {
637,
636,
635,
- // 634,
+ 634,
633,
// 632 NA
631,
diff --git a/src/nvim/vim.h b/src/nvim/vim.h
index 2e20d48f90..5f9785a9a9 100644
--- a/src/nvim/vim.h
+++ b/src/nvim/vim.h
@@ -35,7 +35,15 @@ Error: configure did not run properly.Check auto/config.log.
#include "nvim/os/os_defs.h" /* bring lots of system header files */
-#define NUMBUFLEN 65 // length of a buffer to store a number in ASCII
+/// length of a buffer to store a number in ASCII (64 bits binary + NUL)
+#define NUMBUFLEN 65
+
+// flags for vim_str2nr()
+#define STR2NR_BIN 1
+#define STR2NR_OCT 2
+#define STR2NR_HEX 4
+#define STR2NR_ALL (STR2NR_BIN + STR2NR_OCT + STR2NR_HEX)
+#define STR2NR_FORCE 8 // only when ONE of the above is used
#define MAX_TYPENR 65535
diff --git a/src/nvim/window.c b/src/nvim/window.c
index 191cb04d75..e84d8df36b 100644
--- a/src/nvim/window.c
+++ b/src/nvim/window.c
@@ -3281,17 +3281,27 @@ void goto_tabpage_win(tabpage_T *tp, win_T *wp)
}
}
-/*
- * Move the current tab page to before tab page "nr".
- */
+// Move the current tab page to after tab page "nr".
void tabpage_move(int nr)
{
- int n = nr;
- tabpage_T *tp;
+ int n = 1;
+ tabpage_T *tp;
+ tabpage_T *tp_dst;
if (first_tabpage->tp_next == NULL)
return;
+ for (tp = first_tabpage; tp->tp_next != NULL && n < nr; tp = tp->tp_next) {
+ ++n;
+ }
+
+ if (tp == curtab || (nr > 0 && tp->tp_next != NULL
+ && tp->tp_next == curtab)) {
+ return;
+ }
+
+ tp_dst = tp;
+
/* Remove the current tab page from the list of tab pages. */
if (curtab == first_tabpage)
first_tabpage = curtab->tp_next;
@@ -3304,15 +3314,13 @@ void tabpage_move(int nr)
tp->tp_next = curtab->tp_next;
}
- /* Re-insert it at the specified position. */
- if (n <= 0) {
+ // Re-insert it at the specified position.
+ if (nr <= 0) {
curtab->tp_next = first_tabpage;
first_tabpage = curtab;
} else {
- for (tp = first_tabpage; tp->tp_next != NULL && n > 1; tp = tp->tp_next)
- --n;
- curtab->tp_next = tp->tp_next;
- tp->tp_next = curtab;
+ curtab->tp_next = tp_dst->tp_next;
+ tp_dst->tp_next = curtab;
}
/* Need to redraw the tabline. Tab page contents doesn't change. */
diff --git a/test/functional/api/server_requests_spec.lua b/test/functional/api/server_requests_spec.lua
index 16a4423535..c0099e44c4 100644
--- a/test/functional/api/server_requests_spec.lua
+++ b/test/functional/api/server_requests_spec.lua
@@ -43,7 +43,7 @@ describe('server -> client', function()
stop()
end
- local function on_request(method, args)
+ local function on_request()
-- No need to evaluate the args, we are only interested in
-- a response that contains an array with an empty string.
return {1, 2, '', 3, 'asdf'}
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 55db9169fa..6e1879035b 100644
--- a/test/functional/legacy/039_visual_block_mode_commands_spec.lua
+++ b/test/functional/legacy/039_visual_block_mode_commands_spec.lua
@@ -5,7 +5,7 @@ local helpers = require('test.functional.helpers')
local nvim, eq = helpers.meths, helpers.eq
local insert, feed = helpers.insert, helpers.feed
local clear, expect = helpers.clear, helpers.expect
-local source, execute = helpers.source, helpers.execute
+local execute = helpers.execute
describe('Visual block mode', function()
diff --git a/test/functional/legacy/045_folding_spec.lua b/test/functional/legacy/045_folding_spec.lua
new file mode 100644
index 0000000000..04b623ff3b
--- /dev/null
+++ b/test/functional/legacy/045_folding_spec.lua
@@ -0,0 +1,139 @@
+-- Tests for folding.
+
+local helpers = require('test.functional.helpers')
+local feed, insert, clear, execute, expect =
+ helpers.feed, helpers.insert, helpers.clear, helpers.execute, helpers.expect
+
+describe('folding', function()
+ before_each(clear)
+
+ it('is working', function()
+ insert([[
+ 1 aa
+ 2 bb
+ 3 cc
+ 4 dd {{{
+ 5 ee {{{ }}}
+ 6 ff }}}
+ 7 gg
+ 8 hh
+ 9 ii
+ a jj
+ b kk
+ last]])
+
+ -- Basic test if a fold can be created, opened, moving to the end and
+ -- closed.
+ execute('/^1')
+ feed('zf2j')
+ execute('call append("$", "manual " . getline(foldclosed(".")))')
+ feed('zo')
+ execute('call append("$", foldclosed("."))')
+ feed(']z')
+ execute('call append("$", getline("."))')
+ feed('zc')
+ execute('call append("$", getline(foldclosed(".")))')
+ -- Test folding with markers.
+ execute('set fdm=marker fdl=1 fdc=3')
+ execute('/^5')
+ execute('call append("$", "marker " . foldlevel("."))')
+ feed('[z')
+ execute('call append("$", foldlevel("."))')
+ feed('jo{{ <esc>r{jj')
+ execute('call append("$", foldlevel("."))')
+ feed('kYpj')
+ execute('call append("$", foldlevel("."))')
+ -- Test folding with indent.
+ execute('set fdm=indent sw=2')
+ execute('/^2 b')
+ feed('i <esc>jI <esc>')
+ execute('call append("$", "indent " . foldlevel("."))')
+ feed('k')
+ execute('call append("$", foldlevel("."))')
+ -- Test syntax folding.
+ execute('set fdm=syntax fdl=0')
+ execute('syn region Hup start="dd" end="ii" fold contains=Fd1,Fd2,Fd3')
+ execute('syn region Fd1 start="ee" end="ff" fold contained')
+ execute('syn region Fd2 start="gg" end="hh" fold contained')
+ execute('syn region Fd3 start="commentstart" end="commentend" fold contained')
+ feed('Gzk')
+ execute('call append("$", "folding " . getline("."))')
+ feed('k')
+ execute('call append("$", getline("."))')
+ feed('jAcommentstart <esc>Acommentend<esc>')
+ execute('set fdl=1')
+ feed('3j')
+ execute('call append("$", getline("."))')
+ execute('set fdl=0')
+ feed('zO<C-L>j')
+ execute('call append("$", getline("."))')
+ -- Test expression folding.
+ execute('fun Flvl()')
+ execute(' let l = getline(v:lnum)')
+ execute(' if l =~ "bb$"')
+ execute(' return 2')
+ execute(' elseif l =~ "gg$"')
+ execute(' return "s1"')
+ execute(' elseif l =~ "ii$"')
+ execute(' return ">2"')
+ execute(' elseif l =~ "kk$"')
+ execute(' return "0"')
+ execute(' endif')
+ execute(' return "="')
+ execute('endfun')
+ execute('set fdm=expr fde=Flvl()')
+ execute('/bb$')
+ execute('call append("$", "expr " . foldlevel("."))')
+ execute('/hh$')
+ execute('call append("$", foldlevel("."))')
+ execute('/ii$')
+ execute('call append("$", foldlevel("."))')
+ execute('/kk$')
+ execute('call append("$", foldlevel("."))')
+ execute('0,/^last/delete')
+ execute('delfun Flvl')
+
+ -- Assert buffer contents.
+ expect([[
+ manual 1 aa
+ -1
+ 3 cc
+ 1 aa
+ marker 2
+ 1
+ 1
+ 0
+ indent 2
+ 1
+ folding 9 ii
+ 3 cc
+ 7 gg
+ 8 hh
+ expr 2
+ 1
+ 2
+ 0]])
+ end)
+
+ it('can open after :move', function()
+ insert([[
+ Test fdm=indent and :move bug END
+ line2
+ Test fdm=indent START
+ line3
+ line4]])
+
+ execute('set noai nosta')
+ execute('set fdm=indent')
+ execute('1m1')
+ feed('2jzc')
+ execute('m0')
+
+ expect([[
+ Test fdm=indent START
+ line3
+ line4
+ Test fdm=indent and :move bug END
+ line2]])
+ end)
+end)
diff --git a/test/functional/legacy/057_sort_spec.lua b/test/functional/legacy/057_sort_spec.lua
index 65defbae96..7eed31e292 100644
--- a/test/functional/legacy/057_sort_spec.lua
+++ b/test/functional/legacy/057_sort_spec.lua
@@ -600,39 +600,72 @@ describe(':sort', function()
eq('Vim(sort):E474: Invalid argument', eval('tmpvar'))
expect(text)
end)
-
+
it('binary', function()
insert([[
- 0b111000
- 0b101100
- 0b101001
- 0b101001
- 0b101000
- 0b000000
- 0b001000
- 0b010000
- 0b101000
- 0b100000
- 0b101010
- 0b100010
- 0b100100
- 0b100010]])
+ 0b111000
+ 0b101100
+ 0b101001
+ 0b101001
+ 0b101000
+ 0b000000
+ 0b001000
+ 0b010000
+ 0b101000
+ 0b100000
+ 0b101010
+ 0b100010
+ 0b100100
+ 0b100010]])
execute([[sort b]])
expect([[
- 0b000000
- 0b001000
- 0b010000
- 0b100000
- 0b100010
- 0b100010
- 0b100100
- 0b101000
- 0b101000
- 0b101001
- 0b101001
- 0b101010
- 0b101100
- 0b111000]])
+ 0b000000
+ 0b001000
+ 0b010000
+ 0b100000
+ 0b100010
+ 0b100010
+ 0b100100
+ 0b101000
+ 0b101000
+ 0b101001
+ 0b101001
+ 0b101010
+ 0b101100
+ 0b111000]])
end)
+ it('binary with leading characters', function()
+ insert([[
+ 0b100010
+ 0b010000
+ 0b101001
+ b0b101100
+ 0b100010
+ 0b100100
+ a0b001000
+ 0b101000
+ 0b101000
+ a0b101001
+ ab0b100000
+ 0b101010
+ 0b000000
+ b0b111000]])
+ execute([[sort b]])
+ expect([[
+ 0b000000
+ a0b001000
+ 0b010000
+ ab0b100000
+ 0b100010
+ 0b100010
+ 0b100100
+ 0b101000
+ 0b101000
+ 0b101001
+ a0b101001
+ 0b101010
+ b0b101100
+ b0b111000]])
+ end)
end)
diff --git a/test/functional/legacy/059_utf8_spell_checking_spec.lua b/test/functional/legacy/059_utf8_spell_checking_spec.lua
index 5794e875a0..63df387be3 100644
--- a/test/functional/legacy/059_utf8_spell_checking_spec.lua
+++ b/test/functional/legacy/059_utf8_spell_checking_spec.lua
@@ -31,8 +31,6 @@ describe("spell checking with 'encoding' set to utf-8", function()
RAR ?
BAD !
- #NOSPLITSUGS
-
PFX I N 1
PFX I 0 in .
@@ -92,8 +90,6 @@ describe("spell checking with 'encoding' set to utf-8", function()
RAR ?
BAD !
- #NOSPLITSUGS
-
PFX I N 1
PFX I 0 in .
@@ -300,6 +296,24 @@ describe("spell checking with 'encoding' set to utf-8", function()
tail/123
middle/77,1
]])
+ write_latin1('Xtest8.aff', [[
+ SET ISO8859-1
+
+ NOSPLITSUGS
+ ]])
+ write_latin1('Xtest8.dic', [[
+ 1234
+ foo
+ bar
+ faabar
+ ]])
+ write_latin1('Xtest9.aff', [[
+ ]])
+ write_latin1('Xtest9.dic', [[
+ 1234
+ foo
+ bar
+ ]])
write_latin1('Xtest-sal.aff', [[
SET ISO8859-1
TRY esianrtolcdugmphbyfvkwjkqxz-ëéèêïîäàâöüû'ESIANRTOLCDUGMPHBYFVKWJKQXZ
@@ -314,8 +328,6 @@ describe("spell checking with 'encoding' set to utf-8", function()
RAR ?
BAD !
- #NOSPLITSUGS
-
PFX I N 1
PFX I 0 in .
@@ -483,6 +495,10 @@ describe("spell checking with 'encoding' set to utf-8", function()
os.remove('Xtest6.dic')
os.remove('Xtest7.aff')
os.remove('Xtest7.dic')
+ os.remove('Xtest8.aff')
+ os.remove('Xtest8.dic')
+ os.remove('Xtest9.aff')
+ os.remove('Xtest9.dic')
end)
-- Function to test .aff/.dic with list of good and bad words. This was a
@@ -940,4 +956,46 @@ describe("spell checking with 'encoding' set to utf-8", function()
leadprobar
['leadprebar', 'lead prebar', 'leadbar']]=])
end)
+
+ it('part 8-8', function()
+ insert([[
+ 8good: foo bar faabar
+ bad: foobar barfoo
+ badend
+ ]])
+ -- NOSPLITSUGS
+ test_one(8, 8)
+ -- Assert buffer contents.
+ execute('1,/^test 8-8/-1d')
+ expect([=[
+ test 8-8
+ # file: Xtest.utf-8.spl
+ bar
+ faabar
+ foo
+ -------
+ bad
+ ['bar', 'foo']
+ foobar
+ ['faabar', 'foo bar', 'bar']
+ barfoo
+ ['bar foo', 'bar', 'foo']]=])
+ end)
+
+ it('part 9-9', function()
+ insert([[
+ 9good: 0b1011 0777 1234 0x01ff
+ badend
+ ]])
+ -- NOSPLITSUGS
+ test_one(9, 9)
+ -- Assert buffer contents.
+ execute('1,/^test 9-9/-1d')
+ expect([=[
+ test 9-9
+ # file: Xtest.utf-8.spl
+ bar
+ foo
+ -------]=])
+ end)
end)
diff --git a/test/functional/legacy/062_tab_pages_spec.lua b/test/functional/legacy/062_tab_pages_spec.lua
index 6bbb06f9a7..f1c8b8d58b 100644
--- a/test/functional/legacy/062_tab_pages_spec.lua
+++ b/test/functional/legacy/062_tab_pages_spec.lua
@@ -86,21 +86,35 @@ describe('tab pages', function()
feed('1gt')
eq(1, eval('tabpagenr()'))
execute('tabmove 5')
- eq(6, eval('tabpagenr()'))
- execute('tabmove -2')
+ eq(5, eval('tabpagenr()'))
+ execute('.tabmove')
+ eq(5, eval('tabpagenr()'))
+ execute('tabmove -')
eq(4, eval('tabpagenr()'))
+ execute('tabmove +')
+ eq(5, eval('tabpagenr()'))
+ execute('tabmove -2')
+ eq(3, eval('tabpagenr()'))
execute('tabmove +4')
- eq(8, eval('tabpagenr()'))
+ eq(7, eval('tabpagenr()'))
execute('tabmove')
eq(10, eval('tabpagenr()'))
execute('tabmove -20')
eq(1, eval('tabpagenr()'))
execute('tabmove +20')
eq(10, eval('tabpagenr()'))
+ execute('0tabmove')
+ eq(1, eval('tabpagenr()'))
+ execute('$tabmove')
+ eq(10, eval('tabpagenr()'))
+ execute('tabmove 0')
+ eq(1, eval('tabpagenr()'))
+ execute('tabmove $')
+ eq(10, eval('tabpagenr()'))
execute('3tabmove')
eq(4, eval('tabpagenr()'))
execute('7tabmove 5')
- eq(6, eval('tabpagenr()'))
+ eq(5, eval('tabpagenr()'))
execute('let a="No error caught."')
execute('try')
execute('tabmove foo')
diff --git a/test/functional/legacy/063_match_and_matchadd_spec.lua b/test/functional/legacy/063_match_and_matchadd_spec.lua
index a354d4d328..23b4f4551b 100644
--- a/test/functional/legacy/063_match_and_matchadd_spec.lua
+++ b/test/functional/legacy/063_match_and_matchadd_spec.lua
@@ -89,7 +89,11 @@ describe('063: Test for ":match", "matchadd()" and related functions', function(
execute("call clearmatches()")
execute("call setmatches(ml)")
eq(ml, eval('getmatches()'))
+
+ -- Check that "setmatches()" can correctly restore the matches from matchaddpos()
execute("call clearmatches()")
+ execute("call setmatches(ml)")
+ eq(ml, eval('getmatches()'))
-- Check that "setmatches()" will not add two matches with the same ID. The
-- expected behaviour (for now) is to add the first match but not the
diff --git a/test/functional/legacy/eval_spec.lua b/test/functional/legacy/eval_spec.lua
index 05cd73dbd4..1c81b47ed6 100644
--- a/test/functional/legacy/eval_spec.lua
+++ b/test/functional/legacy/eval_spec.lua
@@ -3,7 +3,7 @@
local helpers = require('test.functional.helpers')
local feed, insert, source = helpers.feed, helpers.insert, helpers.source
local clear, execute, expect = helpers.clear, helpers.execute, helpers.expect
-local eq, eval, wait, write_file = helpers.eq, helpers.eval, helpers.wait, helpers.write_file
+local eq, eval, write_file = helpers.eq, helpers.eval, helpers.write_file
local function has_clipboard()
clear()
diff --git a/test/functional/legacy/glob2regpat_spec.lua b/test/functional/legacy/glob2regpat_spec.lua
index 357128bcb6..0492143616 100644
--- a/test/functional/legacy/glob2regpat_spec.lua
+++ b/test/functional/legacy/glob2regpat_spec.lua
@@ -1,7 +1,7 @@
-- Tests for signs
local helpers = require('test.functional.helpers')
-local clear, execute, expect = helpers.clear, helpers.execute, helpers.expect
+local clear, execute = helpers.clear, helpers.execute
local eq, neq, eval = helpers.eq, helpers.neq, helpers.eval
describe('glob2regpat()', function()
diff --git a/test/functional/legacy/increment_spec.lua b/test/functional/legacy/increment_spec.lua
new file mode 100644
index 0000000000..6139ec0b67
--- /dev/null
+++ b/test/functional/legacy/increment_spec.lua
@@ -0,0 +1,723 @@
+-- Tests for using Ctrl-A/Ctrl-X on visual selections
+
+local helpers = require('test.functional.helpers')
+local source, execute = helpers.source, helpers.execute
+local call, clear = helpers.call, helpers.clear
+local eq, nvim = helpers.eq, helpers.meths
+
+describe('Ctrl-A/Ctrl-X on visual selections', function()
+
+ before_each(function()
+ clear()
+ source([=[
+ " 1) Ctrl-A on visually selected number
+ " Text:
+ " foobar-10
+ " Expected:
+ " 1) Ctrl-A on start of line:
+ " foobar-9
+ " 2) Ctrl-A on visually selected "-10":
+ " foobar-9
+ " 3) Ctrl-A on visually selected "10":
+ " foobar-11
+ " 4) Ctrl-X on visually selected "-10"
+ " foobar-11
+ " 5) Ctrl-X on visually selected "10"
+ " foobar-9
+ func Test_visual_increment_01()
+ call setline(1, repeat(["foobaar-10"], 5))
+
+ call cursor(1, 1)
+ exec "norm! \<C-A>"
+ call assert_equal("foobaar-9", getline('.'))
+ call assert_equal([0, 1, 9, 0], getpos('.'))
+
+ call cursor(2, 1)
+ exec "norm! f-v$\<C-A>"
+ call assert_equal("foobaar-9", getline('.'))
+ call assert_equal([0, 2, 8, 0], getpos('.'))
+
+ call cursor(3, 1)
+ exec "norm! f1v$\<C-A>"
+ call assert_equal("foobaar-11", getline('.'))
+ call assert_equal([0, 3, 9, 0], getpos('.'))
+
+ call cursor(4, 1)
+ exec "norm! f-v$\<C-X>"
+ call assert_equal("foobaar-11", getline('.'))
+ call assert_equal([0, 4, 8, 0], getpos('.'))
+
+ call cursor(5, 1)
+ exec "norm! f1v$\<C-X>"
+ call assert_equal("foobaar-9", getline('.'))
+ call assert_equal([0, 5, 9, 0], getpos('.'))
+ endfunc
+
+ " 2) Ctrl-A on visually selected lines
+ " Text:
+ " 10
+ " 20
+ " 30
+ " 40
+ "
+ " Expected:
+ " 1) Ctrl-A on visually selected lines:
+ " 11
+ " 21
+ " 31
+ " 41
+ "
+ " 2) Ctrl-X on visually selected lines:
+ " 9
+ " 19
+ " 29
+ " 39
+ func Test_visual_increment_02()
+ call setline(1, ["10", "20", "30", "40"])
+ exec "norm! GV3k$\<C-A>"
+ call assert_equal(["11", "21", "31", "41"], getline(1, '$'))
+ call assert_equal([0, 1, 1, 0], getpos('.'))
+
+ call setline(1, ["10", "20", "30", "40"])
+ exec "norm! GV3k$\<C-X>"
+ call assert_equal(["9", "19", "29", "39"], getline(1, '$'))
+ call assert_equal([0, 1, 1, 0], getpos('.'))
+ endfunc
+
+ " 3) g Ctrl-A on visually selected lines, with non-numbers in between
+ " Text:
+ " 10
+ "
+ " 20
+ "
+ " 30
+ "
+ " 40
+ "
+ " Expected:
+ " 1) 2 g Ctrl-A on visually selected lines:
+ " 12
+ "
+ " 24
+ "
+ " 36
+ "
+ " 48
+ " 2) 2 g Ctrl-X on visually selected lines
+ " 8
+ "
+ " 16
+ "
+ " 24
+ "
+ " 32
+ func Test_visual_increment_03()
+ call setline(1, ["10", "", "20", "", "30", "", "40"])
+ exec "norm! GV6k2g\<C-A>"
+ call assert_equal(["12", "", "24", "", "36", "", "48"], getline(1, '$'))
+ call assert_equal([0, 1, 1, 0], getpos('.'))
+
+ call setline(1, ["10", "", "20", "", "30", "", "40"])
+ exec "norm! GV6k2g\<C-X>"
+ call assert_equal(["8", "", "16", "", "24", "", "32"], getline(1, '$'))
+ call assert_equal([0, 1, 1, 0], getpos('.'))
+ endfunc
+
+ " 4) Ctrl-A on non-number
+ " Text:
+ " foobar-10
+ " Expected:
+ " 1) visually select foobar:
+ " foobar-10
+ func Test_visual_increment_04()
+ call setline(1, ["foobar-10"])
+ exec "norm! vf-\<C-A>"
+ call assert_equal(["foobar-10"], getline(1, '$'))
+ " NOTE: I think this is correct behavior...
+ call assert_equal([0, 1, 1, 0], getpos('.'))
+ endfunc
+
+ " 5) g<Ctrl-A> on letter
+ " Test:
+ " a
+ " a
+ " a
+ " a
+ " Expected:
+ " 1) g Ctrl-A on visually selected lines
+ " b
+ " c
+ " d
+ " e
+ func Test_visual_increment_05()
+ set nrformats+=alpha
+ call setline(1, repeat(["a"], 4))
+ exec "norm! GV3kg\<C-A>"
+ call assert_equal(["b", "c", "d", "e"], getline(1, '$'))
+ call assert_equal([0, 1, 1, 0], getpos('.'))
+ endfunc
+
+ " 6) g<Ctrl-A> on letter
+ " Test:
+ " z
+ " z
+ " z
+ " z
+ " Expected:
+ " 1) g Ctrl-X on visually selected lines
+ " y
+ " x
+ " w
+ " v
+ func Test_visual_increment_06()
+ set nrformats+=alpha
+ call setline(1, repeat(["z"], 4))
+ exec "norm! GV3kg\<C-X>"
+ call assert_equal(["y", "x", "w", "v"], getline(1, '$'))
+ call assert_equal([0, 1, 1, 0], getpos('.'))
+ endfunc
+
+ " 7) <Ctrl-A> on letter
+ " Test:
+ " 2
+ " 1
+ " 0
+ " -1
+ " -2
+ "
+ " Expected:
+ " 1) Ctrl-A on visually selected lines
+ " 3
+ " 2
+ " 1
+ " 0
+ " -1
+ "
+ " 2) Ctrl-X on visually selected lines
+ " 1
+ " 0
+ " -1
+ " -2
+ " -3
+ func Test_visual_increment_07()
+ call setline(1, ["2", "1", "0", "-1", "-2"])
+ exec "norm! GV4k\<C-A>"
+ call assert_equal(["3", "2", "1", "0", "-1"], getline(1, '$'))
+ call assert_equal([0, 1, 1, 0], getpos('.'))
+
+ call setline(1, ["2", "1", "0", "-1", "-2"])
+ exec "norm! GV4k\<C-X>"
+ call assert_equal(["1", "0", "-1", "-2", "-3"], getline(1, '$'))
+ call assert_equal([0, 1, 1, 0], getpos('.'))
+ endfunc
+
+ " 8) Block increment on 0x9
+ " Text:
+ " 0x9
+ " 0x9
+ " Expected:
+ " 1) Ctrl-A on visually block selected region (cursor at beginning):
+ " 0xa
+ " 0xa
+ " 2) Ctrl-A on visually block selected region (cursor at end)
+ " 0xa
+ " 0xa
+ func Test_visual_increment_08()
+ call setline(1, repeat(["0x9"], 2))
+ exec "norm! \<C-V>j$\<C-A>"
+ call assert_equal(["0xa", "0xa"], getline(1, '$'))
+ call assert_equal([0, 1, 1, 0], getpos('.'))
+
+ call setline(1, repeat(["0x9"], 2))
+ exec "norm! gg$\<C-V>+\<C-A>"
+ call assert_equal(["0xa", "0xa"], getline(1, '$'))
+ call assert_equal([0, 1, 1, 0], getpos('.'))
+ endfunc
+
+ " 9) Increment and redo
+ " Text:
+ " 2
+ " 2
+ "
+ " 3
+ " 3
+ "
+ " Expected:
+ " 1) 2 Ctrl-A on first 2 visually selected lines
+ " 4
+ " 4
+ " 2) redo (.) on 3
+ " 5
+ " 5
+ func Test_visual_increment_09()
+ call setline(1, ["2", "2", "", "3", "3", ""])
+ exec "norm! ggVj2\<C-A>"
+ call assert_equal(["4", "4", "", "3", "3", ""], getline(1, '$'))
+ call assert_equal([0, 1, 1, 0], getpos('.'))
+
+ exec "norm! 3j."
+ call assert_equal(["4", "4", "", "5", "5", ""], getline(1, '$'))
+ call assert_equal([0, 4, 1, 0], getpos('.'))
+ endfunc
+
+ " 10) sequentially decrement 1
+ " Text:
+ " 1
+ " 1
+ " 1
+ " 1
+ " Expected:
+ " 1) g Ctrl-X on visually selected lines
+ " 0
+ " -1
+ " -2
+ " -3
+ func Test_visual_increment_10()
+ call setline(1, repeat(["1"], 4))
+ exec "norm! GV3kg\<C-X>"
+ call assert_equal(["0", "-1", "-2", "-3"], getline(1, '$'))
+ call assert_equal([0, 1, 1, 0], getpos('.'))
+ endfunc
+
+ " 11) visually block selected indented lines
+ " Text:
+ " 1
+ " 1
+ " 1
+ " 1
+ " Expexted:
+ " 1) g Ctrl-A on block selected indented lines
+ " 2
+ " 1
+ " 3
+ " 4
+ func Test_visual_increment_11()
+ call setline(1, [" 1", "1", " 1", " 1"])
+ exec "norm! f1\<C-V>3jg\<C-A>"
+ call assert_equal([" 2", "1", " 3", " 4"], getline(1, '$'))
+ call assert_equal([0, 1, 5, 0], getpos('.'))
+ endfunc
+
+ " 12) visually selected several columns
+ " Text:
+ " 0 0
+ " 0 0
+ " 0 0
+ " Expected:
+ " 1) 'v' select last zero and first zeroes
+ " 0 1
+ " 1 0
+ " 1 0
+ func Test_visual_increment_12()
+ call setline(1, repeat(["0 0"], 3))
+ exec "norm! $v++\<C-A>"
+ call assert_equal(["0 1", "1 0", "1 0"], getline(1, '$'))
+ call assert_equal([0, 1, 3, 0], getpos('.'))
+ endfunc
+
+ " 13) visually selected part of columns
+ " Text:
+ " max: 100px
+ " max: 200px
+ " max: 300px
+ " max: 400px
+ " Expected:
+ " 1) 'v' on first two numbers Ctrl-A
+ " max: 110px
+ " max: 220px
+ " max: 330px
+ " max: 400px
+ " 2) 'v' on first two numbers Ctrl-X
+ " max: 90px
+ " max: 190px
+ " max: 290px
+ " max: 400px
+ func Test_visual_increment_13()
+ call setline(1, ["max: 100px", "max: 200px", "max: 300px", "max: 400px"])
+ exec "norm! f1\<C-V>l2j\<C-A>"
+ call assert_equal(["max: 110px", "max: 210px", "max: 310px", "max: 400px"], getline(1, '$'))
+ call assert_equal([0, 1, 6, 0], getpos('.'))
+
+ call setline(1, ["max: 100px", "max: 200px", "max: 300px", "max: 400px"])
+ exec "norm! ggf1\<C-V>l2j\<C-X>"
+ call assert_equal(["max: 90px", "max: 190px", "max: 290px", "max: 400px"], getline(1, '$'))
+ call assert_equal([0, 1, 6, 0], getpos('.'))
+ endfunc
+
+ " 14) redo in block mode
+ " Text:
+ " 1 1
+ " 1 1
+ " Expected:
+ " 1) Ctrl-a on first column, redo on second column
+ " 2 2
+ " 2 2
+ func Test_visual_increment_14()
+ call setline(1, repeat(["1 1"], 2))
+ exec "norm! G\<C-V>k\<C-A>w."
+ call assert_equal(["2 2", "2 2"], getline(1, '$'))
+ call assert_equal([0, 1, 3, 0], getpos('.'))
+ endfunc
+
+ " 15) block select single numbers
+ " Text:
+ " 101
+ " Expected:
+ " 1) Ctrl-a on visually selected zero
+ " 111
+ func Test_visual_increment_15()
+ call setline(1, ["101"])
+ exec "norm! lv\<C-A>"
+ call assert_equal(["111"], getline(1, '$'))
+ call assert_equal([0, 1, 2, 0], getpos('.'))
+ endfunc
+
+ " 16) increment right aligned numbers
+ " Text:
+ " 1
+ " 19
+ " 119
+ " Expected:
+ " 1) Ctrl-a on line selected region
+ " 2
+ " 20
+ " 120
+ func Test_visual_increment_16()
+ call setline(1, [" 1", " 19", " 119"])
+ exec "norm! VG\<C-A>"
+ call assert_equal([" 2", " 20", " 120"], getline(1, '$'))
+ call assert_equal([0, 1, 1, 0], getpos('.'))
+ endfunc
+
+ " 17) block-wise increment and redo
+ " Text:
+ " 100
+ " 1
+ "
+ " 100
+ " 1
+ "
+ " Expected:
+ " 1) Ctrl-V j $ on first block, afterwards '.' on second
+ " 101
+ " 2
+ "
+ " 101
+ " 2
+ func Test_visual_increment_17()
+ call setline(1, [" 100", " 1", "", " 100", " 1"])
+ exec "norm! \<C-V>j$\<C-A>2j."
+ call assert_equal([" 101", " 2", "", " 101", " 1"], getline(1, '$'))
+ call assert_equal([0, 3, 1, 0], getpos('.'))
+ endfunc
+
+ " 18) repeat of g<Ctrl-a>
+ " Text:
+ " 0
+ " 0
+ " 0
+ " 0
+ "
+ " Expected:
+ " 1) V 4j g<ctrl-a>, repeat twice afterwards with .
+ " 3
+ " 6
+ " 9
+ " 12
+ func Test_visual_increment_18()
+ call setline(1, repeat(["0"], 4))
+ exec "norm! GV3kg\<C-A>"
+ exec "norm! .."
+ call assert_equal(["3", "6", "9", "12"], getline(1, '$'))
+ call assert_equal([0, 1, 1, 0], getpos('.'))
+ endfunc
+
+ " 19) increment on number with nrformat including alpha
+ " Text:
+ " 1
+ " 1a
+ "
+ " Expected:
+ " 1) <Ctrl-V>j$ <ctrl-a>
+ " 2
+ " 2a
+ func Test_visual_increment_19()
+ set nrformats+=alpha
+ call setline(1, ["1", "1a"])
+ exec "norm! \<C-V>G$\<C-A>"
+ call assert_equal(["2", "2a"], getline(1, '$'))
+ call assert_equal([0, 1, 1, 0], getpos('.'))
+ endfunc
+
+ " 20) increment a single letter
+ " Text:
+ " a
+ "
+ " Expected:
+ " 1) <Ctrl-a> and cursor is on a
+ " b
+ func Test_visual_increment_20()
+ set nrformats+=alpha
+ call setline(1, ["a"])
+ exec "norm! \<C-A>"
+ call assert_equal(["b"], getline(1, '$'))
+ call assert_equal([0, 1, 1, 0], getpos('.'))
+ endfunc
+
+ " 21) block-wise increment on part of hexadecimal
+ " Text:
+ " 0x123456
+ "
+ " Expected:
+ " 1) Ctrl-V f3 <ctrl-a>
+ " 0x124456
+ func Test_visual_increment_21()
+ call setline(1, ["0x123456"])
+ exec "norm! \<C-V>f3\<C-A>"
+ call assert_equal(["0x124456"], getline(1, '$'))
+ call assert_equal([0, 1, 1, 0], getpos('.'))
+ endfunc
+
+ " 22) Block increment on 0b0
+ " Text:
+ " 0b1
+ " 0b1
+ " Expected:
+ " 1) Ctrl-A on visually block selected region (cursor at beginning):
+ " 0b10
+ " 0b10
+ " 2) Ctrl-A on visually block selected region (cursor at end)
+ " 0b10
+ " 0b10
+ func Test_visual_increment_22()
+ call setline(1, repeat(["0b1"], 2))
+ exec "norm! \<C-V>j$\<C-A>"
+ call assert_equal(repeat(["0b10"], 2), getline(1, '$'))
+ call assert_equal([0, 1, 1, 0], getpos('.'))
+
+ call setline(1, repeat(["0b1"], 2))
+ exec "norm! $\<C-V>+\<C-A>"
+ call assert_equal(repeat(["0b10"], 2), getline(1, '$'))
+ call assert_equal([0, 1, 1, 0], getpos('.'))
+ endfunc
+
+ " 23) block-wise increment on part of binary
+ " Text:
+ " 0b1001
+ "
+ " Expected:
+ " 1) Ctrl-V 5l <ctrl-a>
+ " 0b1011
+ func Test_visual_increment_23()
+ call setline(1, ["0b1001"])
+ exec "norm! \<C-V>4l\<C-A>"
+ call assert_equal(["0b1011"], getline(1, '$'))
+ call assert_equal([0, 1, 1, 0], getpos('.'))
+ endfunc
+
+ " 24) increment hexadecimal
+ " Text:
+ " 0x0b1001
+ "
+ " Expected:
+ " 1) <ctrl-a>
+ " 0x0b1002
+ func Test_visual_increment_24()
+ call setline(1, ["0x0b1001"])
+ exec "norm! \<C-V>$\<C-A>"
+ call assert_equal(["0x0b1002"], getline(1, '$'))
+ call assert_equal([0, 1, 1, 0], getpos('.'))
+ endfunc
+
+ " 25) increment binary with nrformats including alpha
+ " Text:
+ " 0b1001a
+ "
+ " Expected:
+ " 1) <ctrl-a>
+ " 0b1010a
+ func Test_visual_increment_25()
+ set nrformats+=alpha
+ call setline(1, ["0b1001a"])
+ exec "norm! \<C-V>$\<C-A>"
+ call assert_equal(["0b1010a"], getline(1, '$'))
+ call assert_equal([0, 1, 1, 0], getpos('.'))
+ endfunc
+
+ " 26) increment binary with 32 bits
+ " Text:
+ " 0b11111111111111111111111111111110
+ "
+ " Expected:
+ " 1) <ctrl-a>
+ " 0b11111111111111111111111111111111
+ func Test_visual_increment_26()
+ set nrformats+=alpha
+ call setline(1, ["0b11111111111111111111111111111110"])
+ exec "norm! \<C-V>$\<C-A>"
+ call assert_equal(["0b11111111111111111111111111111111"], getline(1, '$'))
+ call assert_equal([0, 1, 1, 0], getpos('.'))
+ set nrformats-=alpha
+ endfunc
+
+ " 27) increment with 'rightreft', if supported
+ func Test_visual_increment_27()
+ if exists('+rightleft')
+ set rightleft
+ call setline(1, ["1234 56"])
+
+ exec "norm! $\<C-A>"
+ call assert_equal(["1234 57"], getline(1, '$'))
+ call assert_equal([0, 1, 7, 0], getpos('.'))
+
+ exec "norm! \<C-A>"
+ call assert_equal(["1234 58"], getline(1, '$'))
+ call assert_equal([0, 1, 7, 0], getpos('.'))
+ set norightleft
+ endif
+ endfunc
+
+ " Tab code and linewise-visual inc/dec
+ func Test_visual_increment_28()
+ call setline(1, ["x\<TAB>10", "\<TAB>-1"])
+ exec "norm! Vj\<C-A>"
+ call assert_equal(["x\<TAB>11", "\<TAB>0"], getline(1, '$'))
+ call assert_equal([0, 1, 1, 0], getpos('.'))
+
+ call setline(1, ["x\<TAB>10", "\<TAB>-1"])
+ exec "norm! ggVj\<C-X>"
+ call assert_equal(["x\<TAB>9", "\<TAB>-2"], getline(1, '$'))
+ call assert_equal([0, 1, 1, 0], getpos('.'))
+ endfunc
+
+ " Tab code and linewise-visual inc/dec with 'nrformats'+=alpha
+ func Test_visual_increment_29()
+ set nrformats+=alpha
+ call setline(1, ["x\<TAB>10", "\<TAB>-1"])
+ exec "norm! Vj\<C-A>"
+ call assert_equal(["y\<TAB>10", "\<TAB>0"], getline(1, '$'))
+ call assert_equal([0, 1, 1, 0], getpos('.'))
+
+ call setline(1, ["x\<TAB>10", "\<TAB>-1"])
+ exec "norm! ggVj\<C-X>"
+ call assert_equal(["w\<TAB>10", "\<TAB>-2"], getline(1, '$'))
+ call assert_equal([0, 1, 1, 0], getpos('.'))
+ endfunc
+
+ " Tab code and character-visual inc/dec
+ func Test_visual_increment_30()
+ call setline(1, ["x\<TAB>10", "\<TAB>-1"])
+ exec "norm! f1vjf1\<C-A>"
+ call assert_equal(["x\<TAB>11", "\<TAB>0"], getline(1, '$'))
+ call assert_equal([0, 1, 3, 0], getpos('.'))
+
+ call setline(1, ["x\<TAB>10", "\<TAB>-1"])
+ exec "norm! ggf1vjf1\<C-X>"
+ call assert_equal(["x\<TAB>9", "\<TAB>-2"], getline(1, '$'))
+ call assert_equal([0, 1, 3, 0], getpos('.'))
+ endfunc
+
+ " Tab code and blockwise-visual inc/dec
+ func Test_visual_increment_31()
+ call setline(1, ["x\<TAB>10", "\<TAB>-1"])
+ exec "norm! f1\<C-V>jl\<C-A>"
+ call assert_equal(["x\<TAB>11", "\<TAB>0"], getline(1, '$'))
+ call assert_equal([0, 1, 3, 0], getpos('.'))
+
+ call setline(1, ["x\<TAB>10", "\<TAB>-1"])
+ exec "norm! ggf1\<C-V>jl\<C-X>"
+ call assert_equal(["x\<TAB>9", "\<TAB>-2"], getline(1, '$'))
+ call assert_equal([0, 1, 3, 0], getpos('.'))
+ endfunc
+
+ " Tab code and blockwise-visual decrement with 'linebreak' and 'showbreak'
+ func Test_visual_increment_32()
+ 28vnew dummy_31
+ set linebreak showbreak=+
+ call setline(1, ["x\<TAB>\<TAB>\<TAB>10", "\<TAB>\<TAB>\<TAB>\<TAB>-1"])
+ exec "norm! ggf0\<C-V>jg_\<C-X>"
+ call assert_equal(["x\<TAB>\<TAB>\<TAB>1-1", "\<TAB>\<TAB>\<TAB>\<TAB>-2"], getline(1, '$'))
+ call assert_equal([0, 1, 6, 0], getpos('.'))
+ bwipe!
+ endfunc
+
+ " Tab code and blockwise-visual increment with $
+ func Test_visual_increment_33()
+ call setline(1, ["\<TAB>123", "456"])
+ exec "norm! gg0\<C-V>j$\<C-A>"
+ call assert_equal(["\<TAB>124", "457"], getline(1, '$'))
+ call assert_equal([0, 1, 1, 0], getpos('.'))
+ endfunc
+
+ " Tab code and blockwise-visual increment and redo
+ func Test_visual_increment_34()
+ call setline(1, ["\<TAB>123", " 456789"])
+ exec "norm! gg0\<C-V>j\<C-A>"
+ call assert_equal(["\<TAB>123", " 457789"], getline(1, '$'))
+ call assert_equal([0, 1, 1, 0], getpos('.'))
+
+ exec "norm! .."
+ call assert_equal(["\<TAB>123", " 459789"], getline(1, '$'))
+ call assert_equal([0, 1, 1, 0], getpos('.'))
+ endfunc
+
+ " Tab code, spaces and character-visual increment and redo
+ func Test_visual_increment_35()
+ call setline(1, ["\<TAB>123", " 123", "\<TAB>123", "\<TAB>123"])
+ exec "norm! ggvjf3\<C-A>..."
+ call assert_equal(["\<TAB>127", " 127", "\<TAB>123", "\<TAB>123"], getline(1, '$'))
+ call assert_equal([0, 1, 2, 0], getpos('.'))
+ endfunc
+
+ " Tab code, spaces and blockwise-visual increment and redo
+ func Test_visual_increment_36()
+ call setline(1, [" 123", "\<TAB>456789"])
+ exec "norm! G0\<C-V>kl\<C-A>"
+ call assert_equal([" 123", "\<TAB>556789"], getline(1, '$'))
+ call assert_equal([0, 1, 1, 0], getpos('.'))
+
+ exec "norm! ..."
+ call assert_equal([" 123", "\<TAB>856789"], getline(1, '$'))
+ call assert_equal([0, 1, 1, 0], getpos('.'))
+ endfunc
+
+ " block-wise increment and dot-repeat
+ " Text:
+ " 1 23
+ " 4 56
+ "
+ " Expected:
+ " 1) f2 Ctrl-V jl <ctrl-a>, repeat twice afterwards with .
+ " 1 26
+ " 4 59
+ "
+ " Try with and without indent.
+ func Test_visual_increment_37()
+ call setline(1, [" 1 23", " 4 56"])
+ exec "norm! ggf2\<C-V>jl\<C-A>.."
+ call assert_equal([" 1 26", " 4 59"], getline(1, 2))
+
+ call setline(1, ["1 23", "4 56"])
+ exec "norm! ggf2\<C-V>jl\<C-A>.."
+ call assert_equal(["1 26", "4 59"], getline(1, 2))
+ endfunc
+
+ " Check redo after the normal mode increment
+ func Test_visual_increment_38()
+ exec "norm! i10\<ESC>5\<C-A>."
+ call assert_equal(["20"], getline(1, '$'))
+ call assert_equal([0, 1, 2, 0], getpos('.'))
+ endfunc
+ ]=])
+ end)
+
+ for i = 1, 38 do
+ local id = string.format('%02d', i)
+
+ it('works on Test ' .. id, function()
+ execute('set nrformats&vi') -- &vi makes Vim compatible
+ call('Test_visual_increment_' .. id)
+ eq({}, nvim.get_vvar('errors'))
+ end)
+ end
+end)
diff --git a/test/functional/legacy/quickfix_spec.lua b/test/functional/legacy/quickfix_spec.lua
index 7a9958b949..88f86815b3 100644
--- a/test/functional/legacy/quickfix_spec.lua
+++ b/test/functional/legacy/quickfix_spec.lua
@@ -1,8 +1,7 @@
-- Test for the quickfix commands.
local helpers = require('test.functional.helpers')
-local insert, source = helpers.insert, helpers.source
-local clear, expect = helpers.clear, helpers.expect
+local source, clear = helpers.source, helpers.clear
describe('helpgrep', function()
before_each(clear)
diff --git a/test/functional/legacy/set_spec.lua b/test/functional/legacy/set_spec.lua
new file mode 100644
index 0000000000..f81fcd3700
--- /dev/null
+++ b/test/functional/legacy/set_spec.lua
@@ -0,0 +1,15 @@
+-- Tests for :set
+
+local helpers = require('test.functional.helpers')
+local clear, execute, eval, eq =
+ helpers.clear, helpers.execute, helpers.eval, helpers.eq
+
+describe(':set', function()
+ before_each(clear)
+
+ it('recognizes a trailing comma with +=', function()
+ execute('set wildignore=*.png,')
+ execute('set wildignore+=*.jpg')
+ eq('*.png,*.jpg', eval('&wildignore'))
+ end)
+end)
diff --git a/test/functional/legacy/textobjects_spec.lua b/test/functional/legacy/textobjects_spec.lua
new file mode 100644
index 0000000000..1e8e0b0bcb
--- /dev/null
+++ b/test/functional/legacy/textobjects_spec.lua
@@ -0,0 +1,61 @@
+local helpers = require('test.functional.helpers')
+local call = helpers.call
+local clear = helpers.clear
+local execute = helpers.execute
+local expect = helpers.expect
+local source = helpers.source
+
+describe('Text object', function()
+ before_each(function()
+ clear()
+ execute('set shada=')
+ source([[
+ function SelectionOut(data)
+ new
+ call setline(1, a:data)
+ call setreg('"', '')
+ normal! ggfrmavi)y
+ $put =getreg('\"')
+ call setreg('"', '')
+ normal! `afbmavi)y
+ $put =getreg('\"')
+ call setreg('"', '')
+ normal! `afgmavi)y
+ $put =getreg('\"')
+ endfunction
+ ]])
+ end)
+
+ it('Test for vi) without cpo-M', function()
+ execute('set cpo-=M')
+ call('SelectionOut', '(red \\(blue) green)')
+
+ expect([[
+ (red \(blue) green)
+ red \(blue
+ red \(blue
+ ]])
+ end)
+
+ it('Test for vi) with cpo-M #1', function()
+ execute('set cpo+=M')
+ call('SelectionOut', '(red \\(blue) green)')
+
+ expect([[
+ (red \(blue) green)
+ red \(blue) green
+ blue
+ red \(blue) green]])
+ end)
+
+ it('Test for vi) with cpo-M #2', function()
+ execute('set cpo+=M')
+ call('SelectionOut', '(red (blue\\) green)')
+
+ expect([[
+ (red (blue\) green)
+ red (blue\) green
+ blue\
+ red (blue\) green]])
+ end)
+end)
diff --git a/test/functional/ui/highlight_spec.lua b/test/functional/ui/highlight_spec.lua
index f9b112e464..6a89b0983d 100644
--- a/test/functional/ui/highlight_spec.lua
+++ b/test/functional/ui/highlight_spec.lua
@@ -14,15 +14,6 @@ describe('color scheme compatibility', function()
request('vim_set_option', 't_Co', '88')
eq('88', request('vim_eval', '&t_Co'))
end)
-
- it('emulates gui_running when a rgb UI is attached', function()
- eq(0, request('vim_eval', 'has("gui_running")'))
- local screen = Screen.new()
- screen:attach()
- eq(1, request('vim_eval', 'has("gui_running")'))
- screen:detach()
- eq(0, request('vim_eval', 'has("gui_running")'))
- end)
end)
diff --git a/test/functional/ui/mouse_spec.lua b/test/functional/ui/mouse_spec.lua
index b3992c4a89..da9d6a0cd2 100644
--- a/test/functional/ui/mouse_spec.lua
+++ b/test/functional/ui/mouse_spec.lua
@@ -1,7 +1,8 @@
local helpers = require('test.functional.helpers')
local Screen = require('test.functional.ui.screen')
-local clear, feed, nvim = helpers.clear, helpers.feed, helpers.nvim
+local clear, feed, meths = helpers.clear, helpers.feed, helpers.meths
local insert, execute = helpers.insert, helpers.execute
+local eq, funcs = helpers.eq, helpers.funcs
describe('Mouse input', function()
local screen
@@ -13,11 +14,11 @@ describe('Mouse input', function()
before_each(function()
clear()
- nvim('set_option', 'mouse', 'a')
- nvim('set_option', 'listchars', 'eol:$')
+ meths.set_option('mouse', 'a')
+ meths.set_option('listchars', 'eol:$')
-- set mouset to very high value to ensure that even in valgrind/travis,
-- nvim will still pick multiple clicks
- nvim('set_option', 'mouset', 5000)
+ meths.set_option('mouset', 5000)
screen = Screen.new(25, 5)
screen:attach()
screen:set_default_attr_ids({
@@ -58,31 +59,149 @@ describe('Mouse input', function()
]])
end)
- it('left click in tabline switches to tab', function()
+ describe('tabline', function()
local tab_attrs = {
tab = { background=Screen.colors.LightGrey, underline=true },
sel = { bold=true },
fill = { reverse=true }
}
- execute('%delete')
- insert('this is foo')
- execute('silent file foo | tabnew | file bar')
- insert('this is bar')
- screen:expect([[
- {tab: + foo }{sel: + bar }{fill: }{tab:X}|
- this is ba^r |
- ~ |
- ~ |
- |
- ]], tab_attrs)
- feed('<LeftMouse><4,0>')
- screen:expect([[
- {sel: + foo }{tab: + bar }{fill: }{tab:X}|
- this is fo^o |
- ~ |
- ~ |
- |
- ]], tab_attrs)
+
+ it('left click in default tabline (position 4) switches to tab', function()
+ execute('%delete')
+ insert('this is foo')
+ execute('silent file foo | tabnew | file bar')
+ insert('this is bar')
+ screen:expect([[
+ {tab: + foo }{sel: + bar }{fill: }{tab:X}|
+ this is ba^r |
+ ~ |
+ ~ |
+ |
+ ]], tab_attrs)
+ feed('<LeftMouse><4,0>')
+ screen:expect([[
+ {sel: + foo }{tab: + bar }{fill: }{tab:X}|
+ this is fo^o |
+ ~ |
+ ~ |
+ |
+ ]], tab_attrs)
+ end)
+
+ it('left click in default tabline (position 24) closes tab', function()
+ meths.set_option('hidden', true)
+ execute('%delete')
+ insert('this is foo')
+ execute('silent file foo | tabnew | file bar')
+ insert('this is bar')
+ screen:expect([[
+ {tab: + foo }{sel: + bar }{fill: }{tab:X}|
+ this is ba^r |
+ ~ |
+ ~ |
+ |
+ ]], tab_attrs)
+ feed('<LeftMouse><24,0>')
+ screen:expect([[
+ this is fo^o |
+ ~ |
+ ~ |
+ ~ |
+ |
+ ]], tab_attrs)
+ end)
+
+ it('double click in default tabline (position 4) opens new tab', function()
+ meths.set_option('hidden', true)
+ execute('%delete')
+ insert('this is foo')
+ execute('silent file foo | tabnew | file bar')
+ insert('this is bar')
+ screen:expect([[
+ {tab: + foo }{sel: + bar }{fill: }{tab:X}|
+ this is ba^r |
+ ~ |
+ ~ |
+ |
+ ]], tab_attrs)
+ feed('<2-LeftMouse><4,0>')
+ screen:expect([[
+ {sel: Name] }{tab: + foo + bar }{fill: }{tab:X}|
+ ^ |
+ ~ |
+ ~ |
+ |
+ ]], tab_attrs)
+ end)
+
+ describe('%@ label', function()
+ before_each(function()
+ execute([[
+ function Test(...)
+ let g:reply = a:000
+ return copy(a:000) " Check for memory leaks: return should be freed
+ endfunction
+ ]])
+ execute([[
+ function Test2(...)
+ return call('Test', a:000 + [2])
+ endfunction
+ ]])
+ meths.set_option('tabline', '%@Test@test%X-%5@Test2@test2')
+ meths.set_option('showtabline', 2)
+ screen:expect([[
+ {fill:test-test2 }|
+ mouse |
+ support and selectio^n |
+ ~ |
+ |
+ ]], tab_attrs)
+ meths.set_var('reply', {})
+ end)
+
+ local check_reply = function(expected)
+ eq(expected, meths.get_var('reply'))
+ meths.set_var('reply', {})
+ end
+
+ local test_click = function(name, click_str, click_num, mouse_button,
+ modifiers)
+ it(name .. ' works', function()
+ eq(1, funcs.has('tablineat'))
+ feed(click_str .. '<3,0>')
+ check_reply({0, click_num, mouse_button, modifiers})
+ feed(click_str .. '<4,0>')
+ check_reply({})
+ feed(click_str .. '<6,0>')
+ check_reply({5, click_num, mouse_button, modifiers, 2})
+ feed(click_str .. '<13,0>')
+ check_reply({5, click_num, mouse_button, modifiers, 2})
+ end)
+ end
+
+ test_click('single left click', '<LeftMouse>', 1, 'l', ' ')
+ test_click('shifted single left click', '<S-LeftMouse>', 1, 'l', 's ')
+ test_click('shifted single left click with alt modifier',
+ '<S-A-LeftMouse>', 1, 'l', 's a ')
+ test_click('shifted single left click with alt and ctrl modifiers',
+ '<S-C-A-LeftMouse>', 1, 'l', 'sca ')
+ -- <C-RightMouse> does not work
+ test_click('shifted single right click with alt modifier',
+ '<S-A-RightMouse>', 1, 'r', 's a ')
+ -- Modifiers do not work with MiddleMouse
+ test_click('shifted single middle click with alt and ctrl modifiers',
+ '<MiddleMouse>', 1, 'm', ' ')
+ -- Modifiers do not work with N-*Mouse
+ test_click('double left click', '<2-LeftMouse>', 2, 'l', ' ')
+ test_click('triple left click', '<3-LeftMouse>', 3, 'l', ' ')
+ test_click('quadruple left click', '<4-LeftMouse>', 4, 'l', ' ')
+ test_click('double right click', '<2-RightMouse>', 2, 'r', ' ')
+ test_click('triple right click', '<3-RightMouse>', 3, 'r', ' ')
+ test_click('quadruple right click', '<4-RightMouse>', 4, 'r', ' ')
+ test_click('double middle click', '<2-MiddleMouse>', 2, 'm', ' ')
+ test_click('triple middle click', '<3-MiddleMouse>', 3, 'm', ' ')
+ test_click('quadruple middle click', '<4-MiddleMouse>', 4, 'm', ' ')
+ end)
end)
it('left drag changes visual selection', function()
@@ -211,7 +330,7 @@ describe('Mouse input', function()
end)
it('ctrl + left click will search for a tag', function()
- nvim('set_option', 'tags', './non-existent-tags-file')
+ meths.set_option('tags', './non-existent-tags-file')
feed('<C-LeftMouse><0,0>')
screen:expect([[
E433: No tags file |
diff --git a/test/unit/strings_spec.lua b/test/unit/strings_spec.lua
index b310ccb541..e935d2af6a 100644
--- a/test/unit/strings_spec.lua
+++ b/test/unit/strings_spec.lua
@@ -1,7 +1,6 @@
local helpers = require("test.unit.helpers")
local cimport = helpers.cimport
-local internalize = helpers.internalize
local eq = helpers.eq
local ffi = helpers.ffi
local to_cstr = helpers.to_cstr