diff options
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(¶ms); + // If opened more than one window, start editing files in the other + // windows. + edit_buffers(¶ms, 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 -zOj: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 |